diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-03-10 17:36:21 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2012-03-10 17:42:19 -0500 |
commit | 337c060701fb3d27d9945bf7af7ba194ae2153a8 (patch) | |
tree | 7b2d50a7cc4b291a876e95c60388cf57a52d912a /drivers/target | |
parent | afb999ffc48f5e7ec18e6f8f9e68aa3d0085862d (diff) |
target: Convert se_node_acl->acl_group removal to use ->acl_kref
This patch converts core_tpg_del_initiator_node_acl() shutdown from configfs
context to use se_node_acl->acl_kref and ->acl_free_comp in order to wait for
outstanding fabric callbacks to complete via transport_deregister_session()
callbacks before waking ->acl_free_comp from the last ->acl_kref put.
It also changes core_tpg_del_initiator_node_acl() to setup a local sess_list
with target_get_session() + acl->acl_stop = 1 for active sessions that will
be shutdown, and changes transport_deregister_session_configfs() to check
for ->acl_stop usage.
Cc: Roland Dreier <roland@purestorage.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Joern Engel <joern@logfs.org>
Cc: Andy Grover <agrover@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_tpg.c | 44 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 3 |
2 files changed, 28 insertions, 19 deletions
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index bbed260ec71f..f3ea385737d5 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c | |||
@@ -452,9 +452,10 @@ int core_tpg_del_initiator_node_acl( | |||
452 | struct se_node_acl *acl, | 452 | struct se_node_acl *acl, |
453 | int force) | 453 | int force) |
454 | { | 454 | { |
455 | LIST_HEAD(sess_list); | ||
455 | struct se_session *sess, *sess_tmp; | 456 | struct se_session *sess, *sess_tmp; |
456 | unsigned long flags; | 457 | unsigned long flags; |
457 | int dynamic_acl = 0; | 458 | int dynamic_acl = 0, rc; |
458 | 459 | ||
459 | spin_lock_irq(&tpg->acl_node_lock); | 460 | spin_lock_irq(&tpg->acl_node_lock); |
460 | if (acl->dynamic_node_acl) { | 461 | if (acl->dynamic_node_acl) { |
@@ -465,27 +466,34 @@ int core_tpg_del_initiator_node_acl( | |||
465 | tpg->num_node_acls--; | 466 | tpg->num_node_acls--; |
466 | spin_unlock_irq(&tpg->acl_node_lock); | 467 | spin_unlock_irq(&tpg->acl_node_lock); |
467 | 468 | ||
468 | spin_lock_irqsave(&tpg->session_lock, flags); | 469 | spin_lock_irqsave(&acl->nacl_sess_lock, flags); |
469 | list_for_each_entry_safe(sess, sess_tmp, | 470 | acl->acl_stop = 1; |
470 | &tpg->tpg_sess_list, sess_list) { | 471 | |
471 | if (sess->se_node_acl != acl) | 472 | list_for_each_entry_safe(sess, sess_tmp, &acl->acl_sess_list, |
472 | continue; | 473 | sess_acl_list) { |
473 | /* | 474 | if (sess->sess_tearing_down != 0) |
474 | * Determine if the session needs to be closed by our context. | ||
475 | */ | ||
476 | if (!tpg->se_tpg_tfo->shutdown_session(sess)) | ||
477 | continue; | 475 | continue; |
478 | 476 | ||
479 | spin_unlock_irqrestore(&tpg->session_lock, flags); | 477 | target_get_session(sess); |
480 | /* | 478 | list_move(&sess->sess_acl_list, &sess_list); |
481 | * If the $FABRIC_MOD session for the Initiator Node ACL exists, | 479 | } |
482 | * forcefully shutdown the $FABRIC_MOD session/nexus. | 480 | spin_unlock_irqrestore(&acl->nacl_sess_lock, flags); |
483 | */ | 481 | |
484 | tpg->se_tpg_tfo->close_session(sess); | 482 | list_for_each_entry_safe(sess, sess_tmp, &sess_list, sess_acl_list) { |
483 | list_del(&sess->sess_acl_list); | ||
485 | 484 | ||
486 | spin_lock_irqsave(&tpg->session_lock, flags); | 485 | rc = tpg->se_tpg_tfo->shutdown_session(sess); |
486 | target_put_session(sess); | ||
487 | if (!rc) | ||
488 | continue; | ||
489 | target_put_session(sess); | ||
487 | } | 490 | } |
488 | spin_unlock_irqrestore(&tpg->session_lock, flags); | 491 | target_put_nacl(acl); |
492 | /* | ||
493 | * Wait for last target_put_nacl() to complete in target_complete_nacl() | ||
494 | * for active fabric session transport_deregister_session() callbacks. | ||
495 | */ | ||
496 | wait_for_completion(&acl->acl_free_comp); | ||
489 | 497 | ||
490 | core_tpg_wait_for_nacl_pr_ref(acl); | 498 | core_tpg_wait_for_nacl_pr_ref(acl); |
491 | core_clear_initiator_node_from_tpg(acl, tpg); | 499 | core_clear_initiator_node_from_tpg(acl, tpg); |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index efefbec286fc..ba8eb8373032 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -360,7 +360,8 @@ void transport_deregister_session_configfs(struct se_session *se_sess) | |||
360 | se_nacl = se_sess->se_node_acl; | 360 | se_nacl = se_sess->se_node_acl; |
361 | if (se_nacl) { | 361 | if (se_nacl) { |
362 | spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); | 362 | spin_lock_irqsave(&se_nacl->nacl_sess_lock, flags); |
363 | list_del(&se_sess->sess_acl_list); | 363 | if (se_nacl->acl_stop == 0) |
364 | list_del(&se_sess->sess_acl_list); | ||
364 | /* | 365 | /* |
365 | * If the session list is empty, then clear the pointer. | 366 | * If the session list is empty, then clear the pointer. |
366 | * Otherwise, set the struct se_session pointer from the tail | 367 | * Otherwise, set the struct se_session pointer from the tail |