aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2013-05-15 03:52:44 -0400
committerNicholas Bellinger <nab@linux-iscsi.org>2013-05-30 00:30:33 -0400
commit9b31a328e344e62e7cc98ae574edcb7b674719bb (patch)
tree07baf7e2854dcd8f08066e7285ee68a89a4b9ff8
parentbe646c2d2ba8e2e56596d72633705f8286698c25 (diff)
target: Re-instate sess_wait_list for target_wait_for_sess_cmds
Switch back to pre commit 1c7b13fe652 list splicing logic for active I/O shutdown with tcm_qla2xxx + ib_srpt fabrics. The original commit was done under the incorrect assumption that it's safe to walk se_sess->sess_cmd_list unprotected in target_wait_for_sess_cmds() after sess->sess_tearing_down = 1 has been set by target_sess_cmd_list_set_waiting() during session shutdown. So instead of adding sess->sess_cmd_lock protection around sess->sess_cmd_list during target_wait_for_sess_cmds(), switch back to sess->sess_wait_list to allow wait_for_completion() + TFO->release_cmd() to occur without having to walk ->sess_cmd_list after the list_splice. Also add a check to exit if target_sess_cmd_list_set_waiting() has already been called, and add a WARN_ON to check for any fabric bug where new se_cmds are added to sess->sess_cmd_list after sess->sess_tearing_down = 1 has already been set. Cc: Joern Engel <joern@logfs.org> Cc: Roland Dreier <roland@kernel.org> Cc: stable@vger.kernel.org Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r--drivers/target/target_core_transport.c18
-rw-r--r--include/target/target_core_base.h1
2 files changed, 15 insertions, 4 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 311c11349aab..bbca144821c5 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -221,6 +221,7 @@ struct se_session *transport_init_session(void)
221 INIT_LIST_HEAD(&se_sess->sess_list); 221 INIT_LIST_HEAD(&se_sess->sess_list);
222 INIT_LIST_HEAD(&se_sess->sess_acl_list); 222 INIT_LIST_HEAD(&se_sess->sess_acl_list);
223 INIT_LIST_HEAD(&se_sess->sess_cmd_list); 223 INIT_LIST_HEAD(&se_sess->sess_cmd_list);
224 INIT_LIST_HEAD(&se_sess->sess_wait_list);
224 spin_lock_init(&se_sess->sess_cmd_lock); 225 spin_lock_init(&se_sess->sess_cmd_lock);
225 kref_init(&se_sess->sess_kref); 226 kref_init(&se_sess->sess_kref);
226 227
@@ -2250,11 +2251,14 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
2250 unsigned long flags; 2251 unsigned long flags;
2251 2252
2252 spin_lock_irqsave(&se_sess->sess_cmd_lock, flags); 2253 spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
2253 2254 if (se_sess->sess_tearing_down) {
2254 WARN_ON(se_sess->sess_tearing_down); 2255 spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
2256 return;
2257 }
2255 se_sess->sess_tearing_down = 1; 2258 se_sess->sess_tearing_down = 1;
2259 list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
2256 2260
2257 list_for_each_entry(se_cmd, &se_sess->sess_cmd_list, se_cmd_list) 2261 list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
2258 se_cmd->cmd_wait_set = 1; 2262 se_cmd->cmd_wait_set = 1;
2259 2263
2260 spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); 2264 spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
@@ -2267,9 +2271,10 @@ EXPORT_SYMBOL(target_sess_cmd_list_set_waiting);
2267void target_wait_for_sess_cmds(struct se_session *se_sess) 2271void target_wait_for_sess_cmds(struct se_session *se_sess)
2268{ 2272{
2269 struct se_cmd *se_cmd, *tmp_cmd; 2273 struct se_cmd *se_cmd, *tmp_cmd;
2274 unsigned long flags;
2270 2275
2271 list_for_each_entry_safe(se_cmd, tmp_cmd, 2276 list_for_each_entry_safe(se_cmd, tmp_cmd,
2272 &se_sess->sess_cmd_list, se_cmd_list) { 2277 &se_sess->sess_wait_list, se_cmd_list) {
2273 list_del(&se_cmd->se_cmd_list); 2278 list_del(&se_cmd->se_cmd_list);
2274 2279
2275 pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:" 2280 pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
@@ -2283,6 +2288,11 @@ void target_wait_for_sess_cmds(struct se_session *se_sess)
2283 2288
2284 se_cmd->se_tfo->release_cmd(se_cmd); 2289 se_cmd->se_tfo->release_cmd(se_cmd);
2285 } 2290 }
2291
2292 spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
2293 WARN_ON(!list_empty(&se_sess->sess_cmd_list));
2294 spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
2295
2286} 2296}
2287EXPORT_SYMBOL(target_wait_for_sess_cmds); 2297EXPORT_SYMBOL(target_wait_for_sess_cmds);
2288 2298
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index e773dfa5f98f..4ea4f985f394 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -543,6 +543,7 @@ struct se_session {
543 struct list_head sess_list; 543 struct list_head sess_list;
544 struct list_head sess_acl_list; 544 struct list_head sess_acl_list;
545 struct list_head sess_cmd_list; 545 struct list_head sess_cmd_list;
546 struct list_head sess_wait_list;
546 spinlock_t sess_cmd_lock; 547 spinlock_t sess_cmd_lock;
547 struct kref sess_kref; 548 struct kref sess_kref;
548}; 549};