diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-05-15 03:52:44 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-05-30 00:30:33 -0400 |
commit | 9b31a328e344e62e7cc98ae574edcb7b674719bb (patch) | |
tree | 07baf7e2854dcd8f08066e7285ee68a89a4b9ff8 | |
parent | be646c2d2ba8e2e56596d72633705f8286698c25 (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.c | 18 | ||||
-rw-r--r-- | include/target/target_core_base.h | 1 |
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); | |||
2267 | void target_wait_for_sess_cmds(struct se_session *se_sess) | 2271 | void 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 | } |
2287 | EXPORT_SYMBOL(target_wait_for_sess_cmds); | 2297 | EXPORT_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 | }; |