Skip to content

Commit

Permalink
target: Perform RCU callback barrier before backend/fabric unload
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Nicholas Bellinger committed Jul 31, 2015
1 parent c4cfdd8 commit 9450918
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 2 deletions.
9 changes: 8 additions & 1 deletion drivers/target/target_core_configfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,8 +457,15 @@ void target_unregister_template(const struct target_core_fabric_ops *fo)
if (!strcmp(t->tf_ops->name, fo->name)) {
BUG_ON(atomic_read(&t->tf_access_cnt));
list_del(&t->tf_list);
mutex_unlock(&g_tf_lock);
/*
* Wait for any outstanding fabric se_deve_entry->rcu_head
* callbacks to complete post kfree_rcu(), before allowing
* fabric driver unload of TFO->module to proceed.
*/
rcu_barrier();
kfree(t);
break;
return;
}
}
mutex_unlock(&g_tf_lock);
Expand Down
10 changes: 9 additions & 1 deletion drivers/target/target_core_hba.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,16 @@ void target_backend_unregister(const struct target_backend_ops *ops)
list_for_each_entry(tb, &backend_list, list) {
if (tb->ops == ops) {
list_del(&tb->list);
mutex_unlock(&backend_mutex);
/*
* Wait for any outstanding backend driver ->rcu_head
* callbacks to complete post TBO->free_device() ->
* call_rcu(), before allowing backend driver module
* unload of target_backend_ops->owner to proceed.
*/
rcu_barrier();
kfree(tb);
break;
return;
}
}
mutex_unlock(&backend_mutex);
Expand Down

0 comments on commit 9450918

Please sign in to comment.