On 10/27/2016 05:29 AM, Kirti Wankhede wrote: > +int mdev_register_device(struct device *dev, const struct parent_ops *ops) > +{ > + int ret; > + struct parent_device *parent; > + > + /* check for mandatory ops */ > + if (!ops || !ops->create || !ops->remove || !ops->supported_type_groups) > + return -EINVAL; > + > + dev = get_device(dev); > + if (!dev) > + return -EINVAL; > + > + mutex_lock(&parent_list_lock); > + > + /* Check for duplicate */ > + parent = __find_parent_device(dev); > + if (parent) { > + ret = -EEXIST; > + goto add_dev_err; > + } > + > + parent = kzalloc(sizeof(*parent), GFP_KERNEL); > + if (!parent) { > + ret = -ENOMEM; > + goto add_dev_err; > + } > + > + kref_init(&parent->ref); > + mutex_init(&parent->lock); > + > + parent->dev = dev; > + parent->ops = ops; > + > + ret = parent_create_sysfs_files(parent); > + if (ret) { > + mutex_unlock(&parent_list_lock); > + mdev_put_parent(parent); > + return ret; > + } > + > + ret = class_compat_create_link(mdev_bus_compat_class, dev, NULL); > + if (ret) > + dev_warn(dev, "Failed to create compatibility class link\n"); > + Hi Kirti, Like I replied to previous version: http://www.spinics.net/lists/kvm/msg139331.html You can always check if mdev_bus_compat_class already registered here, and register it if not yet. Same logic should be adopted to mdev_init. Current implementation will simply panic if configured as builtin, which is rare but far from impossible. -- Thanks, Jike > + list_add(&parent->next, &parent_list); > + mutex_unlock(&parent_list_lock); > + > + dev_info(dev, "MDEV: Registered\n"); > + return 0; > + > +add_dev_err: > + mutex_unlock(&parent_list_lock); > + put_device(dev); > + return ret; > +} > +EXPORT_SYMBOL(mdev_register_device); > + > +/* > + * mdev_unregister_device : Unregister a parent device > + * @dev: device structure representing parent device. > + * > + * Remove device from list of registered parent devices. Give a chance to free > + * existing mediated devices for given device. > + */ > + > +void mdev_unregister_device(struct device *dev) > +{ > + struct parent_device *parent; > + bool force_remove = true; > + > + mutex_lock(&parent_list_lock); > + parent = __find_parent_device(dev); > + > + if (!parent) { > + mutex_unlock(&parent_list_lock); > + return; > + } > + dev_info(dev, "MDEV: Unregistering\n"); > + > + list_del(&parent->next); > + class_compat_remove_link(mdev_bus_compat_class, dev, NULL); > + > + device_for_each_child(dev, (void *)&force_remove, > + mdev_device_remove_cb); > + > + parent_remove_sysfs_files(parent); > + > + mutex_unlock(&parent_list_lock); > + mdev_put_parent(parent); > +} > +EXPORT_SYMBOL(mdev_unregister_device); > + > +static void mdev_device_release(struct device *dev) > +{ > + struct mdev_device *mdev = to_mdev_device(dev); > + > + dev_dbg(&mdev->dev, "MDEV: destroying\n"); > + kfree(mdev); > +} > + > +int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid) > +{ > + int ret; > + struct mdev_device *mdev; > + struct parent_device *parent; > + struct mdev_type *type = to_mdev_type(kobj); > + > + parent = mdev_get_parent(type->parent); > + if (!parent) > + return -EINVAL; > + > + mutex_lock(&parent->lock); > + > + /* Check for duplicate */ > + if (mdev_device_exist(parent, uuid)) { > + ret = -EEXIST; > + goto create_err; > + } > + > + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); > + if (!mdev) { > + ret = -ENOMEM; > + goto create_err; > + } > + > + memcpy(&mdev->uuid, &uuid, sizeof(uuid_le)); > + mdev->parent = parent; > + kref_init(&mdev->ref); > + > + mdev->dev.parent = dev; > + mdev->dev.bus = &mdev_bus_type; > + mdev->dev.release = mdev_device_release; > + dev_set_name(&mdev->dev, "%pUl", uuid.b); > + > + ret = device_register(&mdev->dev); > + if (ret) { > + put_device(&mdev->dev); > + goto create_err; > + } > + > + ret = mdev_device_create_ops(kobj, mdev); > + if (ret) > + goto create_failed; > + > + ret = mdev_create_sysfs_files(&mdev->dev, type); > + if (ret) { > + mdev_device_remove_ops(mdev, true); > + goto create_failed; > + } > + > + mdev->type_kobj = kobj; > + dev_dbg(&mdev->dev, "MDEV: created\n"); > + > + mutex_unlock(&parent->lock); > + return ret; > + > +create_failed: > + device_unregister(&mdev->dev); > + > +create_err: > + mutex_unlock(&parent->lock); > + mdev_put_parent(parent); > + return ret; > +} > + > +int mdev_device_remove(struct device *dev, bool force_remove) > +{ > + struct mdev_device *mdev; > + struct parent_device *parent; > + struct mdev_type *type; > + int ret; > + > + mdev = to_mdev_device(dev); > + type = to_mdev_type(mdev->type_kobj); > + parent = mdev->parent; > + mutex_lock(&parent->lock); > + > + ret = mdev_device_remove_ops(mdev, force_remove); > + if (ret) { > + mutex_unlock(&parent->lock); > + return ret; > + } > + > + mdev_remove_sysfs_files(dev, type); > + device_unregister(dev); > + mutex_unlock(&parent->lock); > + mdev_put_parent(parent); > + return ret; > +} > + > +static int __init mdev_init(void) > +{ > + int ret; > + > + ret = mdev_bus_register(); > + if (ret) { > + pr_err("Failed to register mdev bus\n"); > + return ret; > + } > + > + mdev_bus_compat_class = class_compat_register("mdev_bus"); > + if (!mdev_bus_compat_class) { > + mdev_bus_unregister(); > + return -ENOMEM; > + } > + > + /* > + * Attempt to load known vfio_mdev. This gives us a working environment > + * without the user needing to explicitly load vfio_mdev driver. > + */ > + request_module_nowait("vfio_mdev"); > + > + return ret; > +} > + > +static void __exit mdev_exit(void) > +{ > + class_compat_unregister(mdev_bus_compat_class); > + mdev_bus_unregister(); > +} -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html