Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+45 -18
+6 -4
drivers/target/target_core_device.c
··· 92 92 se_cmd->pr_res_key = deve->pr_res_key; 93 93 se_cmd->orig_fe_lun = unpacked_lun; 94 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 99 spin_unlock_irqrestore(&se_sess->se_node_acl->device_list_lock, flags); 97 100 ··· 122 119 se_cmd->se_lun = &se_sess->se_tpg->tpg_virt_lun0; 123 120 se_cmd->orig_fe_lun = 0; 124 121 se_cmd->se_cmd_flags |= SCF_SE_LUN_CMD; 122 + 123 + percpu_ref_get(&se_lun->lun_ref); 124 + se_cmd->lun_ref_active = true; 125 125 } 126 126 127 127 /* Directly associate cmd with se_dev */ ··· 139 133 else if (se_cmd->data_direction == DMA_FROM_DEVICE) 140 134 dev->read_bytes += se_cmd->data_length; 141 135 spin_unlock_irqrestore(&dev->stats_lock, flags); 142 - 143 - spin_lock_irqsave(&se_lun->lun_cmd_lock, flags); 144 - list_add_tail(&se_cmd->se_lun_node, &se_lun->lun_cmd_list); 145 - spin_unlock_irqrestore(&se_lun->lun_cmd_lock, flags); 146 136 147 137 return 0; 148 138 }
+1 -1
drivers/target/target_core_internal.h
··· 100 100 int transport_dump_vpd_ident_type(struct t10_vpd *, unsigned char *, int); 101 101 int transport_dump_vpd_ident(struct t10_vpd *, unsigned char *, int); 102 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 104 void transport_send_task_abort(struct se_cmd *); 105 105 sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size); 106 106 void target_qf_do_work(struct work_struct *work);
+24 -3
drivers/target/target_core_tpg.c
··· 634 634 } 635 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 644 static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg) 638 645 { 639 646 /* Set in core_dev_setup_virtual_lun0() */ ··· 658 651 spin_lock_init(&lun->lun_acl_lock); 659 652 spin_lock_init(&lun->lun_cmd_lock); 660 653 spin_lock_init(&lun->lun_sep_lock); 654 + init_completion(&lun->lun_ref_comp); 661 655 662 - ret = core_tpg_post_addlun(se_tpg, lun, lun_access, dev); 656 + ret = percpu_ref_init(&lun->lun_ref, core_tpg_lun_ref_release); 663 657 if (ret < 0) 664 658 return ret; 659 + 660 + ret = core_tpg_post_addlun(se_tpg, lun, lun_access, dev); 661 + if (ret < 0) { 662 + percpu_ref_cancel_init(&lun->lun_ref); 663 + return ret; 664 + } 665 665 666 666 return 0; 667 667 } ··· 710 696 spin_lock_init(&lun->lun_acl_lock); 711 697 spin_lock_init(&lun->lun_cmd_lock); 712 698 spin_lock_init(&lun->lun_sep_lock); 699 + init_completion(&lun->lun_ref_comp); 713 700 } 714 701 715 702 se_tpg->se_tpg_type = se_tpg_type; ··· 831 816 { 832 817 int ret; 833 818 834 - ret = core_dev_export(lun_ptr, tpg, lun); 819 + ret = percpu_ref_init(&lun->lun_ref, core_tpg_lun_ref_release); 835 820 if (ret < 0) 836 821 return ret; 822 + 823 + ret = core_dev_export(lun_ptr, tpg, lun); 824 + if (ret < 0) { 825 + percpu_ref_cancel_init(&lun->lun_ref); 826 + return ret; 827 + } 837 828 838 829 spin_lock(&tpg->tpg_lun_lock); 839 830 lun->lun_access = lun_access; ··· 854 833 struct se_lun *lun) 855 834 { 856 835 core_clear_lun_from_tpg(lun, tpg); 857 - transport_clear_lun_from_sessions(lun); 836 + transport_clear_lun_ref(lun); 858 837 } 859 838 860 839 struct se_lun *core_tpg_pre_dellun(
+8 -10
drivers/target/target_core_transport.c
··· 575 575 static void transport_lun_remove_cmd(struct se_cmd *cmd) 576 576 { 577 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 580 return; 582 581 583 - spin_lock_irqsave(&lun->lun_cmd_lock, flags); 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); 582 + percpu_ref_put(&lun->lun_ref); 587 583 } 588 584 589 585 void transport_cmd_finish_abort(struct se_cmd *cmd, int remove) ··· 2533 2537 spin_unlock_irqrestore(&lun->lun_cmd_lock, lun_flags); 2534 2538 } 2535 2539 2536 - static int transport_clear_lun_thread(void *p) 2540 + static int transport_clear_lun_ref_thread(void *p) 2537 2541 { 2538 2542 struct se_lun *lun = p; 2539 2543 2540 - __transport_clear_lun_from_sessions(lun); 2544 + percpu_ref_kill(&lun->lun_ref); 2545 + 2546 + wait_for_completion(&lun->lun_ref_comp); 2541 2547 complete(&lun->lun_shutdown_comp); 2542 2548 2543 2549 return 0; 2544 2550 } 2545 2551 2546 - int transport_clear_lun_from_sessions(struct se_lun *lun) 2552 + int transport_clear_lun_ref(struct se_lun *lun) 2547 2553 { 2548 2554 struct task_struct *kt; 2549 2555 2550 - kt = kthread_run(transport_clear_lun_thread, lun, 2556 + kt = kthread_run(transport_clear_lun_ref_thread, lun, 2551 2557 "tcm_cl_%u", lun->unpacked_lun); 2552 2558 if (IS_ERR(kt)) { 2553 2559 pr_err("Unable to start clear_lun thread\n");
+1
drivers/target/target_core_xcopy.c
··· 579 579 spin_lock_init(&pt_cmd->se_lun->lun_acl_lock); 580 580 spin_lock_init(&pt_cmd->se_lun->lun_cmd_lock); 581 581 spin_lock_init(&pt_cmd->se_lun->lun_sep_lock); 582 + init_completion(&pt_cmd->se_lun->lun_ref_comp); 582 583 583 584 pt_cmd->se_dev = se_dev; 584 585
+5
include/target/target_core_base.h
··· 499 499 500 500 /* backend private data */ 501 501 void *priv; 502 + 503 + /* Used for lun->lun_ref counting */ 504 + bool lun_ref_active; 502 505 }; 503 506 504 507 struct se_ua { ··· 760 757 struct se_port *lun_sep; 761 758 struct config_group lun_group; 762 759 struct se_port_stat_grps port_stat_grps; 760 + struct completion lun_ref_comp; 761 + struct percpu_ref lun_ref; 763 762 }; 764 763 765 764 struct scsi_port_stats {