From patchwork Thu Jun 26 19:12:51 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jeff Layton X-Patchwork-Id: 4430831 Return-Path: X-Original-To: patchwork-linux-nfs@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id B0BA59F2C8 for ; Thu, 26 Jun 2014 19:15:30 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id B95CA201BB for ; Thu, 26 Jun 2014 19:15:29 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id AEE142028D for ; Thu, 26 Jun 2014 19:15:28 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751660AbaFZTPZ (ORCPT ); Thu, 26 Jun 2014 15:15:25 -0400 Received: from mail-qc0-f181.google.com ([209.85.216.181]:45659 "EHLO mail-qc0-f181.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751836AbaFZTPW (ORCPT ); Thu, 26 Jun 2014 15:15:22 -0400 Received: by mail-qc0-f181.google.com with SMTP id x13so3606647qcv.12 for ; Thu, 26 Jun 2014 12:15:22 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=xz1kRqbyId2Zu7OcP4E94umMtsxTWuwQZ2iqkovE3yY=; b=j+imtaETaHaJXOpQUabk4XUrOmIZ7qMV4mt4p0ij4kGau7426qX1mtfGh1saQHevtQ 47INI3n7wZY8eDxX5xhbNFaAgyfRI0YqeMZn5jTIL8rPaTPi8DsCmHYAEQoGA/UKCgK3 Ly9nhKDm0IedNuJ7SL/WxqdLXq8Mi2QLGY8LNrB3wZGjgJ0uJmfukEnAkUT8+/x+FJVM 4Srqrc1SslAVMya4Z7asZwMjcM4RhchoJHlGheXbMiGCGuhL1qprAp0F4d1jgJ87H48D O+QMYb0Dnu5rMxo13r9OL+OWpIbHFXpIX2pbokGQz56rk6D5MFqK7JL8hgntqI/PZy1g jcYQ== X-Gm-Message-State: ALoCoQm546CEgTtRSJoFx7qzU4JkVRNYzqkAtogDTYY5/NTtfHL84QPrTpGqya1TbUjw/9ZZRBrM X-Received: by 10.140.108.99 with SMTP id i90mr12507043qgf.56.1403810122031; Thu, 26 Jun 2014 12:15:22 -0700 (PDT) Received: from tlielax.poochiereds.net ([2001:470:8:d63:3a60:77ff:fe93:a95d]) by mx.google.com with ESMTPSA id 88sm4763039qgh.5.2014.06.26.12.15.20 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 26 Jun 2014 12:15:21 -0700 (PDT) From: Jeff Layton To: bfields@fieldses.org Cc: linux-nfs@vger.kernel.org, Trond Myklebust Subject: [PATCH v2 071/117] nfsd: Protect adding/removing open state owners using client_lock Date: Thu, 26 Jun 2014 15:12:51 -0400 Message-Id: <1403810017-16062-72-git-send-email-jlayton@primarydata.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1403810017-16062-1-git-send-email-jlayton@primarydata.com> References: <1403810017-16062-1-git-send-email-jlayton@primarydata.com> Sender: linux-nfs-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-nfs@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: Trond Myklebust Once we remove client mutex protection, we'll need to ensure that stateowner lookup and creation are atomic between concurrent compounds. Ensure that alloc_init_open_stateowner checks the hashtable under the client_lock before adding a new element. Signed-off-by: Trond Myklebust --- fs/nfsd/nfs4state.c | 63 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 9 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 029e41b4de84..4285bc405736 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -72,6 +72,9 @@ static u64 current_sessionid = 1; /* forward declarations */ static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner); static void nfs4_free_generic_stateid(struct nfs4_stid *stid); +static struct nfs4_openowner *find_openstateowner_str_locked( + unsigned int hashval, struct nfsd4_open *open, + bool sessions, struct nfsd_net *nn); static void nfs4_put_stateowner(struct nfs4_stateowner *sop); static __be32 lookup_clientid(clientid_t *clid, struct nfsd4_compound_state *cstate, @@ -998,8 +1001,13 @@ static void release_open_stateid(struct nfs4_ol_stateid *stp) put_generic_stateid(stp); } -static void unhash_openowner(struct nfs4_openowner *oo) +static void unhash_openowner_locked(struct nfs4_openowner *oo) { + struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, + nfsd_net_id); + + lockdep_assert_held(&nn->client_lock); + list_del_init(&oo->oo_owner.so_strhash); list_del_init(&oo->oo_perclient); } @@ -1018,18 +1026,29 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo) static void release_openowner_stateids(struct nfs4_openowner *oo) { struct nfs4_ol_stateid *stp; + struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, + nfsd_net_id); + + lockdep_assert_held(&nn->client_lock); while (!list_empty(&oo->oo_owner.so_stateids)) { stp = list_first_entry(&oo->oo_owner.so_stateids, struct nfs4_ol_stateid, st_perstateowner); + spin_unlock(&nn->client_lock); release_open_stateid(stp); + spin_lock(&nn->client_lock); } } static void release_openowner(struct nfs4_openowner *oo) { - unhash_openowner(oo); + struct nfsd_net *nn = net_generic(oo->oo_owner.so_client->net, + nfsd_net_id); + + spin_lock(&nn->client_lock); + unhash_openowner_locked(oo); release_openowner_stateids(oo); + spin_unlock(&nn->client_lock); release_last_closed_stateid(oo); nfs4_put_stateowner(&oo->oo_owner); } @@ -3008,8 +3027,11 @@ static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, u static void nfs4_unhash_openowner(struct nfs4_stateowner *so) { struct nfs4_openowner *oo = openowner(so); + struct nfsd_net *nn = net_generic(so->so_client->net, nfsd_net_id); - unhash_openowner(oo); + spin_lock(&nn->client_lock); + unhash_openowner_locked(oo); + spin_unlock(&nn->client_lock); } static void nfs4_free_openowner(struct nfs4_stateowner *so) @@ -3025,7 +3047,8 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, struct nfsd4_compound_state *cstate) { struct nfs4_client *clp = cstate->clp; - struct nfs4_openowner *oo; + struct nfsd_net *nn = net_generic(clp->net, nfsd_net_id); + struct nfs4_openowner *oo, *ret; oo = alloc_stateowner(openowner_slab, &open->op_owner, clp); if (!oo) @@ -3040,7 +3063,15 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfsd4_open *open, oo->oo_time = 0; oo->oo_last_closed_stid = NULL; INIT_LIST_HEAD(&oo->oo_close_lru); - hash_openowner(oo, clp, strhashval); + spin_lock(&nn->client_lock); + ret = find_openstateowner_str_locked(strhashval, + open, clp->cl_minorversion, nn); + if (ret == NULL) { + hash_openowner(oo, clp, strhashval); + ret = oo; + } else + nfs4_free_openowner(&oo->oo_owner); + spin_unlock(&nn->client_lock); return oo; } @@ -3114,13 +3145,15 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner, } static struct nfs4_openowner * -find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, +find_openstateowner_str_locked(unsigned int hashval, struct nfsd4_open *open, bool sessions, struct nfsd_net *nn) { struct nfs4_stateowner *so; struct nfs4_openowner *oo; struct nfs4_client *clp; + lockdep_assert_held(&nn->client_lock); + list_for_each_entry(so, &nn->ownerstr_hashtbl[hashval], so_strhash) { if (!so->so_is_open_owner) continue; @@ -3128,15 +3161,27 @@ find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, oo = openowner(so); clp = oo->oo_owner.so_client; if ((bool)clp->cl_minorversion != sessions) - return NULL; - renew_client(oo->oo_owner.so_client); - atomic_inc(&oo->oo_owner.so_count); + break; + renew_client_locked(clp); + atomic_inc(&so->so_count); return oo; } } return NULL; } +static struct nfs4_openowner * +find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, + bool sessions, struct nfsd_net *nn) +{ + struct nfs4_openowner *oo; + + spin_lock(&nn->client_lock); + oo = find_openstateowner_str_locked(hashval, open, sessions, nn); + spin_unlock(&nn->client_lock); + return oo; +} + /* search file_hashtbl[] for file */ static struct nfs4_file * find_file_locked(struct inode *ino)