diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d8149e916dd73b260f054e1a8feba40050c6f1e3..187caa47dad979ca8bd1a2c0013703284daab6f0 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -1694,12 +1694,19 @@ int nfs_rmdir(struct inode *dir, struct dentry *dentry) dir->i_sb->s_id, dir->i_ino, dentry->d_name.name); trace_nfs_rmdir_enter(dir, dentry); - error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); - /* Ensure the VFS deletes this inode */ - if (error == 0 && dentry->d_inode != NULL) - clear_nlink(dentry->d_inode); - else if (error == -ENOENT) - nfs_dentry_handle_enoent(dentry); + if (dentry->d_inode) { + nfs_wait_on_sillyrename(dentry); + error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); + /* Ensure the VFS deletes this inode */ + switch (error) { + case 0: + clear_nlink(dentry->d_inode); + break; + case -ENOENT: + nfs_dentry_handle_enoent(dentry); + } + } else + error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name); trace_nfs_rmdir_exit(dir, dentry, error); return error; diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 2c1485d1841903f990dc0b4ff142fc773d1ce19f..bb939edd4c998cb98b7aeb56ae1aa308e4d9009d 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c @@ -207,6 +207,13 @@ static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data) return ret; } +void nfs_wait_on_sillyrename(struct dentry *dentry) +{ + struct nfs_inode *nfsi = NFS_I(dentry->d_inode); + + wait_event(nfsi->waitqueue, atomic_read(&nfsi->silly_count) <= 1); +} + void nfs_block_sillyrename(struct dentry *dentry) { struct nfs_inode *nfsi = NFS_I(dentry->d_inode); diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 7125cef741642b77ca5c41758c26e500be3a2672..3ea4cde8701ce1e97d6a39a4a1264452468a5254 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h @@ -524,6 +524,7 @@ static inline void nfs4_label_free(void *label) {} * linux/fs/nfs/unlink.c */ extern void nfs_complete_unlink(struct dentry *dentry, struct inode *); +extern void nfs_wait_on_sillyrename(struct dentry *dentry); extern void nfs_block_sillyrename(struct dentry *dentry); extern void nfs_unblock_sillyrename(struct dentry *dentry); extern int nfs_sillyrename(struct inode *dir, struct dentry *dentry);