diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-11-07 00:03:43 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2013-11-07 17:24:52 -0500 |
commit | 5277797dc4ed873d067477d84e910b39d113f649 (patch) | |
tree | 5e2aa87dec2cbcb5bbdfadd697c92e86b0e5aa11 | |
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>
-rw-r--r-- | drivers/target/target_core_device.c | 10 | ||||
-rw-r--r-- | drivers/target/target_core_internal.h | 2 | ||||
-rw-r--r-- | drivers/target/target_core_tpg.c | 27 | ||||
-rw-r--r-- | drivers/target/target_core_transport.c | 18 | ||||
-rw-r--r-- | drivers/target/target_core_xcopy.c | 1 | ||||
-rw-r--r-- | include/target/target_core_base.h | 5 |
6 files changed, 45 insertions, 18 deletions
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index d90dbb0f1a69..569a3c7c9e5a 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c | |||
@@ -92,6 +92,9 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) | |||
92 | se_cmd->pr_res_key = deve->pr_res_key; | 92 | se_cmd->pr_res_key = deve->pr_res_key; |
93 | se_cmd->orig_fe_lun = unpacked_lun; | 93 | se_cmd->orig_fe_lun = unpacked_lun; |
94 | se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; | 94 | se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; |
95 | |||
96 | percpu_ref_get(&se_lun->lun_ref); | ||
97 | se_cmd->lun_ref_active = true; | ||
95 | } | 98 | } |
96 | spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); | 99 | spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); |
97 | 100 | ||
@@ -119,6 +122,9 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) | |||
119 | se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0; | 122 | se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0; |
120 | se_cmd->orig_fe_lun = 0; | 123 | se_cmd->orig_fe_lun = 0; |
121 | se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; | 124 | se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; |
125 | |||
126 | percpu_ref_get(&se_lun->lun_ref); | ||
127 | se_cmd->lun_ref_active = true; | ||
122 | } | 128 | } |
123 | 129 | ||
124 | /* Directly associate cmd with se_dev */ | 130 | /* Directly associate cmd with se_dev */ |
@@ -134,10 +140,6 @@ transport_lookup_cmd_lun(struct se_cmd *se_cmd, u32 unpacked_lun) | |||
134 | dev->read_bytes += se_cmd->data_length; | 140 | dev->read_bytes += se_cmd->data_length; |
135 | spin_unlock_irqrestore(&dev->stats_lock, flags); | 141 | spin_unlock_irqrestore(&dev->stats_lock, flags); |
136 | 142 | ||
137 | spin_lock_irqsave(&se_lun->lun_cmd_lock, flags); | ||
138 | list_add_tail(&se_cmd->se_lun_node, &se_lun->lun_cmd_list); | ||
139 | spin_unlock_irqrestore(&se_lun->lun_cmd_lock, flags); | ||
140 | |||
141 | return 0; | 143 | return 0; |
142 | } | 144 | } |
143 | EXPORT_SYMBOL(transport_lookup_cmd_lun); | 145 | EXPORT_SYMBOL(transport_lookup_cmd_lun); |
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 889af4df8562..47b63b094cdc 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h | |||
@@ -100,7 +100,7 @@ int transport_dump_vpd_assoc(struct t10_vpd *, unsigned char *, int); | |||
100 | int transport_dump_vpd_ident_type(struct t10_vpd *, unsigned char *, int); | 100 | int transport_dump_vpd_ident_type(struct t10_vpd *, unsigned char *, int); |
101 | int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int); | 101 | int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int); |
102 | bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags); | 102 | bool target_stop_cmd(struct se_cmd *cmd, unsigned long *flags); |
103 | int transport_clear_lun_from_sessions(struct se_lun *); | 103 | int transport_clear_lun_ref(struct se_lun *); |
104 | void transport_send_task_abort(struct se_cmd *); | 104 | void transport_send_task_abort(struct se_cmd *); |
105 | sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size); | 105 | sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size); |
106 | void target_qf_do_work(struct work_struct *work); | 106 | void target_qf_do_work(struct work_struct *work); |
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index ec992208dc55..f321af04ef03 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c | |||
@@ -634,6 +634,13 @@ int core_tpg_set_initiator_node_tag( | |||
634 | } | 634 | } |
635 | EXPORT_SYMBOL(core_tpg_set_initiator_node_tag); | 635 | EXPORT_SYMBOL(core_tpg_set_initiator_node_tag); |
636 | 636 | ||
637 | static void core_tpg_lun_ref_release(struct percpu_ref *ref) | ||
638 | { | ||
639 | struct se_lun *lun = container_of(ref, struct se_lun, lun_ref); | ||
640 | |||
641 | complete(&lun->lun_ref_comp); | ||
642 | } | ||
643 | |||
637 | static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) | 644 | static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) |
638 | { | 645 | { |
639 | /* Set in core_dev_setup_virtual_lun0() */ | 646 | /* Set in core_dev_setup_virtual_lun0() */ |
@@ -651,11 +658,18 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) | |||
651 | spin_lock_init(&lun->lun_acl_lock); | 658 | spin_lock_init(&lun->lun_acl_lock); |
652 | spin_lock_init(&lun->lun_cmd_lock); | 659 | spin_lock_init(&lun->lun_cmd_lock); |
653 | spin_lock_init(&lun->lun_sep_lock); | 660 | spin_lock_init(&lun->lun_sep_lock); |
661 | init_completion(&lun->lun_ref_comp); | ||
654 | 662 | ||
655 | ret = core_tpg_post_addlun(se_tpg, lun, lun_access, dev); | 663 | ret = percpu_ref_init(&lun->lun_ref, core_tpg_lun_ref_release); |
656 | if (ret < 0) | 664 | if (ret < 0) |
657 | return ret; | 665 | return ret; |
658 | 666 | ||
667 | ret = core_tpg_post_addlun(se_tpg, lun, lun_access, dev); | ||
668 | if (ret < 0) { | ||
669 | percpu_ref_cancel_init(&lun->lun_ref); | ||
670 | return ret; | ||
671 | } | ||
672 | |||
659 | return 0; | 673 | return 0; |
660 | } | 674 | } |
661 | 675 | ||
@@ -696,6 +710,7 @@ int core_tpg_register( | |||
696 | spin_lock_init(&lun->lun_acl_lock); | 710 | spin_lock_init(&lun->lun_acl_lock); |
697 | spin_lock_init(&lun->lun_cmd_lock); | 711 | spin_lock_init(&lun->lun_cmd_lock); |
698 | spin_lock_init(&lun->lun_sep_lock); | 712 | spin_lock_init(&lun->lun_sep_lock); |
713 | init_completion(&lun->lun_ref_comp); | ||
699 | } | 714 | } |
700 | 715 | ||
701 | se_tpg->se_tpg_type = se_tpg_type; | 716 | se_tpg->se_tpg_type = se_tpg_type; |
@@ -816,10 +831,16 @@ int core_tpg_post_addlun( | |||
816 | { | 831 | { |
817 | int ret; | 832 | int ret; |
818 | 833 | ||
819 | ret = core_dev_export(lun_ptr, tpg, lun); | 834 | ret = percpu_ref_init(&lun->lun_ref, core_tpg_lun_ref_release); |
820 | if (ret < 0) | 835 | if (ret < 0) |
821 | return ret; | 836 | return ret; |
822 | 837 | ||
838 | ret = core_dev_export(lun_ptr, tpg, lun); | ||
839 | if (ret < 0) { | ||
840 | percpu_ref_cancel_init(&lun->lun_ref); | ||
841 | return ret; | ||
842 | } | ||
843 | |||
823 | spin_lock(&tpg->tpg_lun_lock); | 844 | spin_lock(&tpg->tpg_lun_lock); |
824 | lun->lun_access = lun_access; | 845 | lun->lun_access = lun_access; |
825 | lun->lun_status = TRANSPORT_LUN_STATUS_ACTIVE; | 846 | lun->lun_status = TRANSPORT_LUN_STATUS_ACTIVE; |
@@ -833,7 +854,7 @@ static void core_tpg_shutdown_lun( | |||
833 | struct se_lun *lun) | 854 | struct se_lun *lun) |
834 | { | 855 | { |
835 | core_clear_lun_from_tpg(lun, tpg); | 856 | core_clear_lun_from_tpg(lun, tpg); |
836 | transport_clear_lun_from_sessions(lun); | 857 | transport_clear_lun_ref(lun); |
837 | } | 858 | } |
838 | 859 | ||
839 | struct se_lun *core_tpg_pre_dellun( | 860 | struct se_lun *core_tpg_pre_dellun( |
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) | |||
575 | static void transport_lun_remove_cmd(struct se_cmd *cmd) | 575 | static void transport_lun_remove_cmd(struct se_cmd *cmd) |
576 | { | 576 | { |
577 | struct se_lun *lun = cmd->se_lun; | 577 | struct se_lun *lun = cmd->se_lun; |
578 | unsigned long flags; | ||
579 | 578 | ||
580 | if (!lun) | 579 | if (!lun || !cmd->lun_ref_active) |
581 | return; | 580 | return; |
582 | 581 | ||
583 | spin_lock_irqsave(&lun->lun_cmd_lock, flags); | 582 | percpu_ref_put(&lun->lun_ref); |
584 | if (!list_empty(&cmd->se_lun_node)) | ||
585 | list_del_init(&cmd->se_lun_node); | ||
586 | spin_unlock_irqrestore(&lun->lun_cmd_lock, flags); | ||
587 | } | 583 | } |
588 | 584 | ||
589 | void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) | 585 | void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) |
@@ -2537,21 +2533,23 @@ check_cond: | |||
2537 | spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags); | 2533 | spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags); |
2538 | } | 2534 | } |
2539 | 2535 | ||
2540 | static int transport_clear_lun_thread(void *p) | 2536 | static int transport_clear_lun_ref_thread(void *p) |
2541 | { | 2537 | { |
2542 | struct se_lun *lun = p; | 2538 | struct se_lun *lun = p; |
2543 | 2539 | ||
2544 | __transport_clear_lun_from_sessions(lun); | 2540 | percpu_ref_kill(&lun->lun_ref); |
2541 | |||
2542 | wait_for_completion(&lun->lun_ref_comp); | ||
2545 | complete(&lun->lun_shutdown_comp); | 2543 | complete(&lun->lun_shutdown_comp); |
2546 | 2544 | ||
2547 | return 0; | 2545 | return 0; |
2548 | } | 2546 | } |
2549 | 2547 | ||
2550 | int transport_clear_lun_from_sessions(struct se_lun *lun) | 2548 | int transport_clear_lun_ref(struct se_lun *lun) |
2551 | { | 2549 | { |
2552 | struct task_struct *kt; | 2550 | struct task_struct *kt; |
2553 | 2551 | ||
2554 | kt = kthread_run(transport_clear_lun_thread, lun, | 2552 | kt = kthread_run(transport_clear_lun_ref_thread, lun, |
2555 | "tcm_cl_%u", lun->unpacked_lun); | 2553 | "tcm_cl_%u", lun->unpacked_lun); |
2556 | if (IS_ERR(kt)) { | 2554 | if (IS_ERR(kt)) { |
2557 | pr_err("Unable to start clear_lun thread\n"); | 2555 | pr_err("Unable to start clear_lun thread\n"); |
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 4d22e7d2adca..7a870f6add7b 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c | |||
@@ -579,6 +579,7 @@ static int target_xcopy_init_pt_lun( | |||
579 | spin_lock_init(&pt_cmd->se_lun->lun_acl_lock); | 579 | spin_lock_init(&pt_cmd->se_lun->lun_acl_lock); |
580 | spin_lock_init(&pt_cmd->se_lun->lun_cmd_lock); | 580 | spin_lock_init(&pt_cmd->se_lun->lun_cmd_lock); |
581 | spin_lock_init(&pt_cmd->se_lun->lun_sep_lock); | 581 | spin_lock_init(&pt_cmd->se_lun->lun_sep_lock); |
582 | init_completion(&pt_cmd->se_lun->lun_ref_comp); | ||
582 | 583 | ||
583 | pt_cmd->se_dev = se_dev; | 584 | pt_cmd->se_dev = se_dev; |
584 | 585 | ||
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 22e752c4406d..4d16fd9330a6 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h | |||
@@ -499,6 +499,9 @@ struct se_cmd { | |||
499 | 499 | ||
500 | /* backend private data */ | 500 | /* backend private data */ |
501 | void *priv; | 501 | void *priv; |
502 | |||
503 | /* Used for lun->lun_ref counting */ | ||
504 | bool lun_ref_active; | ||
502 | }; | 505 | }; |
503 | 506 | ||
504 | struct se_ua { | 507 | struct se_ua { |
@@ -757,6 +760,8 @@ struct se_lun { | |||
757 | struct se_port *lun_sep; | 760 | struct se_port *lun_sep; |
758 | struct config_group lun_group; | 761 | struct config_group lun_group; |
759 | struct se_port_stat_grps port_stat_grps; | 762 | struct se_port_stat_grps port_stat_grps; |
763 | struct completion lun_ref_comp; | ||
764 | struct percpu_ref lun_ref; | ||
760 | }; | 765 | }; |
761 | 766 | ||
762 | struct scsi_port_stats { | 767 | struct scsi_port_stats { |