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 | 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 | 606 | static const struct nla_policy vdpa_nl_policy[VDPA_ATTR_MAX + 1] = { |
| 482 | 607 | [VDPA_ATTR_MGMTDEV_BUS_NAME] = { .type = NLA_NUL_STRING }, |
| 483 | 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 | 628 | .doit = vdpa_nl_cmd_dev_del_set_doit, |
| 504 | 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 | 639 | static struct genl_family vdpa_nl_family __ro_after_init = { |
| @@ -16,6 +16,7 @@ enum vdpa_command { · 15 unmodified lines | ||
| 16 | 16 | VDPA_CMD_MGMTDEV_GET, /* can dump */ |
| 17 | 17 | VDPA_CMD_DEV_NEW, |
| 18 | 18 | VDPA_CMD_DEV_DEL, |
| 19 | + VDPA_CMD_DEV_GET, /* can dump */ | |
| 19 | 20 | }; |
| 20 | 21 | |
| 21 | 22 | enum vdpa_attr { |
| @@ -27,6 +28,10 @@ enum vdpa_attr { · 5 unmodified lines | ||
| 27 | 28 | VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES, /* u64 */ |
| 28 | 29 | |
| 29 | 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 | 36 | /* new attributes must be added above here */ |
| 32 | 37 | VDPA_ATTR_MAX, |