aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/devlink.c
diff options
context:
space:
mode:
authorAlex Vesker <valex@mellanox.com>2018-07-12 08:13:14 -0400
committerDavid S. Miller <davem@davemloft.net>2018-07-12 20:37:13 -0400
commit4e54795a27f56102649f121a34b8445e42f79ccd (patch)
treecbf6cf97506f1ee17fd9aabfbd41ac8210cda9a0 /net/core/devlink.c
parent866319bb9437614407ca36f8b16f89ab77a6a831 (diff)
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 <valex@mellanox.com> Signed-off-by: Jiri Pirko <jiri@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/devlink.c')
-rw-r--r--net/core/devlink.c182
1 files changed, 182 insertions, 0 deletions
diff --git a/net/core/devlink.c b/net/core/devlink.c
index fc0836371a71..e5118dba6bb4 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -3388,6 +3388,181 @@ static int devlink_nl_cmd_region_del(struct sk_buff *skb,
3388 return 0; 3388 return 0;
3389} 3389}
3390 3390
3391static 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
3415nla_put_failure:
3416 nla_nest_cancel(msg, chunk_attr);
3417 return err;
3418}
3419
3420#define DEVLINK_REGION_READ_CHUNK_SIZE 256
3421
3422static 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
3469static 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
3557nla_put_failure:
3558 genlmsg_cancel(skb, hdr);
3559out_unlock:
3560 mutex_unlock(&devlink->lock);
3561 mutex_unlock(&devlink_mutex);
3562out:
3563 return 0;
3564}
3565
3391static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = { 3566static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
3392 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING }, 3567 [DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING },
3393 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING }, 3568 [DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING },
@@ -3626,6 +3801,13 @@ static const struct genl_ops devlink_nl_ops[] = {
3626 .flags = GENL_ADMIN_PERM, 3801 .flags = GENL_ADMIN_PERM,
3627 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK, 3802 .internal_flags = DEVLINK_NL_FLAG_NEED_DEVLINK,
3628 }, 3803 },
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 },
3629}; 3811};
3630 3812
3631static struct genl_family devlink_nl_family __ro_after_init = { 3813static struct genl_family devlink_nl_family __ro_after_init = {