Commit 1248dc00 authored by David S. Miller's avatar David S. Miller

Merge branch 'devlink-kernel-region-snapshot-id-allocation'

Jakub Kicinski says:

====================
devlink: kernel region snapshot id allocation

currently users have to find a free snapshot id to pass
to the kernel when they are requesting a snapshot to be
taken.

This set extends the kernel so it can allocate the id
on its own and send it back to user space in a response.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 39d01050 aebbd7df
...@@ -14,6 +14,10 @@ Region snapshots are collected by the driver, and can be accessed via read ...@@ -14,6 +14,10 @@ Region snapshots are collected by the driver, and can be accessed via read
or dump commands. This allows future analysis on the created snapshots. or dump commands. This allows future analysis on the created snapshots.
Regions may optionally support triggering snapshots on demand. Regions may optionally support triggering snapshots on demand.
Snapshot identifiers are scoped to the devlink instance, not a region.
All snapshots with the same snapshot id within a devlink instance
correspond to the same event.
The major benefit to creating a region is to provide access to internal The major benefit to creating a region is to provide access to internal
address regions that are otherwise inaccessible to the user. address regions that are otherwise inaccessible to the user.
...@@ -23,7 +27,9 @@ states, but see also :doc:`devlink-health` ...@@ -23,7 +27,9 @@ states, but see also :doc:`devlink-health`
Regions may optionally support capturing a snapshot on demand via the Regions may optionally support capturing a snapshot on demand via the
``DEVLINK_CMD_REGION_NEW`` netlink message. A driver wishing to allow ``DEVLINK_CMD_REGION_NEW`` netlink message. A driver wishing to allow
requested snapshots must implement the ``.snapshot`` callback for the region requested snapshots must implement the ``.snapshot`` callback for the region
in its ``devlink_region_ops`` structure. in its ``devlink_region_ops`` structure. If snapshot id is not set in
the ``DEVLINK_CMD_REGION_NEW`` request kernel will allocate one and send
the snapshot information to user space.
example usage example usage
------------- -------------
...@@ -45,7 +51,8 @@ example usage ...@@ -45,7 +51,8 @@ example usage
$ devlink region del pci/0000:00:05.0/cr-space snapshot 1 $ devlink region del pci/0000:00:05.0/cr-space snapshot 1
# Request an immediate snapshot, if supported by the region # Request an immediate snapshot, if supported by the region
$ devlink region new pci/0000:00:05.0/cr-space snapshot 5 $ devlink region new pci/0000:00:05.0/cr-space
pci/0000:00:05.0/cr-space: snapshot 5
# Dump a snapshot: # Dump a snapshot:
$ devlink region dump pci/0000:00:05.0/fw-health snapshot 1 $ devlink region dump pci/0000:00:05.0/fw-health snapshot 1
......
...@@ -3716,24 +3716,26 @@ static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink, ...@@ -3716,24 +3716,26 @@ static int devlink_nl_region_fill(struct sk_buff *msg, struct devlink *devlink,
return err; return err;
} }
static void devlink_nl_region_notify(struct devlink_region *region, static struct sk_buff *
devlink_nl_region_notify_build(struct devlink_region *region,
struct devlink_snapshot *snapshot, struct devlink_snapshot *snapshot,
enum devlink_command cmd) enum devlink_command cmd, u32 portid, u32 seq)
{ {
struct devlink *devlink = region->devlink; struct devlink *devlink = region->devlink;
struct sk_buff *msg; struct sk_buff *msg;
void *hdr; void *hdr;
int err; int err;
WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
return; return ERR_PTR(-ENOMEM);
hdr = genlmsg_put(msg, 0, 0, &devlink_nl_family, 0, cmd); hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, 0, cmd);
if (!hdr) if (!hdr) {
err = -EMSGSIZE;
goto out_free_msg; goto out_free_msg;
}
err = devlink_nl_put_handle(msg, devlink); err = devlink_nl_put_handle(msg, devlink);
if (err) if (err)
...@@ -3757,15 +3759,30 @@ static void devlink_nl_region_notify(struct devlink_region *region, ...@@ -3757,15 +3759,30 @@ static void devlink_nl_region_notify(struct devlink_region *region,
} }
genlmsg_end(msg, hdr); genlmsg_end(msg, hdr);
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), return msg;
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
return;
out_cancel_msg: out_cancel_msg:
genlmsg_cancel(msg, hdr); genlmsg_cancel(msg, hdr);
out_free_msg: out_free_msg:
nlmsg_free(msg); nlmsg_free(msg);
return ERR_PTR(err);
}
static void devlink_nl_region_notify(struct devlink_region *region,
struct devlink_snapshot *snapshot,
enum devlink_command cmd)
{
struct devlink *devlink = region->devlink;
struct sk_buff *msg;
WARN_ON(cmd != DEVLINK_CMD_REGION_NEW && cmd != DEVLINK_CMD_REGION_DEL);
msg = devlink_nl_region_notify_build(region, snapshot, cmd, 0, 0);
if (IS_ERR(msg))
return;
genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink),
msg, 0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
} }
/** /**
...@@ -4069,6 +4086,8 @@ static int ...@@ -4069,6 +4086,8 @@ static int
devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info) devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
{ {
struct devlink *devlink = info->user_ptr[0]; struct devlink *devlink = info->user_ptr[0];
struct devlink_snapshot *snapshot;
struct nlattr *snapshot_id_attr;
struct devlink_region *region; struct devlink_region *region;
const char *region_name; const char *region_name;
u32 snapshot_id; u32 snapshot_id;
...@@ -4080,11 +4099,6 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info) ...@@ -4080,11 +4099,6 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
return -EINVAL; return -EINVAL;
} }
if (!info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]) {
NL_SET_ERR_MSG_MOD(info->extack, "No snapshot id provided");
return -EINVAL;
}
region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]); region_name = nla_data(info->attrs[DEVLINK_ATTR_REGION_NAME]);
region = devlink_region_get_by_name(devlink, region_name); region = devlink_region_get_by_name(devlink, region_name);
if (!region) { if (!region) {
...@@ -4102,7 +4116,9 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info) ...@@ -4102,7 +4116,9 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
return -ENOSPC; return -ENOSPC;
} }
snapshot_id = nla_get_u32(info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]); snapshot_id_attr = info->attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID];
if (snapshot_id_attr) {
snapshot_id = nla_get_u32(snapshot_id_attr);
if (devlink_region_snapshot_get_by_id(region, snapshot_id)) { if (devlink_region_snapshot_get_by_id(region, snapshot_id)) {
NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use"); NL_SET_ERR_MSG_MOD(info->extack, "The requested snapshot id is already in use");
...@@ -4112,6 +4128,13 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info) ...@@ -4112,6 +4128,13 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
err = __devlink_snapshot_id_insert(devlink, snapshot_id); err = __devlink_snapshot_id_insert(devlink, snapshot_id);
if (err) if (err)
return err; return err;
} else {
err = __devlink_region_snapshot_id_get(devlink, &snapshot_id);
if (err) {
NL_SET_ERR_MSG_MOD(info->extack, "Failed to allocate a new snapshot id");
return err;
}
}
err = region->ops->snapshot(devlink, info->extack, &data); err = region->ops->snapshot(devlink, info->extack, &data);
if (err) if (err)
...@@ -4121,6 +4144,27 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info) ...@@ -4121,6 +4144,27 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
if (err) if (err)
goto err_snapshot_create; goto err_snapshot_create;
if (!snapshot_id_attr) {
struct sk_buff *msg;
snapshot = devlink_region_snapshot_get_by_id(region,
snapshot_id);
if (WARN_ON(!snapshot))
return -EINVAL;
msg = devlink_nl_region_notify_build(region, snapshot,
DEVLINK_CMD_REGION_NEW,
info->snd_portid,
info->snd_seq);
err = PTR_ERR_OR_ZERO(msg);
if (err)
goto err_notify;
err = genlmsg_reply(msg, info);
if (err)
goto err_notify;
}
return 0; return 0;
err_snapshot_create: err_snapshot_create:
...@@ -4128,6 +4172,10 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info) ...@@ -4128,6 +4172,10 @@ devlink_nl_cmd_region_new(struct sk_buff *skb, struct genl_info *info)
err_snapshot_capture: err_snapshot_capture:
__devlink_snapshot_id_decrement(devlink, snapshot_id); __devlink_snapshot_id_decrement(devlink, snapshot_id);
return err; return err;
err_notify:
devlink_region_snapshot_del(region, snapshot);
return err;
} }
static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg, static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
......
...@@ -151,6 +151,19 @@ regions_test() ...@@ -151,6 +151,19 @@ regions_test()
check_region_snapshot_count dummy post-second-delete 2 check_region_snapshot_count dummy post-second-delete 2
sid=$(devlink -j region new $DL_HANDLE/dummy | jq '.[][][][]')
check_err $? "Failed to create a new snapshot with id allocated by the kernel"
check_region_snapshot_count dummy post-first-request 3
devlink region dump $DL_HANDLE/dummy snapshot $sid >> /dev/null
check_err $? "Failed to dump a snapshot with id allocated by the kernel"
devlink region del $DL_HANDLE/dummy snapshot $sid
check_err $? "Failed to delete snapshot with id allocated by the kernel"
check_region_snapshot_count dummy post-first-request 2
log_test "regions test" log_test "regions test"
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment