diff -uNrp linux-2.4.21-rc7/fs/nfs/dir.c linux-2.4.21-rc7-silly/fs/nfs/dir.c --- linux-2.4.21-rc7/fs/nfs/dir.c Sun Jun 8 23:49:21 2003 +++ linux-2.4.21-rc7-silly/fs/nfs/dir.c Mon Jun 9 05:51:48 2003 @@ -738,8 +738,10 @@ static int nfs_rmdir(struct inode *dir, nfs_zap_caches(dir); error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); - if (!error) + if (!error) { + nfs_async_unlink_dequeue(dentry); dentry->d_inode->i_nlink = 0; + } return error; } @@ -772,8 +774,14 @@ dentry->d_parent->d_name.name, dentry->d * We don't allow a dentry to be silly-renamed twice. */ error = -EBUSY; - if (dentry->d_flags & DCACHE_NFSFS_RENAMED) + if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { +#ifdef NFS_PARANOIA + printk("NFS: silly-rename %s/%s with DCACHE_NFSFS_RENAMED " + "already set?\n", + dentry->d_parent->d_name.name, dentry->d_name.name); +#endif goto out; + } sprintf(silly, ".nfs%*.*lx", i_inosize, i_inosize, dentry->d_inode->i_ino); diff -uNrp linux-2.4.21-rc7/fs/nfs/unlink.c linux-2.4.21-rc7-silly/fs/nfs/unlink.c --- linux-2.4.21-rc7/fs/nfs/unlink.c Sun Jun 8 23:49:21 2003 +++ linux-2.4.21-rc7-silly/fs/nfs/unlink.c Mon Jun 9 05:55:31 2003 @@ -21,6 +21,7 @@ struct nfs_unlinkdata { struct rpc_task task; struct rpc_cred *cred; unsigned int count; + int noaction; /* really remove? */ }; static struct nfs_unlinkdata *nfs_deletes; @@ -96,7 +97,7 @@ nfs_async_unlink_init(struct rpc_task *t struct rpc_message msg; int status = -ENOENT; - if (!data->name.len) + if (!data->name.len || data->noaction) goto out_err; memset(&msg, 0, sizeof(msg)); @@ -151,8 +152,7 @@ nfs_async_unlink_release(struct rpc_task /** * nfs_async_unlink - asynchronous unlinking of a file - * @dir: directory in which the file resides. - * @name: name of the file to unlink. + * @dentry: dentry to unlink */ int nfs_async_unlink(struct dentry *dentry) @@ -168,7 +168,7 @@ nfs_async_unlink(struct dentry *dentry) goto out; memset(data, 0, sizeof(*data)); - data->dir = dget(dir); + data->dir = dget(dir); /* dput() in nfs_async_unlink_done() */ data->dentry = dentry; data->next = nfs_deletes; @@ -191,7 +191,7 @@ nfs_async_unlink(struct dentry *dentry) } /** - * nfs_complete_remove - Initialize completion of the sillydelete + * nfs_complete_unlink - Initialize completion of the sillydelete * @dentry: dentry to delete * * Since we're most likely to be called by dentry_iput(), we @@ -203,16 +203,46 @@ nfs_complete_unlink(struct dentry *dentr { struct nfs_unlinkdata *data; - for(data = nfs_deletes; data != NULL; data = data->next) { + for (data = nfs_deletes; data != NULL; data = data->next) { if (dentry == data->dentry) break; } if (!data) return; - data->count++; nfs_copy_dname(dentry, data); dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; if (data->task.tk_rpcwait == &nfs_delete_queue) rpc_wake_up_task(&data->task); - nfs_put_unlinkdata(data); } + +/** + * nfs_async_unlink_dequeue - Remove a previously queued async unlink + * @dir: parent dir being rmdir'd + * + * This function removes all dentrys from nfs_delete_queue whose parent + * is @dir. + * + * When a file is sillydeleted, the dentry gets unhashed and placed on + * nfs_delete_queue for a future [async] unlink (when d_count goes to 0). + * Since the sillyfile can still be found, it may be unlinked independently, + * in which case nfs_delete_queue will have stale data. When the parent + * dir goes away, data->dir being stale is a problem. This is 1 of 2 reasons + * this is only called from rmdir. The other is for performance; we can + * either dequeue on every unlink, or just on rmdir's. + * + * Just calling this on rmdir isn't ideal though, since we can incur a lot + * of extra NFS remove's if sillyrenamed files are themselves unlinked, and + * the parent dirs stick around. rmdir seems more likely though; generally, + * sillyrenamed files won't be accessed other than for 'rm -rf' operations. + */ +void +nfs_async_unlink_dequeue(struct dentry *dir) +{ + struct nfs_unlinkdata *data; + + /* Don't actually try to do anything when d_count goes to 0. */ + for (data = nfs_deletes; data != NULL; data = data->next) + if (data->dir == dir) + data->noaction = 1; +} + diff -uNrp linux-2.4.21-rc7/include/linux/nfs_fs.h linux-2.4.21-rc7-silly/include/linux/nfs_fs.h --- linux-2.4.21-rc7/include/linux/nfs_fs.h Sun Jun 8 23:52:55 2003 +++ linux-2.4.21-rc7-silly/include/linux/nfs_fs.h Mon Jun 9 01:50:14 2003 @@ -198,6 +198,7 @@ extern int nfs_lock(struct file *, int, */ extern int nfs_async_unlink(struct dentry *); extern void nfs_complete_unlink(struct dentry *); +extern void nfs_async_unlink_dequeue(struct dentry *); /* * linux/fs/nfs/write.c