aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2015-07-30 01:27:13 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2015-07-31 01:06:29 -0400
commit9450918293b3c35f11883231a53da1aed2c78403 (patch)
treeed355995df7cb6b312afbad50afd570024e11529
parentc4cfdd81c8fde84e2c75bc90533c7e1276937d3a (diff)
target: Perform RCU callback barrier before backend/fabric unload
This patch addresses a v4.2-rc1 regression where backend driver module unload happening immediately after TBO->free_device() does internal call_rcu(), will currently result in IRQ context rcu_process_callbacks() use-after-free paging OOPsen. It adds the missing rcu_barrier() in target_backend_unregister() to perform an explicit RCU barrier waiting for all RCU callbacks to complete before releasing target_backend_ops memory, and allowing TBO->module exit to proceed. Also, do the same for fabric drivers in target_unregister_template() to ensure se_deve_entry->rcu_head -> kfree_rcu() callbacks have completed, before allowing target_core_fabric_ops->owner module exit to proceed. Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Christoph Hellwig <hch@lst.de> Cc: Hannes Reinecke <hare@suse.de> Cc: Sagi Grimberg <sagig@mellanox.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/target_core_configfs.c9
-rw-r--r--drivers/target/target_core_hba.c10
2 files changed, 17 insertions, 2 deletions
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index c2e9fea90b4a..860e84046177 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -457,8 +457,15 @@ void target_unregister_template(const struct target_core_fabric_ops *fo)
457 if (!strcmp(t->tf_ops->name, fo->name)) { 457 if (!strcmp(t->tf_ops->name, fo->name)) {
458 BUG_ON(atomic_read(&t->tf_access_cnt)); 458 BUG_ON(atomic_read(&t->tf_access_cnt));
459 list_del(&t->tf_list); 459 list_del(&t->tf_list);
460 mutex_unlock(&g_tf_lock);
461 /*
462 * Wait for any outstanding fabric se_deve_entry->rcu_head
463 * callbacks to complete post kfree_rcu(), before allowing
464 * fabric driver unload of TFO->module to proceed.
465 */
466 rcu_barrier();
460 kfree(t); 467 kfree(t);
461 break; 468 return;
462 } 469 }
463 } 470 }
464 mutex_unlock(&g_tf_lock); 471 mutex_unlock(&g_tf_lock);
diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c
index 62ea4e8e70a8..be9cefc07407 100644
--- a/drivers/target/target_core_hba.c
+++ b/drivers/target/target_core_hba.c
@@ -84,8 +84,16 @@ void target_backend_unregister(const struct target_backend_ops *ops)
84 list_for_each_entry(tb, &backend_list, list) { 84 list_for_each_entry(tb, &backend_list, list) {
85 if (tb->ops == ops) { 85 if (tb->ops == ops) {
86 list_del(&tb->list); 86 list_del(&tb->list);
87 mutex_unlock(&backend_mutex);
88 /*
89 * Wait for any outstanding backend driver ->rcu_head
90 * callbacks to complete post TBO->free_device() ->
91 * call_rcu(), before allowing backend driver module
92 * unload of target_backend_ops->owner to proceed.
93 */
94 rcu_barrier();
87 kfree(tb); 95 kfree(tb);
88 break; 96 return;
89 } 97 }
90 } 98 }
91 mutex_unlock(&backend_mutex); 99 mutex_unlock(&backend_mutex);