dir.c | 8 +++++++- unlink.c | 13 ++++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff -u --recursive --new-file --show-c-function linux-2.4.26/fs/nfs/dir.c linux-2.4.26-01-fix_unlink/fs/nfs/dir.c --- linux-2.4.26/fs/nfs/dir.c 2004-04-14 11:28:23.000000000 -0700 +++ linux-2.4.26-01-fix_unlink/fs/nfs/dir.c 2004-04-16 09:35:23.000000000 -0700 @@ -999,7 +999,7 @@ static int nfs_rename(struct inode *old_ 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, @@ -1025,6 +1025,12 @@ static int nfs_rename(struct inode *old_ */ 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) { diff -u --recursive --new-file --show-c-function linux-2.4.26/fs/nfs/unlink.c linux-2.4.26-01-fix_unlink/fs/nfs/unlink.c --- linux-2.4.26/fs/nfs/unlink.c 2004-04-14 11:28:50.000000000 -0700 +++ linux-2.4.26-01-fix_unlink/fs/nfs/unlink.c 2004-04-16 09:35:23.000000000 -0700 @@ -12,6 +12,7 @@ #include #include #include +#include struct nfs_unlinkdata { @@ -21,6 +22,9 @@ struct nfs_unlinkdata { struct rpc_task task; struct rpc_cred *cred; unsigned int count; + + wait_queue_head_t waitq; + int completed; }; static struct nfs_unlinkdata *nfs_deletes; @@ -133,6 +137,8 @@ nfs_async_unlink_done(struct rpc_task *t put_rpccred(data->cred); data->cred = NULL; dput(dir); + data->completed = 1; + wake_up(&data->waitq); } /** @@ -175,6 +181,8 @@ nfs_async_unlink(struct dentry *dentry) 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; @@ -212,7 +220,10 @@ nfs_complete_unlink(struct dentry *dentr 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); }