From d27d945c4f400b45d73d1c155b2e1c689bf893a3 Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Tue, 20 Apr 2010 18:05:16 +0000 Subject: [PATCH] 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 --- scst/src/scst_lib.c | 37 ++++++++++++++++++++++++++++++------- scst/src/scst_main.c | 11 ++++++++++- scst/src/scst_targ.c | 22 ++++++++++++++-------- 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/scst/src/scst_lib.c b/scst/src/scst_lib.c index f02ee7756..8610ac1a0 100644 --- a/scst/src/scst_lib.c +++ b/scst/src/scst_lib.c @@ -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); diff --git a/scst/src/scst_main.c b/scst/src/scst_main.c index 4b59c4e0e..bf8f86ead 100644 --- a/scst/src/scst_main.c +++ b/scst/src/scst_main.c @@ -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: diff --git a/scst/src/scst_targ.c b/scst/src/scst_targ.c index 4654e97c9..d9bcc958a 100644 --- a/scst/src/scst_targ.c +++ b/scst/src/scst_targ.c @@ -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);