Enable user to query vdpa device information. $ vdpa dev add mgmtdev vdpasim_net name foo2 Show the newly created vdpa device by its name: $ vdpa dev show foo2 foo2: type network mgmtdev vdpasim_net vendor_id 0 max_vqs 2 max_vq_size 256 $ vdpa dev show foo2 -jp { "dev": { "foo2": { "type": "network", "mgmtdev": "vdpasim_net", "vendor_id": 0, "max_vqs": 2, "max_vq_size": 256 } } } Signed-off-by: Parav Pandit <parav@nvidia.com> Reviewed-by: Eli Cohen <elic@nvidia.com> Reviewed-by: Jason Wang <jasowang@redhat.com> Link: https://lore.kernel.org/r/20210105103203.82508-6-parav@nvidia.com Including a memory leak fix:
Unified · Split
| @@ -478,6 +478,131 @@ dev_err: · 477 unmodified lines | |||
| 478 | return err; | 478 | return err; |
| 479 | } | 479 | } |
| 480 | 480 | ||
| 481 | static int | ||
| 482 | vdpa_dev_fill(struct vdpa_device *vdev, struct sk_buff *msg, u32 portid, u32 seq, | ||
| 483 | int flags, struct netlink_ext_ack *extack) | ||
| 484 | { | ||
| 485 | u16 max_vq_size; | ||
| 486 | u32 device_id; | ||
| 487 | u32 vendor_id; | ||
| 488 | void *hdr; | ||
| 489 | int err; | ||
| 490 | |||
| 491 | hdr = genlmsg_put(msg, portid, seq, &vdpa_nl_family, flags, VDPA_CMD_DEV_NEW); | ||
| 492 | if (!hdr) | ||
| 493 | return -EMSGSIZE; | ||
| 494 | |||
| 495 | err = vdpa_nl_mgmtdev_handle_fill(msg, vdev->mdev); | ||
| 496 | if (err) | ||
| 497 | goto msg_err; | ||
| 498 | |||
| 499 | device_id = vdev->config->get_device_id(vdev); | ||
| 500 | vendor_id = vdev->config->get_vendor_id(vdev); | ||
| 501 | max_vq_size = vdev->config->get_vq_num_max(vdev); | ||
| 502 | |||
| 503 | err = -EMSGSIZE; | ||
| 504 | if (nla_put_string(msg, VDPA_ATTR_DEV_NAME, dev_name(&vdev->dev))) | ||
| 505 | goto msg_err; | ||
| 506 | if (nla_put_u32(msg, VDPA_ATTR_DEV_ID, device_id)) | ||
| 507 | goto msg_err; | ||
| 508 | if (nla_put_u32(msg, VDPA_ATTR_DEV_VENDOR_ID, vendor_id)) | ||
| 509 | goto msg_err; | ||
| 510 | if (nla_put_u32(msg, VDPA_ATTR_DEV_MAX_VQS, vdev->nvqs)) | ||
| 511 | goto msg_err; | ||
| 512 | if (nla_put_u16(msg, VDPA_ATTR_DEV_MAX_VQ_SIZE, max_vq_size)) | ||
| 513 | goto msg_err; | ||
| 514 | |||
| 515 | genlmsg_end(msg, hdr); | ||
| 516 | return 0; | ||
| 517 | |||
| 518 | msg_err: | ||
| 519 | genlmsg_cancel(msg, hdr); | ||
| 520 | return err; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int vdpa_nl_cmd_dev_get_doit(struct sk_buff *skb, struct genl_info *info) | ||
| 524 | { | ||
| 525 | struct vdpa_device *vdev; | ||
| 526 | struct sk_buff *msg; | ||
| 527 | const char *devname; | ||
| 528 | struct device *dev; | ||
| 529 | int err; | ||
| 530 | |||
| 531 | if (!info->attrs[VDPA_ATTR_DEV_NAME]) | ||
| 532 | return -EINVAL; | ||
| 533 | devname = nla_data(info->attrs[VDPA_ATTR_DEV_NAME]); | ||
| 534 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
| 535 | if (!msg) | ||
| 536 | return -ENOMEM; | ||
| 537 | |||
| 538 | mutex_lock(&vdpa_dev_mutex); | ||
| 539 | dev = bus_find_device(&vdpa_bus, NULL, devname, vdpa_name_match); | ||
| 540 | if (!dev) { | ||
| 541 | NL_SET_ERR_MSG_MOD(info->extack, "device not found"); | ||
| 542 | err = -ENODEV; | ||
| 543 | goto err; | ||
| 544 | } | ||
| 545 | vdev = container_of(dev, struct vdpa_device, dev); | ||
| 546 | if (!vdev->mdev) { | ||
| 547 | err = -EINVAL; | ||
| 548 | goto mdev_err; | ||
| 549 | } | ||
| 550 | err = vdpa_dev_fill(vdev, msg, info->snd_portid, info->snd_seq, 0, info->extack); | ||
| 551 | if (!err) | ||
| 552 | err = genlmsg_reply(msg, info); | ||
| 553 | mdev_err: | ||
| 554 | put_device(dev); | ||
| 555 | err: | ||
| 556 | mutex_unlock(&vdpa_dev_mutex); | ||
| 557 | if (err) | ||
| 558 | nlmsg_free(msg); | ||
| 559 | return err; | ||
| 560 | } | ||
| 561 | |||
| 562 | struct vdpa_dev_dump_info { | ||
| 563 | struct sk_buff *msg; | ||
| 564 | struct netlink_callback *cb; | ||
| 565 | int start_idx; | ||
| 566 | int idx; | ||
| 567 | }; | ||
| 568 | |||
| 569 | static int vdpa_dev_dump(struct device *dev, void *data) | ||
| 570 | { | ||
| 571 | struct vdpa_device *vdev = container_of(dev, struct vdpa_device, dev); | ||
| 572 | struct vdpa_dev_dump_info *info = data; | ||
| 573 | int err; | ||
| 574 | |||
| 575 | if (!vdev->mdev) | ||
| 576 | return 0; | ||
| 577 | if (info->idx < info->start_idx) { | ||
| 578 | info->idx++; | ||
| 579 | return 0; | ||
| 580 | } | ||
| 581 | err = vdpa_dev_fill(vdev, info->msg, NETLINK_CB(info->cb->skb).portid, | ||
| 582 | info->cb->nlh->nlmsg_seq, NLM_F_MULTI, info->cb->extack); | ||
| 583 | if (err) | ||
| 584 | return err; | ||
| 585 | |||
| 586 | info->idx++; | ||
| 587 | return 0; | ||
| 588 | } | ||
| 589 | |||
| 590 | static int vdpa_nl_cmd_dev_get_dumpit(struct sk_buff *msg, struct netlink_callback *cb) | ||
| 591 | { | ||
| 592 | struct vdpa_dev_dump_info info; | ||
| 593 | |||
| 594 | info.msg = msg; | ||
| 595 | info.cb = cb; | ||
| 596 | info.start_idx = cb->args[0]; | ||
| 597 | info.idx = 0; | ||
| 598 | |||
| 599 | mutex_lock(&vdpa_dev_mutex); | ||
| 600 | bus_for_each_dev(&vdpa_bus, NULL, &info, vdpa_dev_dump); | ||
| 601 | mutex_unlock(&vdpa_dev_mutex); | ||
| 602 | cb->args[0] = info.idx; | ||
| 603 | return msg->len; | ||
| 604 | } | ||
| 605 | |||
| 481 | static const struct nla_policy vdpa_nl_policy[VDPA_ATTR_MAX + 1] = { | 606 | static const struct nla_policy vdpa_nl_policy[VDPA_ATTR_MAX + 1] = { |
| 482 | [VDPA_ATTR_MGMTDEV_BUS_NAME] = { .type = NLA_NUL_STRING }, | 607 | [VDPA_ATTR_MGMTDEV_BUS_NAME] = { .type = NLA_NUL_STRING }, |
| 483 | [VDPA_ATTR_MGMTDEV_DEV_NAME] = { .type = NLA_STRING }, | 608 | [VDPA_ATTR_MGMTDEV_DEV_NAME] = { .type = NLA_STRING }, |
| @@ -503,6 +628,12 @@ static const struct genl_ops vdpa_nl_ops[] = { · 19 unmodified lines | |||
| 503 | .doit = vdpa_nl_cmd_dev_del_set_doit, | 628 | .doit = vdpa_nl_cmd_dev_del_set_doit, |
| 504 | .flags = GENL_ADMIN_PERM, | 629 | .flags = GENL_ADMIN_PERM, |
| 505 | }, | 630 | }, |
| 631 | { | ||
| 632 | .cmd = VDPA_CMD_DEV_GET, | ||
| 633 | .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, | ||
| 634 | .doit = vdpa_nl_cmd_dev_get_doit, | ||
| 635 | .dumpit = vdpa_nl_cmd_dev_get_dumpit, | ||
| 636 | }, | ||
| 506 | }; | 637 | }; |
| 507 | 638 | ||
| 508 | static struct genl_family vdpa_nl_family __ro_after_init = { | 639 | static struct genl_family vdpa_nl_family __ro_after_init = { |
| @@ -16,6 +16,7 @@ enum vdpa_command { · 15 unmodified lines | |||
| 16 | VDPA_CMD_MGMTDEV_GET, /* can dump */ | 16 | VDPA_CMD_MGMTDEV_GET, /* can dump */ |
| 17 | VDPA_CMD_DEV_NEW, | 17 | VDPA_CMD_DEV_NEW, |
| 18 | VDPA_CMD_DEV_DEL, | 18 | VDPA_CMD_DEV_DEL, |
| 19 | VDPA_CMD_DEV_GET, /* can dump */ | ||
| 19 | }; | 20 | }; |
| 20 | 21 | ||
| 21 | enum vdpa_attr { | 22 | enum vdpa_attr { |
| @@ -27,6 +28,10 @@ enum vdpa_attr { · 5 unmodified lines | |||
| 27 | VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES, /* u64 */ | 28 | VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES, /* u64 */ |
| 28 | 29 | ||
| 29 | VDPA_ATTR_DEV_NAME, /* string */ | 30 | VDPA_ATTR_DEV_NAME, /* string */ |
| 31 | VDPA_ATTR_DEV_ID, /* u32 */ | ||
| 32 | VDPA_ATTR_DEV_VENDOR_ID, /* u32 */ | ||
| 33 | VDPA_ATTR_DEV_MAX_VQS, /* u32 */ | ||
| 34 | VDPA_ATTR_DEV_MAX_VQ_SIZE, /* u16 */ | ||
| 30 | 35 | ||
| 31 | /* new attributes must be added above here */ | 36 | /* new attributes must be added above here */ |
| 32 | VDPA_ATTR_MAX, | 37 | VDPA_ATTR_MAX, |