- Fix possible deadlock between vdev_sysfs_process_get_filename() and vdisk_del_device()

- Cleanups



git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@3833 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2011-09-01 18:22:27 +00:00
parent 2eb5d1ea6c
commit 960239ed1e
4 changed files with 35 additions and 8 deletions

View File

@@ -2224,6 +2224,14 @@ struct scst_device {
/* Set, if a strictly serialized cmd is waiting blocked */
unsigned short strictly_serialized_cmd_waiting:1;
/*
* Set, if this device is being unregistered. Useful to let sysfs
* attributes know when they should exit immediatelly to prevent
* possible deadlocks with their device unregistration waiting for
* their kobj last put.
*/
unsigned short dev_unregistering:1;
/**************************************************************/
/*************************************************************

View File

@@ -37,6 +37,7 @@
#include <asm/atomic.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/delay.h>
#ifndef INSIDE_KERNEL_TREE
#include <linux/version.h>
#endif
@@ -4416,9 +4417,24 @@ static int vdev_sysfs_process_get_filename(struct scst_sysfs_work_item *work)
dev = work->dev;
if (mutex_lock_interruptible(&scst_vdisk_mutex) != 0) {
res = -EINTR;
goto out_put;
/*
* Since we have a get() on dev->dev_kobj, we can not simply mutex_lock
* scst_vdisk_mutex, because otherwise we can fall in a deadlock with
* vdisk_del_device(), which is waiting for the last ref to dev_kobj
* under scst_vdisk_mutex.
*/
while (!mutex_trylock(&scst_vdisk_mutex)) {
if ((volatile bool)(dev->dev_unregistering)) {
TRACE_MGMT_DBG("Skipping being unregistered dev %s",
dev->virt_name);
res = -ENOENT;
goto out_put;
}
if (signal_pending(current)) {
res = -EINTR;
goto out_put;
}
msleep(100);
}
virt_dev = dev->dh_priv;

View File

@@ -1006,6 +1006,8 @@ static void scst_unregister_device(struct scsi_device *scsidp)
goto out_unlock;
}
dev->dev_unregistering = 1;
list_del(&dev->dev_list_entry);
scst_dg_dev_remove_by_dev(dev);
@@ -1254,6 +1256,8 @@ void scst_unregister_virtual_device(int id)
goto out_unlock;
}
dev->dev_unregistering = 1;
list_del(&dev->dev_list_entry);
scst_pr_clear_dev(dev);

View File

@@ -522,9 +522,9 @@ int scst_sysfs_queue_wait_work(struct scst_sysfs_work_item *work)
* for the last put during some object unregistration and at the same
* time another queued work is having reference on that object taken and
* waiting for attention from the sysfs thread. Generally, all sysfs
* function calling kobject_get() and then queuing sysfs thread job. For
* instance. This is especially dangerous in read only cases, like
* vdev_sysfs_filename_show().
* functions calling kobject_get() and then queuing sysfs thread job
* affected by this. This is especially dangerous in read only cases,
* like vdev_sysfs_filename_show().
*
* So, to eliminate that deadlock we will create an extra sysfs thread
* for each queued sysfs work. This thread will quit as soon as it will
@@ -548,8 +548,7 @@ int scst_sysfs_queue_wait_work(struct scst_sysfs_work_item *work)
timeout = 5*HZ;
continue;
}
TRACE_MGMT_DBG("Time out waiting for work %p",
work);
TRACE_MGMT_DBG("Time out waiting for work %p", work);
res = -EAGAIN;
goto out_put;
} else if (rc < 0) {