vfs: push dentry_unhash on rename_dir into file systems
authorSage Weil <sage@newdream.net>
Tue, 24 May 2011 20:06:07 +0000 (13:06 -0700)
committerAl Viro <viro@zeniv.linux.org.uk>
Thu, 26 May 2011 11:26:48 +0000 (07:26 -0400)
Only a few file systems need this.  Start by pushing it down into each
rename method (except gfs2 and xfs) so that it can be dealt with on a
per-fs basis.

Acked-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Sage Weil <sage@newdream.net>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
36 files changed:
fs/9p/vfs_inode.c
fs/affs/namei.c
fs/afs/dir.c
fs/bfs/dir.c
fs/btrfs/inode.c
fs/ceph/dir.c
fs/cifs/inode.c
fs/coda/dir.c
fs/ecryptfs/inode.c
fs/exofs/namei.c
fs/ext2/namei.c
fs/ext3/namei.c
fs/ext4/namei.c
fs/fat/namei_msdos.c
fs/fat/namei_vfat.c
fs/fuse/dir.c
fs/hfs/dir.c
fs/hfsplus/dir.c
fs/hostfs/hostfs_kern.c
fs/hpfs/namei.c
fs/jffs2/dir.c
fs/jfs/namei.c
fs/libfs.c
fs/logfs/dir.c
fs/minix/namei.c
fs/namei.c
fs/ncpfs/dir.c
fs/nfs/dir.c
fs/nilfs2/namei.c
fs/ocfs2/namei.c
fs/omfs/dir.c
fs/reiserfs/namei.c
fs/sysv/namei.c
fs/ubifs/dir.c
fs/udf/namei.c
fs/ufs/namei.c

index ecd7717..8d7f3e6 100644 (file)
@@ -840,6 +840,9 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        struct p9_fid *newdirfid;
        struct p9_wstat wstat;
 
+       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;
index d087153..03330e2 100644 (file)
@@ -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);
index 9a7f414..2c4e051 100644 (file)
@@ -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);
index b14cebf..c7d1d06 100644 (file)
@@ -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))
index c692dad..3a33ae3 100644 (file)
@@ -6994,6 +6994,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        u64 root_objectid;
        int ret;
 
+       if (new_inode && S_ISDIR(new_dentry->d_inode->i_mode))
+               dentry_unhash(new_dentry);
+
        if (new_dir->i_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
                return -EPERM;
 
index d2e5490..377b964 100644 (file)
@@ -869,6 +869,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 ||
index cee5896..18546b7 100644 (file)
@@ -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))
index 9f72b75..a46126f 100644 (file)
@@ -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);
index c88612f..227b409 100644 (file)
@@ -573,6 +573,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);
index 0697175..de252e5 100644 (file)
@@ -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;
index 7a5ad97..516c31d 100644 (file)
@@ -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);
 
index 552f94d..f89b1d4 100644 (file)
@@ -2298,6 +2298,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);
 
index 957580d..792d06e 100644 (file)
@@ -2352,6 +2352,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);
 
index 0c25cea..c3eccbd 100644 (file)
@@ -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;
index d7b9383..e2466b2 100644 (file)
@@ -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;
index 40d5c2a..e462a7a 100644 (file)
@@ -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);
 
index 616cfe0..1cb70cd 100644 (file)
@@ -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;
index 23451a9..b288350 100644 (file)
@@ -469,10 +469,12 @@ static int hfsplus_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))
+               if (S_ISDIR(new_dentry->d_inode->i_mode)) {
+                       dentry_unhash(new_dentry);
                        res = hfsplus_rmdir(new_dir, new_dentry);
-               else
+               } else {
                        res = hfsplus_unlink(new_dir, new_dentry);
+               }
                if (res)
                        return res;
        }
index 73ea3ba..e6816b9 100644 (file)
@@ -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) {
index b9fe158..d3db95f 100644 (file)
@@ -561,6 +561,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);
index 727d644..05f7332 100644 (file)
@@ -786,6 +786,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
index 0569dac..865df16 100644 (file)
@@ -1097,6 +1097,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);
 
index 1e2ba5a..91a3710 100644 (file)
@@ -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;
 
index 2b32734..f34c9cd 100644 (file)
@@ -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)
index 091626f..f60aed8 100644 (file)
@@ -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;
index 596edb5..787ebc8 100644 (file)
@@ -2950,12 +2950,7 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
  *        HOWEVER, it relies on the assumption that any object with ->lookup()
  *        has no more than 1 dentry.  If "hybrid" objects will ever appear,
  *        we'd better make sure that there's no link(2) for them.
- *     d) some filesystems don't support opened-but-unlinked directories,
- *        either because of layout or because they are not ready to deal with
- *        all cases correctly. The latter will be fixed (taking this sort of
- *        stuff into VFS), but the former is not going away. Solution: the same
- *        trick as in rmdir().
- *     e) conversion from fhandle to dentry may come in the wrong moment - when
+ *     d) conversion from fhandle to dentry may come in the wrong moment - when
  *        we are removing the target. Solution: we will have to grab ->i_mutex
  *        in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on
  *        ->i_mutex on parents, which works but leads to some truly excessive
@@ -2986,11 +2981,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;
index 57336b7..e3e646b 100644 (file)
@@ -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);
 
index 48483b5..87daf79 100644 (file)
@@ -1959,6 +1959,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
index 78306e6..1102a5f 100644 (file)
@@ -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;
index b017ebb..f3582a6 100644 (file)
@@ -1066,6 +1066,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. */
 
index 95ef443..c368360 100644 (file)
@@ -382,6 +382,9 @@ static int omfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        int err;
 
        if (new_inode) {
+               if (S_ISDIR(new_inode->i_mode))
+                       dentry_unhash(new_dentry);
+
                /* overwriting existing file/dir */
                err = omfs_remove(new_dir, new_dentry);
                if (err)
index 43e94f0..76c8164 100644 (file)
@@ -1227,6 +1227,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,
index fac64ac..e2cc675 100644 (file)
@@ -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;
index 6ca9176..d80810b 100644 (file)
@@ -978,6 +978,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.
index b70f026..4d76594 100644 (file)
@@ -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)
index 3a769d5..953ebdf 100644 (file)
@@ -284,6 +284,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;