From: Jeff Layton <jlayton@kernel.org>
To: Chuck Lever III <chuck.lever@oracle.com>
Cc: Linux NFS Mailing List <linux-nfs@vger.kernel.org>,
Neil Brown <neilb@suse.de>
Subject: Re: [PATCH v3 3/4] nfsd: close race between unhashing and LRU addition
Date: Fri, 28 Oct 2022 16:04:22 -0400 [thread overview]
Message-ID: <e64b1d579f4846331fdedad9bcdfe5eb52a7105c.camel@kernel.org> (raw)
In-Reply-To: <08778EE0-CBDC-467B-ACA6-9D8E6719E1BB@oracle.com>
On Fri, 2022-10-28 at 19:50 +0000, Chuck Lever III wrote:
>
> > On Oct 28, 2022, at 2:57 PM, Jeff Layton <jlayton@kernel.org> wrote:
> >
> > The list_lru_add and list_lru_del functions use list_empty checks to see
> > whether the object is already on the LRU. That's fine in most cases, but
> > we occasionally repurpose nf_lru after unhashing. It's possible for an
> > LRU removal to remove it from a different list altogether if we lose a
> > race.
>
> I've never seen that happen. lru field re-use is actually used in other
> places in the kernel. Shouldn't we try to find and fix such races?
>
> Wasn't the idea to reduce the complexity of nfsd_file_put ?
>
It certainly seems theoretically possible here. Maybe those other places
have other ways to ensure that it doesn't occur. We are dealing with RCU
freed structures here, so we can't always rely on locks to keep things
nice and serialized.
FWIW, I left this as a separate patch just to illustrate the race and
fix, but we probably would want to squash this one into the first.
> > Add a new NFSD_FILE_LRU flag, which indicates that the object actually
> > resides on the LRU and not some other list. Use that when adding and
> > removing it from the LRU instead of just relying on list_empty checks.
> >
> > Add an extra HASHED check after adding the entry to the LRU. If it's now
> > clear, just remove it from the LRU again and put the reference if that
> > remove is successful.
> >
> > Signed-off-by: Jeff Layton <jlayton@kernel.org>
> > ---
> > fs/nfsd/filecache.c | 44 +++++++++++++++++++++++++++++---------------
> > fs/nfsd/filecache.h | 1 +
> > 2 files changed, 30 insertions(+), 15 deletions(-)
> >
> > diff --git a/fs/nfsd/filecache.c b/fs/nfsd/filecache.c
> > index d928c5e38eeb..47cdc6129a7b 100644
> > --- a/fs/nfsd/filecache.c
> > +++ b/fs/nfsd/filecache.c
> > @@ -403,18 +403,22 @@ nfsd_file_check_writeback(struct nfsd_file *nf)
> > static bool nfsd_file_lru_add(struct nfsd_file *nf)
> > {
> > set_bit(NFSD_FILE_REFERENCED, &nf->nf_flags);
> > - if (list_lru_add(&nfsd_file_lru, &nf->nf_lru)) {
> > - trace_nfsd_file_lru_add(nf);
> > - return true;
> > + if (!test_and_set_bit(NFSD_FILE_LRU, &nf->nf_flags)) {
> > + if (list_lru_add(&nfsd_file_lru, &nf->nf_lru)) {
> > + trace_nfsd_file_lru_add(nf);
> > + return true;
> > + }
> > }
> > return false;
> > }
> >
> > static bool nfsd_file_lru_remove(struct nfsd_file *nf)
> > {
> > - if (list_lru_del(&nfsd_file_lru, &nf->nf_lru)) {
> > - trace_nfsd_file_lru_del(nf);
> > - return true;
> > + if (test_and_clear_bit(NFSD_FILE_LRU, &nf->nf_flags)) {
> > + if (list_lru_del(&nfsd_file_lru, &nf->nf_lru)) {
> > + trace_nfsd_file_lru_del(nf);
> > + return true;
> > + }
> > }
> > return false;
> > }
> > @@ -469,20 +473,30 @@ nfsd_file_put(struct nfsd_file *nf)
> > {
> > trace_nfsd_file_put(nf);
> >
> > - /*
> > - * The HASHED check is racy. We may end up with the occasional
> > - * unhashed entry on the LRU, but they should get cleaned up
> > - * like any other.
> > - */
> > if (test_bit(NFSD_FILE_GC, &nf->nf_flags) &&
> > test_bit(NFSD_FILE_HASHED, &nf->nf_flags)) {
> > /*
> > - * If this is the last reference (nf_ref == 1), then transfer
> > - * it to the LRU. If the add to the LRU fails, just put it as
> > - * usual.
> > + * If this is the last reference (nf_ref == 1), then try to
> > + * transfer it to the LRU.
> > */
> > - if (refcount_dec_not_one(&nf->nf_ref) || nfsd_file_lru_add(nf))
> > + if (refcount_dec_not_one(&nf->nf_ref))
> > return;
> > +
> > + /* Try to add it to the LRU. If that fails, decrement. */
> > + if (nfsd_file_lru_add(nf)) {
> > + /* If it's still hashed, we're done */
> > + if (test_bit(NFSD_FILE_HASHED, &nf->nf_flags))
> > + return;
> > +
> > + /*
> > + * We're racing with unhashing, so try to remove it from
> > + * the LRU. If removal fails, then someone else already
> > + * has our reference and we're done. If it succeeds,
> > + * fall through to decrement.
> > + */
> > + if (!nfsd_file_lru_remove(nf))
> > + return;
> > + }
> > }
> > if (refcount_dec_and_test(&nf->nf_ref))
> > nfsd_file_free(nf);
> > diff --git a/fs/nfsd/filecache.h b/fs/nfsd/filecache.h
> > index b7efb2c3ddb1..e52ab7d5a44c 100644
> > --- a/fs/nfsd/filecache.h
> > +++ b/fs/nfsd/filecache.h
> > @@ -39,6 +39,7 @@ struct nfsd_file {
> > #define NFSD_FILE_PENDING (1)
> > #define NFSD_FILE_REFERENCED (2)
> > #define NFSD_FILE_GC (3)
> > +#define NFSD_FILE_LRU (4) /* file is on LRU */
> > unsigned long nf_flags;
> > struct inode *nf_inode; /* don't deref */
> > refcount_t nf_ref;
> > --
> > 2.37.3
> >
>
> --
> Chuck Lever
>
>
>
--
Jeff Layton <jlayton@kernel.org>
next prev parent reply other threads:[~2022-10-28 20:04 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-28 18:57 [PATCH v3 0/4] nfsd: clean up refcounting in the filecache Jeff Layton
2022-10-28 18:57 ` [PATCH v3 1/4] nfsd: remove the pages_flushed statistic from filecache Jeff Layton
2022-10-28 19:41 ` Chuck Lever III
2022-10-28 18:57 ` [PATCH v3 2/4] nfsd: rework refcounting in filecache Jeff Layton
2022-10-28 19:49 ` Chuck Lever III
2022-10-28 20:13 ` Jeff Layton
2022-10-28 20:39 ` Chuck Lever III
2022-10-28 21:03 ` Jeff Layton
2022-10-28 21:23 ` Chuck Lever III
2022-10-31 9:40 ` Jeff Layton
2022-11-01 13:58 ` Chuck Lever III
2022-11-01 14:19 ` Jeff Layton
2022-10-28 18:57 ` [PATCH v3 3/4] nfsd: close race between unhashing and LRU addition Jeff Layton
2022-10-28 19:50 ` Chuck Lever III
2022-10-28 20:04 ` Jeff Layton [this message]
2022-10-30 21:45 ` NeilBrown
2022-10-31 2:51 ` Chuck Lever III
2022-10-31 10:08 ` Jeff Layton
2022-10-31 13:14 ` Chuck Lever III
2022-10-31 13:28 ` Jeff Layton
2022-10-31 10:01 ` Jeff Layton
2022-10-28 18:57 ` [PATCH v3 4/4] nfsd: start non-blocking writeback after adding nfsd_file to the LRU Jeff Layton
2022-10-28 19:50 ` Chuck Lever III
2022-10-28 20:30 ` Jeff Layton
2022-10-28 20:57 ` Chuck Lever III
2022-10-31 9:36 ` Jeff Layton
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=e64b1d579f4846331fdedad9bcdfe5eb52a7105c.camel@kernel.org \
--to=jlayton@kernel.org \
--cc=chuck.lever@oracle.com \
--cc=linux-nfs@vger.kernel.org \
--cc=neilb@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox