Fix for possible crash on unload for kernels below 2.6.25

git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1633 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
Vladislav Bolkhovitin
2010-04-20 18:05:16 +00:00
parent ab0d13c09c
commit d27d945c4f
3 changed files with 54 additions and 16 deletions

View File

@@ -2548,6 +2548,25 @@ static int scst_ioc_keeper_thread(void *arg)
return 0;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
static struct kref *scst_alloc_io_context_kref(void)
{
struct kref *io_context_kref;
io_context_kref = kmalloc(sizeof(*io_context_kref), GFP_KERNEL);
if (io_context_kref == NULL) {
PRINT_ERROR("Unable to alloc io_context_kref "
"(size %zd)", sizeof(*io_context_kref));
goto out;
}
kref_init(io_context_kref);
out:
return io_context_kref;
}
#endif
/* scst_mutex supposed to be held */
int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev)
{
@@ -2640,17 +2659,11 @@ int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
else {
struct kref *io_context_kref;
io_context_kref = kmalloc(sizeof(*io_context_kref),
GFP_KERNEL);
io_context_kref = scst_alloc_io_context_kref();
if (io_context_kref == NULL) {
PRINT_ERROR("Unable to alloc io_context_kref "
"(size %zd)", sizeof(*io_context_kref));
res = -ENOMEM;
goto out;
}
kref_init(io_context_kref);
tgt_dev->tgt_dev_cmd_threads.io_context_kref =
io_context_kref;
}
@@ -2674,11 +2687,21 @@ int scst_tgt_dev_setup_threads(struct scst_tgt_dev *tgt_dev)
break;
}
case SCST_THREADS_POOL_SHARED:
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
struct kref *io_context_kref = scst_alloc_io_context_kref();
if (io_context_kref == NULL) {
res = -ENOMEM;
goto out;
}
dev->dev_cmd_threads.io_context_kref = io_context_kref;
#endif
tgt_dev->active_cmd_threads = &dev->dev_cmd_threads;
res = scst_add_threads(tgt_dev->active_cmd_threads, dev, NULL,
tgt_dev->sess->tgt->tgtt->threads_num);
break;
}
default:
PRINT_CRIT_ERROR("Unknown threads pool type %d (dev %s)",
dev->threads_pool_type, dev->virt_name);

View File

@@ -1430,7 +1430,7 @@ int scst_add_threads(struct scst_cmd_threads *cmd_threads,
thr = kmalloc(sizeof(*thr), GFP_KERNEL);
if (!thr) {
res = -ENOMEM;
PRINT_ERROR("fail to allocate thr %d", res);
PRINT_ERROR("Fail to allocate thr %d", res);
goto out_error;
}
@@ -1461,6 +1461,15 @@ int scst_add_threads(struct scst_cmd_threads *cmd_threads,
wake_up_process(thr->cmd_thread);
}
if (cmd_threads != &scst_main_cmd_threads) {
/*
* Wait for io_context gets initialized to avoid possible races
* for it from the sharing it tgt_devs.
*/
while (cmd_threads->io_context == NULL)
msleep(50);
}
res = 0;
out:

View File

@@ -3893,6 +3893,9 @@ int scst_cmd_thread(void *arg)
#else
current->io_context = p_cmd_threads->io_context;
kref_get(p_cmd_threads->io_context_kref);
TRACE_DBG("kref %p, new refcount %d",
p_cmd_threads->io_context_kref,
atomic_read(&p_cmd_threads->io_context_kref->refcount));
#endif
TRACE_MGMT_DBG("Linked IO context %p "
"(p_cmd_threads %p)", p_cmd_threads->io_context,
@@ -3937,16 +3940,19 @@ int scst_cmd_thread(void *arg)
EXTRACHECKS_BUG_ON((p_cmd_threads->nr_threads == 1) &&
!list_empty(&p_cmd_threads->active_cmd_list));
if ((p_cmd_threads->nr_threads == 1) &&
(p_cmd_threads != &scst_main_cmd_threads))
p_cmd_threads->io_context = NULL;
if (p_cmd_threads != &scst_main_cmd_threads) {
if (p_cmd_threads->nr_threads == 1)
p_cmd_threads->io_context = NULL;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
if (!kref_put(p_cmd_threads->io_context_kref, kref_free))
current->io_context = NULL;
else
p_cmd_threads->io_context_kref = NULL;
TRACE_DBG("kref %p, old refcount %d",
p_cmd_threads->io_context_kref,
atomic_read(&p_cmd_threads->io_context_kref->refcount));
if (kref_put(p_cmd_threads->io_context_kref, kref_free))
p_cmd_threads->io_context_kref = NULL;
else
current->io_context = NULL;
#endif
}
PRINT_INFO("Processing thread %s (PID %d) finished", current->comm,
current->pid);