Linux NFS development
 help / color / mirror / Atom feed
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>

  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