From patchwork Fri Mar 27 08:04:59 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Nicholas A. Bellinger" X-Patchwork-Id: 6103971 Return-Path: X-Original-To: patchwork-linux-scsi@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 9451F9F399 for ; Fri, 27 Mar 2015 08:06:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 53284203E5 for ; Fri, 27 Mar 2015 08:06:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E92AB203F7 for ; Fri, 27 Mar 2015 08:06:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753645AbbC0IGf (ORCPT ); Fri, 27 Mar 2015 04:06:35 -0400 Received: from mail-ob0-f170.google.com ([209.85.214.170]:36471 "EHLO mail-ob0-f170.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753568AbbC0IGO (ORCPT ); Fri, 27 Mar 2015 04:06:14 -0400 Received: by obbld8 with SMTP id ld8so13551305obb.3 for ; Fri, 27 Mar 2015 01:06:14 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=HCJFIo2b3zdtkj4kAk7IB8jAhtIJCzxJqinik0OkgYU=; b=K3QmOxaOfOgU0MPjfTWI1EVbRXZ9W/t9ob5EpFYc6sXeB+fa9hyOwVaLOUM2jpP4uw m0sDEVMyT4VeB7mSP5k1hqNKxcG/hlItmvIqq7jZrY+3x5TK+CZOi4f4Pe107lGOyZg+ ivBz/g6c5CKi0wxkPvz+sKXZViZE5tWfdzGz/VX2UwlRbAhJReMPCH7KxH7QsxCL7gF2 pxdPJnACokQjM0GV4TmxLvjt/VRLNpTXDICCvcEbSWfUzhlM8hqOh/Lr0AxMBmQJeO1q wcMxZX/FL6WqhgBvQ+EhdkxaMQRCDPTYVUHfvYxJS43xiWsJQPvCTy36CICdpNtk9Gxc SgSg== X-Gm-Message-State: ALoCoQlIhgySDdNV8fkjRJywo49WPJSbgmClMbbxMehwFUFrcELx8/XVDzaIevoB/goBGkyYDbmp X-Received: by 10.202.222.213 with SMTP id v204mr14395399oig.103.1427443574012; Fri, 27 Mar 2015 01:06:14 -0700 (PDT) Received: from localhost.localdomain (mail.linux-iscsi.org. [67.23.28.174]) by mx.google.com with ESMTPSA id h4sm711520obr.18.2015.03.27.01.06.13 (version=TLSv1 cipher=RC4-SHA bits=128/128); Fri, 27 Mar 2015 01:06:13 -0700 (PDT) From: "Nicholas A. Bellinger" To: target-devel Cc: linux-scsi , Hannes Reinecke , Christoph Hellwig , Sagi Grimberg , Nicholas Bellinger Subject: [RFC 09/22] target/pr: Convert registration check to RCU pointer Date: Fri, 27 Mar 2015 08:04:59 +0000 Message-Id: <1427443512-8925-10-git-send-email-nab@daterainc.com> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1427443512-8925-1-git-send-email-nab@daterainc.com> References: <1427443512-8925-1-git-send-email-nab@daterainc.com> Sender: linux-scsi-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-scsi@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Nicholas Bellinger This patch converts core_scsi3_pr_seq_non_holder() check for non reservation holding registrations to use se_deve->pr_reg as an RCU protected pointer. It also includes associated rcu_assign_pointer() + synchronize_rcu() in __core_scsi3_add_registration() and __core_scsi3_free_registration() for the RCU updater path. Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 1 + drivers/target/target_core_pr.c | 69 +++++++++++++++++++++++++++---------- include/target/target_core_base.h | 6 ++-- 3 files changed, 54 insertions(+), 22 deletions(-) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 473543e..670b1b5 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -432,6 +432,7 @@ int core_disable_device_list_for_node( */ spin_lock_irq(&nacl->lun_entry_lock); core_scsi3_ua_release_all(deve); + rcu_assign_pointer(deve->pr_reg, NULL); rcu_assign_pointer(deve->se_lun, NULL); rcu_assign_pointer(deve->se_lun_acl, NULL); deve->lun_flags = 0; diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 123e449..e23fe68 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -312,9 +312,12 @@ static int core_scsi3_pr_seq_non_holder( int we = 0; /* Write Exclusive */ int legacy = 0; /* Act like a legacy device and return * RESERVATION CONFLICT on some CDBs */ + bool registered; rcu_read_lock(); se_deve = rcu_dereference(nacl->lun_entry_hlist[cmd->orig_fe_lun]); + registered = (se_deve->pr_reg != NULL); + rcu_read_unlock(); /* * Determine if the registration should be ignored due to * non-matching ISIDs in target_scsi3_pr_reservation_check(). @@ -331,7 +334,7 @@ static int core_scsi3_pr_seq_non_holder( * Some commands are only allowed for the persistent reservation * holder. */ - if ((se_deve->def_pr_registered) && !(ignore_reg)) + if ((registered) && !(ignore_reg)) registered_nexus = 1; break; case PR_TYPE_WRITE_EXCLUSIVE_REGONLY: @@ -341,7 +344,7 @@ static int core_scsi3_pr_seq_non_holder( * Some commands are only allowed for registered I_T Nexuses. */ reg_only = 1; - if ((se_deve->def_pr_registered) && !(ignore_reg)) + if ((registered) && !(ignore_reg)) registered_nexus = 1; break; case PR_TYPE_WRITE_EXCLUSIVE_ALLREG: @@ -351,14 +354,12 @@ static int core_scsi3_pr_seq_non_holder( * Each registered I_T Nexus is a reservation holder. */ all_reg = 1; - if ((se_deve->def_pr_registered) && !(ignore_reg)) + if ((registered) && !(ignore_reg)) registered_nexus = 1; break; default: - rcu_read_unlock(); return -EINVAL; } - rcu_read_unlock(); /* * Referenced from spc4r17 table 45 for *NON* PR holder access */ @@ -996,10 +997,6 @@ static void __core_scsi3_dump_registration( pr_reg->pr_reg_aptpl); } -/* - * this function can be called with struct se_device->dev_reservation_lock - * when register_move = 1 - */ static void __core_scsi3_add_registration( struct se_device *dev, struct se_node_acl *nacl, @@ -1010,6 +1007,7 @@ static void __core_scsi3_add_registration( struct target_core_fabric_ops *tfo = nacl->se_tpg->se_tpg_tfo; struct t10_pr_registration *pr_reg_tmp, *pr_reg_tmp_safe; struct t10_reservation *pr_tmpl = &dev->t10_pr; + struct se_dev_entry *deve; /* * Increment PRgeneration counter for struct se_device upon a successful @@ -1026,10 +1024,20 @@ static void __core_scsi3_add_registration( spin_lock(&pr_tmpl->registration_lock); list_add_tail(&pr_reg->pr_reg_list, &pr_tmpl->registration_list); - pr_reg->pr_reg_deve->def_pr_registered = 1; __core_scsi3_dump_registration(tfo, dev, nacl, pr_reg, register_type); spin_unlock(&pr_tmpl->registration_lock); + + spin_lock(&nacl->lun_entry_lock); + deve = nacl->lun_entry_hlist[pr_reg->pr_res_mapped_lun]; + rcu_assign_pointer(deve->pr_reg, pr_reg); + spin_unlock(&nacl->lun_entry_lock); + /* + * Wait for read path critical RCU in core_scsi3_pr_seq_non_holder() + * conditional checks for deve->pr_reg pointer access complete. + */ + synchronize_rcu(); + /* * Skip extra processing for ALL_TG_PT=0 or REGISTER_AND_MOVE. */ @@ -1041,6 +1049,8 @@ static void __core_scsi3_add_registration( */ list_for_each_entry_safe(pr_reg_tmp, pr_reg_tmp_safe, &pr_reg->pr_reg_atp_list, pr_reg_atp_mem_list) { + struct se_node_acl *nacl_tmp = pr_reg_tmp->pr_reg_nacl; + list_del(&pr_reg_tmp->pr_reg_atp_mem_list); pr_reg_tmp->pr_res_generation = core_scsi3_pr_generation(dev); @@ -1048,12 +1058,21 @@ static void __core_scsi3_add_registration( spin_lock(&pr_tmpl->registration_lock); list_add_tail(&pr_reg_tmp->pr_reg_list, &pr_tmpl->registration_list); - pr_reg_tmp->pr_reg_deve->def_pr_registered = 1; - __core_scsi3_dump_registration(tfo, dev, - pr_reg_tmp->pr_reg_nacl, pr_reg_tmp, - register_type); + __core_scsi3_dump_registration(tfo, dev, nacl_tmp, pr_reg_tmp, + register_type); spin_unlock(&pr_tmpl->registration_lock); + + spin_lock(&nacl->lun_entry_lock); + deve = nacl_tmp->lun_entry_hlist[pr_reg_tmp->pr_res_mapped_lun]; + rcu_assign_pointer(deve->pr_reg, pr_reg_tmp); + spin_unlock(&nacl->lun_entry_lock); + /* + * Wait for read path critical RCU in core_scsi3_pr_seq_non_holder() + * conditional checks for deve->pr_reg pointer access complete. + */ + synchronize_rcu(); + /* * Drop configfs group dependency reference from * __core_scsi3_alloc_registration() @@ -1227,13 +1246,13 @@ static void __core_scsi3_free_registration( struct target_core_fabric_ops *tfo = pr_reg->pr_reg_nacl->se_tpg->se_tpg_tfo; struct t10_reservation *pr_tmpl = &dev->t10_pr; + struct se_node_acl *nacl = pr_reg->pr_reg_nacl; + struct se_dev_entry *deve; char i_buf[PR_REG_ISID_ID_LEN]; memset(i_buf, 0, PR_REG_ISID_ID_LEN); core_pr_dump_initiator_port(pr_reg, i_buf, PR_REG_ISID_ID_LEN); - pr_reg->pr_reg_deve->def_pr_registered = 0; - pr_reg->pr_reg_deve->pr_res_key = 0; if (!list_empty(&pr_reg->pr_reg_list)) list_del(&pr_reg->pr_reg_list); /* @@ -1242,6 +1261,8 @@ static void __core_scsi3_free_registration( */ if (dec_holders) core_scsi3_put_pr_reg(pr_reg); + + spin_unlock(&pr_tmpl->registration_lock); /* * Wait until all reference from any other I_T nexuses for this * *pr_reg have been released. Because list_del() is called above, @@ -1249,13 +1270,22 @@ static void __core_scsi3_free_registration( * count back to zero, and we release *pr_reg. */ while (atomic_read(&pr_reg->pr_res_holders) != 0) { - spin_unlock(&pr_tmpl->registration_lock); pr_debug("SPC-3 PR [%s] waiting for pr_res_holders\n", tfo->get_fabric_name()); cpu_relax(); - spin_lock(&pr_tmpl->registration_lock); } + spin_lock(&nacl->lun_entry_lock); + deve = nacl->lun_entry_hlist[pr_reg->pr_res_mapped_lun]; + rcu_assign_pointer(deve->pr_reg, NULL); + spin_unlock(&nacl->lun_entry_lock); + /* + * Wait for read path critical RCU in core_scsi3_pr_seq_non_holder() + * conditional checks for deve->pr_reg pointer access complete. + */ + synchronize_rcu(); + + spin_lock(&pr_tmpl->registration_lock); pr_debug("SPC-3 PR [%s] Service Action: UNREGISTER Initiator" " Node: %s%s\n", tfo->get_fabric_name(), pr_reg->pr_reg_nacl->initiatorname, @@ -3448,13 +3478,14 @@ after_iport_check: dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, iport_ptr); if (!dest_pr_reg) { + spin_unlock(&dev->dev_reservation_lock); if (core_scsi3_alloc_registration(cmd->se_dev, dest_node_acl, dest_se_deve, iport_ptr, sa_res_key, 0, aptpl, 2, 1)) { - spin_unlock(&dev->dev_reservation_lock); ret = TCM_INVALID_PARAMETER_LIST; goto out; } + spin_lock(&dev->dev_reservation_lock); dest_pr_reg = __core_scsi3_locate_pr_reg(dev, dest_node_acl, iport_ptr); new_reg = 1; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c4d182f..2566ce5 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -652,7 +652,6 @@ struct se_lun_acl { }; struct se_dev_entry { - bool def_pr_registered; /* See transport_lunflags_table */ u32 lun_flags; u32 mapped_lun; @@ -666,9 +665,10 @@ struct se_dev_entry { /* Used for PR SPEC_I_PT=1 and REGISTER_AND_MOVE */ struct percpu_ref pr_ref; struct completion pr_comp; - struct se_lun_acl *se_lun_acl; + struct se_lun_acl __rcu *se_lun_acl; spinlock_t ua_lock; - struct se_lun *se_lun; + struct se_lun __rcu *se_lun; + struct t10_pr_registration __rcu *pr_reg; struct list_head alua_port_list; struct list_head ua_list; };