For special mdev type which can aggregate instances for mdev device, this extends mdev create interface by allowing extra "instances=xxx" parameter, which is passed to mdev device model to be able to create arbitrary bundled number of instances for target mdev device. For created mdev device, also create new sysfs attr "instances" to show. For compatibility, current default instances is 1. Cc: Alex Williamson <alex.williamson@xxxxxxxxxx> Cc: Kirti Wankhede <kwankhede@xxxxxxxxxx> Signed-off-by: Zhenyu Wang <zhenyuw@xxxxxxxxxxxxxxx> --- drivers/gpu/drm/i915/gvt/kvmgt.c | 3 ++- drivers/s390/cio/vfio_ccw_ops.c | 3 ++- drivers/vfio/mdev/mdev_core.c | 11 ++++++--- drivers/vfio/mdev/mdev_private.h | 6 ++++- drivers/vfio/mdev/mdev_sysfs.c | 42 +++++++++++++++++++++++++++----- include/linux/mdev.h | 3 ++- samples/vfio-mdev/mbochs.c | 3 ++- samples/vfio-mdev/mdpy.c | 3 ++- samples/vfio-mdev/mtty.c | 3 ++- 9 files changed, 60 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index df4e4a07db3d..4a543e23b9a0 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -444,7 +444,8 @@ static void kvmgt_put_vfio_device(void *vgpu) vfio_device_put(((struct intel_vgpu *)vgpu)->vdev.vfio_device); } -static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev) +static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev, + unsigned int instances) { struct intel_vgpu *vgpu = NULL; struct intel_vgpu_type *type; diff --git a/drivers/s390/cio/vfio_ccw_ops.c b/drivers/s390/cio/vfio_ccw_ops.c index 41eeb57d68a3..4c37826ec9d0 100644 --- a/drivers/s390/cio/vfio_ccw_ops.c +++ b/drivers/s390/cio/vfio_ccw_ops.c @@ -106,7 +106,8 @@ static struct attribute_group *mdev_type_groups[] = { NULL, }; -static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev) +static int vfio_ccw_mdev_create(struct kobject *kobj, struct mdev_device *mdev, + unsigned int instances) { struct vfio_ccw_private *private = dev_get_drvdata(mdev_parent_dev(mdev)); diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index 0212f0ee8aea..98b0a78e6832 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c @@ -104,12 +104,13 @@ 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); + ret = parent->ops->create(kobj, mdev, instances); if (ret) return ret; @@ -276,7 +277,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; @@ -316,6 +318,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 +326,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..aa0b4b64c503 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; }; @@ -52,13 +53,16 @@ struct mdev_type { #define to_mdev_type(_kobj) \ container_of(_kobj, struct mdev_type, kobj) +#define MDEV_CREATE_OPT_LEN 32 + int parent_create_sysfs_files(struct mdev_parent *parent); 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..5a417a20e774 100644 --- a/drivers/vfio/mdev/mdev_sysfs.c +++ b/drivers/vfio/mdev/mdev_sysfs.c @@ -54,11 +54,15 @@ 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, *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; + + if (count > UUID_STRING_LEN + 1 + MDEV_CREATE_OPT_LEN) return -EINVAL; str = kstrndup(buf, count, GFP_KERNEL); @@ -66,13 +70,31 @@ static ssize_t create_store(struct kobject *kobj, struct device *dev, return -ENOMEM; ret = uuid_le_to_bin(str, &uuid); - kfree(str); - if (ret) + if (ret) { + kfree(str); return ret; + } - ret = mdev_device_create(kobj, dev, uuid); - if (ret) + if (count > UUID_STRING_LEN + 1) { + opt = str + UUID_STRING_LEN; + if (*opt++ != ',' || + strncmp(opt, "instances=", 10)) { + kfree(str); + return -EINVAL; + } + opt += 10; + if (kstrtouint(opt, 10, &instances)) { + kfree(str); + return -EINVAL; + } + } + + ret = mdev_device_create(kobj, dev, uuid, instances); + if (ret) { + kfree(str); return ret; + } + kfree(str); return count; } @@ -246,10 +268,18 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr, return count; } +static ssize_t instances_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct mdev_device *mdev = to_mdev_device(dev); + return sprintf(buf, "%u\n", mdev->type_instances); +} + static DEVICE_ATTR_WO(remove); +static DEVICE_ATTR_RO(instances); static const struct attribute *mdev_device_attrs[] = { &dev_attr_remove.attr, + &dev_attr_instances.attr, NULL, }; diff --git a/include/linux/mdev.h b/include/linux/mdev.h index b6e048e1045f..12d42aa30f81 100644 --- a/include/linux/mdev.h +++ b/include/linux/mdev.h @@ -70,7 +70,8 @@ struct mdev_parent_ops { const struct attribute_group **mdev_attr_groups; struct attribute_group **supported_type_groups; - int (*create)(struct kobject *kobj, struct mdev_device *mdev); + int (*create)(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); diff --git a/samples/vfio-mdev/mbochs.c b/samples/vfio-mdev/mbochs.c index 2960e26c6ea4..8b2a9e98c587 100644 --- a/samples/vfio-mdev/mbochs.c +++ b/samples/vfio-mdev/mbochs.c @@ -432,7 +432,8 @@ static int mbochs_reset(struct mdev_device *mdev) return 0; } -static int mbochs_create(struct kobject *kobj, struct mdev_device *mdev) +static int mbochs_create(struct kobject *kobj, struct mdev_device *mdev, + unsigned int instances) { const struct mbochs_type *type = mbochs_find_type(kobj); struct device *dev = mdev_dev(mdev); diff --git a/samples/vfio-mdev/mdpy.c b/samples/vfio-mdev/mdpy.c index 96e7969c473a..0ec48ea5225a 100644 --- a/samples/vfio-mdev/mdpy.c +++ b/samples/vfio-mdev/mdpy.c @@ -226,7 +226,8 @@ static int mdpy_reset(struct mdev_device *mdev) return 0; } -static int mdpy_create(struct kobject *kobj, struct mdev_device *mdev) +static int mdpy_create(struct kobject *kobj, struct mdev_device *mdev, + unsigned int instances) { const struct mdpy_type *type = mdpy_find_type(kobj); struct device *dev = mdev_dev(mdev); diff --git a/samples/vfio-mdev/mtty.c b/samples/vfio-mdev/mtty.c index 7abb79d8313d..ff2eaffa1155 100644 --- a/samples/vfio-mdev/mtty.c +++ b/samples/vfio-mdev/mtty.c @@ -727,7 +727,8 @@ static ssize_t mdev_access(struct mdev_device *mdev, char *buf, size_t count, return ret; } -int mtty_create(struct kobject *kobj, struct mdev_device *mdev) +int mtty_create(struct kobject *kobj, struct mdev_device *mdev, + unsigned int instances) { struct mdev_state *mdev_state; char name[MTTY_STRING_LEN]; -- 2.18.0.rc2