diff options
| -rw-r--r-- | drivers/vfio/mdev/mdev_core.c | 94 | ||||
| -rw-r--r-- | drivers/vfio/mdev/mdev_private.h | 2 | ||||
| -rw-r--r-- | drivers/vfio/mdev/mdev_sysfs.c | 2 |
3 files changed, 27 insertions, 71 deletions
diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c index 3cc1a05fde1c..0bef0cae1d4b 100644 --- a/drivers/vfio/mdev/mdev_core.c +++ b/drivers/vfio/mdev/mdev_core.c | |||
| @@ -102,55 +102,10 @@ static void mdev_put_parent(struct mdev_parent *parent) | |||
| 102 | kref_put(&parent->ref, mdev_release_parent); | 102 | kref_put(&parent->ref, mdev_release_parent); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | static int mdev_device_create_ops(struct kobject *kobj, | ||
| 106 | struct mdev_device *mdev) | ||
| 107 | { | ||
| 108 | struct mdev_parent *parent = mdev->parent; | ||
| 109 | int ret; | ||
| 110 | |||
| 111 | ret = parent->ops->create(kobj, mdev); | ||
| 112 | if (ret) | ||
| 113 | return ret; | ||
| 114 | |||
| 115 | ret = sysfs_create_groups(&mdev->dev.kobj, | ||
| 116 | parent->ops->mdev_attr_groups); | ||
| 117 | if (ret) | ||
| 118 | parent->ops->remove(mdev); | ||
| 119 | |||
| 120 | return ret; | ||
| 121 | } | ||
| 122 | |||
| 123 | /* | ||
| 124 | * mdev_device_remove_ops gets called from sysfs's 'remove' and when parent | ||
| 125 | * device is being unregistered from mdev device framework. | ||
| 126 | * - 'force_remove' is set to 'false' when called from sysfs's 'remove' which | ||
| 127 | * indicates that if the mdev device is active, used by VMM or userspace | ||
| 128 | * application, vendor driver could return error then don't remove the device. | ||
| 129 | * - 'force_remove' is set to 'true' when called from mdev_unregister_device() | ||
| 130 | * which indicate that parent device is being removed from mdev device | ||
| 131 | * framework so remove mdev device forcefully. | ||
| 132 | */ | ||
| 133 | static int mdev_device_remove_ops(struct mdev_device *mdev, bool force_remove) | ||
| 134 | { | ||
| 135 | struct mdev_parent *parent = mdev->parent; | ||
| 136 | int ret; | ||
| 137 | |||
| 138 | /* | ||
| 139 | * Vendor driver can return error if VMM or userspace application is | ||
| 140 | * using this mdev device. | ||
| 141 | */ | ||
| 142 | ret = parent->ops->remove(mdev); | ||
| 143 | if (ret && !force_remove) | ||
| 144 | return ret; | ||
| 145 | |||
| 146 | sysfs_remove_groups(&mdev->dev.kobj, parent->ops->mdev_attr_groups); | ||
| 147 | return 0; | ||
| 148 | } | ||
| 149 | |||
| 150 | static int mdev_device_remove_cb(struct device *dev, void *data) | 105 | static int mdev_device_remove_cb(struct device *dev, void *data) |
| 151 | { | 106 | { |
| 152 | if (dev_is_mdev(dev)) | 107 | if (dev_is_mdev(dev)) |
| 153 | mdev_device_remove(dev, true); | 108 | mdev_device_remove(dev); |
| 154 | 109 | ||
| 155 | return 0; | 110 | return 0; |
| 156 | } | 111 | } |
| @@ -310,41 +265,43 @@ int mdev_device_create(struct kobject *kobj, | |||
| 310 | 265 | ||
| 311 | mdev->parent = parent; | 266 | mdev->parent = parent; |
| 312 | 267 | ||
| 268 | device_initialize(&mdev->dev); | ||
| 313 | mdev->dev.parent = dev; | 269 | mdev->dev.parent = dev; |
| 314 | mdev->dev.bus = &mdev_bus_type; | 270 | mdev->dev.bus = &mdev_bus_type; |
| 315 | mdev->dev.release = mdev_device_release; | 271 | mdev->dev.release = mdev_device_release; |
| 316 | dev_set_name(&mdev->dev, "%pUl", uuid); | 272 | dev_set_name(&mdev->dev, "%pUl", uuid); |
| 273 | mdev->dev.groups = parent->ops->mdev_attr_groups; | ||
| 274 | mdev->type_kobj = kobj; | ||
| 317 | 275 | ||
| 318 | ret = device_register(&mdev->dev); | 276 | ret = parent->ops->create(kobj, mdev); |
| 319 | if (ret) { | 277 | if (ret) |
| 320 | put_device(&mdev->dev); | 278 | goto ops_create_fail; |
| 321 | goto mdev_fail; | ||
| 322 | } | ||
| 323 | 279 | ||
| 324 | ret = mdev_device_create_ops(kobj, mdev); | 280 | ret = device_add(&mdev->dev); |
| 325 | if (ret) | 281 | if (ret) |
| 326 | goto create_fail; | 282 | goto add_fail; |
| 327 | 283 | ||
| 328 | ret = mdev_create_sysfs_files(&mdev->dev, type); | 284 | ret = mdev_create_sysfs_files(&mdev->dev, type); |
| 329 | if (ret) { | 285 | if (ret) |
| 330 | mdev_device_remove_ops(mdev, true); | 286 | goto sysfs_fail; |
| 331 | goto create_fail; | ||
| 332 | } | ||
| 333 | 287 | ||
| 334 | mdev->type_kobj = kobj; | ||
| 335 | mdev->active = true; | 288 | mdev->active = true; |
| 336 | dev_dbg(&mdev->dev, "MDEV: created\n"); | 289 | dev_dbg(&mdev->dev, "MDEV: created\n"); |
| 337 | 290 | ||
| 338 | return 0; | 291 | return 0; |
| 339 | 292 | ||
| 340 | create_fail: | 293 | sysfs_fail: |
| 341 | device_unregister(&mdev->dev); | 294 | device_del(&mdev->dev); |
| 295 | add_fail: | ||
| 296 | parent->ops->remove(mdev); | ||
| 297 | ops_create_fail: | ||
| 298 | put_device(&mdev->dev); | ||
| 342 | mdev_fail: | 299 | mdev_fail: |
| 343 | mdev_put_parent(parent); | 300 | mdev_put_parent(parent); |
| 344 | return ret; | 301 | return ret; |
| 345 | } | 302 | } |
| 346 | 303 | ||
| 347 | int mdev_device_remove(struct device *dev, bool force_remove) | 304 | int mdev_device_remove(struct device *dev) |
| 348 | { | 305 | { |
| 349 | struct mdev_device *mdev, *tmp; | 306 | struct mdev_device *mdev, *tmp; |
| 350 | struct mdev_parent *parent; | 307 | struct mdev_parent *parent; |
| @@ -373,16 +330,15 @@ int mdev_device_remove(struct device *dev, bool force_remove) | |||
| 373 | mutex_unlock(&mdev_list_lock); | 330 | mutex_unlock(&mdev_list_lock); |
| 374 | 331 | ||
| 375 | type = to_mdev_type(mdev->type_kobj); | 332 | type = to_mdev_type(mdev->type_kobj); |
| 333 | mdev_remove_sysfs_files(dev, type); | ||
| 334 | device_del(&mdev->dev); | ||
| 376 | parent = mdev->parent; | 335 | parent = mdev->parent; |
| 336 | ret = parent->ops->remove(mdev); | ||
| 337 | if (ret) | ||
| 338 | dev_err(&mdev->dev, "Remove failed: err=%d\n", ret); | ||
| 377 | 339 | ||
| 378 | ret = mdev_device_remove_ops(mdev, force_remove); | 340 | /* Balances with device_initialize() */ |
| 379 | if (ret) { | 341 | put_device(&mdev->dev); |
| 380 | mdev->active = true; | ||
| 381 | return ret; | ||
| 382 | } | ||
| 383 | |||
| 384 | mdev_remove_sysfs_files(dev, type); | ||
| 385 | device_unregister(dev); | ||
| 386 | mdev_put_parent(parent); | 342 | mdev_put_parent(parent); |
| 387 | 343 | ||
| 388 | return 0; | 344 | return 0; |
diff --git a/drivers/vfio/mdev/mdev_private.h b/drivers/vfio/mdev/mdev_private.h index 36cbbdb754de..924ed2274941 100644 --- a/drivers/vfio/mdev/mdev_private.h +++ b/drivers/vfio/mdev/mdev_private.h | |||
| @@ -60,6 +60,6 @@ void mdev_remove_sysfs_files(struct device *dev, struct mdev_type *type); | |||
| 60 | 60 | ||
| 61 | int mdev_device_create(struct kobject *kobj, | 61 | int mdev_device_create(struct kobject *kobj, |
| 62 | struct device *dev, const guid_t *uuid); | 62 | struct device *dev, const guid_t *uuid); |
| 63 | int mdev_device_remove(struct device *dev, bool force_remove); | 63 | int mdev_device_remove(struct device *dev); |
| 64 | 64 | ||
| 65 | #endif /* MDEV_PRIVATE_H */ | 65 | #endif /* MDEV_PRIVATE_H */ |
diff --git a/drivers/vfio/mdev/mdev_sysfs.c b/drivers/vfio/mdev/mdev_sysfs.c index cbf94b8165ea..9f774b91d275 100644 --- a/drivers/vfio/mdev/mdev_sysfs.c +++ b/drivers/vfio/mdev/mdev_sysfs.c | |||
| @@ -236,7 +236,7 @@ static ssize_t remove_store(struct device *dev, struct device_attribute *attr, | |||
| 236 | if (val && device_remove_file_self(dev, attr)) { | 236 | if (val && device_remove_file_self(dev, attr)) { |
| 237 | int ret; | 237 | int ret; |
| 238 | 238 | ||
| 239 | ret = mdev_device_remove(dev, false); | 239 | ret = mdev_device_remove(dev); |
| 240 | if (ret) { | 240 | if (ret) { |
| 241 | device_create_file(dev, attr); | 241 | device_create_file(dev, attr); |
| 242 | return ret; | 242 | return ret; |
