Linux NFS development
 help / color / mirror / Atom feed
From: Trond Myklebust <trond.myklebust@fys.uio.no>
To: Chuck Lever <chucklever@gmail.com>
Cc: nfs@lists.sourceforge.net
Subject: Re: [PATCH 23/25] NFS: Fix double d_drop in nfs_instantiate()	error path
Date: Wed, 09 Aug 2006 11:34:27 -0400	[thread overview]
Message-ID: <1155137667.5731.90.camel@localhost> (raw)
In-Reply-To: <20060809145946.3914.34497.stgit@picasso.dsl.sfldmi.ameritech.net>

On Wed, 2006-08-09 at 10:59 -0400, Chuck Lever wrote:
> If the LOOKUP or GETATTR in nfs_instantiate fail, nfs_instantiate will do a
> d_drop before returning.  But some callers already do a d_drop in the case
> of an error return.  Make certain we do only one d_drop in all error paths.

Hmm... Calling d_drop() twice is at worst an inefficiency. It is not
strictly speaking a bug.

> This bug was introduced because over time, the symlink proc API diverged
> slightly from the create/mkdir/mknod proc API.  To prevent other bugs of
> this type, change the symlink proc API to be more like create/mkdir/mknod
> and move the nfs_instantiate call into the symlink proc routines so it is
> used in exactly the same way for create, mkdir, mknod, and symlink.
> 
> Test plan:
> Connectathon, all versions of NFS.
> 
> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
> ---
> 
>  fs/nfs/dir.c            |   16 ++++------------
>  fs/nfs/nfs3proc.c       |   26 ++++++++++++++++----------
>  fs/nfs/nfs4proc.c       |   31 ++++++++++++++++---------------
>  fs/nfs/proc.c           |   29 +++++++++++++++++++++--------
>  include/linux/nfs_xdr.h |    5 ++---
>  5 files changed, 59 insertions(+), 48 deletions(-)
> 
> diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
> index 428d963..ff4e852 100644
> --- a/fs/nfs/dir.c
> +++ b/fs/nfs/dir.c
> @@ -1143,23 +1143,20 @@ int nfs_instantiate(struct dentry *dentr
>  		struct inode *dir = dentry->d_parent->d_inode;
>  		error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
>  		if (error)
> -			goto out_err;
> +			return error;
>  	}
>  	if (!(fattr->valid & NFS_ATTR_FATTR)) {
>  		struct nfs_server *server = NFS_SB(dentry->d_sb);
>  		error = server->rpc_ops->getattr(server, fhandle, fattr);
>  		if (error < 0)
> -			goto out_err;
> +			return error;
>  	}
>  	inode = nfs_fhget(dentry->d_sb, fhandle, fattr);
>  	error = PTR_ERR(inode);
>  	if (IS_ERR(inode))
> -		goto out_err;
> +		return error;
>  	d_instantiate(dentry, inode);
>  	return 0;
> -out_err:
> -	d_drop(dentry);
> -	return error;
>  }
>  
>  /*
> @@ -1444,8 +1441,6 @@ static int
>  nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
>  {
>  	struct iattr attr;
> -	struct nfs_fattr sym_attr;
> -	struct nfs_fh sym_fh;
>  	struct qstr qsymname;
>  	int error;
>  
> @@ -1469,12 +1464,9 @@ #endif
>  
>  	lock_kernel();
>  	nfs_begin_data_update(dir);
> -	error = NFS_PROTO(dir)->symlink(dir, &dentry->d_name, &qsymname,
> -					  &attr, &sym_fh, &sym_attr);
> +	error = NFS_PROTO(dir)->symlink(dir, dentry, &qsymname, &attr);
>  	nfs_end_data_update(dir);
>  	if (!error)
> -		error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
> -	else
>  		d_drop(dentry);
>  	unlock_kernel();
>  	return error;
> diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
> index 7143b1f..15eac8d 100644
> --- a/fs/nfs/nfs3proc.c
> +++ b/fs/nfs/nfs3proc.c
> @@ -544,23 +544,23 @@ nfs3_proc_link(struct inode *inode, stru
>  }
>  
>  static int
> -nfs3_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
> -		  struct iattr *sattr, struct nfs_fh *fhandle,
> -		  struct nfs_fattr *fattr)
> +nfs3_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
> +		  struct iattr *sattr)
>  {
> -	struct nfs_fattr	dir_attr;
> +	struct nfs_fh fhandle;
> +	struct nfs_fattr fattr, dir_attr;
>  	struct nfs3_symlinkargs	arg = {
>  		.fromfh		= NFS_FH(dir),
> -		.fromname	= name->name,
> -		.fromlen	= name->len,
> +		.fromname	= dentry->d_name.name,
> +		.fromlen	= dentry->d_name.len,
>  		.topath		= path->name,
>  		.tolen		= path->len,
>  		.sattr		= sattr
>  	};
>  	struct nfs3_diropres	res = {
>  		.dir_attr	= &dir_attr,
> -		.fh		= fhandle,
> -		.fattr		= fattr
> +		.fh		= &fhandle,
> +		.fattr		= &fattr
>  	};
>  	struct rpc_message msg = {
>  		.rpc_proc	= &nfs3_procedures[NFS3PROC_SYMLINK],
> @@ -571,11 +571,17 @@ nfs3_proc_symlink(struct inode *dir, str
>  
>  	if (path->len > NFS3_MAXPATHLEN)
>  		return -ENAMETOOLONG;
> -	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
> +
> +	dprintk("NFS call  symlink %s -> %s\n", dentry->d_name.name,
> +			path->name);
>  	nfs_fattr_init(&dir_attr);
> -	nfs_fattr_init(fattr);
> +	nfs_fattr_init(&fattr);
>  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
>  	nfs_post_op_update_inode(dir, &dir_attr);
> +	if (status != 0)
> +		goto out;
> +	status = nfs_instantiate(dentry, &fhandle, &fattr);
> +out:
>  	dprintk("NFS reply symlink: %d\n", status);
>  	return status;
>  }
> diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
> index e6ee97f..370b5ab 100644
> --- a/fs/nfs/nfs4proc.c
> +++ b/fs/nfs/nfs4proc.c
> @@ -2089,24 +2089,24 @@ static int nfs4_proc_link(struct inode *
>  	return err;
>  }
>  
> -static int _nfs4_proc_symlink(struct inode *dir, struct qstr *name,
> -		struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
> -		struct nfs_fattr *fattr)
> +static int _nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
> +		struct qstr *path, struct iattr *sattr)
>  {
>  	struct nfs_server *server = NFS_SERVER(dir);
> -	struct nfs_fattr dir_fattr;
> +	struct nfs_fh fhandle;
> +	struct nfs_fattr fattr, dir_fattr;
>  	struct nfs4_create_arg arg = {
>  		.dir_fh = NFS_FH(dir),
>  		.server = server,
> -		.name = name,
> +		.name = &dentry->d_name,
>  		.attrs = sattr,
>  		.ftype = NF4LNK,
>  		.bitmask = server->attr_bitmask,
>  	};
>  	struct nfs4_create_res res = {
>  		.server = server,
> -		.fh = fhandle,
> -		.fattr = fattr,
> +		.fh = &fhandle,
> +		.fattr = &fattr,
>  		.dir_fattr = &dir_fattr,
>  	};
>  	struct rpc_message msg = {
> @@ -2118,27 +2118,28 @@ static int _nfs4_proc_symlink(struct ino
>  
>  	if (path->len > NFS4_MAXPATHLEN)
>  		return -ENAMETOOLONG;
> +
>  	arg.u.symlink = path;
> -	nfs_fattr_init(fattr);
> +	nfs_fattr_init(&fattr);
>  	nfs_fattr_init(&dir_fattr);
>  	
>  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
> -	if (!status)
> +	if (!status) {
>  		update_changeattr(dir, &res.dir_cinfo);
> -	nfs_post_op_update_inode(dir, res.dir_fattr);
> +		nfs_post_op_update_inode(dir, res.dir_fattr);
> +		status = nfs_instantiate(dentry, &fhandle, &fattr);
> +	}
>  	return status;
>  }
>  
> -static int nfs4_proc_symlink(struct inode *dir, struct qstr *name,
> -		struct qstr *path, struct iattr *sattr, struct nfs_fh *fhandle,
> -		struct nfs_fattr *fattr)
> +static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry,
> +		struct qstr *path, struct iattr *sattr)
>  {
>  	struct nfs4_exception exception = { };
>  	int err;
>  	do {
>  		err = nfs4_handle_exception(NFS_SERVER(dir),
> -				_nfs4_proc_symlink(dir, name, path, sattr,
> -					fhandle, fattr),
> +				_nfs4_proc_symlink(dir, dentry, path, sattr),
>  				&exception);
>  	} while (exception.retry);
>  	return err;
> diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
> index b3899ea..7512f71 100644
> --- a/fs/nfs/proc.c
> +++ b/fs/nfs/proc.c
> @@ -425,14 +425,15 @@ nfs_proc_link(struct inode *inode, struc
>  }
>  
>  static int
> -nfs_proc_symlink(struct inode *dir, struct qstr *name, struct qstr *path,
> -		 struct iattr *sattr, struct nfs_fh *fhandle,
> -		 struct nfs_fattr *fattr)
> +nfs_proc_symlink(struct inode *dir, struct dentry *dentry, struct qstr *path,
> +		 struct iattr *sattr)
>  {
> +	struct nfs_fh fhandle;
> +	struct nfs_fattr fattr;
>  	struct nfs_symlinkargs	arg = {
>  		.fromfh		= NFS_FH(dir),
> -		.fromname	= name->name,
> -		.fromlen	= name->len,
> +		.fromname	= dentry->d_name.name,
> +		.fromlen	= dentry->d_name.len,
>  		.topath		= path->name,
>  		.tolen		= path->len,
>  		.sattr		= sattr
> @@ -445,11 +446,23 @@ nfs_proc_symlink(struct inode *dir, stru
>  
>  	if (path->len > NFS2_MAXPATHLEN)
>  		return -ENAMETOOLONG;
> -	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
> -	nfs_fattr_init(fattr);
> -	fhandle->size = 0;
> +
> +	dprintk("NFS call  symlink %s -> %s\n", dentry->d_name.name,
> +			path->name);
>  	status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
>  	nfs_mark_for_revalidate(dir);
> +
> +	/*
> +	 * V2 SYMLINK requests don't return any attributes.  Setting the
> +	 * filehandle size to zero indicates to nfs_instantiate that it
> +	 * should fill in the data with a LOOKUP call on the wire.
> +	 */
> +	if (status == 0) {
> +		nfs_fattr_init(&fattr);
> +		fhandle.size = 0;
> +		status = nfs_instantiate(dentry, &fhandle, &fattr);
> +	}
> +
>  	dprintk("NFS reply symlink: %d\n", status);
>  	return status;
>  }
> diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
> index 0c1093c..cfabcd1 100644
> --- a/include/linux/nfs_xdr.h
> +++ b/include/linux/nfs_xdr.h
> @@ -790,9 +790,8 @@ struct nfs_rpc_ops {
>  	int	(*rename)  (struct inode *, struct qstr *,
>  			    struct inode *, struct qstr *);
>  	int	(*link)    (struct inode *, struct inode *, struct qstr *);
> -	int	(*symlink) (struct inode *, struct qstr *, struct qstr *,
> -			    struct iattr *, struct nfs_fh *,
> -			    struct nfs_fattr *);
> +	int	(*symlink) (struct inode *, struct dentry *, struct qstr *,
> +			    struct iattr *);
>  	int	(*mkdir)   (struct inode *, struct dentry *, struct iattr *);
>  	int	(*rmdir)   (struct inode *, struct qstr *);
>  	int	(*readdir) (struct dentry *, struct rpc_cred *,


-------------------------------------------------------------------------
Using Tomcat but need to do more? Need to support web services, security?
Get stuff done quickly with pre-integrated technology to make your job easier
Download IBM WebSphere Application Server v.1.0.1 based on Apache Geronimo
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=120709&bid=263057&dat=121642
_______________________________________________
NFS maillist  -  NFS@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfs

  reply	other threads:[~2006-08-09 15:35 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-08-09 14:47 [PATCH 00/25] RPC client transport switch, continued Chuck Lever
2006-08-09 14:58 ` [PATCH 01/25] SUNRPC: avoid choosing an IPMI port for RPC traffic Chuck Lever
2006-08-09 15:04   ` Christoph Hellwig
2006-08-09 14:58 ` [PATCH 02/25] SUNRPC: Create a helper to tell whether a transport is bound Chuck Lever
2006-08-09 15:19   ` Trond Myklebust
2006-08-09 15:27     ` Chuck Lever
2006-08-09 15:37       ` Trond Myklebust
2006-08-09 14:58 ` [PATCH 03/25] SUNRPC: Make RPC portmapper use per-transport storage Chuck Lever
2006-08-09 14:58 ` [PATCH 04/25] SUNRPC: Clean-up after recent changes to sunrpc/pmap_clnt.c Chuck Lever
2006-08-09 14:59 ` [PATCH 05/25] SUNRPC: Support for RPC child tasks no longer needed Chuck Lever
2006-08-09 14:59 ` [PATCH 06/25] SUNRPC: Introduce transport switch callout for pluggable rpcbind Chuck Lever
2006-08-09 14:59 ` [PATCH 07/25] SUNRPC: create API for getting remote peer address Chuck Lever
2006-08-09 15:06   ` Christoph Hellwig
2006-08-09 14:59 ` [PATCH 08/25] LOCKD: Teach lockd to use the new rpc_peeraddr() API Chuck Lever
2006-08-09 14:59 ` [PATCH 09/25] SUNRPC: Teach the RPC portmapper " Chuck Lever
2006-08-09 14:59 ` [PATCH 10/25] SUNRPC: remove extraneous header inclusions Chuck Lever
2006-08-09 14:59 ` [PATCH 11/25] SUNRPC: add xprt switch API for printing formatted remote peer addresses Chuck Lever
2006-08-09 14:59 ` [PATCH 12/25] SUNRPC: Create API for displaying remote peer address Chuck Lever
2006-08-09 14:59 ` [PATCH 13/25] SUNRPC: Teach rpc_pipe.c to use new rpc_peeraddr() API Chuck Lever
2006-08-09 14:59 ` [PATCH 14/25] SUNRPC: Use "sockaddr_storage" for storing RPC client's remote peer address Chuck Lever
2006-08-09 14:59 ` [PATCH 15/25] SUNRPC: Clean-up after previous patches Chuck Lever
2006-08-09 14:59 ` [PATCH 16/25] SUNRPC: use sockaddr + size when creating remote transport endpoints Chuck Lever
2006-08-09 14:59 ` [PATCH 17/25] LOCKD: Convert to use new rpc_create() API Chuck Lever
2006-08-09 14:59 ` [PATCH 18/25] NFS: Convert NFS client " Chuck Lever
2006-08-09 15:30   ` Trond Myklebust
2006-08-09 14:59 ` [PATCH 19/25] NFSD: Convert NFS server callback logic to use new rpc_create API Chuck Lever
2006-08-09 14:59 ` [PATCH 20/25] SUNRPC: Convert RPC portmapper to use new rpc_create() API Chuck Lever
2006-08-09 14:59 ` [PATCH 21/25] SUNRPC: Eliminate xprt_create_proto and rpc_create_client Chuck Lever
2006-08-09 14:59 ` [PATCH 22/25] NFS: remove a no-longer-needed error check in nfs_symlink() Chuck Lever
2006-08-10  2:10   ` Greg Banks
2006-08-10 12:36     ` Peter Staubach
2006-08-09 14:59 ` [PATCH 23/25] NFS: Fix double d_drop in nfs_instantiate() error path Chuck Lever
2006-08-09 15:34   ` Trond Myklebust [this message]
2006-08-09 14:59 ` [PATCH 24/25] NFS: copy symlinks into page cache before sending NFS SYMLINK request Chuck Lever
2006-08-09 14:59 ` [PATCH 25/25] NFS: Use cached page as buffer for NFS symlink requests Chuck Lever

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=1155137667.5731.90.camel@localhost \
    --to=trond.myklebust@fys.uio.no \
    --cc=chucklever@gmail.com \
    --cc=nfs@lists.sourceforge.net \
    /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