Received: by 2002:a05:6359:c8b:b0:c7:702f:21d4 with SMTP id go11csp1159359rwb; Thu, 6 Oct 2022 09:09:22 -0700 (PDT) X-Google-Smtp-Source: AMsMyM7vJvmAVzD7a7/jpJ5hhglKOytmYDBbhPSbD4Koj9QNmYhYj/gxeBosi3sdAxMW/BkfB64w X-Received: by 2002:a05:6402:278b:b0:458:d5af:aaa0 with SMTP id b11-20020a056402278b00b00458d5afaaa0mr485489ede.91.1665072562097; Thu, 06 Oct 2022 09:09:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1665072562; cv=none; d=google.com; s=arc-20160816; b=zMwCcga2SeAJG6c/m5+OoIidyHEb6XHXus+wBclGZvIAHBimeMxyFQT3hRElM1pkAu sQZXAuqn2Bb/21dOLPWG3J8bA7W0ViMn2LqSWuhG5vZUyCOITcRIFzo3NtyUftIGTd1k lNAzmaR9bSYlwC81lordxJj7adkRZR3/oYNYqAP9oBj7+0MTL2nvzHbALgUNG7Fp8/BF pNOQF+Il5FwwhmslXJcnwsiEQ15/5laPjWby5AONT3Rapq1w3bs9/FM1KszkeP3q0+bU vP3mA/fv06/GQrQ7KIU1Ii9268hR1LBoJ87q3A3D9MtCz8JFQ+963mwc3RN6s6IdxMNZ 4uVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:user-agent :content-transfer-encoding:references:in-reply-to:date:to:from :subject:message-id:dkim-signature; bh=ni6DCFkbavjKWUh/boEE+qoCikxpB5K3jQSYCtzNKJM=; b=cZpKSXEiONLy1rgtcVj3ik1DH21jkQ+wghwhOzmhlPibJEaBD4HeXOfuiwXIvtKHGk OaRgssU9M1AeVp4InYEt+/p38yYbPHkzXYjWcXNo7jXkgeMSTPOassf3vTyMePHOER7M 9qb0BgRvzYLVW8dP31EYn7lX3ZADotnCWhDnitxzKLKG2xUHRXaHiprgJ1uk4YXDteKc NhcjNDMr71/syI/MXNHTenLCBF+9x8e6XRIBPDRSFDK0xrz+8DvUdIljLLFb7hs/+bBG kL2GzSdxL8qsEk5UpBVzaSkDsLafR8QKM3LDppKexmc2LbV0l4v/V9Bg2i1WX5XLJLrF VPmA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=qiRXLy0a; spf=pass (google.com: domain of linux-nfs-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-nfs-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id qb3-20020a1709077e8300b0078330773290si16748332ejc.396.2022.10.06.09.08.45; Thu, 06 Oct 2022 09:09:22 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-nfs-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=k20201202 header.b=qiRXLy0a; spf=pass (google.com: domain of linux-nfs-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-nfs-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231400AbiJFP7N (ORCPT + 99 others); Thu, 6 Oct 2022 11:59:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37026 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231295AbiJFP7M (ORCPT ); Thu, 6 Oct 2022 11:59:12 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6968BA0241 for ; Thu, 6 Oct 2022 08:59:10 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 02DE1619EC for ; Thu, 6 Oct 2022 15:59:10 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1FFA7C433D7; Thu, 6 Oct 2022 15:59:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1665071949; bh=hRrDLT4PO3+c3WJGuNZLK3BLxzt5GgONTs5rNdCB4z4=; h=Subject:From:To:Date:In-Reply-To:References:From; b=qiRXLy0ahRiT52XdPrzr0G007G1bzdmzkJFmRRbqLoAszAHqLcWzFlHxYZ79m5BzD fExxjQdvVQnU6kRqP2F2K4XUDJtsQhTzMJsbBcJVCLXHEYSfh6uF9TIuLy/sAqHrtj LFzwUNY1Ic9+002hVxIAnwEwMCOYiSpYJZsVMXdSHtFnY1uuQX5J+CqI3mZaT7zesB f1PWu4tS39QOX8EsIgpuVlTOVyYwSW5DhivKUXyKjKLU8+AHdOBkWveccNBKLxe7JF 9fzqngDuangyKRH9dfoY/LvF3jp/7kS981oXennXH8eqIn33MRbS3avvxPT5cYPqzo ujdXtUDSQl1WQ== Message-ID: <4acac2ce88920ec3b25d52ac97ed5739838a85ac.camel@kernel.org> Subject: Re: [PATCH RFC 5/9] NFSD: Add an NFSD_FILE_GC flag to enable nfsd_file garbage collection From: Jeff Layton To: Chuck Lever , linux-nfs@vger.kernel.org Date: Thu, 06 Oct 2022 11:59:07 -0400 In-Reply-To: <166498176824.1527.5576152854743615272.stgit@manet.1015granger.net> References: <166497916751.1527.11190362197003358927.stgit@manet.1015granger.net> <166498176824.1527.5576152854743615272.stgit@manet.1015granger.net> Content-Type: text/plain; charset="ISO-8859-15" Content-Transfer-Encoding: quoted-printable User-Agent: Evolution 3.44.4 (3.44.4-2.fc36) MIME-Version: 1.0 X-Spam-Status: No, score=-7.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI, SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-nfs@vger.kernel.org On Wed, 2022-10-05 at 10:56 -0400, Chuck Lever wrote: > NFSv4 operations manage the lifetime of nfsd_file items they use by > means of NFSv4 OPEN and CLOSE. Hence there's no need for them to be > garbage collected. >=20 > Introduce a mechanism to enable garbage collection for nfsd_file > items used only by NFSv2/3 callers. >=20 > Note that the change in nfsd_file_put() ensures that both CLOSE and > DELEGRETURN will actually close out and free an nfsd_file on last > reference of a non-garbage-collected file. >=20 > Link: https://bugzilla.linux-nfs.org/show_bug.cgi?id=3D394 > Suggested-by: Trond Myklebust > Signed-off-by: Chuck Lever > --- > fs/nfsd/filecache.c | 61 +++++++++++++++++++++++++++++++++++++++++++++= ------ > fs/nfsd/filecache.h | 3 +++ > fs/nfsd/nfs3proc.c | 4 ++- > fs/nfsd/trace.h | 3 ++- > fs/nfsd/vfs.c | 4 ++- > 5 files changed, 63 insertions(+), 12 deletions(-) >=20 > diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c > index b7aa523c2010..01c27deabf83 100644 > --- a/fs/nfsd/filecache.c > +++ b/fs/nfsd/filecache.c > @@ -63,6 +63,7 @@ struct nfsd_file_lookup_key { > struct net *net; > const struct cred *cred; > unsigned char need; > + unsigned char gc:1; > enum nfsd_file_lookup_type type; > }; > =20 > @@ -162,6 +163,8 @@ static int nfsd_file_obj_cmpfn(struct rhashtable_comp= are_arg *arg, > return 1; > if (!nfsd_match_cred(nf->nf_cred, key->cred)) > return 1; > + if (test_bit(NFSD_FILE_GC, &nf->nf_flags) !=3D key->gc) > + return 1; > if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) =3D=3D 0) > return 1; > break; > @@ -297,6 +300,8 @@ nfsd_file_alloc(struct nfsd_file_lookup_key *key, uns= igned int may) > nf->nf_flags =3D 0; > __set_bit(NFSD_FILE_HASHED, &nf->nf_flags); > __set_bit(NFSD_FILE_PENDING, &nf->nf_flags); > + if (key->gc) > + __set_bit(NFSD_FILE_GC, &nf->nf_flags); > nf->nf_inode =3D key->inode; > /* nf_ref is pre-incremented for hash table */ > refcount_set(&nf->nf_ref, 2); > @@ -428,16 +433,27 @@ nfsd_file_put_noref(struct nfsd_file *nf) > } > } > =20 > +static void > +nfsd_file_unhash_and_put(struct nfsd_file *nf) > +{ > + if (nfsd_file_unhash(nf)) > + nfsd_file_put_noref(nf); > +} > + > void > nfsd_file_put(struct nfsd_file *nf) > { > might_sleep(); > =20 > - nfsd_file_lru_add(nf); > + if (test_bit(NFSD_FILE_GC, &nf->nf_flags) =3D=3D 1) > + nfsd_file_lru_add(nf); > + else if (refcount_read(&nf->nf_ref) =3D=3D 2) > + nfsd_file_unhash_and_put(nf); > + > if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags) =3D=3D 0) { > nfsd_file_flush(nf); > nfsd_file_put_noref(nf); > - } else if (nf->nf_file) { > + } else if (nf->nf_file && test_bit(NFSD_FILE_GC, &nf->nf_flags) =3D=3D = 1) { > nfsd_file_put_noref(nf); > nfsd_file_schedule_laundrette(); > } else > @@ -1017,12 +1033,14 @@ nfsd_file_is_cached(struct inode *inode) > =20 > static __be32 > nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, > - unsigned int may_flags, struct nfsd_file **pnf, bool open) > + unsigned int may_flags, struct nfsd_file **pnf, > + bool open, int want_gc) want_gc should be a bool > { > struct nfsd_file_lookup_key key =3D { > .type =3D NFSD_FILE_KEY_FULL, > .need =3D may_flags & NFSD_FILE_MAY_MASK, > .net =3D SVC_NET(rqstp), > + .gc =3D want_gc, > }; > bool open_retry =3D true; > struct nfsd_file *nf; > @@ -1117,14 +1135,35 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, stru= ct svc_fh *fhp, > * then unhash. > */ > if (status !=3D nfs_ok || key.inode->i_nlink =3D=3D 0) > - if (nfsd_file_unhash(nf)) > - nfsd_file_put_noref(nf); > + nfsd_file_unhash_and_put(nf); > clear_bit_unlock(NFSD_FILE_PENDING, &nf->nf_flags); > smp_mb__after_atomic(); > wake_up_bit(&nf->nf_flags, NFSD_FILE_PENDING); > goto out; > } > =20 > +/** > + * nfsd_file_acquire_gc - Get a struct nfsd_file with an open file > + * @rqstp: the RPC transaction being executed > + * @fhp: the NFS filehandle of the file to be opened > + * @may_flags: NFSD_MAY_ settings for the file > + * @pnf: OUT: new or found "struct nfsd_file" object > + * > + * The nfsd_file object returned by this API is reference-counted > + * and garbage-collected. The object is retained for a few > + * seconds after the final nfsd_file_put() in case the caller > + * wants to re-use it. > + * > + * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in > + * network byte order is returned. > + */ > +__be32 > +nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp, > + unsigned int may_flags, struct nfsd_file **pnf) > +{ > + return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, 1); > +} > + > /** > * nfsd_file_acquire - Get a struct nfsd_file with an open file > * @rqstp: the RPC transaction being executed > @@ -1132,6 +1171,10 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struc= t svc_fh *fhp, > * @may_flags: NFSD_MAY_ settings for the file > * @pnf: OUT: new or found "struct nfsd_file" object > * > + * The nfsd_file_object returned by this API is reference-counted > + * but not garbage-collected. The object is released one RCU grace > + * period after the final nfsd_file_put(). > + * > * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in > * network byte order is returned. > */ > @@ -1139,7 +1182,7 @@ __be32 > nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, > unsigned int may_flags, struct nfsd_file **pnf) > { > - return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true); > + return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, true, 0); > } > =20 > /** > @@ -1149,6 +1192,10 @@ nfsd_file_acquire(struct svc_rqst *rqstp, struct s= vc_fh *fhp, > * @may_flags: NFSD_MAY_ settings for the file > * @pnf: OUT: new or found "struct nfsd_file" object > * > + * The nfsd_file_object returned by this API is reference-counted > + * but not garbage-collected. The object is released immediately > + * one RCU grace period after the final nfsd_file_put(). > + * > * Returns nfs_ok and sets @pnf on success; otherwise an nfsstat in > * network byte order is returned. > */ > @@ -1156,7 +1203,7 @@ __be32 > nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, > unsigned int may_flags, struct nfsd_file **pnf) > { > - return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false); > + return nfsd_file_do_acquire(rqstp, fhp, may_flags, pnf, false, 0); > } > =20 > /* > diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h > index f81c198f4ed6..0f6546bcd3e0 100644 > --- a/fs/nfsd/filecache.h > +++ b/fs/nfsd/filecache.h > @@ -38,6 +38,7 @@ struct nfsd_file { > #define NFSD_FILE_HASHED (0) > #define NFSD_FILE_PENDING (1) > #define NFSD_FILE_REFERENCED (2) > +#define NFSD_FILE_GC (3) > unsigned long nf_flags; > struct inode *nf_inode; /* don't deref */ > refcount_t nf_ref; > @@ -55,6 +56,8 @@ void nfsd_file_put(struct nfsd_file *nf); > struct nfsd_file *nfsd_file_get(struct nfsd_file *nf); > void nfsd_file_close_inode_sync(struct inode *inode); > bool nfsd_file_is_cached(struct inode *inode); > +__be32 nfsd_file_acquire_gc(struct svc_rqst *rqstp, struct svc_fh *fhp, > + unsigned int may_flags, struct nfsd_file **nfp); > __be32 nfsd_file_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp, > unsigned int may_flags, struct nfsd_file **nfp); > __be32 nfsd_file_create(struct svc_rqst *rqstp, struct svc_fh *fhp, > diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c > index d12823371857..6a5ad6c91d8e 100644 > --- a/fs/nfsd/nfs3proc.c > +++ b/fs/nfsd/nfs3proc.c > @@ -779,8 +779,8 @@ nfsd3_proc_commit(struct svc_rqst *rqstp) > (unsigned long long) argp->offset); > =20 > fh_copy(&resp->fh, &argp->fh); > - resp->status =3D nfsd_file_acquire(rqstp, &resp->fh, NFSD_MAY_WRITE | > - NFSD_MAY_NOT_BREAK_LEASE, &nf); > + resp->status =3D nfsd_file_acquire_gc(rqstp, &resp->fh, NFSD_MAY_WRITE = | > + NFSD_MAY_NOT_BREAK_LEASE, &nf); > if (resp->status) > goto out; > resp->status =3D nfsd_commit(rqstp, &resp->fh, nf, argp->offset, > diff --git a/fs/nfsd/trace.h b/fs/nfsd/trace.h > index 9ebd67d461f9..4921144880d3 100644 > --- a/fs/nfsd/trace.h > +++ b/fs/nfsd/trace.h > @@ -742,7 +742,8 @@ DEFINE_CLID_EVENT(confirmed_r); > __print_flags(val, "|", \ > { 1 << NFSD_FILE_HASHED, "HASHED" }, \ > { 1 << NFSD_FILE_PENDING, "PENDING" }, \ > - { 1 << NFSD_FILE_REFERENCED, "REFERENCED"}) > + { 1 << NFSD_FILE_REFERENCED, "REFERENCED"}, \ > + { 1 << NFSD_FILE_GC, "GC"}) > =20 > DECLARE_EVENT_CLASS(nfsd_file_class, > TP_PROTO(struct nfsd_file *nf), > diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c > index 44f210ba17cc..89d682a56fc4 100644 > --- a/fs/nfsd/vfs.c > +++ b/fs/nfsd/vfs.c > @@ -1060,7 +1060,7 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc= _fh *fhp, > __be32 err; > =20 > trace_nfsd_read_start(rqstp, fhp, offset, *count); > - err =3D nfsd_file_acquire(rqstp, fhp, NFSD_MAY_READ, &nf); > + err =3D nfsd_file_acquire_gc(rqstp, fhp, NFSD_MAY_READ, &nf); > if (err) > return err; > =20 > @@ -1092,7 +1092,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *f= hp, loff_t offset, > =20 > trace_nfsd_write_start(rqstp, fhp, offset, *cnt); > =20 > - err =3D nfsd_file_acquire(rqstp, fhp, NFSD_MAY_WRITE, &nf); > + err =3D nfsd_file_acquire_gc(rqstp, fhp, NFSD_MAY_WRITE, &nf); > if (err) > goto out; > =20 >=20 >=20 Looks reasonable otherwise though. I like this approach. --=20 Jeff Layton