* [PATCH 1/7] vfs: dentry_unhash immediately prior to rmdir
2011-03-30 22:09 [PATCH 0/7] Do not dentry_unhash() in VFS Sage Weil
@ 2011-03-30 22:09 ` Sage Weil
2011-03-30 22:09 ` [PATCH 2/7] vfs: remove dget() from dentry_unhash() Sage Weil
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Sage Weil @ 2011-03-30 22:09 UTC (permalink / raw)
To: viro, linux-fsdevel; +Cc: linux-kernel, mszeredi, Sage Weil
This presumes that there is no reason to unhash a dentry if we fail because
it is a mountpoint or the LSM check fails, and that the LSM checks do not
depend on the dentry being unhashed.
Signed-off-by: Sage Weil <sage@newdream.net>
---
fs/namei.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index a4689eb..f47a5c0 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2838,24 +2838,24 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
return -EPERM;
mutex_lock(&dentry->d_inode->i_mutex);
- dentry_unhash(dentry);
if (d_mountpoint(dentry))
error = -EBUSY;
else {
error = security_inode_rmdir(dir, dentry);
if (!error) {
+ dentry_unhash(dentry);
error = dir->i_op->rmdir(dir, dentry);
if (!error) {
dentry->d_inode->i_flags |= S_DEAD;
dont_mount(dentry);
}
+ dput(dentry);
}
}
mutex_unlock(&dentry->d_inode->i_mutex);
if (!error) {
d_delete(dentry);
}
- dput(dentry);
return error;
}
--
1.7.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 2/7] vfs: remove dget() from dentry_unhash()
2011-03-30 22:09 [PATCH 0/7] Do not dentry_unhash() in VFS Sage Weil
2011-03-30 22:09 ` [PATCH 1/7] vfs: dentry_unhash immediately prior to rmdir Sage Weil
@ 2011-03-30 22:09 ` Sage Weil
2011-03-30 22:09 ` [PATCH 3/7] vfs: push dentry_unhash on rmdir into file systems Sage Weil
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Sage Weil @ 2011-03-30 22:09 UTC (permalink / raw)
To: viro, linux-fsdevel; +Cc: linux-kernel, mszeredi, Sage Weil
This serves no useful purpose that I can discern. All callers (rename,
rmdir) hold their own reference to the dentry.
A quick audit of all file systems showed no relevant checks on the value
of d_count in vfs_rmdir/vfs_rename_dir paths.
Signed-off-by: Sage Weil <sage@newdream.net>
---
fs/hpfs/namei.c | 3 ---
fs/namei.c | 5 +----
fs/reiserfs/xattr.c | 1 -
3 files changed, 1 insertions(+), 8 deletions(-)
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index f4ad9e3..00c8218 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -415,7 +415,6 @@ again:
mutex_unlock(&hpfs_i(inode)->i_parent_mutex);
dentry_unhash(dentry);
if (!d_unhashed(dentry)) {
- dput(dentry);
unlock_kernel();
return -ENOSPC;
}
@@ -423,7 +422,6 @@ again:
!S_ISREG(inode->i_mode) ||
get_write_access(inode)) {
d_rehash(dentry);
- dput(dentry);
} else {
struct iattr newattrs;
/*printk("HPFS: truncating file before delete.\n");*/
@@ -431,7 +429,6 @@ again:
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
err = notify_change(dentry, &newattrs);
put_write_access(inode);
- dput(dentry);
if (!err)
goto again;
}
diff --git a/fs/namei.c b/fs/namei.c
index f47a5c0..316e89b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2819,10 +2819,9 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
*/
void dentry_unhash(struct dentry *dentry)
{
- dget(dentry);
shrink_dcache_parent(dentry);
spin_lock(&dentry->d_lock);
- if (dentry->d_count == 2)
+ if (dentry->d_count == 1)
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
}
@@ -2849,7 +2848,6 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
dentry->d_inode->i_flags |= S_DEAD;
dont_mount(dentry);
}
- dput(dentry);
}
}
mutex_unlock(&dentry->d_inode->i_mutex);
@@ -3260,7 +3258,6 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
mutex_unlock(&target->i_mutex);
if (d_unhashed(new_dentry))
d_rehash(new_dentry);
- dput(new_dentry);
}
if (!error)
if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 5c11ca8..7451ec4 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -105,7 +105,6 @@ static int xattr_rmdir(struct inode *dir, struct dentry *dentry)
mutex_unlock(&dentry->d_inode->i_mutex);
if (!error)
d_delete(dentry);
- dput(dentry);
return error;
}
--
1.7.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 3/7] vfs: push dentry_unhash on rmdir into file systems
2011-03-30 22:09 [PATCH 0/7] Do not dentry_unhash() in VFS Sage Weil
2011-03-30 22:09 ` [PATCH 1/7] vfs: dentry_unhash immediately prior to rmdir Sage Weil
2011-03-30 22:09 ` [PATCH 2/7] vfs: remove dget() from dentry_unhash() Sage Weil
@ 2011-03-30 22:09 ` Sage Weil
2011-03-30 22:09 ` [PATCH 4/7] vfs: push dentry_unhash on rename_dir " Sage Weil
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Sage Weil @ 2011-03-30 22:09 UTC (permalink / raw)
To: viro, linux-fsdevel; +Cc: linux-kernel, mszeredi, Sage Weil
Only a few file systems need this. Start by pushing it down into each
fs rmdir method so it can be dealt with on a per-fs basis.
This does not change behavior for any in-tree file systems.
Signed-off-by: Sage Weil <sage@newdream.net>
---
fs/9p/vfs_inode.c | 1 +
fs/affs/namei.c | 2 ++
fs/afs/dir.c | 2 ++
fs/autofs4/root.c | 2 ++
fs/btrfs/inode.c | 2 ++
fs/ceph/dir.c | 3 +++
fs/cifs/inode.c | 2 ++
fs/coda/dir.c | 2 ++
fs/configfs/dir.c | 2 ++
fs/ecryptfs/inode.c | 2 ++
fs/exofs/namei.c | 2 ++
fs/ext2/namei.c | 2 ++
fs/ext3/namei.c | 2 ++
fs/ext4/namei.c | 2 ++
fs/fat/namei_msdos.c | 2 ++
fs/fat/namei_vfat.c | 2 ++
fs/fuse/dir.c | 2 ++
fs/gfs2/ops_inode.c | 2 ++
fs/hfs/dir.c | 3 +++
fs/hfsplus/dir.c | 2 ++
fs/hostfs/hostfs_kern.c | 2 ++
fs/hpfs/namei.c | 2 ++
fs/jffs2/dir.c | 2 ++
fs/jfs/namei.c | 2 ++
fs/libfs.c | 2 ++
fs/logfs/dir.c | 2 ++
fs/minix/namei.c | 2 ++
fs/namei.c | 1 -
fs/ncpfs/dir.c | 2 ++
fs/nfs/dir.c | 2 ++
fs/nilfs2/namei.c | 2 ++
fs/ocfs2/namei.c | 3 +++
fs/omfs/dir.c | 2 ++
fs/reiserfs/namei.c | 2 ++
fs/sysv/namei.c | 2 ++
fs/ubifs/dir.c | 2 ++
fs/udf/namei.c | 2 ++
fs/ufs/namei.c | 2 ++
38 files changed, 76 insertions(+), 1 deletions(-)
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index b76a40b..eb83ad1 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -731,6 +731,7 @@ int v9fs_vfs_unlink(struct inode *i, struct dentry *d)
int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
{
+ dentry_unhash(d);
return v9fs_remove(i, d, 1);
}
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index e3e9efc..d087153 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -320,6 +320,8 @@ affs_rmdir(struct inode *dir, struct dentry *dentry)
dentry->d_inode->i_ino,
(int)dentry->d_name.len, dentry->d_name.name);
+ dentry_unhash(dentry);
+
return affs_remove_header(dentry);
}
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 20c106f..9a7f414 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -845,6 +845,8 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
_enter("{%x:%u},{%s}",
dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
+ dentry_unhash(dentry);
+
ret = -ENAMETOOLONG;
if (dentry->d_name.len >= AFSNAMEMAX)
goto error;
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index 014e7ab..64415f4 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -600,6 +600,8 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
return -EACCES;
+ dentry_unhash(dentry);
+
if (atomic_dec_and_test(&ino->count)) {
p_ino = autofs4_dentry_ino(dentry->d_parent);
if (p_ino && dentry->d_parent != dentry)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 9007bbd..bd3527b 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3005,6 +3005,8 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
return -ENOTEMPTY;
+ dentry_unhash(dentry);
+
trans = __unlink_start_trans(dir, dentry);
if (IS_ERR(trans))
return PTR_ERR(trans);
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index ebafa65..c1d9d6f 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -824,6 +824,9 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
int err = -EROFS;
int op;
+ if ((dentry->d_inode->i_mode & S_IFMT) == S_IFDIR)
+ dentry_unhash(dentry);
+
if (ceph_snap(dir) == CEPH_SNAPDIR) {
/* rmdir .snap/foo is RMSNAP */
dout("rmsnap dir %p '%.*s' dn %p\n", dir, dentry->d_name.len,
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 8852470..cee5896 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1461,6 +1461,8 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry)
cFYI(1, "cifs_rmdir, inode = 0x%p", inode);
+ dentry_unhash(direntry);
+
xid = GetXid();
full_path = build_path_from_dentry(direntry);
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 2b8dae4..9f72b75 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -336,6 +336,8 @@ static int coda_rmdir(struct inode *dir, struct dentry *de)
int len = de->d_name.len;
int error;
+ dentry_unhash(de);
+
error = venus_rmdir(dir->i_sb, coda_i2f(dir), name, len);
if (!error) {
/* VFS may delete the child */
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 90ff3cb..468c77c 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -1355,6 +1355,8 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
struct module *subsys_owner = NULL, *dead_item_owner = NULL;
int ret;
+ dentry_unhash(dentry);
+
if (dentry->d_parent == configfs_sb->s_root)
return -EPERM;
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index b592938..6f8a00b 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -556,6 +556,8 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
struct dentry *lower_dir_dentry;
int rc;
+ dentry_unhash(dentry);
+
lower_dentry = ecryptfs_dentry_to_lower(dentry);
dget(dentry);
lower_dir_dentry = lock_parent(lower_dentry);
diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c
index 4d70db1..0697175 100644
--- a/fs/exofs/namei.c
+++ b/fs/exofs/namei.c
@@ -227,6 +227,8 @@ static int exofs_rmdir(struct inode *dir, struct dentry *dentry)
struct inode *inode = dentry->d_inode;
int err = -ENOTEMPTY;
+ dentry_unhash(dentry);
+
if (exofs_empty_dir(inode)) {
err = exofs_unlink(dir, dentry);
if (!err) {
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index adb9185..23aa4b3 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -296,6 +296,8 @@ static int ext2_rmdir (struct inode * dir, struct dentry *dentry)
struct inode * inode = dentry->d_inode;
int err = -ENOTEMPTY;
+ dentry_unhash(dentry);
+
if (ext2_empty_dir(inode)) {
err = ext2_unlink(dir, dentry);
if (!err) {
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index b27ba71..3256f48 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -2074,6 +2074,8 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
struct ext3_dir_entry_2 * de;
handle_t *handle;
+ dentry_unhash(dentry);
+
/* Initialize quotas before so that eventual writes go in
* separate transaction */
dquot_initialize(dir);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 5485390..39a93c2 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2122,6 +2122,8 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
struct ext4_dir_entry_2 *de;
handle_t *handle;
+ dentry_unhash(dentry);
+
/* Initialize quotas before so that eventual writes go in
* separate transaction */
dquot_initialize(dir);
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index 7114990..0c25cea 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -326,6 +326,8 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
struct fat_slot_info sinfo;
int err;
+ dentry_unhash(dentry);
+
lock_super(sb);
/*
* Check whether the directory is not in use, then check
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index adae3fb..d7b9383 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -824,6 +824,8 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)
struct fat_slot_info sinfo;
int err;
+ dentry_unhash(dentry);
+
lock_super(sb);
err = fat_dir_empty(inode);
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 8bd0ef9..4459fda 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -667,6 +667,8 @@ static int fuse_rmdir(struct inode *dir, struct dentry *entry)
if (IS_ERR(req))
return PTR_ERR(req);
+ dentry_unhash(entry);
+
req->in.h.opcode = FUSE_RMDIR;
req->in.h.nodeid = get_node_id(dir);
req->in.numargs = 1;
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index d8b26ac..6baa30f 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -572,6 +572,8 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
struct gfs2_holder ri_gh;
int error;
+ dentry_unhash(dentry);
+
error = gfs2_rindex_hold(sdp, &ri_gh);
if (error)
return error;
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index b4d70b1..616cfe0 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -253,6 +253,9 @@ static int hfs_remove(struct inode *dir, struct dentry *dentry)
struct inode *inode = dentry->d_inode;
int res;
+ if (S_ISDIR(inode->i_mode))
+ dentry_unhash(dentry);
+
if (S_ISDIR(inode->i_mode) && inode->i_size != 2)
return -ENOTEMPTY;
res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 4df5059..23451a9 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -370,6 +370,8 @@ static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
struct inode *inode = dentry->d_inode;
int res;
+ dentry_unhash(dentry);
+
if (inode->i_size != 2)
return -ENOTEMPTY;
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 2638c83..73ea3ba 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -683,6 +683,8 @@ int hostfs_rmdir(struct inode *ino, struct dentry *dentry)
char *file;
int err;
+ dentry_unhash(dentry);
+
if ((file = dentry_name(dentry)) == NULL)
return -ENOMEM;
err = do_rmdir(file);
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index 00c8218..c6674ae 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -462,6 +462,8 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
int err;
int r;
+ dentry_unhash(dentry);
+
hpfs_adjust_length(name, &len);
lock_kernel();
mutex_lock(&hpfs_i(inode)->i_parent_mutex);
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 9297865..4619ee4 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -610,6 +610,8 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
int ret;
uint32_t now = get_seconds();
+ dentry_unhash(dentry);
+
for (fd = f->dents ; fd; fd = fd->next) {
if (fd->ino)
return -ENOTEMPTY;
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 5a2b269..32eebe6 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -360,6 +360,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
+ dentry_unhash(dentry);
+
/* Init inode for quota operations. */
dquot_initialize(dip);
dquot_initialize(ip);
diff --git a/fs/libfs.c b/fs/libfs.c
index c88eab5..1e2ba5a 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -311,6 +311,8 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry)
if (!simple_empty(dentry))
return -ENOTEMPTY;
+ dentry_unhash(dentry);
+
drop_nlink(dentry->d_inode);
simple_unlink(dir, dentry);
drop_nlink(dir);
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c
index f9ddf0c..9a77518 100644
--- a/fs/logfs/dir.c
+++ b/fs/logfs/dir.c
@@ -273,6 +273,8 @@ static int logfs_rmdir(struct inode *dir, struct dentry *dentry)
{
struct inode *inode = dentry->d_inode;
+ dentry_unhash(dentry);
+
if (!logfs_empty_dir(inode))
return -ENOTEMPTY;
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 6e6777f..091626f 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -168,6 +168,8 @@ static int minix_rmdir(struct inode * dir, struct dentry *dentry)
struct inode * inode = dentry->d_inode;
int err = -ENOTEMPTY;
+ dentry_unhash(dentry);
+
if (minix_empty_dir(inode)) {
err = minix_unlink(dir, dentry);
if (!err) {
diff --git a/fs/namei.c b/fs/namei.c
index 316e89b..fbbc6d7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2842,7 +2842,6 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
else {
error = security_inode_rmdir(dir, dentry);
if (!error) {
- dentry_unhash(dentry);
error = dir->i_op->rmdir(dir, dentry);
if (!error) {
dentry->d_inode->i_flags |= S_DEAD;
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index f6946bb..57336b7 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -1033,6 +1033,8 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
DPRINTK("ncp_rmdir: removing %s/%s\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
+ dentry_unhash(dentry);
+
error = -EBUSY;
if (!d_unhashed(dentry))
goto out;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 2c3eb33..78cdbdd 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1668,6 +1668,8 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
dfprintk(VFS, "NFS: rmdir(%s/%ld), %s\n",
dir->i_sb->s_id, dir->i_ino, dentry->d_name.name);
+ dentry_unhash(dentry);
+
error = NFS_PROTO(dir)->rmdir(dir, &dentry->d_name);
/* Ensure the VFS deletes this inode */
if (error == 0 && dentry->d_inode != NULL)
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index 161791d..87dddb1 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -334,6 +334,8 @@ static int nilfs_rmdir(struct inode *dir, struct dentry *dentry)
struct nilfs_transaction_info ti;
int err;
+ dentry_unhash(dentry);
+
err = nilfs_transaction_begin(dir->i_sb, &ti, 0);
if (err)
return err;
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 849fb4a..65e4dfd 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -812,6 +812,9 @@ static int ocfs2_unlink(struct inode *dir,
mlog_entry("(0x%p, 0x%p, '%.*s')\n", dir, dentry,
dentry->d_name.len, dentry->d_name.name);
+ if (S_ISDIR(inode->i_mode))
+ dentry_unhash(dentry);
+
dquot_initialize(dir);
BUG_ON(dentry->d_parent->d_inode != dir);
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c
index 393f3f6..3cc7e89 100644
--- a/fs/omfs/dir.c
+++ b/fs/omfs/dir.c
@@ -256,6 +256,8 @@ static int omfs_rmdir(struct inode *dir, struct dentry *dentry)
int err = -ENOTEMPTY;
struct inode *inode = dentry->d_inode;
+ dentry_unhash(dentry);
+
if (omfs_dir_is_empty(inode)) {
err = omfs_unlink(dir, dentry);
if (!err)
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 68fdf45..c2d2412 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -831,6 +831,8 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry)
INITIALIZE_PATH(path);
struct reiserfs_dir_entry de;
+ dentry_unhash(dentry);
+
/* we will be doing 2 balancings and update 2 stat data, we change quotas
* of the owner of the directory and of the owner of the parent directory.
* The quota structure is possibly deleted only on last iput => outside
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index e474fbc..fac64ac 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -196,6 +196,8 @@ static int sysv_rmdir(struct inode * dir, struct dentry * dentry)
struct inode *inode = dentry->d_inode;
int err = -ENOTEMPTY;
+ dentry_unhash(dentry);
+
if (sysv_empty_dir(inode)) {
err = sysv_unlink(dir, dentry);
if (!err) {
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 14f64b6..c2d0756 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -674,6 +674,8 @@ static int ubifs_rmdir(struct inode *dir, struct dentry *dentry)
struct ubifs_inode *dir_ui = ubifs_inode(dir);
struct ubifs_budget_req req = { .mod_dent = 1, .dirtied_ino = 2 };
+ dentry_unhash(dentry);
+
/*
* Budget request settings: deletion direntry, deletion inode and
* changing the parent inode. If budgeting fails, go ahead anyway
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index b7c338d..45d1c99 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -783,6 +783,8 @@ static int udf_rmdir(struct inode *dir, struct dentry *dentry)
struct fileIdentDesc *fi, cfi;
struct kernel_lb_addr tloc;
+ dentry_unhash(dentry);
+
retval = -ENOENT;
fi = udf_find_entry(dir, &dentry->d_name, &fibh, &cfi);
if (!fi)
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index d6f6815..a430d7b 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -259,6 +259,8 @@ static int ufs_rmdir (struct inode * dir, struct dentry *dentry)
struct inode * inode = dentry->d_inode;
int err= -ENOTEMPTY;
+ dentry_unhash(dentry);
+
lock_kernel();
if (ufs_empty_dir (inode)) {
err = ufs_unlink(dir, dentry);
--
1.7.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 4/7] vfs: push dentry_unhash on rename_dir into file systems
2011-03-30 22:09 [PATCH 0/7] Do not dentry_unhash() in VFS Sage Weil
` (2 preceding siblings ...)
2011-03-30 22:09 ` [PATCH 3/7] vfs: push dentry_unhash on rmdir into file systems Sage Weil
@ 2011-03-30 22:09 ` Sage Weil
2011-03-31 3:09 ` Dave Chinner
2011-03-30 22:09 ` [PATCH 5/7] vfs: update dentry_unhash() comment Sage Weil
` (2 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: Sage Weil @ 2011-03-30 22:09 UTC (permalink / raw)
To: viro, linux-fsdevel; +Cc: linux-kernel, mszeredi, Sage Weil
Only a few file systems need this. Start by pushing it down into each
rename method so that it can be dealt with on a per-fs basis.
Signed-off-by: Sage Weil <sage@newdream.net>
---
fs/9p/vfs_inode.c | 3 +++
fs/affs/namei.c | 3 +++
fs/afs/dir.c | 3 +++
fs/bfs/dir.c | 3 +++
fs/btrfs/inode.c | 3 +++
fs/ceph/dir.c | 3 +++
fs/cifs/inode.c | 3 +++
fs/coda/dir.c | 3 +++
fs/ecryptfs/inode.c | 3 +++
fs/exofs/namei.c | 3 +++
fs/ext2/namei.c | 3 +++
fs/ext3/namei.c | 3 +++
fs/ext4/namei.c | 3 +++
fs/fat/namei_msdos.c | 3 +++
fs/fat/namei_vfat.c | 3 +++
fs/fuse/dir.c | 4 ++++
fs/gfs2/ops_inode.c | 3 +++
fs/hfs/dir.c | 3 +++
fs/hostfs/hostfs_kern.c | 3 +++
fs/hpfs/namei.c | 4 ++++
fs/jffs2/dir.c | 3 +++
fs/jfs/namei.c | 3 +++
fs/libfs.c | 3 +++
fs/logfs/dir.c | 3 +++
fs/minix/namei.c | 3 +++
fs/namei.c | 5 +----
fs/ncpfs/dir.c | 3 +++
fs/nfs/dir.c | 3 +++
fs/nilfs2/namei.c | 3 +++
fs/ocfs2/namei.c | 3 +++
fs/omfs/dir.c | 3 +++
fs/reiserfs/namei.c | 3 +++
fs/sysv/namei.c | 3 +++
fs/ubifs/dir.c | 3 +++
fs/udf/namei.c | 3 +++
fs/ufs/namei.c | 3 +++
36 files changed, 108 insertions(+), 4 deletions(-)
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index eb83ad1..7ce3619 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -756,6 +756,9 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct p9_wstat wstat;
int retval;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
P9_DPRINTK(P9_DEBUG_VFS, "\n");
retval = 0;
old_inode = old_dentry->d_inode;
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index d087153..03330e2 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -419,6 +419,9 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct buffer_head *bh = NULL;
int retval;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
pr_debug("AFFS: rename(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
(u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
(u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index 9a7f414..2c4e051 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -1148,6 +1148,9 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct key *key;
int ret;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
vnode = AFS_FS_I(old_dentry->d_inode);
orig_dvnode = AFS_FS_I(old_dir);
new_dvnode = AFS_FS_I(new_dir);
diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c
index 685ecff..fb71de1 100644
--- a/fs/bfs/dir.c
+++ b/fs/bfs/dir.c
@@ -224,6 +224,9 @@ static int bfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct bfs_sb_info *info;
int error = -ENOENT;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
old_bh = new_bh = NULL;
old_inode = old_dentry->d_inode;
if (S_ISDIR(old_inode->i_mode))
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index bd3527b..9b48003 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6823,6 +6823,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
u64 root_objectid;
int ret;
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
if (new_dir->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
return -EPERM;
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index c1d9d6f..06524c7 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -866,6 +866,9 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
struct ceph_mds_request *req;
int err;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
if (ceph_snap(old_dir) != ceph_snap(new_dir))
return -EXDEV;
if (ceph_snap(old_dir) != CEPH_NOSNAP ||
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index cee5896..18546b7 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1571,6 +1571,9 @@ int cifs_rename(struct inode *source_dir, struct dentry *source_dentry,
FILE_UNIX_BASIC_INFO *info_buf_target;
int xid, rc, tmprc;
+ if (target_dentry->d_inode && S_ISDIR(target_dentry->d_inode->i_mode))
+ dentry_unhash(target_dentry);
+
cifs_sb = CIFS_SB(source_dir->i_sb);
tlink = cifs_sb_tlink(cifs_sb);
if (IS_ERR(tlink))
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 9f72b75..a46126f 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -361,6 +361,9 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
int new_length = new_dentry->d_name.len;
int error;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
error = venus_rename(old_dir->i_sb, coda_i2f(old_dir),
coda_i2f(new_dir), old_length, new_length,
(const char *) old_name, (const char *)new_name);
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 6f8a00b..ea221bf 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -610,6 +610,9 @@ ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct dentry *lower_new_dir_dentry;
struct dentry *trap = NULL;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);
dget(lower_old_dentry);
diff --git a/fs/exofs/namei.c b/fs/exofs/namei.c
index 0697175..de252e5 100644
--- a/fs/exofs/namei.c
+++ b/fs/exofs/namei.c
@@ -251,6 +251,9 @@ static int exofs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct exofs_dir_entry *old_de;
int err = -ENOENT;
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
old_de = exofs_find_entry(old_dir, old_dentry, &old_page);
if (!old_de)
goto out;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 23aa4b3..c2b209b 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -320,6 +320,9 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry,
struct ext2_dir_entry_2 * old_de;
int err = -ENOENT;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
dquot_initialize(old_dir);
dquot_initialize(new_dir);
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 3256f48..1b3f814 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -2305,6 +2305,9 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
struct ext3_dir_entry_2 * old_de, * new_de;
int retval, flush_file = 0;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
dquot_initialize(old_dir);
dquot_initialize(new_dir);
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index 39a93c2..90cf091 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -2356,6 +2356,9 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry,
struct ext4_dir_entry_2 *old_de, *new_de;
int retval, force_da_alloc = 0;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
dquot_initialize(old_dir);
dquot_initialize(new_dir);
diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c
index 0c25cea..c3eccbd 100644
--- a/fs/fat/namei_msdos.c
+++ b/fs/fat/namei_msdos.c
@@ -459,6 +459,9 @@ static int do_msdos_rename(struct inode *old_dir, unsigned char *old_name,
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
err = fat_scan(old_dir, old_name, &old_sinfo);
if (err) {
err = -EIO;
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index d7b9383..e2466b2 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -933,6 +933,9 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
int err, is_dir, update_dotdot, corrupt = 0;
struct super_block *sb = old_dir->i_sb;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index 4459fda..8e20db1 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -693,6 +693,10 @@ static int fuse_rename(struct inode *olddir, struct dentry *oldent,
struct fuse_rename_in inarg;
struct fuse_conn *fc = get_fuse_conn(olddir);
struct fuse_req *req = fuse_get_req(fc);
+
+ if (newent->d_inode && S_ISDIR(newent->d_inode->i_mode))
+ dentry_unhash(newent);
+
if (IS_ERR(req))
return PTR_ERR(req);
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c
index 6baa30f..3fd5a31 100644
--- a/fs/gfs2/ops_inode.c
+++ b/fs/gfs2/ops_inode.c
@@ -743,6 +743,9 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
int error;
if (ndentry->d_inode) {
+ if (S_ISDIR(ndentry->d_inode->i_mode))
+ dentry_unhash(ndentry);
+
nip = GFS2_I(ndentry->d_inode);
if (ip == nip)
return 0;
diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c
index 616cfe0..1cb70cd 100644
--- a/fs/hfs/dir.c
+++ b/fs/hfs/dir.c
@@ -286,6 +286,9 @@ static int hfs_rename(struct inode *old_dir, struct dentry *old_dentry,
/* Unlink destination if it already exists */
if (new_dentry->d_inode) {
+ if (S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
res = hfs_remove(new_dir, new_dentry);
if (res)
return res;
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c
index 73ea3ba..e6816b9 100644
--- a/fs/hostfs/hostfs_kern.c
+++ b/fs/hostfs/hostfs_kern.c
@@ -738,6 +738,9 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from,
char *from_name, *to_name;
int err;
+ if (to->d_inode && S_ISDIR(to->d_inode->i_mode))
+ dentry_unhash(to);
+
if ((from_name = dentry_name(from)) == NULL)
return -ENOMEM;
if ((to_name = dentry_name(to)) == NULL) {
diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c
index c6674ae..04713f7 100644
--- a/fs/hpfs/namei.c
+++ b/fs/hpfs/namei.c
@@ -562,6 +562,10 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct buffer_head *bh;
struct fnode *fnode;
int err;
+
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
if ((err = hpfs_chk_name(new_name, &new_len))) return err;
err = 0;
hpfs_adjust_length(old_name, &old_len);
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 4619ee4..80879d1 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -787,6 +787,9 @@ static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
uint8_t type;
uint32_t now;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
/* The VFS will check for us and prevent trying to rename a
* file over a directory and vice versa, but if it's a directory,
* the VFS can't check whether the victim is empty. The filesystem
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 32eebe6..d213b62 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -1100,6 +1100,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
new_dentry->d_name.name);
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
dquot_initialize(old_dir);
dquot_initialize(new_dir);
diff --git a/fs/libfs.c b/fs/libfs.c
index 1e2ba5a..91a3710 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -325,6 +325,9 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *inode = old_dentry->d_inode;
int they_are_dirs = S_ISDIR(old_dentry->d_inode->i_mode);
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
if (!simple_empty(new_dentry))
return -ENOTEMPTY;
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c
index 9a77518..7409059 100644
--- a/fs/logfs/dir.c
+++ b/fs/logfs/dir.c
@@ -624,6 +624,9 @@ static int logfs_rename_cross(struct inode *old_dir, struct dentry *old_dentry,
loff_t pos;
int err;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
/* 1. locate source dd */
err = logfs_get_dd(old_dir, old_dentry, &dd, &pos);
if (err)
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 091626f..f60aed8 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -192,6 +192,9 @@ static int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
struct minix_dir_entry * old_de;
int err = -ENOENT;
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
old_de = minix_find_entry(old_dentry, &old_page);
if (!old_de)
goto out;
diff --git a/fs/namei.c b/fs/namei.c
index fbbc6d7..17de6ab 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3244,11 +3244,8 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
mutex_lock(&target->i_mutex);
if (d_mountpoint(old_dentry)||d_mountpoint(new_dentry))
error = -EBUSY;
- else {
- if (target)
- dentry_unhash(new_dentry);
+ else
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
- }
if (target) {
if (!error) {
target->i_flags |= S_DEAD;
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 57336b7..e3e646b 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -1141,6 +1141,9 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
ncp_age_dentry(server, old_dentry);
ncp_age_dentry(server, new_dentry);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 78cdbdd..2520def 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -1879,6 +1879,9 @@ static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
new_dentry->d_count);
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
/*
* For non-directories, check whether the target is busy and if so,
* make a copy of the dentry and then do a silly-rename. If the
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index 87dddb1..b0ec307 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -371,6 +371,9 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct nilfs_transaction_info ti;
int err;
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
err = nilfs_transaction_begin(old_dir->i_sb, &ti, 1);
if (unlikely(err))
return err;
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index 65e4dfd..68dccef 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -1067,6 +1067,9 @@ static int ocfs2_rename(struct inode *old_dir,
struct ocfs2_dir_lookup_result orphan_insert = { NULL, };
struct ocfs2_dir_lookup_result target_insert = { NULL, };
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
/* At some point it might be nice to break this function up a
* bit. */
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c
index 3cc7e89..08e7c60 100644
--- a/fs/omfs/dir.c
+++ b/fs/omfs/dir.c
@@ -394,6 +394,9 @@ static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry,
is_dir = S_ISDIR(old_inode->i_mode);
if (new_inode) {
+ if (S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
/* overwriting existing file/dir */
err = -ENOTEMPTY;
if (is_dir && !omfs_dir_is_empty(new_inode))
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index c2d2412..fee5284 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -1230,6 +1230,9 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
unsigned long savelink = 1;
struct timespec ctime;
+ if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+ dentry_unhash(new_dentry);
+
/* three balancings: (1) old name removal, (2) new name insertion
and (3) maybe "save" link insertion
stat data updates: (1) old directory,
diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c
index fac64ac..e2cc675 100644
--- a/fs/sysv/namei.c
+++ b/fs/sysv/namei.c
@@ -224,6 +224,9 @@ static int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
struct sysv_dir_entry * old_de;
int err = -ENOENT;
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
old_de = sysv_find_entry(old_dentry, &old_page);
if (!old_de)
goto out;
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index c2d0756..d5dfd6b 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -996,6 +996,9 @@ static int ubifs_rename(struct inode *old_dir, struct dentry *old_dentry,
.dirtied_ino_d = ALIGN(old_inode_ui->data_len, 8) };
struct timespec time;
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
/*
* Budget request settings: deletion direntry, new direntry, removing
* the old inode, and changing old and new parent directory inodes.
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 45d1c99..f9729a2 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -1083,6 +1083,9 @@ static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
struct kernel_lb_addr tloc;
struct udf_inode_info *old_iinfo = UDF_I(old_inode);
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
ofi = udf_find_entry(old_dir, &old_dentry->d_name, &ofibh, &ocfi);
if (ofi) {
if (ofibh.sbh != ofibh.ebh)
diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c
index a430d7b..85a2204 100644
--- a/fs/ufs/namei.c
+++ b/fs/ufs/namei.c
@@ -285,6 +285,9 @@ static int ufs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct ufs_dir_entry *old_de;
int err = -ENOENT;
+ if (new_inode && S_ISDIR(new_inode->i_mode))
+ dentry_unhash(new_dentry);
+
old_de = ufs_find_entry(old_dir, &old_dentry->d_name, &old_page);
if (!old_de)
goto out;
--
1.7.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH 4/7] vfs: push dentry_unhash on rename_dir into file systems
2011-03-30 22:09 ` [PATCH 4/7] vfs: push dentry_unhash on rename_dir " Sage Weil
@ 2011-03-31 3:09 ` Dave Chinner
2011-03-31 4:40 ` Sage Weil
0 siblings, 1 reply; 10+ messages in thread
From: Dave Chinner @ 2011-03-31 3:09 UTC (permalink / raw)
To: Sage Weil; +Cc: viro, linux-fsdevel, linux-kernel, mszeredi
On Wed, Mar 30, 2011 at 03:09:25PM -0700, Sage Weil wrote:
> Only a few file systems need this. Start by pushing it down into each
> rename method so that it can be dealt with on a per-fs basis.
What is the criteria for a filesystem needing this?
> Signed-off-by: Sage Weil <sage@newdream.net>
> ---
> fs/9p/vfs_inode.c | 3 +++
> fs/affs/namei.c | 3 +++
> fs/afs/dir.c | 3 +++
> fs/bfs/dir.c | 3 +++
> fs/btrfs/inode.c | 3 +++
> fs/ceph/dir.c | 3 +++
> fs/cifs/inode.c | 3 +++
> fs/coda/dir.c | 3 +++
> fs/ecryptfs/inode.c | 3 +++
> fs/exofs/namei.c | 3 +++
> fs/ext2/namei.c | 3 +++
> fs/ext3/namei.c | 3 +++
> fs/ext4/namei.c | 3 +++
> fs/fat/namei_msdos.c | 3 +++
> fs/fat/namei_vfat.c | 3 +++
> fs/fuse/dir.c | 4 ++++
> fs/gfs2/ops_inode.c | 3 +++
> fs/hfs/dir.c | 3 +++
> fs/hostfs/hostfs_kern.c | 3 +++
> fs/hpfs/namei.c | 4 ++++
> fs/jffs2/dir.c | 3 +++
> fs/jfs/namei.c | 3 +++
> fs/libfs.c | 3 +++
> fs/logfs/dir.c | 3 +++
> fs/minix/namei.c | 3 +++
> fs/namei.c | 5 +----
> fs/ncpfs/dir.c | 3 +++
> fs/nfs/dir.c | 3 +++
> fs/nilfs2/namei.c | 3 +++
> fs/ocfs2/namei.c | 3 +++
> fs/omfs/dir.c | 3 +++
> fs/reiserfs/namei.c | 3 +++
> fs/sysv/namei.c | 3 +++
> fs/ubifs/dir.c | 3 +++
> fs/udf/namei.c | 3 +++
> fs/ufs/namei.c | 3 +++
> 36 files changed, 108 insertions(+), 4 deletions(-)
You didn't push it down into XFS, hence my question....
Cheers,
Dave.
--
Dave Chinner
david@fromorbit.com
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 4/7] vfs: push dentry_unhash on rename_dir into file systems
2011-03-31 3:09 ` Dave Chinner
@ 2011-03-31 4:40 ` Sage Weil
0 siblings, 0 replies; 10+ messages in thread
From: Sage Weil @ 2011-03-31 4:40 UTC (permalink / raw)
To: Dave Chinner; +Cc: viro, linux-fsdevel, linux-kernel, mszeredi
On Thu, 31 Mar 2011, Dave Chinner wrote:
> On Wed, Mar 30, 2011 at 03:09:25PM -0700, Sage Weil wrote:
> > Only a few file systems need this. Start by pushing it down into each
> > rename method so that it can be dealt with on a per-fs basis.
>
> What is the criteria for a filesystem needing this?
As I understand it, it's normally just a question of whether the FS can
handle references to the directory's struct inode and dentry after they've
been unlinked. A few file systems bail out of rmdir/rename if
!d_unhashed(dentry) (dentry_unhash() doesn't unhash if there are any other
dentry references).
All but a handful of file systems should be able to drop the dentry_unhash
entirely.
> > Signed-off-by: Sage Weil <sage@newdream.net>
> > ---
> > fs/9p/vfs_inode.c | 3 +++
> > fs/affs/namei.c | 3 +++
> > fs/afs/dir.c | 3 +++
> > fs/bfs/dir.c | 3 +++
> > fs/btrfs/inode.c | 3 +++
> > fs/ceph/dir.c | 3 +++
> > fs/cifs/inode.c | 3 +++
> > fs/coda/dir.c | 3 +++
> > fs/ecryptfs/inode.c | 3 +++
> > fs/exofs/namei.c | 3 +++
> > fs/ext2/namei.c | 3 +++
> > fs/ext3/namei.c | 3 +++
> > fs/ext4/namei.c | 3 +++
> > fs/fat/namei_msdos.c | 3 +++
> > fs/fat/namei_vfat.c | 3 +++
> > fs/fuse/dir.c | 4 ++++
> > fs/gfs2/ops_inode.c | 3 +++
> > fs/hfs/dir.c | 3 +++
> > fs/hostfs/hostfs_kern.c | 3 +++
> > fs/hpfs/namei.c | 4 ++++
> > fs/jffs2/dir.c | 3 +++
> > fs/jfs/namei.c | 3 +++
> > fs/libfs.c | 3 +++
> > fs/logfs/dir.c | 3 +++
> > fs/minix/namei.c | 3 +++
> > fs/namei.c | 5 +----
> > fs/ncpfs/dir.c | 3 +++
> > fs/nfs/dir.c | 3 +++
> > fs/nilfs2/namei.c | 3 +++
> > fs/ocfs2/namei.c | 3 +++
> > fs/omfs/dir.c | 3 +++
> > fs/reiserfs/namei.c | 3 +++
> > fs/sysv/namei.c | 3 +++
> > fs/ubifs/dir.c | 3 +++
> > fs/udf/namei.c | 3 +++
> > fs/ufs/namei.c | 3 +++
> > 36 files changed, 108 insertions(+), 4 deletions(-)
>
> You didn't push it down into XFS, hence my question....
Whoops... I was grepping for .rmdir and .rename in fs/*.c. I'll fix it
up.
sage
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 5/7] vfs: update dentry_unhash() comment
2011-03-30 22:09 [PATCH 0/7] Do not dentry_unhash() in VFS Sage Weil
` (3 preceding siblings ...)
2011-03-30 22:09 ` [PATCH 4/7] vfs: push dentry_unhash on rename_dir " Sage Weil
@ 2011-03-30 22:09 ` Sage Weil
2011-03-30 22:09 ` [PATCH 6/7] libfs: drop unneeded dentry_unhash Sage Weil
2011-03-30 22:09 ` [PATCH 7/7] vfs: fix vfs_rename_dir for FS_RENAME_DOES_D_MOVE filesystems Sage Weil
6 siblings, 0 replies; 10+ messages in thread
From: Sage Weil @ 2011-03-30 22:09 UTC (permalink / raw)
To: viro, linux-fsdevel; +Cc: linux-kernel, mszeredi, Sage Weil
The helper is now only called by file systems, not the VFS.
Signed-off-by: Sage Weil <sage@newdream.net>
---
fs/namei.c | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index 17de6ab..d376688 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -2803,10 +2803,10 @@ SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
}
/*
- * We try to drop the dentry early: we should have
- * a usage count of 2 if we're the only user of this
- * dentry, and if that is true (possibly after pruning
- * the dcache), then we drop the dentry now.
+ * The dentry_unhash() helper will try to drop the dentry early: we
+ * should have a usage count of 1 if we're the only user of this
+ * dentry, and if that is true (possibly after pruning the dcache),
+ * then we drop the dentry now.
*
* A low-level filesystem can, if it choses, legally
* do a
--
1.7.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 6/7] libfs: drop unneeded dentry_unhash
2011-03-30 22:09 [PATCH 0/7] Do not dentry_unhash() in VFS Sage Weil
` (4 preceding siblings ...)
2011-03-30 22:09 ` [PATCH 5/7] vfs: update dentry_unhash() comment Sage Weil
@ 2011-03-30 22:09 ` Sage Weil
2011-03-30 22:09 ` [PATCH 7/7] vfs: fix vfs_rename_dir for FS_RENAME_DOES_D_MOVE filesystems Sage Weil
6 siblings, 0 replies; 10+ messages in thread
From: Sage Weil @ 2011-03-30 22:09 UTC (permalink / raw)
To: viro, linux-fsdevel; +Cc: linux-kernel, mszeredi, Sage Weil
There are no libfs issues with dangling references to empty directories.
Replace dentry_unhash() calls with shrink_dcache_parent().
Signed-off-by: Sage Weil <sage@newdream.net>
---
fs/libfs.c | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/fs/libfs.c b/fs/libfs.c
index 91a3710..65aa858 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -311,8 +311,7 @@ int simple_rmdir(struct inode *dir, struct dentry *dentry)
if (!simple_empty(dentry))
return -ENOTEMPTY;
- dentry_unhash(dentry);
-
+ shrink_dcache_parent(dentry);
drop_nlink(dentry->d_inode);
simple_unlink(dir, dentry);
drop_nlink(dir);
@@ -325,8 +324,8 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *inode = old_dentry->d_inode;
int they_are_dirs = S_ISDIR(old_dentry->d_inode->i_mode);
- if (new_dentry->d_inode && S_ISDIR(new_dentry->d_inode->i_mode))
- dentry_unhash(new_dentry);
+ if (new_dentry->d_inode && they_are_dirs)
+ shrink_dcache_parent(new_dentry);
if (!simple_empty(new_dentry))
return -ENOTEMPTY;
--
1.7.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 7/7] vfs: fix vfs_rename_dir for FS_RENAME_DOES_D_MOVE filesystems
2011-03-30 22:09 [PATCH 0/7] Do not dentry_unhash() in VFS Sage Weil
` (5 preceding siblings ...)
2011-03-30 22:09 ` [PATCH 6/7] libfs: drop unneeded dentry_unhash Sage Weil
@ 2011-03-30 22:09 ` Sage Weil
6 siblings, 0 replies; 10+ messages in thread
From: Sage Weil @ 2011-03-30 22:09 UTC (permalink / raw)
To: viro, linux-fsdevel; +Cc: linux-kernel, mszeredi, Miklos Szeredi
From: Miklos Szeredi <miklos@suse.cz>
vfs_rename_dir() doesn't properly account for filesystems with
FS_RENAME_DOES_D_MOVE. If new_dentry has a target inode attached, it
unhashes the new_dentry prior to the rename() iop and rehashes it after,
but doesn't account for the possibility that rename() may have swapped
{old,new}_dentry. For FS_RENAME_DOES_D_MOVE filesystems, it rehashes
new_dentry (now the old renamed-from name, which d_move() expected to go
away), such that a subsequent lookup will find it. Currently all
FS_RENAME_DOES_D_MOVE filesystems compensate for this by failing in
d_revalidate.
The bug was introduced by: commit 349457ccf2592c14bdf13b6706170ae2e94931b1
"[PATCH] Allow file systems to manually d_move() inside of ->rename()"
Fix by not rehashing the new dentry. Rehashing used to be needed by
d_move() but isn't anymore.
Reported-by: Sage Weil <sage@newdream.net>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
fs/namei.c | 2 --
1 files changed, 0 insertions(+), 2 deletions(-)
diff --git a/fs/namei.c b/fs/namei.c
index d376688..98119a5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -3252,8 +3252,6 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
dont_mount(new_dentry);
}
mutex_unlock(&target->i_mutex);
- if (d_unhashed(new_dentry))
- d_rehash(new_dentry);
}
if (!error)
if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
--
1.7.0
^ permalink raw reply [flat|nested] 10+ messages in thread