| From 33eb496b7b4aecb63311e10103d96f709f66803b Mon Sep 17 00:00:00 2001 |
| From: Nicholas Bellinger <nab@linux-iscsi.org> |
| Date: Mon, 27 Mar 2017 16:12:43 -0700 |
| Subject: [PATCH] target: Avoid mappedlun symlink creation during lun shutdown |
| |
| commit 49cb77e297dc611a1b795cfeb79452b3002bd331 upstream. |
| |
| This patch closes a race between se_lun deletion during configfs |
| unlink in target_fabric_port_unlink() -> core_dev_del_lun() |
| -> core_tpg_remove_lun(), when transport_clear_lun_ref() blocks |
| waiting for percpu_ref RCU grace period to finish, but a new |
| NodeACL mappedlun is added before the RCU grace period has |
| completed. |
| |
| This can happen in target_fabric_mappedlun_link() because it |
| only checks for se_lun->lun_se_dev, which is not cleared until |
| after transport_clear_lun_ref() percpu_ref RCU grace period |
| finishes. |
| |
| This bug originally manifested as NULL pointer dereference |
| OOPsen in target_stat_scsi_att_intr_port_show_attr_dev() on |
| v4.1.y code, because it dereferences lun->lun_se_dev without |
| a explicit NULL pointer check. |
| |
| In post v4.1 code with target-core RCU conversion, the code |
| in target_stat_scsi_att_intr_port_show_attr_dev() no longer |
| uses se_lun->lun_se_dev, but the same race still exists. |
| |
| To address the bug, go ahead and set se_lun>lun_shutdown as |
| early as possible in core_tpg_remove_lun(), and ensure new |
| NodeACL mappedlun creation in target_fabric_mappedlun_link() |
| fails during se_lun shutdown. |
| |
| Reported-by: James Shen <jcs@datera.io> |
| Cc: James Shen <jcs@datera.io> |
| Tested-by: James Shen <jcs@datera.io> |
| Cc: stable@vger.kernel.org # 3.10+ |
| Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c |
| index 31a096aa16ab..6e456de5e564 100644 |
| --- a/drivers/target/target_core_fabric_configfs.c |
| +++ b/drivers/target/target_core_fabric_configfs.c |
| @@ -92,6 +92,11 @@ static int target_fabric_mappedlun_link( |
| pr_err("Source se_lun->lun_se_dev does not exist\n"); |
| return -EINVAL; |
| } |
| + if (lun->lun_shutdown) { |
| + pr_err("Unable to create mappedlun symlink because" |
| + " lun->lun_shutdown=true\n"); |
| + return -EINVAL; |
| + } |
| se_tpg = lun->lun_tpg; |
| |
| nacl_ci = &lun_acl_ci->ci_parent->ci_group->cg_item; |
| diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c |
| index 2744251178ad..1949f50725a5 100644 |
| --- a/drivers/target/target_core_tpg.c |
| +++ b/drivers/target/target_core_tpg.c |
| @@ -640,6 +640,8 @@ void core_tpg_remove_lun( |
| */ |
| struct se_device *dev = rcu_dereference_raw(lun->lun_se_dev); |
| |
| + lun->lun_shutdown = true; |
| + |
| core_clear_lun_from_tpg(lun, tpg); |
| /* |
| * Wait for any active I/O references to percpu se_lun->lun_ref to |
| @@ -661,6 +663,8 @@ void core_tpg_remove_lun( |
| } |
| if (!(dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)) |
| hlist_del_rcu(&lun->link); |
| + |
| + lun->lun_shutdown = false; |
| mutex_unlock(&tpg->tpg_lun_mutex); |
| |
| percpu_ref_exit(&lun->lun_ref); |
| diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h |
| index 6233e8fd95b5..0383c601e17c 100644 |
| --- a/include/target/target_core_base.h |
| +++ b/include/target/target_core_base.h |
| @@ -705,6 +705,7 @@ struct se_lun { |
| u64 unpacked_lun; |
| #define SE_LUN_LINK_MAGIC 0xffff7771 |
| u32 lun_link_magic; |
| + bool lun_shutdown; |
| bool lun_access_ro; |
| u32 lun_index; |
| |
| -- |
| 2.12.0 |
| |