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>
This commit is contained in:
Родитель
9fd60088ff
Коммит
3ccd6e83df
|
@ -427,8 +427,6 @@ void core_disable_device_list_for_node(
|
|||
|
||||
hlist_del_rcu(&orig->link);
|
||||
clear_bit(DEF_PR_REG_ACTIVE, &orig->deve_flags);
|
||||
rcu_assign_pointer(orig->se_lun, NULL);
|
||||
rcu_assign_pointer(orig->se_lun_acl, NULL);
|
||||
orig->lun_flags = 0;
|
||||
orig->creation_time = 0;
|
||||
orig->attach_count--;
|
||||
|
@ -439,6 +437,9 @@ void core_disable_device_list_for_node(
|
|||
kref_put(&orig->pr_kref, target_pr_kref_release);
|
||||
wait_for_completion(&orig->pr_comp);
|
||||
|
||||
rcu_assign_pointer(orig->se_lun, NULL);
|
||||
rcu_assign_pointer(orig->se_lun_acl, NULL);
|
||||
|
||||
kfree_rcu(orig, rcu_head);
|
||||
|
||||
core_scsi3_free_pr_reg_from_nacl(dev, nacl);
|
||||
|
|
|
@ -618,7 +618,7 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration(
|
|||
struct se_device *dev,
|
||||
struct se_node_acl *nacl,
|
||||
struct se_lun *lun,
|
||||
struct se_dev_entry *deve,
|
||||
struct se_dev_entry *dest_deve,
|
||||
u64 mapped_lun,
|
||||
unsigned char *isid,
|
||||
u64 sa_res_key,
|
||||
|
@ -640,7 +640,29 @@ static struct t10_pr_registration *__core_scsi3_do_alloc_registration(
|
|||
INIT_LIST_HEAD(&pr_reg->pr_reg_atp_mem_list);
|
||||
atomic_set(&pr_reg->pr_res_holders, 0);
|
||||
pr_reg->pr_reg_nacl = nacl;
|
||||
pr_reg->pr_reg_deve = deve;
|
||||
/*
|
||||
* For destination registrations for ALL_TG_PT=1 and SPEC_I_PT=1,
|
||||
* the se_dev_entry->pr_ref will have been already obtained by
|
||||
* core_get_se_deve_from_rtpi() or __core_scsi3_alloc_registration().
|
||||
*
|
||||
* Otherwise, locate se_dev_entry now and obtain a reference until
|
||||
* registration completes in __core_scsi3_add_registration().
|
||||
*/
|
||||
if (dest_deve) {
|
||||
pr_reg->pr_reg_deve = dest_deve;
|
||||
} else {
|
||||
rcu_read_lock();
|
||||
pr_reg->pr_reg_deve = target_nacl_find_deve(nacl, mapped_lun);
|
||||
if (!pr_reg->pr_reg_deve) {
|
||||
rcu_read_unlock();
|
||||
pr_err("Unable to locate PR deve %s mapped_lun: %llu\n",
|
||||
nacl->initiatorname, mapped_lun);
|
||||
kmem_cache_free(t10_pr_reg_cache, pr_reg);
|
||||
return NULL;
|
||||
}
|
||||
kref_get(&pr_reg->pr_reg_deve->pr_kref);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
pr_reg->pr_res_mapped_lun = mapped_lun;
|
||||
pr_reg->pr_aptpl_target_lun = lun->unpacked_lun;
|
||||
pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi;
|
||||
|
@ -936,17 +958,29 @@ static int __core_scsi3_check_aptpl_registration(
|
|||
!(strcmp(pr_reg->pr_tport, t_port)) &&
|
||||
(pr_reg->pr_reg_tpgt == tpgt) &&
|
||||
(pr_reg->pr_aptpl_target_lun == target_lun)) {
|
||||
/*
|
||||
* Obtain the ->pr_reg_deve pointer + reference, that
|
||||
* is released by __core_scsi3_add_registration() below.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
pr_reg->pr_reg_deve = target_nacl_find_deve(nacl, mapped_lun);
|
||||
if (!pr_reg->pr_reg_deve) {
|
||||
pr_err("Unable to locate PR APTPL %s mapped_lun:"
|
||||
" %llu\n", nacl->initiatorname, mapped_lun);
|
||||
rcu_read_unlock();
|
||||
continue;
|
||||
}
|
||||
kref_get(&pr_reg->pr_reg_deve->pr_kref);
|
||||
rcu_read_unlock();
|
||||
|
||||
pr_reg->pr_reg_nacl = nacl;
|
||||
pr_reg->tg_pt_sep_rtpi = lun->lun_rtpi;
|
||||
|
||||
list_del(&pr_reg->pr_reg_aptpl_list);
|
||||
spin_unlock(&pr_tmpl->aptpl_reg_lock);
|
||||
/*
|
||||
* At this point all of the pointers in *pr_reg will
|
||||
* be setup, so go ahead and add the registration.
|
||||
*/
|
||||
|
||||
__core_scsi3_add_registration(dev, nacl, pr_reg, 0, 0);
|
||||
/*
|
||||
* If this registration is the reservation holder,
|
||||
|
@ -1044,18 +1078,11 @@ static void __core_scsi3_add_registration(
|
|||
|
||||
__core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type);
|
||||
spin_unlock(&pr_tmpl->registration_lock);
|
||||
|
||||
rcu_read_lock();
|
||||
deve = pr_reg->pr_reg_deve;
|
||||
if (deve)
|
||||
set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags);
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE.
|
||||
*/
|
||||
if (!pr_reg->pr_reg_all_tg_pt || register_move)
|
||||
return;
|
||||
goto out;
|
||||
/*
|
||||
* Walk pr_reg->pr_reg_atp_list and add registrations for ALL_TG_PT=1
|
||||
* allocated in __core_scsi3_alloc_registration()
|
||||
|
@ -1075,19 +1102,31 @@ static void __core_scsi3_add_registration(
|
|||
__core_scsi3_dump_registration(tfo, dev, nacl_tmp, pr_reg_tmp,
|
||||
register_type);
|
||||
spin_unlock(&pr_tmpl->registration_lock);
|
||||
|
||||
/*
|
||||
* Drop configfs group dependency reference and deve->pr_kref
|
||||
* obtained from __core_scsi3_alloc_registration() code.
|
||||
*/
|
||||
rcu_read_lock();
|
||||
deve = pr_reg_tmp->pr_reg_deve;
|
||||
if (deve)
|
||||
if (deve) {
|
||||
set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags);
|
||||
core_scsi3_lunacl_undepend_item(deve);
|
||||
pr_reg_tmp->pr_reg_deve = NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* Drop configfs group dependency reference from
|
||||
* __core_scsi3_alloc_registration()
|
||||
*/
|
||||
core_scsi3_lunacl_undepend_item(pr_reg_tmp->pr_reg_deve);
|
||||
}
|
||||
out:
|
||||
/*
|
||||
* Drop deve->pr_kref obtained in __core_scsi3_do_alloc_registration()
|
||||
*/
|
||||
rcu_read_lock();
|
||||
deve = pr_reg->pr_reg_deve;
|
||||
if (deve) {
|
||||
set_bit(DEF_PR_REG_ACTIVE, &deve->deve_flags);
|
||||
kref_put(&deve->pr_kref, target_pr_kref_release);
|
||||
pr_reg->pr_reg_deve = NULL;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static int core_scsi3_alloc_registration(
|
||||
|
@ -1785,9 +1824,11 @@ core_scsi3_decode_spec_i_port(
|
|||
dest_node_acl->initiatorname, i_buf, (dest_se_deve) ?
|
||||
dest_se_deve->mapped_lun : 0);
|
||||
|
||||
if (!dest_se_deve)
|
||||
if (!dest_se_deve) {
|
||||
kref_put(&local_pr_reg->pr_reg_deve->pr_kref,
|
||||
target_pr_kref_release);
|
||||
continue;
|
||||
|
||||
}
|
||||
core_scsi3_lunacl_undepend_item(dest_se_deve);
|
||||
core_scsi3_nodeacl_undepend_item(dest_node_acl);
|
||||
core_scsi3_tpg_undepend_item(dest_tpg);
|
||||
|
@ -1823,9 +1864,11 @@ out:
|
|||
|
||||
kmem_cache_free(t10_pr_reg_cache, dest_pr_reg);
|
||||
|
||||
if (!dest_se_deve)
|
||||
if (!dest_se_deve) {
|
||||
kref_put(&local_pr_reg->pr_reg_deve->pr_kref,
|
||||
target_pr_kref_release);
|
||||
continue;
|
||||
|
||||
}
|
||||
core_scsi3_lunacl_undepend_item(dest_se_deve);
|
||||
core_scsi3_nodeacl_undepend_item(dest_node_acl);
|
||||
core_scsi3_tpg_undepend_item(dest_tpg);
|
||||
|
|
Загрузка…
Ссылка в новой задаче