diff options
| author | Jiri Kosina <jkosina@suse.cz> | 2011-09-15 15:08:05 +0200 | 
|---|---|---|
| committer | Jiri Kosina <jkosina@suse.cz> | 2011-09-15 15:08:18 +0200 | 
| commit | e060c38434b2caa78efe7cedaff4191040b65a15 (patch) | |
| tree | 407361230bf6733f63d8e788e4b5e6566ee04818 /fs/nfs/unlink.c | |
| parent | 10e4ac572eeffe5317019bd7330b6058a400dfc2 (diff) | |
| parent | cc39c6a9bbdebfcf1a7dee64d83bf302bc38d941 (diff) | |
| download | olio-linux-3.10-e060c38434b2caa78efe7cedaff4191040b65a15.tar.xz olio-linux-3.10-e060c38434b2caa78efe7cedaff4191040b65a15.zip  | |
Merge branch 'master' into for-next
Fast-forward merge with Linus to be able to merge patches
based on more recent version of the tree.
Diffstat (limited to 'fs/nfs/unlink.c')
| -rw-r--r-- | fs/nfs/unlink.c | 37 | 
1 files changed, 27 insertions, 10 deletions
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 8d6864c2a5f..b2fbbde58e4 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -147,7 +147,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n  	alias = d_lookup(parent, &data->args.name);  	if (alias != NULL) { -		int ret = 0; +		int ret;  		void *devname_garbage = NULL;  		/* @@ -155,14 +155,16 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n  		 * the sillyrename information to the aliased dentry.  		 */  		nfs_free_dname(data); +		ret = nfs_copy_dname(alias, data);  		spin_lock(&alias->d_lock); -		if (alias->d_inode != NULL && +		if (ret == 0 && alias->d_inode != NULL &&  		    !(alias->d_flags & DCACHE_NFSFS_RENAMED)) {  			devname_garbage = alias->d_fsdata;  			alias->d_fsdata = data;  			alias->d_flags |= DCACHE_NFSFS_RENAMED;  			ret = 1; -		} +		} else +			ret = 0;  		spin_unlock(&alias->d_lock);  		nfs_dec_sillycount(dir);  		dput(alias); @@ -171,8 +173,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n  		 * point dentry is definitely not a root, so we won't need  		 * that anymore.  		 */ -		if (devname_garbage) -			kfree(devname_garbage); +		kfree(devname_garbage);  		return ret;  	}  	data->dir = igrab(dir); @@ -204,8 +205,6 @@ static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data)  	if (parent == NULL)  		goto out_free;  	dir = parent->d_inode; -	if (nfs_copy_dname(dentry, data) != 0) -		goto out_dput;  	/* Non-exclusive lock protects against concurrent lookup() calls */  	spin_lock(&dir->i_lock);  	if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) == 0) { @@ -366,6 +365,8 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata)  	struct nfs_renamedata *data = calldata;  	struct inode *old_dir = data->old_dir;  	struct inode *new_dir = data->new_dir; +	struct dentry *old_dentry = data->old_dentry; +	struct dentry *new_dentry = data->new_dentry;  	if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) {  		nfs_restart_rpc(task, NFS_SERVER(old_dir)->nfs_client); @@ -373,12 +374,12 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata)  	}  	if (task->tk_status != 0) { -		nfs_cancel_async_unlink(data->old_dentry); +		nfs_cancel_async_unlink(old_dentry);  		return;  	} -	nfs_set_verifier(data->old_dentry, nfs_save_change_attribute(old_dir)); -	d_move(data->old_dentry, data->new_dentry); +	d_drop(old_dentry); +	d_drop(new_dentry);  }  /** @@ -501,6 +502,14 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir,   * and only performs the unlink once the last reference to it is put.   *   * The final cleanup is done during dentry_iput. + * + * (Note: NFSv4 is stateful, and has opens, so in theory an NFSv4 server + * could take responsibility for keeping open files referenced.  The server + * would also need to ensure that opened-but-deleted files were kept over + * reboots.  However, we may not assume a server does so.  (RFC 5661 + * does provide an OPEN4_RESULT_PRESERVE_UNLINKED flag that a server can + * use to advertise that it does this; some day we may take advantage of + * it.))   */  int  nfs_sillyrename(struct inode *dir, struct dentry *dentry) @@ -560,6 +569,14 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)  	if (error)  		goto out_dput; +	/* populate unlinkdata with the right dname */ +	error = nfs_copy_dname(sdentry, +				(struct nfs_unlinkdata *)dentry->d_fsdata); +	if (error) { +		nfs_cancel_async_unlink(dentry); +		goto out_dput; +	} +  	/* run the rename task, undo unlink if it fails */  	task = nfs_async_rename(dir, dir, dentry, sdentry);  	if (IS_ERR(task)) {  |