aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2016-12-30 10:13:33 -0500
committerAlex Williamson <alex.williamson@redhat.com>2016-12-30 10:13:33 -0500
commit49550787a90b5bfa44d8dc424d11824dbe21473d (patch)
treefa32ae34a162eab3b96c2f1740aa64af822b5e5f
parent6c38c055cc4c0a5da31873d173b2de3085f43f33 (diff)
vfio-mdev: Fix remove race
Using the mtty mdev sample driver we can generate a remove race by starting one shell that continuously creates mtty devices and several other shells all attempting to remove devices, in my case four remove shells. The fault occurs in mdev_remove_sysfs_files() where the passed type arg is NULL, which suggests we've received a struct device in mdev_device_remove() but it's in some sort of teardown state. The solution here is to make use of the accidentally unused list_head on the mdev_device such that the mdev core keeps a list of all the mdev devices. This allows us to validate that we have a valid mdev before we start removal, remove it from the list to prevent others from working on it, and if the vendor driver refuses to remove, we can re-add it to the list. Cc: Kirti Wankhede <kwankhede@nvidia.com> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
-rw-r--r--drivers/vfio/mdev/mdev_core.c36
1 files changed, 34 insertions, 2 deletions
diff --git a/drivers/vfio/mdev/mdev_core.c b/drivers/vfio/mdev/mdev_core.c
index be1ee89ee917..6bb4d4c469ab 100644
--- a/drivers/vfio/mdev/mdev_core.c
+++ b/drivers/vfio/mdev/mdev_core.c
@@ -27,6 +27,9 @@ static LIST_HEAD(parent_list);
27static DEFINE_MUTEX(parent_list_lock); 27static DEFINE_MUTEX(parent_list_lock);
28static struct class_compat *mdev_bus_compat_class; 28static struct class_compat *mdev_bus_compat_class;
29 29
30static LIST_HEAD(mdev_list);
31static DEFINE_MUTEX(mdev_list_lock);
32
30static int _find_mdev_device(struct device *dev, void *data) 33static int _find_mdev_device(struct device *dev, void *data)
31{ 34{
32 struct mdev_device *mdev; 35 struct mdev_device *mdev;
@@ -316,6 +319,11 @@ int mdev_device_create(struct kobject *kobj, struct device *dev, uuid_le uuid)
316 dev_dbg(&mdev->dev, "MDEV: created\n"); 319 dev_dbg(&mdev->dev, "MDEV: created\n");
317 320
318 mutex_unlock(&parent->lock); 321 mutex_unlock(&parent->lock);
322
323 mutex_lock(&mdev_list_lock);
324 list_add(&mdev->next, &mdev_list);
325 mutex_unlock(&mdev_list_lock);
326
319 return ret; 327 return ret;
320 328
321create_failed: 329create_failed:
@@ -329,12 +337,30 @@ create_err:
329 337
330int mdev_device_remove(struct device *dev, bool force_remove) 338int mdev_device_remove(struct device *dev, bool force_remove)
331{ 339{
332 struct mdev_device *mdev; 340 struct mdev_device *mdev, *tmp;
333 struct parent_device *parent; 341 struct parent_device *parent;
334 struct mdev_type *type; 342 struct mdev_type *type;
335 int ret; 343 int ret;
344 bool found = false;
336 345
337 mdev = to_mdev_device(dev); 346 mdev = to_mdev_device(dev);
347
348 mutex_lock(&mdev_list_lock);
349 list_for_each_entry(tmp, &mdev_list, next) {
350 if (tmp == mdev) {
351 found = true;
352 break;
353 }
354 }
355
356 if (found)
357 list_del(&mdev->next);
358
359 mutex_unlock(&mdev_list_lock);
360
361 if (!found)
362 return -ENODEV;
363
338 type = to_mdev_type(mdev->type_kobj); 364 type = to_mdev_type(mdev->type_kobj);
339 parent = mdev->parent; 365 parent = mdev->parent;
340 mutex_lock(&parent->lock); 366 mutex_lock(&parent->lock);
@@ -342,6 +368,11 @@ int mdev_device_remove(struct device *dev, bool force_remove)
342 ret = mdev_device_remove_ops(mdev, force_remove); 368 ret = mdev_device_remove_ops(mdev, force_remove);
343 if (ret) { 369 if (ret) {
344 mutex_unlock(&parent->lock); 370 mutex_unlock(&parent->lock);
371
372 mutex_lock(&mdev_list_lock);
373 list_add(&mdev->next, &mdev_list);
374 mutex_unlock(&mdev_list_lock);
375
345 return ret; 376 return ret;
346 } 377 }
347 378
@@ -349,7 +380,8 @@ int mdev_device_remove(struct device *dev, bool force_remove)
349 device_unregister(dev); 380 device_unregister(dev);
350 mutex_unlock(&parent->lock); 381 mutex_unlock(&parent->lock);
351 mdev_put_parent(parent); 382 mdev_put_parent(parent);
352 return ret; 383
384 return 0;
353} 385}
354 386
355static int __init mdev_init(void) 387static int __init mdev_init(void)