From: Jeff Layton <jlayton@kernel.org>
To: NeilBrown <neilb@suse.de>, Chuck Lever III <chuck.lever@oracle.com>
Cc: Linux NFS Mailing List <linux-nfs@vger.kernel.org>
Subject: Re: [PATCH 02/13] NFSD: verify the opened dentry after setting a delegation
Date: Wed, 27 Jul 2022 11:44:13 -0400 [thread overview]
Message-ID: <fb0bded1bb43404be5c577968894e637216d313e.camel@kernel.org> (raw)
In-Reply-To: <165881793054.21666.4968784719648129759.stgit@noble.brown>
On Tue, 2022-07-26 at 16:45 +1000, NeilBrown wrote:
> From: Jeff Layton <jlayton@kernel.org>
>
> Between opening a file and setting a delegation on it, someone could
> rename or unlink the dentry. If this happens, we do not want to grant a
> delegation on the open.
>
> On a CLAIM_NULL open, we're opening by filename, and we may (in the
> non-create case) or may not (in the create case) be holding i_rwsem
> when attempting to set a delegation. The latter case allows a
> race.
>
> After getting a lease, redo the lookup of the file being opened and
> validate that the resulting dentry matches the one in the open file
> description.
>
> To properly redo the lookup we need an rqst pointer to pass to
> nfsd_lookup_dentry(), so make sure that is available.
>
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> Signed-off-by: NeilBrown <neilb@suse.de>
> ---
> fs/nfsd/nfs4proc.c | 1 +
> fs/nfsd/nfs4state.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++-----
> fs/nfsd/xdr4.h | 1 +
> 3 files changed, 51 insertions(+), 5 deletions(-)
>
> diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
> index 5af9f8d1feb6..d57f91fa9f70 100644
> --- a/fs/nfsd/nfs4proc.c
> +++ b/fs/nfsd/nfs4proc.c
> @@ -547,6 +547,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
> open->op_openowner);
>
> open->op_filp = NULL;
> + open->op_rqstp = rqstp;
>
> /* This check required by spec. */
> if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
> diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
> index 279c7a1502c9..8f64af3e38d8 100644
> --- a/fs/nfsd/nfs4state.c
> +++ b/fs/nfsd/nfs4state.c
> @@ -5288,11 +5288,44 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp,
> return 0;
> }
>
> +/*
> + * It's possible that between opening the dentry and setting the delegation,
> + * that it has been renamed or unlinked. Redo the lookup to verify that this
> + * hasn't happened.
> + */
> +static int
> +nfsd4_verify_deleg_dentry(struct nfsd4_open *open, struct nfs4_file *fp,
> + struct svc_fh *parent)
> +{
> + struct svc_export *exp;
> + struct dentry *child;
> + __be32 err;
> +
> + /* parent may already be locked, and it may get unlocked by
> + * this call, but that is safe.
> + */
> + err = nfsd_lookup_dentry(open->op_rqstp, parent,
> + open->op_fname, open->op_fnamelen,
> + &exp, &child);
> +
Note that in the middle of this series, you may end up triggering the
printk in fh_lock_nested if you call nfsd_lookup_dentry and the fh is
already locked. I assume that gets resolved by the end of the series
however.
> + if (err)
> + return -EAGAIN;
> +
> + dput(child);
> + if (child != file_dentry(fp->fi_deleg_file->nf_file))
> + return -EAGAIN;
> +
> + return 0;
> +}
> +
> static struct nfs4_delegation *
> -nfs4_set_delegation(struct nfs4_client *clp,
> - struct nfs4_file *fp, struct nfs4_clnt_odstate *odstate)
> +nfs4_set_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
> + struct svc_fh *parent)
> {
> int status = 0;
> + struct nfs4_client *clp = stp->st_stid.sc_client;
> + struct nfs4_file *fp = stp->st_stid.sc_file;
> + struct nfs4_clnt_odstate *odstate = stp->st_clnt_odstate;
> struct nfs4_delegation *dp;
> struct nfsd_file *nf;
> struct file_lock *fl;
> @@ -5347,6 +5380,13 @@ nfs4_set_delegation(struct nfs4_client *clp,
> locks_free_lock(fl);
> if (status)
> goto out_clnt_odstate;
> +
> + if (parent) {
> + status = nfsd4_verify_deleg_dentry(open, fp, parent);
> + if (status)
> + goto out_unlock;
> + }
> +
> status = nfsd4_check_conflicting_opens(clp, fp);
> if (status)
> goto out_unlock;
> @@ -5402,11 +5442,13 @@ static void nfsd4_open_deleg_none_ext(struct nfsd4_open *open, int status)
> * proper support for them.
> */
> static void
> -nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
> +nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp,
> + struct svc_fh *currentfh)
> {
> struct nfs4_delegation *dp;
> struct nfs4_openowner *oo = openowner(stp->st_stateowner);
> struct nfs4_client *clp = stp->st_stid.sc_client;
> + struct svc_fh *parent = NULL;
> int cb_up;
> int status = 0;
>
> @@ -5420,6 +5462,8 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
> goto out_no_deleg;
> break;
> case NFS4_OPEN_CLAIM_NULL:
> + parent = currentfh;
> + fallthrough;
> case NFS4_OPEN_CLAIM_FH:
> /*
> * Let's not give out any delegations till everyone's
> @@ -5434,7 +5478,7 @@ nfs4_open_delegation(struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
> default:
> goto out_no_deleg;
> }
> - dp = nfs4_set_delegation(clp, stp->st_stid.sc_file, stp->st_clnt_odstate);
> + dp = nfs4_set_delegation(open, stp, parent);
> if (IS_ERR(dp))
> goto out_no_deleg;
>
> @@ -5566,7 +5610,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
> * Attempt to hand out a delegation. No error return, because the
> * OPEN succeeds even if we fail.
> */
> - nfs4_open_delegation(open, stp);
> + nfs4_open_delegation(open, stp, &resp->cstate.current_fh);
> nodeleg:
> status = nfs_ok;
> trace_nfsd_open(&stp->st_stid.sc_stateid);
> diff --git a/fs/nfsd/xdr4.h b/fs/nfsd/xdr4.h
> index 7b744011f2d3..189f0600dbe8 100644
> --- a/fs/nfsd/xdr4.h
> +++ b/fs/nfsd/xdr4.h
> @@ -279,6 +279,7 @@ struct nfsd4_open {
> struct nfs4_clnt_odstate *op_odstate; /* used during processing */
> struct nfs4_acl *op_acl;
> struct xdr_netobj op_label;
> + struct svc_rqst *op_rqstp;
> };
>
> struct nfsd4_open_confirm {
>
>
--
Jeff Layton <jlayton@kernel.org>
next prev parent reply other threads:[~2022-07-27 15:44 UTC|newest]
Thread overview: 37+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-07-26 6:45 [PATCH 00/13] NFSD: clean up locking NeilBrown
2022-07-26 6:45 ` [PATCH 03/13] NFSD: introduce struct nfsd_attrs NeilBrown
2022-07-28 14:53 ` Chuck Lever III
2022-07-26 6:45 ` [PATCH 13/13] NFSD: discard fh_locked flag and fh_lock/fh_unlock NeilBrown
2022-07-26 6:45 ` [PATCH 12/13] NFSD: use (un)lock_inode instead of fh_(un)lock for file operations NeilBrown
2022-07-28 14:55 ` Chuck Lever III
2022-07-26 6:45 ` [PATCH 05/13] NFSD: add security label to struct nfsd_attrs NeilBrown
2022-07-28 14:54 ` Chuck Lever III
2022-07-29 1:11 ` NeilBrown
2022-07-26 6:45 ` [PATCH 07/13] NFSD: change nfsd_create()/nfsd_symlink() to unlock directory before returning NeilBrown
2022-07-26 6:45 ` [PATCH 04/13] NFSD: set attributes when creating symlinks NeilBrown
2022-07-26 12:40 ` Chuck Lever III
2022-07-26 12:53 ` Jeff Layton
2022-07-26 13:02 ` Chuck Lever III
2022-07-26 22:01 ` NeilBrown
2022-07-28 14:53 ` Chuck Lever III
2022-07-29 1:09 ` NeilBrown
2022-07-26 6:45 ` [PATCH 06/13] NFSD: add posix ACLs to struct nfsd_attrs NeilBrown
2022-07-29 14:24 ` Chuck Lever III
2022-08-01 0:13 ` NeilBrown
2022-07-26 6:45 ` [PATCH 08/13] NFSD: always drop directory lock in nfsd_unlink() NeilBrown
2022-07-26 6:45 ` [PATCH 10/13] NFSD: reduce locking in nfsd_lookup() NeilBrown
2022-07-28 14:54 ` Chuck Lever III
2022-07-26 6:45 ` [PATCH 11/13] NFSD: use explicit lock/unlock for directory ops NeilBrown
2022-07-28 14:54 ` Chuck Lever III
2022-07-29 1:27 ` NeilBrown
2022-07-29 14:31 ` Chuck Lever III
2022-07-29 14:34 ` Chuck Lever III
2022-07-26 6:45 ` [PATCH 02/13] NFSD: verify the opened dentry after setting a delegation NeilBrown
2022-07-27 15:44 ` Jeff Layton [this message]
2022-07-26 6:45 ` [PATCH 01/13] NFSD: drop fh argument from alloc_init_deleg NeilBrown
2022-07-26 6:45 ` [PATCH 09/13] NFSD: only call fh_unlock() once in nfsd_link() NeilBrown
2022-07-27 15:50 ` [PATCH 00/13] NFSD: clean up locking Jeff Layton
2022-07-27 17:12 ` Chuck Lever III
2022-07-27 23:48 ` NeilBrown
2022-07-28 14:52 ` Chuck Lever III
2022-07-29 1:29 ` NeilBrown
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=fb0bded1bb43404be5c577968894e637216d313e.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