2005-04-16 15:20:36 -07:00
/*
* linux / fs / nfs / unlink . c
*
* nfs sillydelete handling
*
*/
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/dcache.h>
# include <linux/sunrpc/sched.h>
# include <linux/sunrpc/clnt.h>
# include <linux/nfs_fs.h>
2007-10-19 19:59:18 -07:00
# include <linux/sched.h>
# include <linux/wait.h>
2010-09-17 17:31:30 -04:00
# include <linux/namei.h>
2005-04-16 15:20:36 -07:00
2007-11-08 04:05:04 -05:00
# include "internal.h"
2009-04-01 09:22:24 -04:00
# include "nfs4_fs.h"
2010-09-17 17:31:30 -04:00
# include "iostat.h"
# include "delegation.h"
2007-11-08 04:05:04 -05:00
2005-04-16 15:20:36 -07:00
/**
2007-07-14 15:39:58 -04:00
* nfs_free_unlinkdata - release data from a sillydelete operation .
2005-04-16 15:20:36 -07:00
* @ data : pointer to unlink structure .
*/
static void
2007-07-14 15:39:58 -04:00
nfs_free_unlinkdata ( struct nfs_unlinkdata * data )
2005-04-16 15:20:36 -07:00
{
2007-07-14 15:39:58 -04:00
iput ( data - > dir ) ;
put_rpccred ( data - > cred ) ;
kfree ( data - > args . name . name ) ;
kfree ( data ) ;
2005-04-16 15:20:36 -07:00
}
# define NAME_ALLOC_LEN(len) ((len+16) & ~15)
/**
* nfs_copy_dname - copy dentry name to data structure
* @ dentry : pointer to dentry
* @ data : nfs_unlinkdata
*/
2007-07-14 15:39:58 -04:00
static int nfs_copy_dname ( struct dentry * dentry , struct nfs_unlinkdata * data )
2005-04-16 15:20:36 -07:00
{
char * str ;
int len = dentry - > d_name . len ;
2007-07-14 15:39:58 -04:00
str = kmemdup ( dentry - > d_name . name , NAME_ALLOC_LEN ( len ) , GFP_KERNEL ) ;
2005-04-16 15:20:36 -07:00
if ( ! str )
2007-07-14 15:39:58 -04:00
return - ENOMEM ;
data - > args . name . len = len ;
data - > args . name . name = str ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
2007-10-15 18:17:53 -04:00
static void nfs_free_dname ( struct nfs_unlinkdata * data )
{
kfree ( data - > args . name . name ) ;
data - > args . name . name = NULL ;
data - > args . name . len = 0 ;
}
static void nfs_dec_sillycount ( struct inode * dir )
{
struct nfs_inode * nfsi = NFS_I ( dir ) ;
if ( atomic_dec_return ( & nfsi - > silly_count ) = = 1 )
wake_up ( & nfsi - > waitqueue ) ;
}
2005-04-16 15:20:36 -07:00
/**
* nfs_async_unlink_done - Sillydelete post - processing
* @ task : rpc_task of the sillydelete
*
* Do the directory attribute update .
*/
2006-01-03 09:55:04 +01:00
static void nfs_async_unlink_done ( struct rpc_task * task , void * calldata )
2005-04-16 15:20:36 -07:00
{
2007-07-14 15:39:58 -04:00
struct nfs_unlinkdata * data = calldata ;
struct inode * dir = data - > dir ;
if ( ! NFS_PROTO ( dir ) - > unlink_done ( task , dir ) )
2011-10-19 12:17:29 -07:00
rpc_restart_call_prepare ( task ) ;
2005-04-16 15:20:36 -07:00
}
/**
* nfs_async_unlink_release - Release the sillydelete data .
* @ task : rpc_task of the sillydelete
*
* We need to call nfs_put_unlinkdata as a ' tk_release ' task since the
* rpc_task would be freed too .
*/
2006-01-03 09:55:04 +01:00
static void nfs_async_unlink_release ( void * calldata )
2005-04-16 15:20:36 -07:00
{
2006-01-03 09:55:04 +01:00
struct nfs_unlinkdata * data = calldata ;
2008-07-27 18:03:19 -04:00
struct super_block * sb = data - > dir - > i_sb ;
2007-10-15 18:17:53 -04:00
nfs_dec_sillycount ( data - > dir ) ;
2007-07-14 15:39:58 -04:00
nfs_free_unlinkdata ( data ) ;
2008-07-27 18:19:01 -04:00
nfs_sb_deactive ( sb ) ;
2005-04-16 15:20:36 -07:00
}
2012-03-11 13:11:00 -04:00
static void nfs_unlink_prepare ( struct rpc_task * task , void * calldata )
2009-04-01 09:22:24 -04:00
{
struct nfs_unlinkdata * data = calldata ;
2012-03-19 14:54:41 -04:00
NFS_PROTO ( data - > dir ) - > unlink_rpc_prepare ( task , data ) ;
2009-04-01 09:22:24 -04:00
}
2006-01-03 09:55:04 +01:00
static const struct rpc_call_ops nfs_unlink_ops = {
. rpc_call_done = nfs_async_unlink_done ,
. rpc_release = nfs_async_unlink_release ,
2009-04-01 09:22:24 -04:00
. rpc_call_prepare = nfs_unlink_prepare ,
2006-01-03 09:55:04 +01:00
} ;
2007-10-15 18:17:53 -04:00
static int nfs_do_call_unlink ( struct dentry * parent , struct inode * dir , struct nfs_unlinkdata * data )
2007-07-14 15:39:58 -04:00
{
2007-07-14 15:40:01 -04:00
struct rpc_message msg = {
. rpc_argp = & data - > args ,
. rpc_resp = & data - > res ,
. rpc_cred = data - > cred ,
} ;
2007-07-14 15:39:59 -04:00
struct rpc_task_setup task_setup_data = {
2007-07-14 15:40:01 -04:00
. rpc_message = & msg ,
2007-07-14 15:39:59 -04:00
. callback_ops = & nfs_unlink_ops ,
. callback_data = data ,
2008-07-27 18:19:01 -04:00
. workqueue = nfsiod_workqueue ,
2007-07-14 15:39:59 -04:00
. flags = RPC_TASK_ASYNC ,
} ;
2007-07-14 15:39:58 -04:00
struct rpc_task * task ;
2007-10-15 18:17:53 -04:00
struct dentry * alias ;
alias = d_lookup ( parent , & data - > args . name ) ;
if ( alias ! = NULL ) {
2011-07-18 11:26:30 -04:00
int ret ;
2011-03-16 05:44:14 -04:00
void * devname_garbage = NULL ;
2008-01-28 19:42:59 -05:00
2007-10-15 18:17:53 -04:00
/*
* Hey , we raced with lookup . . . See if we need to transfer
* the sillyrename information to the aliased dentry .
*/
nfs_free_dname ( data ) ;
2011-07-18 11:26:30 -04:00
ret = nfs_copy_dname ( alias , data ) ;
2007-10-15 18:17:53 -04:00
spin_lock ( & alias - > d_lock ) ;
2011-07-18 11:26:30 -04:00
if ( ret = = 0 & & alias - > d_inode ! = NULL & &
2008-01-28 19:42:59 -05:00
! ( alias - > d_flags & DCACHE_NFSFS_RENAMED ) ) {
2011-03-16 05:44:14 -04:00
devname_garbage = alias - > d_fsdata ;
2007-10-15 18:17:53 -04:00
alias - > d_fsdata = data ;
2008-01-26 17:37:47 -05:00
alias - > d_flags | = DCACHE_NFSFS_RENAMED ;
2007-10-15 18:17:53 -04:00
ret = 1 ;
2011-07-18 11:26:30 -04:00
} else
ret = 0 ;
2007-10-15 18:17:53 -04:00
spin_unlock ( & alias - > d_lock ) ;
nfs_dec_sillycount ( dir ) ;
dput ( alias ) ;
2011-03-16 05:44:14 -04:00
/*
* If we ' d displaced old cached devname , free it . At that
* point dentry is definitely not a root , so we won ' t need
* that anymore .
*/
2011-07-18 11:26:30 -04:00
kfree ( devname_garbage ) ;
2007-10-15 18:17:53 -04:00
return ret ;
}
data - > dir = igrab ( dir ) ;
if ( ! data - > dir ) {
nfs_dec_sillycount ( dir ) ;
return 0 ;
}
2008-07-27 18:19:01 -04:00
nfs_sb_active ( dir - > i_sb ) ;
2007-10-15 18:17:53 -04:00
data - > args . fh = NFS_FH ( dir ) ;
2010-04-16 16:22:50 -04:00
nfs_fattr_init ( data - > res . dir_attr ) ;
2007-10-15 18:17:53 -04:00
2007-07-14 15:40:01 -04:00
NFS_PROTO ( dir ) - > unlink_setup ( & msg , dir ) ;
2007-07-14 15:39:59 -04:00
2007-07-14 15:40:01 -04:00
task_setup_data . rpc_client = NFS_CLIENT ( dir ) ;
2007-07-14 15:39:59 -04:00
task = rpc_run_task ( & task_setup_data ) ;
2007-10-15 18:17:53 -04:00
if ( ! IS_ERR ( task ) )
2011-02-21 11:05:41 -08:00
rpc_put_task_async ( task ) ;
2007-10-15 18:17:53 -04:00
return 1 ;
}
static int nfs_call_unlink ( struct dentry * dentry , struct nfs_unlinkdata * data )
{
2007-07-14 15:39:58 -04:00
struct dentry * parent ;
struct inode * dir ;
2007-10-15 18:17:53 -04:00
int ret = 0 ;
2007-07-14 15:39:58 -04:00
parent = dget_parent ( dentry ) ;
if ( parent = = NULL )
goto out_free ;
2007-10-15 18:17:53 -04:00
dir = parent - > d_inode ;
/* Non-exclusive lock protects against concurrent lookup() calls */
spin_lock ( & dir - > i_lock ) ;
if ( atomic_inc_not_zero ( & NFS_I ( dir ) - > silly_count ) = = 0 ) {
/* Deferred delete */
hlist_add_head ( & data - > list , & NFS_I ( dir ) - > silly_list ) ;
spin_unlock ( & dir - > i_lock ) ;
ret = 1 ;
goto out_dput ;
}
spin_unlock ( & dir - > i_lock ) ;
ret = nfs_do_call_unlink ( parent , dir , data ) ;
out_dput :
2007-07-14 15:39:58 -04:00
dput ( parent ) ;
2007-10-15 18:17:53 -04:00
out_free :
return ret ;
}
2007-07-14 15:39:58 -04:00
2007-10-15 18:17:53 -04:00
void nfs_block_sillyrename ( struct dentry * dentry )
{
struct nfs_inode * nfsi = NFS_I ( dentry - > d_inode ) ;
2007-07-14 15:39:58 -04:00
2007-10-15 18:17:53 -04:00
wait_event ( nfsi - > waitqueue , atomic_cmpxchg ( & nfsi - > silly_count , 1 , 0 ) = = 1 ) ;
}
void nfs_unblock_sillyrename ( struct dentry * dentry )
{
struct inode * dir = dentry - > d_inode ;
struct nfs_inode * nfsi = NFS_I ( dir ) ;
struct nfs_unlinkdata * data ;
atomic_inc ( & nfsi - > silly_count ) ;
spin_lock ( & dir - > i_lock ) ;
while ( ! hlist_empty ( & nfsi - > silly_list ) ) {
if ( ! atomic_inc_not_zero ( & nfsi - > silly_count ) )
break ;
data = hlist_entry ( nfsi - > silly_list . first , struct nfs_unlinkdata , list ) ;
hlist_del ( & data - > list ) ;
spin_unlock ( & dir - > i_lock ) ;
if ( nfs_do_call_unlink ( dentry , dir , data ) = = 0 )
nfs_free_unlinkdata ( data ) ;
spin_lock ( & dir - > i_lock ) ;
}
spin_unlock ( & dir - > i_lock ) ;
2007-07-14 15:39:58 -04:00
}
2005-04-16 15:20:36 -07:00
/**
* nfs_async_unlink - asynchronous unlinking of a file
2007-07-14 15:39:58 -04:00
* @ dir : parent directory of dentry
2005-04-16 15:20:36 -07:00
* @ dentry : dentry to unlink
*/
2010-09-17 17:31:30 -04:00
static int
2007-07-14 15:39:58 -04:00
nfs_async_unlink ( struct inode * dir , struct dentry * dentry )
2005-04-16 15:20:36 -07:00
{
2007-07-14 15:39:58 -04:00
struct nfs_unlinkdata * data ;
int status = - ENOMEM ;
2011-03-16 05:44:14 -04:00
void * devname_garbage = NULL ;
2005-04-16 15:20:36 -07:00
2006-03-20 13:44:10 -05:00
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
2007-07-14 15:39:58 -04:00
if ( data = = NULL )
2005-04-16 15:20:36 -07:00
goto out ;
2008-03-12 12:25:28 -04:00
data - > cred = rpc_lookup_cred ( ) ;
2005-04-16 15:20:36 -07:00
if ( IS_ERR ( data - > cred ) ) {
status = PTR_ERR ( data - > cred ) ;
goto out_free ;
}
2010-04-16 16:22:50 -04:00
data - > res . dir_attr = & data - > dir_attr ;
2005-04-16 15:20:36 -07:00
2007-07-14 15:39:58 -04:00
status = - EBUSY ;
2005-04-16 15:20:36 -07:00
spin_lock ( & dentry - > d_lock ) ;
2007-07-14 15:39:58 -04:00
if ( dentry - > d_flags & DCACHE_NFSFS_RENAMED )
goto out_unlock ;
2005-04-16 15:20:36 -07:00
dentry - > d_flags | = DCACHE_NFSFS_RENAMED ;
2011-03-16 05:44:14 -04:00
devname_garbage = dentry - > d_fsdata ;
2007-07-14 15:39:58 -04:00
dentry - > d_fsdata = data ;
2005-04-16 15:20:36 -07:00
spin_unlock ( & dentry - > d_lock ) ;
2011-03-16 05:44:14 -04:00
/*
* If we ' d displaced old cached devname , free it . At that
* point dentry is definitely not a root , so we won ' t need
* that anymore .
*/
if ( devname_garbage )
kfree ( devname_garbage ) ;
2007-07-14 15:39:58 -04:00
return 0 ;
out_unlock :
spin_unlock ( & dentry - > d_lock ) ;
put_rpccred ( data - > cred ) ;
2005-04-16 15:20:36 -07:00
out_free :
kfree ( data ) ;
2007-07-14 15:39:58 -04:00
out :
2005-04-16 15:20:36 -07:00
return status ;
}
/**
* nfs_complete_unlink - Initialize completion of the sillydelete
* @ dentry : dentry to delete
2007-07-14 15:39:58 -04:00
* @ inode : inode
2005-04-16 15:20:36 -07:00
*
* Since we ' re most likely to be called by dentry_iput ( ) , we
* only use the dentry to find the sillydelete . We then copy the name
* into the qstr .
*/
void
2007-07-14 15:39:58 -04:00
nfs_complete_unlink ( struct dentry * dentry , struct inode * inode )
2005-04-16 15:20:36 -07:00
{
2007-07-14 15:39:58 -04:00
struct nfs_unlinkdata * data = NULL ;
2005-04-16 15:20:36 -07:00
spin_lock ( & dentry - > d_lock ) ;
2007-07-14 15:39:58 -04:00
if ( dentry - > d_flags & DCACHE_NFSFS_RENAMED ) {
dentry - > d_flags & = ~ DCACHE_NFSFS_RENAMED ;
data = dentry - > d_fsdata ;
2011-03-16 05:44:14 -04:00
dentry - > d_fsdata = NULL ;
2007-07-14 15:39:58 -04:00
}
2005-04-16 15:20:36 -07:00
spin_unlock ( & dentry - > d_lock ) ;
2007-07-14 15:39:58 -04:00
if ( data ! = NULL & & ( NFS_STALE ( inode ) | | ! nfs_call_unlink ( dentry , data ) ) )
nfs_free_unlinkdata ( data ) ;
2005-04-16 15:20:36 -07:00
}
2010-09-17 17:31:30 -04:00
2010-09-17 17:31:57 -04:00
/* Cancel a queued async unlink. Called when a sillyrename run fails. */
static void
nfs_cancel_async_unlink ( struct dentry * dentry )
{
spin_lock ( & dentry - > d_lock ) ;
if ( dentry - > d_flags & DCACHE_NFSFS_RENAMED ) {
struct nfs_unlinkdata * data = dentry - > d_fsdata ;
dentry - > d_flags & = ~ DCACHE_NFSFS_RENAMED ;
2011-03-16 05:44:14 -04:00
dentry - > d_fsdata = NULL ;
2010-09-17 17:31:57 -04:00
spin_unlock ( & dentry - > d_lock ) ;
nfs_free_unlinkdata ( data ) ;
return ;
}
spin_unlock ( & dentry - > d_lock ) ;
}
/**
* nfs_async_rename_done - Sillyrename post - processing
* @ task : rpc_task of the sillyrename
* @ calldata : nfs_renamedata for the sillyrename
*
* Do the directory attribute updates and the d_move
*/
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 ;
2011-07-18 11:26:30 -04:00
struct dentry * old_dentry = data - > old_dentry ;
struct dentry * new_dentry = data - > new_dentry ;
2010-09-17 17:31:57 -04:00
if ( ! NFS_PROTO ( old_dir ) - > rename_done ( task , old_dir , new_dir ) ) {
2011-10-19 12:17:29 -07:00
rpc_restart_call_prepare ( task ) ;
2010-09-17 17:31:57 -04:00
return ;
}
if ( task - > tk_status ! = 0 ) {
2011-07-18 11:26:30 -04:00
nfs_cancel_async_unlink ( old_dentry ) ;
2010-09-17 17:31:57 -04:00
return ;
}
2011-07-18 11:26:30 -04:00
d_drop ( old_dentry ) ;
d_drop ( new_dentry ) ;
2010-09-17 17:31:57 -04:00
}
/**
* nfs_async_rename_release - Release the sillyrename data .
* @ calldata : the struct nfs_renamedata to be released
*/
static void nfs_async_rename_release ( void * calldata )
{
struct nfs_renamedata * data = calldata ;
struct super_block * sb = data - > old_dir - > i_sb ;
if ( data - > old_dentry - > d_inode )
nfs_mark_for_revalidate ( data - > old_dentry - > d_inode ) ;
dput ( data - > old_dentry ) ;
dput ( data - > new_dentry ) ;
iput ( data - > old_dir ) ;
iput ( data - > new_dir ) ;
nfs_sb_deactive ( sb ) ;
put_rpccred ( data - > cred ) ;
kfree ( data ) ;
}
static void nfs_rename_prepare ( struct rpc_task * task , void * calldata )
{
struct nfs_renamedata * data = calldata ;
2012-03-19 14:54:42 -04:00
NFS_PROTO ( data - > old_dir ) - > rename_rpc_prepare ( task , data ) ;
2010-09-17 17:31:57 -04:00
}
static const struct rpc_call_ops nfs_rename_ops = {
. rpc_call_done = nfs_async_rename_done ,
. rpc_release = nfs_async_rename_release ,
. rpc_call_prepare = nfs_rename_prepare ,
} ;
/**
* nfs_async_rename - perform an asynchronous rename operation
* @ old_dir : directory that currently holds the dentry to be renamed
* @ new_dir : target directory for the rename
* @ old_dentry : original dentry to be renamed
* @ new_dentry : dentry to which the old_dentry should be renamed
*
* It ' s expected that valid references to the dentries and inodes are held
*/
static struct rpc_task *
nfs_async_rename ( struct inode * old_dir , struct inode * new_dir ,
struct dentry * old_dentry , struct dentry * new_dentry )
{
struct nfs_renamedata * data ;
struct rpc_message msg = { } ;
struct rpc_task_setup task_setup_data = {
. rpc_message = & msg ,
. callback_ops = & nfs_rename_ops ,
. workqueue = nfsiod_workqueue ,
. rpc_client = NFS_CLIENT ( old_dir ) ,
. flags = RPC_TASK_ASYNC ,
} ;
2010-09-24 09:17:01 -04:00
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
2010-09-17 17:31:57 -04:00
if ( data = = NULL )
return ERR_PTR ( - ENOMEM ) ;
2010-12-21 10:52:24 -05:00
task_setup_data . callback_data = data ;
2010-09-17 17:31:57 -04:00
data - > cred = rpc_lookup_cred ( ) ;
if ( IS_ERR ( data - > cred ) ) {
2010-09-21 16:52:40 -04:00
struct rpc_task * task = ERR_CAST ( data - > cred ) ;
2010-09-17 17:31:57 -04:00
kfree ( data ) ;
return task ;
}
msg . rpc_argp = & data - > args ;
msg . rpc_resp = & data - > res ;
msg . rpc_cred = data - > cred ;
/* set up nfs_renamedata */
data - > old_dir = old_dir ;
2010-10-27 11:00:08 -04:00
ihold ( old_dir ) ;
2010-09-17 17:31:57 -04:00
data - > new_dir = new_dir ;
2010-10-27 11:00:08 -04:00
ihold ( new_dir ) ;
2010-09-17 17:31:57 -04:00
data - > old_dentry = dget ( old_dentry ) ;
data - > new_dentry = dget ( new_dentry ) ;
nfs_fattr_init ( & data - > old_fattr ) ;
nfs_fattr_init ( & data - > new_fattr ) ;
/* set up nfs_renameargs */
data - > args . old_dir = NFS_FH ( old_dir ) ;
data - > args . old_name = & old_dentry - > d_name ;
data - > args . new_dir = NFS_FH ( new_dir ) ;
data - > args . new_name = & new_dentry - > d_name ;
/* set up nfs_renameres */
data - > res . old_fattr = & data - > old_fattr ;
data - > res . new_fattr = & data - > new_fattr ;
nfs_sb_active ( old_dir - > i_sb ) ;
NFS_PROTO ( data - > old_dir ) - > rename_setup ( & msg , old_dir ) ;
2010-09-21 16:52:40 -04:00
return rpc_run_task ( & task_setup_data ) ;
2010-09-17 17:31:57 -04:00
}
2010-09-17 17:31:30 -04:00
/**
* nfs_sillyrename - Perform a silly - rename of a dentry
* @ dir : inode of directory that contains dentry
* @ dentry : dentry to be sillyrenamed
*
* NFSv2 / 3 is stateless and the server doesn ' t know when the client is
* holding a file open . To prevent application problems when a file is
* unlinked while it ' s still open , the client performs a " silly-rename " .
* That is , it renames the file to a hidden file in the same directory ,
* and only performs the unlink once the last reference to it is put .
*
* The final cleanup is done during dentry_iput .
2011-07-15 19:09:08 -04:00
*
* ( 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 . ) )
2010-09-17 17:31:30 -04:00
*/
int
nfs_sillyrename ( struct inode * dir , struct dentry * dentry )
{
static unsigned int sillycounter ;
const int fileidsize = sizeof ( NFS_FILEID ( dentry - > d_inode ) ) * 2 ;
const int countersize = sizeof ( sillycounter ) * 2 ;
const int slen = sizeof ( " .nfs " ) + fileidsize + countersize - 1 ;
char silly [ slen + 1 ] ;
struct dentry * sdentry ;
2010-09-17 17:31:57 -04:00
struct rpc_task * task ;
2010-09-17 17:31:30 -04:00
int error = - EIO ;
dfprintk ( VFS , " NFS: silly-rename(%s/%s, ct=%d) \n " ,
dentry - > d_parent - > d_name . name , dentry - > d_name . name ,
2011-01-07 17:49:32 +11:00
dentry - > d_count ) ;
2010-09-17 17:31:30 -04:00
nfs_inc_stats ( dir , NFSIOS_SILLYRENAME ) ;
/*
* We don ' t allow a dentry to be silly - renamed twice .
*/
error = - EBUSY ;
if ( dentry - > d_flags & DCACHE_NFSFS_RENAMED )
goto out ;
sprintf ( silly , " .nfs%*.*Lx " ,
fileidsize , fileidsize ,
( unsigned long long ) NFS_FILEID ( dentry - > d_inode ) ) ;
/* Return delegation in anticipation of the rename */
nfs_inode_return_delegation ( dentry - > d_inode ) ;
sdentry = NULL ;
do {
char * suffix = silly + slen - countersize ;
dput ( sdentry ) ;
sillycounter + + ;
sprintf ( suffix , " %*.*x " , countersize , countersize , sillycounter ) ;
dfprintk ( VFS , " NFS: trying to rename %s to %s \n " ,
dentry - > d_name . name , silly ) ;
sdentry = lookup_one_len ( silly , dentry - > d_parent , slen ) ;
/*
* N . B . Better to return EBUSY here . . . it could be
* dangerous to delete the file while it ' s in use .
*/
if ( IS_ERR ( sdentry ) )
goto out ;
} while ( sdentry - > d_inode ! = NULL ) ; /* need negative lookup */
2010-09-17 17:31:57 -04:00
/* queue unlink first. Can't do this from rpc_release as it
* has to allocate memory
*/
error = nfs_async_unlink ( dir , dentry ) ;
if ( error )
goto out_dput ;
2011-07-18 11:26:30 -04:00
/* 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 ;
}
2010-09-17 17:31:57 -04:00
/* run the rename task, undo unlink if it fails */
task = nfs_async_rename ( dir , dir , dentry , sdentry ) ;
if ( IS_ERR ( task ) ) {
error = - EBUSY ;
nfs_cancel_async_unlink ( dentry ) ;
goto out_dput ;
2010-09-17 17:31:30 -04:00
}
2010-09-17 17:31:57 -04:00
/* wait for the RPC task to complete, unless a SIGKILL intervenes */
error = rpc_wait_for_completion_task ( task ) ;
if ( error = = 0 )
error = task - > tk_status ;
rpc_put_task ( task ) ;
out_dput :
2010-09-17 17:31:30 -04:00
dput ( sdentry ) ;
out :
return error ;
}