summaryrefslogtreecommitdiff
path: root/drivers/target/target_core_transport.c
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2013-11-06 21:03:43 -0800
committerNicholas Bellinger <nab@linux-iscsi.org>2013-11-07 14:24:52 -0800
commit5277797dc4ed873d067477d84e910b39d113f649 (patch)
tree5e2aa87dec2cbcb5bbdfadd697c92e86b0e5aa11 /drivers/target/target_core_transport.c
parentc9e8d128fe316751230ee0c53478740c64f58436 (diff)
target: Add percpu refcounting for se_lun access
This patch adds percpu refcounting for se_lun access that allows the association of an se_lun + se_cmd in transport_lookup_cmd_lun() to occur without an extra list_head for tracking outstanding I/O during se_lun shutdown. This effectively changes se_lun shutdown logic to wait for outstanding I/O percpu references to complete in transport_lun_remove_cmd() using se_lun->lun_ref_comp, instead of explicitly draining the per se_lun command list and waiting for individual se_cmd descriptor processing to complete. Cc: Kent Overstreet <kmo@daterainc.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_transport.c')
-rw-r--r--drivers/target/target_core_transport.c18
1 files changed, 8 insertions, 10 deletions
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 84747cc1aac0..ad143d7293ec 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -575,15 +575,11 @@ static int transport_cmd_check_stop_to_fabric(struct se_cmd *cmd)
static void transport_lun_remove_cmd(struct se_cmd *cmd)
{
struct se_lun *lun = cmd->se_lun;
- unsigned long flags;
- if (!lun)
+ if (!lun || !cmd->lun_ref_active)
return;
- spin_lock_irqsave(&lun->lun_cmd_lock, flags);
- if (!list_empty(&cmd->se_lun_node))
- list_del_init(&cmd->se_lun_node);
- spin_unlock_irqrestore(&lun->lun_cmd_lock, flags);
+ percpu_ref_put(&lun->lun_ref);
}
void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
@@ -2537,21 +2533,23 @@ check_cond:
spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags);
}
-static int transport_clear_lun_thread(void *p)
+static int transport_clear_lun_ref_thread(void *p)
{
struct se_lun *lun = p;
- __transport_clear_lun_from_sessions(lun);
+ percpu_ref_kill(&lun->lun_ref);
+
+ wait_for_completion(&lun->lun_ref_comp);
complete(&lun->lun_shutdown_comp);
return 0;
}
-int transport_clear_lun_from_sessions(struct se_lun *lun)
+int transport_clear_lun_ref(struct se_lun *lun)
{
struct task_struct *kt;
- kt = kthread_run(transport_clear_lun_thread, lun,
+ kt = kthread_run(transport_clear_lun_ref_thread, lun,
"tcm_cl_%u", lun->unpacked_lun);
if (IS_ERR(kt)) {
pr_err("Unable to start clear_lun thread\n");