--- linux-2.5.70-patched/fs/nfs/dir.c.orig 2003-05-28 17:42:11.000000000 +0200 +++ linux-2.5.70-patched/fs/nfs/dir.c 2003-05-29 17:34:56.000000000 +0200 @@ -1165,7 +1165,7 @@ struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; struct dentry *dentry = NULL, *rehash = NULL; - int error = -EBUSY; + int error; /* * To prevent any new references to the target during the rename, @@ -1192,6 +1192,12 @@ */ if (!new_inode) goto go_ahead; + /* If target is a hard link to the source, then noop */ + error = 0; + if (NFS_FILEID(new_inode) == NFS_FILEID(old_inode)) + goto out; + + error = -EBUSY; if (S_ISDIR(new_inode->i_mode)) goto out; else if (atomic_read(&new_dentry->d_count) > 1) { @@ -1242,9 +1248,11 @@ out: if (rehash) d_rehash(rehash); - if (!error && !S_ISDIR(old_inode->i_mode)) - d_move(old_dentry, new_dentry); - nfs_renew_times(new_dentry); + if (!error) { + if (!S_ISDIR(old_inode->i_mode)) + d_move(old_dentry, new_dentry); + nfs_renew_times(new_dentry); + } /* new dentry created? */ if (dentry) --- linux-2.5.70-patched/fs/nfs/nfs3proc.c.orig 2003-02-11 08:22:51.000000000 +0100 +++ linux-2.5.70-patched/fs/nfs/nfs3proc.c 2003-05-29 17:36:40.000000000 +0200 @@ -407,16 +407,21 @@ static int nfs3_proc_unlink_setup(struct rpc_message *msg, struct dentry *dir, struct qstr *name) { + struct { + struct nfs3_diropargs arg; + struct nfs_fattr res; + } *data; struct nfs3_diropargs *arg; struct nfs_fattr *res; - arg = (struct nfs3_diropargs *)kmalloc(sizeof(*arg)+sizeof(*res), GFP_KERNEL); - if (!arg) + data = kmalloc(sizeof(*data), GFP_KERNEL); + if (!data) return -ENOMEM; - res = (struct nfs_fattr*)(arg + 1); + arg = &data->arg; arg->fh = NFS_FH(dir->d_inode); arg->name = name->name; arg->len = name->len; + res = &data->res; res->valid = 0; msg->rpc_proc = &nfs3_procedures[NFS3PROC_REMOVE]; msg->rpc_argp = arg; --- linux-2.5.70-patched/fs/nfs/unlink.c.orig 2002-11-13 13:31:50.000000000 +0100 +++ linux-2.5.70-patched/fs/nfs/unlink.c 2003-05-28 19:48:24.000000000 +0200 @@ -12,6 +12,7 @@ #include #include #include +#include struct nfs_unlinkdata { @@ -21,6 +22,9 @@ struct rpc_task task; struct rpc_cred *cred; unsigned int count; + + wait_queue_head_t waitq; + int completed; }; static struct nfs_unlinkdata *nfs_deletes; @@ -132,6 +136,8 @@ put_rpccred(data->cred); data->cred = NULL; dput(dir); + data->completed = 1; + wake_up(&data->waitq); } /** @@ -174,6 +180,8 @@ nfs_deletes = data; data->count = 1; + init_waitqueue_head(&data->waitq); + task = &data->task; rpc_init_task(task, clnt, nfs_async_unlink_done , RPC_TASK_ASYNC); task->tk_calldata = data; @@ -211,7 +219,10 @@ data->count++; nfs_copy_dname(dentry, data); dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; - if (data->task.tk_rpcwait == &nfs_delete_queue) + if (data->task.tk_rpcwait == &nfs_delete_queue) { + struct rpc_clnt *clnt = data->task.tk_client; rpc_wake_up_task(&data->task); + nfs_wait_event(clnt, data->waitq, data->completed == 1); + } nfs_put_unlinkdata(data); }