For special mdev type which can aggregate instances for mdev device,
this extends mdev create interface by allowing extra "aggregate=xxx"
parameter, which is passed to mdev device model to be able to create
bundled number of instances for target mdev device.

v2: create new create_with_instances operator for vendor driver
v3:
- Change parameter name as "aggregate="
- Fix new interface comments.
- Parameter checking for new option, pass UUID string only to
  parse and properly end parameter for kstrtouint() conversion.

Cc: Kirti Wankhede <kwankh...@nvidia.com>
Cc: Alex Williamson <alex.william...@redhat.com>
Cc: Kevin Tian <kevin.t...@intel.com>
Cc: Cornelia Huck <coh...@redhat.com>
Signed-off-by: Zhenyu Wang <zhen...@linux.intel.com>
---
 drivers/vfio/mdev/mdev_core.c    | 21 +++++++++++++++++----
 drivers/vfio/mdev/mdev_private.h |  4 +++-
 drivers/vfio/mdev/mdev_sysfs.c   | 32 ++++++++++++++++++++++++++++----
 include/linux/mdev.h             | 11 +++++++++++
 4 files changed, 59 insertions(+), 9 deletions(-)

diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c
index 0212f0ee8aea..545c52ec7618 100644
--- a/drivers/vfio/mdev/mdev_core.c
+++ b/drivers/vfio/mdev/mdev_core.c
@@ -104,12 +104,17 @@ static inline void mdev_put_parent(struct mdev_parent 
*parent)
 }
 
 static int mdev_device_create_ops(struct kobject *kobj,
-                                 struct mdev_device *mdev)
+                                 struct mdev_device *mdev,
+                                 unsigned int instances)
 {
        struct mdev_parent *parent = mdev->parent;
        int ret;
 
-       ret = parent->ops->create(kobj, mdev);
+       if (instances > 1) {
+               ret = parent->ops->create_with_instances(kobj, mdev,
+                                                        instances);
+       } else
+               ret = parent->ops->create(kobj, mdev);
        if (ret)
                return ret;
 
@@ -276,7 +281,8 @@ static void mdev_device_release(struct device *dev)
        kfree(mdev);
 }
 
-int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
+int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid,
+                      unsigned int instances)
 {
        int ret;
        struct mdev_device *mdev, *tmp;
@@ -287,6 +293,12 @@ int mdev_device_create(struct kobject *kobj, struct device 
*dev, uuid_le uuid)
        if (!parent)
                return -EINVAL;
 
+       if (instances > 1 &&
+           !parent->ops->create_with_instances) {
+               ret = -EINVAL;
+               goto mdev_fail;
+       }
+
        mutex_lock(&mdev_list_lock);
 
        /* Check for duplicate */
@@ -316,6 +328,7 @@ int mdev_device_create(struct kobject *kobj, struct device 
*dev, uuid_le uuid)
        mdev->dev.bus     = &mdev_bus_type;
        mdev->dev.release = mdev_device_release;
        dev_set_name(&mdev->dev, "%pUl", uuid.b);
+       mdev->type_instances = instances;
 
        ret = device_register(&mdev->dev);
        if (ret) {
@@ -323,7 +336,7 @@ int mdev_device_create(struct kobject *kobj, struct device 
*dev, uuid_le uuid)
                goto mdev_fail;
        }
 
-       ret = mdev_device_create_ops(kobj, mdev);
+       ret = mdev_device_create_ops(kobj, mdev, instances);
        if (ret)
                goto create_fail;
 
diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h
index b5819b7d7ef7..e90d295d3927 100644
--- a/drivers/vfio/mdev/mdev_private.h
+++ b/drivers/vfio/mdev/mdev_private.h
@@ -33,6 +33,7 @@ struct mdev_device {
        struct kref ref;
        struct list_head next;
        struct kobject *type_kobj;
+       unsigned int type_instances;
        bool active;
 };
 
@@ -58,7 +59,8 @@ void parent_remove_sysfs_files(struct mdev_parent *parent);
 int  mdev_create_sysfs_files(struct device *dev, struct mdev_type *type);
 void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type);
 
