Skip to content

Commit 4e54795

Browse files
alexveskerdavem330
authored andcommitted
devlink: Add support for region snapshot read command
Add support for DEVLINK_CMD_REGION_READ_GET used for both reading and dumping region data. Read allows reading from a region specific address for given length. Dump allows reading the full region. If only snapshot ID is provided a snapshot dump will be done. If snapshot ID, Address and Length are provided a snapshot read will done. This is used for both snapshot access and will be used in the same way to access current data on the region. Signed-off-by: Alex Vesker <[email protected]> Signed-off-by: Jiri Pirko <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 866319b commit 4e54795

File tree

2 files changed

+189
-0
lines changed

2 files changed

+189
-0
lines changed

include/uapi/linux/devlink.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ enum devlink_command {
8787
DEVLINK_CMD_REGION_SET,
8888
DEVLINK_CMD_REGION_NEW,
8989
DEVLINK_CMD_REGION_DEL,
90+
DEVLINK_CMD_REGION_READ,
9091

9192
/* add new commands above here */
9293
__DEVLINK_CMD_MAX,
@@ -273,6 +274,12 @@ enum devlink_attr {
273274
DEVLINK_ATTR_REGION_SNAPSHOT, /* nested */
274275
DEVLINK_ATTR_REGION_SNAPSHOT_ID, /* u32 */
275276

277+
DEVLINK_ATTR_REGION_CHUNKS, /* nested */
278+
DEVLINK_ATTR_REGION_CHUNK, /* nested */
279+
DEVLINK_ATTR_REGION_CHUNK_DATA, /* binary */
280+
DEVLINK_ATTR_REGION_CHUNK_ADDR, /* u64 */
281+
DEVLINK_ATTR_REGION_CHUNK_LEN, /* u64 */
282+
276283
/* add new attributes above here, update the policy in devlink.c */
277284

278285
__DEVLINK_ATTR_MAX,

net/core/devlink.c

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3388,6 +3388,181 @@ static int devlink_nl_cmd_region_del(struct sk_buff *skb,
33883388
return 0;
33893389
}
33903390

3391+
static int devlink_nl_cmd_region_read_chunk_fill(struct sk_buff *msg,
3392+
struct devlink *devlink,
3393+
u8 *chunk, u32 chunk_size,
3394+
u64 addr)
3395+
{
3396+
struct nlattr *chunk_attr;
3397+
int err;
3398+
3399+
chunk_attr = nla_nest_start(msg, DEVLINK_ATTR_REGION_CHUNK);
3400+
if (!chunk_attr)
3401+
return -EINVAL;
3402+
3403+
err = nla_put(msg, DEVLINK_ATTR_REGION_CHUNK_DATA, chunk_size, chunk);
3404+
if (err)
3405+
goto nla_put_failure;
3406+
3407+
err = nla_put_u64_64bit(msg, DEVLINK_ATTR_REGION_CHUNK_ADDR, addr,
3408+
DEVLINK_ATTR_PAD);
3409+
if (err)
3410+
goto nla_put_failure;
3411+
3412+
nla_nest_end(msg, chunk_attr);
3413+
return 0;
3414+
3415+
nla_put_failure:
3416+
nla_nest_cancel(msg, chunk_attr);
3417+
return err;
3418+
}
3419+
3420+
#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3421+
3422+
static int devlink_nl_region_read_snapshot_fill(struct sk_buff *skb,
3423+
struct devlink *devlink,
3424+
struct devlink_region *region,
3425+
struct nlattr **attrs,
3426+
u64 start_offset,
3427+
u64 end_offset,
3428+
bool dump,
3429+
u64 *new_offset)
3430+
{
3431+
struct devlink_snapshot *snapshot;
3432+
u64 curr_offset = start_offset;
3433+
u32 snapshot_id;
3434+
int err = 0;
3435+
3436+
*new_offset = start_offset;
3437+
3438+
snapshot_id = nla_get_u32(attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
3439+
snapshot = devlink_region_snapshot_get_by_id(region, snapshot_id);
3440+
if (!snapshot)
3441+
return -EINVAL;
3442+
3443+
if (end_offset > snapshot->data_len || dump)
3444+
end_offset = snapshot->data_len;
3445+
3446+
while (curr_offset < end_offset) {
3447+
u32 data_size;
3448+
u8 *data;
3449+
3450+
if (end_offset - curr_offset < DEVLINK_REGION_READ_CHUNK_SIZE)
3451+
data_size = end_offset - curr_offset;
3452+
else
3453+
data_size = DEVLINK_REGION_READ_CHUNK_SIZE;
3454+
3455+
data = &snapshot->data[curr_offset];
3456+
err = devlink_nl_cmd_region_read_chunk_fill(skb, devlink,
3457+
data, data_size,
3458+
curr_offset);
3459+
if (err)
3460+
break;
3461+
3462+
curr_offset += data_size;
3463+
}
3464+
*new_offset = curr_offset;
3465+
3466+
return err;
3467+
}
3468+
3469+
static int devlink_nl_cmd_region_read_dumpit(struct sk_buff *skb,
3470+
struct netlink_callback *cb)
3471+
{
3472+
u64 ret_offset, start_offset, end_offset = 0;
3473+
struct nlattr *attrs[DEVLINK_ATTR_MAX + 1];
3474+
const struct genl_ops *ops = cb->data;
3475+
struct devlink_region *region;
3476+
struct nlattr *chunks_attr;
3477+
const char *region_name;
3478+
struct devlink *devlink;
3479+
bool dump = true;
3480+
void *hdr;
3481+
int err;
3482+
3483+
start_offset = *((u64 *)&cb->args[0]);
3484+
3485+
err = nlmsg_parse(cb->nlh, GENL_HDRLEN + devlink_nl_family.hdrsize,
3486+
attrs, DEVLINK_ATTR_MAX, ops->policy, NULL);
3487+
if (err)
3488+
goto out;
3489+
3490+
devlink = devlink_get_from_attrs(sock_net(cb->skb->sk), attrs);
3491+
if (IS_ERR(devlink))
3492+
goto out;
3493+
3494+
mutex_lock(&devlink_mutex);
3495+
mutex_lock(&devlink->lock);
3496+
3497+
if (!attrs[DEVLINK_ATTR_REGION_NAME] ||
3498+
!attrs[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
3499+
goto out_unlock;
3500+
3501+
region_name = nla_data(attrs[DEVLINK_ATTR_REGION_NAME]);
3502+
region = devlink_region_get_by_name(devlink, region_name);
3503+
if (!region)
3504+
goto out_unlock;
3505+
3506+
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq,
3507+
&devlink_nl_family, NLM_F_ACK | NLM_F_MULTI,
3508+
DEVLINK_CMD_REGION_READ);
3509+
if (!hdr)
3510+
goto out_unlock;
3511+
3512+
err = devlink_nl_put_handle(skb, devlink);
3513+
if (err)
3514+
goto nla_put_failure;
3515+
3516+
err = nla_put_string(skb, DEVLINK_ATTR_REGION_NAME, region_name);
3517+
if (err)
3518+
goto nla_put_failure;
3519+
3520+
chunks_attr = nla_nest_start(skb, DEVLINK_ATTR_REGION_CHUNKS);
3521+
if (!chunks_attr)
3522+
goto nla_put_failure;
3523+
3524+
if (attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR] &&
3525+
attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]) {
3526+
if (!start_offset)
3527+
start_offset =
3528+
nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3529+
3530+
end_offset = nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_ADDR]);
3531+
end_offset += nla_get_u64(attrs[DEVLINK_ATTR_REGION_CHUNK_LEN]);
3532+
dump = false;
3533+
}
3534+
3535+
err = devlink_nl_region_read_snapshot_fill(skb, devlink,
3536+
region, attrs,
3537+
start_offset,
3538+
end_offset, dump,
3539+
&ret_offset);
3540+
3541+
if (err && err != -EMSGSIZE)
3542+
goto nla_put_failure;
3543+
3544+
/* Check if there was any progress done to prevent infinite loop */
3545+
if (ret_offset == start_offset)
3546+
goto nla_put_failure;
3547+
3548+
*((u64 *)&cb->args[0]) = ret_offset;
3549+
3550+
nla_nest_end(skb, chunks_attr);
3551+
genlmsg_end(skb, hdr);
3552+
mutex_unlock(&devlink->lock);
3553+
mutex_unlock(&devlink_mutex);
3554+
3555+
return skb->len;
3556+
3557+
nla_put_failure:
3558+
genlmsg_cancel(skb, hdr);
3559+
out_unlock:
3560+
mutex_unlock(&devlink->lock);
3561+
mutex_unlock(&devlink_mutex);
3562+
out:
3563+
return 0;
3564+
}
3565+
33913566
static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
33923567
[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
33933568
[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
@@ -3626,6 +3801,13 @@ static const struct genl_ops devlink_nl_ops[] = {
36263801
.flags = GENL_ADMIN_PERM,
36273802
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
36283803
},
3804+
{
3805+
.cmd = DEVLINK_CMD_REGION_READ,
3806+
.dumpit = devlink_nl_cmd_region_read_dumpit,
3807+
.policy = devlink_nl_policy,
3808+
.flags = GENL_ADMIN_PERM,
3809+
.internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
3810+
},
36293811
};
36303812

36313813
static struct genl_family devlink_nl_family __ro_after_init = {

0 commit comments

Comments
 (0)