diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-11-06 21:03:43 -0800 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-11-07 14:24:52 -0800 |
commit | 5277797dc4ed873d067477d84e910b39d113f649 (patch) | |
tree | 5e2aa87dec2cbcb5bbdfadd697c92e86b0e5aa11 /drivers/target/target_core_transport.c | |
parent | c9e8d128fe316751230ee0c53478740c64f58436 (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.c | 18 |
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"); |