-int  mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le 
uuid);
+int  mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid,
+                       unsigned int instances);
 int  mdev_device_remove(struct device *dev, bool force_remove);
 
 #endif /* MDEV_PRIVATE_H */
diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c
index 249472f05509..aefed0c8891b 100644
--- a/drivers/vfio/mdev/mdev_sysfs.c
+++ b/drivers/vfio/mdev/mdev_sysfs.c
@@ -54,14 +54,21 @@ static const struct sysfs_ops mdev_type_sysfs_ops = {
 static ssize_t create_store(struct kobject *kobj, struct device *dev,
                            const char *buf, size_t count)
 {
-       char *str;
+       char *str, *param, *opt = NULL;
        uuid_le uuid;
        int ret;
+       unsigned int instances = 1;
 
-       if ((count < UUID_STRING_LEN) || (count > UUID_STRING_LEN + 1))
+       if (count < UUID_STRING_LEN)
                return -EINVAL;
 
-       str = kstrndup(buf, count, GFP_KERNEL);
+       if ((param = strnchr(buf, count, ',')) == NULL) {
+               if (count > UUID_STRING_LEN + 1)
+                       return -EINVAL;
+       } else if (param - buf != UUID_STRING_LEN)
+               return -EINVAL;
+
+       str = kstrndup(buf, UUID_STRING_LEN, GFP_KERNEL);
        if (!str)
                return -ENOMEM;
 
@@ -70,7 +77,24 @@ static ssize_t create_store(struct kobject *kobj, struct 
device *dev,
        if (ret)
                return ret;
 
-       ret = mdev_device_create(kobj, dev, uuid);
+       if (param) {
+               opt = kstrndup(param + 1, count - UUID_STRING_LEN - 1,
+                              GFP_KERNEL);
+               if (!opt)
+                       return -ENOMEM;
+               if (strncmp(opt, "aggregate=", 10)) {
+                       kfree(opt);
+                       return -EINVAL;
+               }
+               opt += 10;
+               if (kstrtouint(opt, 10, &instances)) {
+                       kfree(opt);
+                       return -EINVAL;
+               }
+               kfree(opt);
+       }
+
+       ret = mdev_device_create(kobj, dev, uuid, instances);
        if (ret)
                return ret;
 
diff --git a/include/linux/mdev.h b/include/linux/mdev.h
index b6e048e1045f..c12c0bfc5598 100644
--- a/include/linux/mdev.h
+++ b/include/linux/mdev.h
@@ -31,6 +31,14 @@ struct mdev_device;
  *                     @mdev: mdev_device structure on of mediated device
  *                           that is being created
  *                     Returns integer: success (0) or error (< 0)
+ * @create_with_instances: Allocate aggregated instances' resources in parent 
device's
+ *                     driver for a particular mediated device. Optional if 
aggregated
+ *                      resources are not supported.
+ *                     @kobj: kobject of type for which 'create' is called.
+ *                     @mdev: mdev_device structure on of mediated device
+ *                           that is being created
+ *                      @instances: number of instances to aggregate
+ *                     Returns integer: success (0) or error (< 0)
  * @remove:            Called to free resources in parent device's driver for a
  *                     a mediated device. It is mandatory to provide 'remove'
  *                     ops.
@@ -71,6 +79,9 @@ struct mdev_parent_ops {
        struct attribute_group **supported_type_groups;
 
        int     (*create)(struct kobject *kobj, struct mdev_device *mdev);
+       int     (*create_with_instances)(struct kobject *kobj,
+                                        struct mdev_device *mdev,
+                                        unsigned int instances);
        int     (*remove)(struct mdev_device *mdev);
        int     (*open)(struct mdev_device *mdev);
        void    (*release)(struct mdev_device *mdev);
-- 
2.19.1

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list

Reply via email to