diff options
author | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-09-13 05:30:46 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-09-25 02:17:07 -0400 |
commit | 3ccd6e83df8a0d4a664edeecc453c4fa046395fb (patch) | |
tree | 1c8e69d2f81bb214c545b663508364247fb699ea /drivers/target | |
parent | 9fd60088ffed7573c2d409ddc63a2150a5edd5d8 (diff) |
target: Fix PR registration + APTPL RCU conversion regression
This patch fixes a v4.2+ regression introduced by commit 79dc9c9e86
where lookup of t10_pr_registration->pr_reg_deve and associated
->pr_kref get was missing from __core_scsi3_do_alloc_registration(),
which is responsible for setting DEF_PR_REG_ACTIVE.
This would result in REGISTER operations completing successfully,
but subsequent core_scsi3_pr_seq_non_holder() checking would fail
with !DEF_PR_REG_ACTIVE -> RESERVATION CONFLICT status.
Update __core_scsi3_add_registration() to drop ->pr_kref reference
after registration and any optional ALL_TG_PT=1 processing has
completed. Update core_scsi3_decode_spec_i_port() to release
the new parent local_pr_reg->pr_kref as well.
Also, update __core_scsi3_check_aptpl_registration() to perform
the same target_nacl_find_deve() lookup + ->pr_kref get, now that
__core_scsi3_add_registration() expects to drop the reference.
Finally, since there are cases when se_dev_entry->se_lun_acl can
still be dereferenced in core_scsi3_lunacl_undepend_item() while
holding ->pr_kref, go ahead and move explicit rcu_assign_pointer()
NULL assignments within core_disable_device_list_for_node() until
after orig->pr_comp finishes.
Reported-by: Scott L. Lykens <scott@lykens.org>
Tested-by: Scott L. Lykens <scott@lykens.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Lee Duncan <lduncan@suse.com>
Cc: <stable@vger.kernel.org> # v4.2+
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target')
-rw-r--r-- | drivers/target/target_core_device.c | 5 | ||||
-rw-r--r-- | drivers/target/target_core_pr.c | 91 |
2 files changed, 70 insertions, 26 deletions
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index dcc424ac35d4..abf20763b0b6 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c | |||
@@ -427,8 +427,6 @@ void core_disable_device_list_for_node( | |||
427 | 427 | ||
428 | hlist_del_rcu(&orig->link); | 428 | hlist_del_rcu(&orig->link); |
429 | clear_bit(DEF_PR_REG_ACTIVE, &orig->deve_flags); | 429 | clear_bit(DEF_PR_REG_ACTIVE, &orig->deve_flags); |
430 | rcu_assign_pointer(orig->se_lun, NULL); | ||
431 | rcu_assign_pointer(orig->se_lun_acl, NULL); | ||
432 | orig->lun_flags = 0; | 430 | orig->lun_flags = 0; |
433 | orig->creation_time = 0; | 431 | orig->creation_time = 0; |
434 | orig->attach_count--; | 432 | orig->attach_count--; |
@@ -439,6 +437,9 @@ void core_disable_device_list_for_node( | |||
439 | kref_put(&orig->pr_kref, target_pr_kref_release); | 437 | kref_put(&orig->pr_kref, target_pr_kref_release); |
440 | wait_for_completion(&orig->pr_comp); | 438 | wait_for_completion(&orig->pr_comp); |
441 | 439 | ||
440 | rcu_assign_pointer(orig->se_lun, NULL); | ||
441 | rcu_assign_pointer(orig->se_lun_acl, NULL); | ||
442 | |||
442 | kfree_rcu(orig, rcu_head); | 443 | kfree_rcu(orig, rcu_head); |
443 | 444 | ||
444 | core_scsi3_free_pr_reg_from_nacl(dev, nacl); | 445 | core_scsi3_free_pr_reg_from_nacl(dev, nacl); |
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 5ab7100de17e..e7933115087a 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
@@ -618,7 +618,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( | |||
618 | struct se_device *dev, | 618 | struct se_device *dev, |
619 | struct se_node_acl *nacl, | 619 | struct se_node_acl *nacl, |
620 | struct se_lun *lun, | 620 | struct se_lun *lun, |
621 | struct se_dev_entry *deve, | 621 | struct se_dev_entry *dest_deve, |
622 | u64 mapped_lun, | 622 | u64 mapped_lun, |
623 | unsigned char *isid, | 623 | unsigned char *isid, |
624 | u64 sa_res_key, | 624 | u64 sa_res_key, |
@@ -640,7 +640,29 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration( | |||
640 | INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list); | 640 | INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list); |
641 | atomic_set(&pr_reg->pr_res_holders, 0); | 641 | atomic_set(&pr_reg->pr_res_holders, 0); |
642 | pr_reg->pr_reg_nacl = nacl; | 642 | pr_reg->pr_reg_nacl = nacl; |
643 | pr_reg->pr_reg_deve = deve; | 643 | /* |
644 | * For destination registrations for ALL_TG_PT=1 and SPEC_I_PT=1, | ||
645 | * the se_dev_entry->pr_ref will have been already obtained by | ||
646 | * core_get_se_deve_from_rtpi() or __core_scsi3_alloc_registration(). | ||
647 | * | ||
648 | * Otherwise, locate se_dev_entry now and obtain a reference until | ||
649 | * registration completes in __core_scsi3_add_registration(). | ||
650 | */ | ||
651 | if (dest_deve) { | ||
652 | pr_reg->pr_reg_deve = dest_deve; | ||
653 | } else { | ||
654 | rcu_read_lock(); | ||
655 | pr_reg->pr_reg_deve = target_nacl_find_deve(nacl, mapped_lun); | ||
656 | if (!pr_reg->pr_reg_deve) { | ||
657 | rcu_read_unlock(); | ||
658 | pr_err("Unable to locate PR deve %s mapped_lun: %llu\n", | ||
659 | nacl->initiatorname, mapped_lun); | ||
660 | kmem_cache_free(t10_pr_reg_cache, pr_reg); | ||
661 | return NULL; | ||
662 | } | ||
663 | kref_get(&pr_reg->pr_reg_deve->pr_kref); | ||
664 | rcu_read_unlock(); | ||
665 | } | ||
644 | pr_reg->pr_res_mapped_lun = mapped_lun; | 666 | pr_reg->pr_res_mapped_lun = mapped_lun; |
645 | pr_reg->pr_aptpl_target_lun = lun->unpacked_lun; | 667 | pr_reg->pr_aptpl_target_lun = lun->unpacked_lun; |
646 | pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi; | 668 | pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi; |
@@ -936,17 +958,29 @@ static int __core_scsi3_check_aptpl_registration( | |||
936 | !(strcmp(pr_reg->pr_tport, t_port)) && | 958 | !(strcmp(pr_reg->pr_tport, t_port)) && |
937 | (pr_reg->pr_reg_tpgt == tpgt) && | 959 | (pr_reg->pr_reg_tpgt == tpgt) && |
938 | (pr_reg->pr_aptpl_target_lun == target_lun)) { | 960 | (pr_reg->pr_aptpl_target_lun == target_lun)) { |
961 | /* | ||
962 | * Obtain the ->pr_reg_deve pointer + reference, that | ||
963 | * is released by __core_scsi3_add_registration() below. | ||
964 | */ | ||
965 | rcu_read_lock(); | ||
966 | pr_reg->pr_reg_deve = target_nacl_find_deve(nacl, mapped_lun); | ||
967 | if (!pr_reg->pr_reg_deve) { | ||
968 | pr_err("Unable to locate PR APTPL %s mapped_lun:" | ||
969 | " %llu\n", nacl->initiatorname, mapped_lun); | ||
970 | rcu_read_unlock(); | ||
971 | continue; | ||
972 | } | ||
973 | kref_get(&pr_reg->pr_reg_deve->pr_kref); | ||
974 | rcu_read_unlock(); | ||
939 | 975 | ||
940 | pr_reg->pr_reg_nacl = nacl; | 976 | pr_reg->pr_reg_nacl = nacl; |
941 | pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi; | 977 | pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi; |
942 | |||
943 | list_del(&pr_reg->pr_reg_aptpl_list); | 978 | list_del(&pr_reg->pr_reg_aptpl_list); |
944 | spin_unlock(&pr_tmpl->aptpl_reg_lock); | 979 | spin_unlock(&pr_tmpl->aptpl_reg_lock); |
945 | /* | 980 | /* |
946 | * At this point all of the pointers in *pr_reg will | 981 | * At this point all of the pointers in *pr_reg will |
947 | * be setup, so go ahead and add the registration. | 982 | * be setup, so go ahead and add the registration. |
948 | */ | 983 | */ |
949 | |||
950 | __core_scsi3_add_registration(dev, nacl, pr_reg, 0, 0); | 984 | __core_scsi3_add_registration(dev, nacl, pr_reg, 0, 0); |
951 | /* | 985 | /* |
952 | * If this registration is the reservation holder, | 986 | * If this registration is the reservation holder, |
@@ -1044,18 +1078,11 @@ static void __core_scsi3_add_registration( | |||
1044 | 1078 | ||
1045 | __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type); | 1079 | __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type); |
1046 | spin_unlock(&pr_tmpl->registration_lock); | 1080 | spin_unlock(&pr_tmpl->registration_lock); |
1047 | |||
1048 | rcu_read_lock(); | ||
1049 | deve = pr_reg->pr_reg_deve; | ||
1050 | if (deve) | ||
1051 | set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); | ||
1052 | rcu_read_unlock(); | ||
1053 | |||
1054 | /* | 1081 | /* |
1055 | * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE. | 1082 | * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE. |
1056 | */ | 1083 | */ |
1057 | if (!pr_reg->pr_reg_all_tg_pt || register_move) | 1084 | if (!pr_reg->pr_reg_all_tg_pt || register_move) |
1058 | return; | 1085 | goto out; |
1059 | /* | 1086 | /* |
1060 | * Walk pr_reg->pr_reg_atp_list and add registrations for ALL_TG_PT=1 | 1087 | * Walk pr_reg->pr_reg_atp_list and add registrations for ALL_TG_PT=1 |
1061 | * allocated in __core_scsi3_alloc_registration() | 1088 | * allocated in __core_scsi3_alloc_registration() |
@@ -1075,19 +1102,31 @@ static void __core_scsi3_add_registration( | |||
1075 | __core_scsi3_dump_registration(tfo, dev, nacl_tmp, pr_reg_tmp, | 1102 | __core_scsi3_dump_registration(tfo, dev, nacl_tmp, pr_reg_tmp, |
1076 | register_type); | 1103 | register_type); |
1077 | spin_unlock(&pr_tmpl->registration_lock); | 1104 | spin_unlock(&pr_tmpl->registration_lock); |
1078 | 1105 | /* | |
1106 | * Drop configfs group dependency reference and deve->pr_kref | ||
1107 | * obtained from __core_scsi3_alloc_registration() code. | ||
1108 | */ | ||
1079 | rcu_read_lock(); | 1109 | rcu_read_lock(); |
1080 | deve = pr_reg_tmp->pr_reg_deve; | 1110 | deve = pr_reg_tmp->pr_reg_deve; |
1081 | if (deve) | 1111 | if (deve) { |
1082 | set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); | 1112 | set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); |
1113 | core_scsi3_lunacl_undepend_item(deve); | ||
1114 | pr_reg_tmp->pr_reg_deve = NULL; | ||
1115 | } | ||
1083 | rcu_read_unlock(); | 1116 | rcu_read_unlock(); |
1084 | |||
1085 | /* | ||
1086 | * Drop configfs group dependency reference from | ||
1087 | * __core_scsi3_alloc_registration() | ||
1088 | */ | ||
1089 | core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve); | ||
1090 | } | 1117 | } |
1118 | out: | ||
1119 | /* | ||
1120 | * Drop deve->pr_kref obtained in __core_scsi3_do_alloc_registration() | ||
1121 | */ | ||
1122 | rcu_read_lock(); | ||
1123 | deve = pr_reg->pr_reg_deve; | ||
1124 | if (deve) { | ||
1125 | set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags); | ||
1126 | kref_put(&deve->pr_kref, target_pr_kref_release); | ||
1127 | pr_reg->pr_reg_deve = NULL; | ||
1128 | } | ||
1129 | rcu_read_unlock(); | ||
1091 | } | 1130 | } |
1092 | 1131 | ||
1093 | static int core_scsi3_alloc_registration( | 1132 | static int core_scsi3_alloc_registration( |
@@ -1785,9 +1824,11 @@ core_scsi3_decode_spec_i_port( | |||
1785 | dest_node_acl->initiatorname, i_buf, (dest_se_deve) ? | 1824 | dest_node_acl->initiatorname, i_buf, (dest_se_deve) ? |
1786 | dest_se_deve->mapped_lun : 0); | 1825 | dest_se_deve->mapped_lun : 0); |
1787 | 1826 | ||
1788 | if (!dest_se_deve) | 1827 | if (!dest_se_deve) { |
1828 | kref_put(&local_pr_reg->pr_reg_deve->pr_kref, | ||
1829 | target_pr_kref_release); | ||
1789 | continue; | 1830 | continue; |
1790 | 1831 | } | |
1791 | core_scsi3_lunacl_undepend_item(dest_se_deve); | 1832 | core_scsi3_lunacl_undepend_item(dest_se_deve); |
1792 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 1833 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
1793 | core_scsi3_tpg_undepend_item(dest_tpg); | 1834 | core_scsi3_tpg_undepend_item(dest_tpg); |
@@ -1823,9 +1864,11 @@ out: | |||
1823 | 1864 | ||
1824 | kmem_cache_free(t10_pr_reg_cache, dest_pr_reg); | 1865 | kmem_cache_free(t10_pr_reg_cache, dest_pr_reg); |
1825 | 1866 | ||
1826 | if (!dest_se_deve) | 1867 | if (!dest_se_deve) { |
1868 | kref_put(&local_pr_reg->pr_reg_deve->pr_kref, | ||
1869 | target_pr_kref_release); | ||
1827 | continue; | 1870 | continue; |
1828 | 1871 | } | |
1829 | core_scsi3_lunacl_undepend_item(dest_se_deve); | 1872 | core_scsi3_lunacl_undepend_item(dest_se_deve); |
1830 | core_scsi3_nodeacl_undepend_item(dest_node_acl); | 1873 | core_scsi3_nodeacl_undepend_item(dest_node_acl); |
1831 | core_scsi3_tpg_undepend_item(dest_tpg); | 1874 | core_scsi3_tpg_undepend_item(dest_tpg); |