Hi. Here's a new version of rename patch (this time against -pre4).
News:
        *       In case we are doing a cross-directory rename and the source
                is a directory we have to change .. in it. Thus we need write
                permissions. Check added. Kudos to James Griffiths.
        *       If source and target are links to the same inode no permissions
                matter - rename() should do nothing and return 0. Fixed.
        *       In ext2, ufs, smbfs, coda and nfs lots of excessive name length
                checks trimmed. It's enough to do it once in ->lookup() and
                return -ENAMETOOLONG if name is bad. Then no other method will
                receive such dentry.
        *       Related to previous: mknod() on ext2 and ufs would return
                -ENAMETOOLONG in some cases when -EIO should be returned.
                Fixed as the side effect of trimmage above.
        *       Dead code removed from {ext2,ufs}_link() - check for
                target being IMMUTABLE/APPEND-ONLY is already done in VFS,
                so there is no need in duplication.
        *       Bug introduced by msdos rename() cleanup fixed - 
                rename("foo",".foo") might blow up. Badly.

Please, try it out. Patch is attached.
                                                Cheers,
                                                        Al
diff -urN linux-2.2.2-pre4/fs/affs/namei.c linux.bird.rename/fs/affs/namei.c
--- linux-2.2.2-pre4/fs/affs/namei.c    Tue Feb 16 11:53:47 1999
+++ linux.bird.rename/fs/affs/namei.c   Tue Feb 16 11:58:16 1999
@@ -548,32 +548,14 @@
                           "No inode for entry found (key=%lu)\n",new_ino);
                goto end_rename;
        }
-       if (new_inode == old_inode) {
-               if (old_ino == new_ino) {       /* Filename might have changed case    
 */
-                       retval = new_dentry->d_name.len < 31 ? new_dentry->d_name.len 
: 30;
-                       strncpy(DIR_END(old_bh->b_data,old_inode)->dir_name + 1,
-                               new_dentry->d_name.name,retval);
-                       DIR_END(old_bh->b_data,old_inode)->dir_name[0] = retval;
-                       goto new_checksum;
-               }
-               retval = 0;
-               goto end_rename;
-       }
        if (S_ISDIR(old_inode->i_mode)) {
-               retval = -EINVAL;
-               if (is_subdir(new_dentry, old_dentry))
-                       goto end_rename;
                if (new_inode) {
-                       if (new_dentry->d_count > 1)
-                               shrink_dcache_parent(new_dentry);
-                       retval = -EBUSY;
-                       if (new_dentry->d_count > 1)
-                               goto end_rename;
                        retval = -ENOTEMPTY;
                        if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
                                goto end_rename;
                }
 
+               retval = -ENOENT;
                if (affs_parent_ino(old_inode) != old_dir->i_ino)
                        goto end_rename;
        }
@@ -593,7 +575,6 @@
        
affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name);
        if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir)))
                goto end_rename;
-new_checksum:
        affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5);
 
        new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime
@@ -604,7 +585,8 @@
        mark_inode_dirty(new_dir);
        mark_inode_dirty(old_dir);
        mark_buffer_dirty(old_bh,1);
-       d_move(old_dentry,new_dentry);
+       if (!S_ISDIR(old_inode->i_mode))
+               d_move(old_dentry,new_dentry);
        
 end_rename:
        affs_brelse(old_bh);
diff -urN linux-2.2.2-pre4/fs/coda/dir.c linux.bird.rename/fs/coda/dir.c
--- linux-2.2.2-pre4/fs/coda/dir.c      Tue Feb 16 11:53:48 1999
+++ linux.bird.rename/fs/coda/dir.c     Tue Feb 16 11:58:16 1999
@@ -246,12 +246,6 @@
 
        dircnp = ITOC(dir);
 
-        if ( length > CODA_MAXNAMLEN ) {
-               printk("name too long: create, %s(%s)\n", 
-                      coda_f2s(&dircnp->c_fid), name);
-               return -ENAMETOOLONG;
-        }
-
        error = venus_create(dir->i_sb, &(dircnp->c_fid), name, length, 
                                0, mode, 0, &newfid, &attrs);
 
@@ -302,12 +296,6 @@
 
        dircnp = ITOC(dir);
 
-        if ( length > CODA_MAXNAMLEN ) {
-               printk("name too long: mknod, %s(%s)\n", 
-                      coda_f2s(&dircnp->c_fid), name);
-               return -ENAMETOOLONG;
-        }
-
        error = venus_create(dir->i_sb, &(dircnp->c_fid), name, length, 
                                0, mode, rdev, &newfid, &attrs);
 
@@ -349,9 +337,6 @@
                return -ENOENT;
        }
 
-        if ( len > CODA_MAXNAMLEN )
-                return -ENAMETOOLONG;
-
        if (coda_isroot(dir) && coda_iscontrol(name, len))
                return -EPERM;
 
@@ -409,11 +394,6 @@
        CDEBUG(D_INODE, "old: fid: %s\n", coda_f2s(&(cnp->c_fid)));
        CDEBUG(D_INODE, "directory: %s\n", coda_f2s(&(dir_cnp->c_fid)));
 
-        if ( len > CODA_MAXNAMLEN ) {
-                printk("coda_link: name too long. \n");
-                return -ENAMETOOLONG;
-        }
-
         error = venus_link(dir_inode->i_sb,&(cnp->c_fid), &(dir_cnp->c_fid), 
                           (const char *)name, len);
 
@@ -448,9 +428,6 @@
        if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
                return -EPERM;
 
-       if ( len > CODA_MAXNAMLEN )
-                return -ENAMETOOLONG;
-
        symlen = strlen(symname);
        if ( symlen > CODA_MAXPATHLEN )
                 return -ENAMETOOLONG;
@@ -519,9 +496,6 @@
        }
         dircnp = ITOC(dir);
 
-       if (len > CODA_MAXNAMLEN)
-               return -ENAMETOOLONG;
-
        if (!list_empty(&de->d_hash))
                return -EBUSY;
        error = venus_rmdir(dir->i_sb, &(dircnp->c_fid), name, len);
@@ -553,10 +527,6 @@
        ENTRY;
        coda_vfs_stat.rename++;
 
-        if ( (old_length > CODA_MAXNAMLEN) || new_length > CODA_MAXNAMLEN ) {
-                return -ENAMETOOLONG;
-        }
-
         old_cnp = ITOC(old_dir);
         new_cnp = ITOC(new_dir);
 
@@ -565,21 +535,6 @@
               old_name, old_length, strlen(old_name), new_name, new_length, 
               strlen(new_name),old_dentry->d_count, new_dentry->d_count);
 
-       if (new_inode == old_inode)
-               return 0;
-
-       /* make sure target is not in use */
-       if (new_inode && S_ISDIR(new_inode->i_mode)) { 
-               /*
-                 * Prune any children before testing for busy.
-                 */
-                if (new_dentry->d_count > 1)
-                        shrink_dcache_parent(new_dentry);
-
-                if (new_dentry->d_count > 1)
-                        return -EBUSY;
-        }
-
        /* the C library will do unlink/create etc */
        if ( coda_crossvol_rename == 0 && 
             old_cnp->c_fid.Volume != new_cnp->c_fid.Volume )
@@ -599,7 +554,8 @@
        coda_flag_inode(new_dir, C_VATTR);
 
        CDEBUG(D_INODE, "result %d\n", error); 
-       d_move(old_dentry, new_dentry);
+       if (!S_ISDIR(old_inode->i_mode))
+               d_move(old_dentry, new_dentry);
 
        EXIT;
        return 0;
diff -urN linux-2.2.2-pre4/fs/ext2/namei.c linux.bird.rename/fs/ext2/namei.c
--- linux-2.2.2-pre4/fs/ext2/namei.c    Tue Feb 16 11:53:46 1999
+++ linux.bird.rename/fs/ext2/namei.c   Tue Feb 16 12:59:57 1999
@@ -218,12 +218,6 @@
                return NULL;
        sb = dir->i_sb;
 
-       if (namelen > EXT2_NAME_LEN)
-       {
-               *err = -ENAMETOOLONG;
-               return NULL;
-       }
-
        if (!namelen)
                return NULL;
        /*
@@ -409,10 +403,6 @@
        struct ext2_dir_entry_2 * de;
        int err = -EIO;
 
-       err = -ENAMETOOLONG;
-       if (dentry->d_name.len > EXT2_NAME_LEN)
-               goto out;
-
        inode = ext2_new_inode (dir, mode, &err);
        if (!inode)
                goto out;
@@ -474,10 +464,6 @@
        struct ext2_dir_entry_2 * de;
        int err;
 
-       err = -ENAMETOOLONG;
-       if (dentry->d_name.len > EXT2_NAME_LEN)
-               goto out;
-
        err = -EMLINK;
        if (dir->i_nlink >= EXT2_LINK_MAX)
                goto out;
@@ -618,10 +604,6 @@
        struct buffer_head * bh;
        struct ext2_dir_entry_2 * de;
 
-       retval = -ENAMETOOLONG;
-       if (dentry->d_name.len > EXT2_NAME_LEN)
-               goto out;
-
        retval = -ENOENT;
        bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
        if (!bh)
@@ -634,14 +616,12 @@
        if (le32_to_cpu(de->inode) != inode->i_ino)
                goto end_rmdir;
 
+       retval = -ENOTEMPTY;
        if (!empty_dir (inode))
-               retval = -ENOTEMPTY;
-       else if (le32_to_cpu(de->inode) != inode->i_ino)
-               retval = -ENOENT;
-       else {
-               retval = ext2_delete_entry (de, bh);
-               dir->i_version = ++event;
-       }
+               goto end_rmdir;
+
+       retval = ext2_delete_entry (de, bh);
+       dir->i_version = ++event;
        if (retval)
                goto end_rmdir;
        mark_buffer_dirty(bh, 1);
@@ -665,7 +645,6 @@
 
 end_rmdir:
        brelse (bh);
-out:
        return retval;
 }
 
@@ -676,10 +655,6 @@
        struct buffer_head * bh;
        struct ext2_dir_entry_2 * de;
 
-       retval = -ENAMETOOLONG;
-       if (dentry->d_name.len > EXT2_NAME_LEN)
-               goto out;
-
        retval = -ENOENT;
        bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
        if (!bh)
@@ -718,7 +693,6 @@
 
 end_unlink:
        brelse (bh);
-out:
        return retval;
 }
 
@@ -805,9 +779,6 @@
        if (S_ISDIR(inode->i_mode))
                return -EPERM;
 
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               return -EPERM;
-
        if (inode->i_nlink >= EXT2_LINK_MAX)
                return -EMLINK;
 
@@ -851,17 +822,10 @@
        le16_to_cpu(((struct ext2_dir_entry_2 *) buffer)->rec_len)))->inode
 
 /*
- * rename uses retrying to avoid race-conditions: at least they should be
- * minimal.
- * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
- * checks fail, it tries to restart itself again. Very practical - no changes
- * are done until we know everything works ok.. and then all the changes can be
- * done in one fell swoop when we have claimed all the buffers needed.
- *
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
-static int do_ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
+int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
                           struct inode * new_dir,struct dentry *new_dentry)
 {
        struct inode * old_inode, * new_inode;
@@ -870,9 +834,6 @@
        int retval;
 
        old_bh = new_bh = dir_bh = NULL;
-       retval = -ENAMETOOLONG;
-       if (old_dentry->d_name.len > EXT2_NAME_LEN)
-               goto end_rename;
 
        old_bh = ext2_find_entry (old_dir, old_dentry->d_name.name, 
old_dentry->d_name.len, &old_de);
        /*
@@ -897,24 +858,13 @@
                        DQUOT_INIT(new_inode);
                }
        }
-       retval = 0;
-       if (new_inode == old_inode)
-               goto end_rename;
        if (S_ISDIR(old_inode->i_mode)) {
-               retval = -EINVAL;
-               if (is_subdir(new_dentry, old_dentry))
-                       goto end_rename;
                if (new_inode) {
-                       /* Prune any children before testing for busy */
-                       if (new_dentry->d_count > 1)
-                               shrink_dcache_parent(new_dentry);
-                       retval = -EBUSY;
-                       if (new_dentry->d_count > 1)
-                               goto end_rename;
                        retval = -ENOTEMPTY;
                        if (!empty_dir (new_inode))
                                goto end_rename;
                }
+               retval = -EIO;
                dir_bh = ext2_bread (old_inode, 0, 0, &retval);
                if (!dir_bh)
                        goto end_rename;
@@ -978,7 +928,8 @@
        }
 
        /* Update the dcache */
-       d_move(old_dentry, new_dentry);
+       if (!S_ISDIR(old_inode->i_mode))
+               d_move(old_dentry, new_dentry);
        retval = 0;
 
 end_rename:
@@ -986,31 +937,4 @@
        brelse (old_bh);
        brelse (new_bh);
        return retval;
-}
-
-/*
- * Ok, rename also locks out other renames, as they can change the parent of
- * a directory, and we don't want any races. Other races are checked for by
- * "do_rename()", which restarts if there are inconsistencies.
- *
- * Note that there is no race between different filesystems: it's only within
- * the same device that races occur: many renames can happen at once, as long
- * as they are on different partitions.
- *
- * In the second extended file system, we use a lock flag stored in the memory
- * super-block.  This way, we really lock other renames only if they occur
- * on the same file system
- */
-int ext2_rename (struct inode * old_dir, struct dentry *old_dentry,
-                struct inode * new_dir, struct dentry *new_dentry)
-{
-       int result;
-
-       while (old_dir->i_sb->u.ext2_sb.s_rename_lock)
-               sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
-       old_dir->i_sb->u.ext2_sb.s_rename_lock = 1;
-       result = do_ext2_rename (old_dir, old_dentry, new_dir, new_dentry);
-       old_dir->i_sb->u.ext2_sb.s_rename_lock = 0;
-       wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
-       return result;
 }
diff -urN linux-2.2.2-pre4/fs/ext2/super.c linux.bird.rename/fs/ext2/super.c
--- linux-2.2.2-pre4/fs/ext2/super.c    Tue Feb 16 11:53:46 1999
+++ linux.bird.rename/fs/ext2/super.c   Tue Feb 16 11:58:16 1999
@@ -543,8 +543,6 @@
        else
                sb->u.ext2_sb.s_resgid = le16_to_cpu(es->s_def_resgid);
        sb->u.ext2_sb.s_mount_state = le16_to_cpu(es->s_state);
-       sb->u.ext2_sb.s_rename_lock = 0;
-       sb->u.ext2_sb.s_rename_wait = NULL;
        sb->u.ext2_sb.s_addr_per_block_bits =
                log2 (EXT2_ADDR_PER_BLOCK(sb));
        sb->u.ext2_sb.s_desc_per_block_bits =
diff -urN linux-2.2.2-pre4/fs/hfs/dir.c linux.bird.rename/fs/hfs/dir.c
--- linux-2.2.2-pre4/fs/hfs/dir.c       Tue Feb 16 11:53:49 1999
+++ linux.bird.rename/fs/hfs/dir.c      Tue Feb 16 11:58:16 1999
@@ -431,7 +431,8 @@
                }
        
                /* update dcache */
-               d_move(old_dentry, new_dentry);
+               if (!is_dir)
+                       d_move(old_dentry, new_dentry);
        }
 
 hfs_rename_put:
diff -urN linux-2.2.2-pre4/fs/minix/namei.c linux.bird.rename/fs/minix/namei.c
--- linux-2.2.2-pre4/fs/minix/namei.c   Tue Feb 16 11:53:45 1999
+++ linux.bird.rename/fs/minix/namei.c  Tue Feb 16 11:58:16 1999
@@ -604,7 +604,7 @@
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
-static int do_minix_rename(struct inode * old_dir, struct dentry *old_dentry,
+int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
                           struct inode * new_dir, struct dentry *new_dentry)
 {
        struct inode * old_inode, * new_inode;
@@ -640,24 +640,11 @@
                        new_bh = NULL;
                }
        }
-       if (new_inode == old_inode) {
-               retval = 0;
-               goto end_rename;
-       }
        if (S_ISDIR(old_inode->i_mode)) {
-               retval = -EINVAL;
-               if (is_subdir(new_dentry, old_dentry))
-                       goto end_rename;
                if (new_inode) {
-                       /* Prune any children before testing for busy */
-                       if (new_dentry->d_count > 1)
-                               shrink_dcache_parent(new_dentry);
-                       retval = -EBUSY;
-                       if (new_dentry->d_count > 1)
                        retval = -ENOTEMPTY;
                        if (!empty_dir(new_inode))
                                goto end_rename;
-                       retval = -EBUSY;
                }
                retval = -EIO;
                dir_bh = minix_bread(old_inode,0,0);
@@ -714,37 +701,12 @@
                }
        }
        /* Update the dcache */
-       d_move(old_dentry, new_dentry);
+       if (!S_ISDIR(old_inode->i_mode))
+               d_move(old_dentry, new_dentry);
        retval = 0;
 end_rename:
        brelse(dir_bh);
        brelse(old_bh);
        brelse(new_bh);
        return retval;
-}
-
-/*
- * Ok, rename also locks out other renames, as they can change the parent of
- * a directory, and we don't want any races. Other races are checked for by
- * "do_rename()", which restarts if there are inconsistencies.
- *
- * Note that there is no race between different filesystems: it's only within
- * the same device that races occur: many renames can happen at once, as long
- * as they are on different partitions.
- */
-int minix_rename(struct inode * old_dir, struct dentry *old_dentry,
-                struct inode * new_dir, struct dentry *new_dentry)
-{
-       static struct wait_queue * wait = NULL;
-       static int lock = 0;
-       int result;
-
-       while (lock)
-               sleep_on(&wait);
-       lock = 1;
-       result = do_minix_rename(old_dir, old_dentry,
-                                new_dir, new_dentry);
-       lock = 0;
-       wake_up(&wait);
-       return result;
 }
diff -urN linux-2.2.2-pre4/fs/msdos/namei.c linux.bird.rename/fs/msdos/namei.c
--- linux-2.2.2-pre4/fs/msdos/namei.c   Tue Feb 16 11:53:45 1999
+++ linux.bird.rename/fs/msdos/namei.c  Tue Feb 16 13:08:38 1999
@@ -327,6 +327,7 @@
        fat_date_unix2dos(dir->i_mtime,&de->time,&de->date);
        de->size = 0;
        fat_mark_buffer_dirty(sb, bh, 1);
+
        if ((*result = iget(dir->i_sb,ino)) != NULL)
                msdos_read_inode(*result);
        fat_brelse(sb, bh);
@@ -405,23 +406,22 @@
        struct msdos_dir_entry *de;
        int result = 0;
 
-       if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
-               pos = 0;
-               bh = NULL;
-               while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
-                       /* Ignore vfat longname entries */
-                       if (de->attr == ATTR_EXT)
-                               continue;
-                       if (!IS_FREE(de->name) && 
-                           strncmp(de->name,MSDOS_DOT   , MSDOS_NAME) &&
-                           strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
-                               result = -ENOTEMPTY;
-                               break;
-                       }
+       pos = 0;
+       bh = NULL;
+       while (fat_get_entry(dir,&pos,&bh,&de) > -1) {
+               /* Ignore vfat longname entries */
+               if (de->attr == ATTR_EXT)
+                       continue;
+               if (!IS_FREE(de->name) && 
+                   strncmp(de->name,MSDOS_DOT   , MSDOS_NAME) &&
+                   strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
+                       result = -ENOTEMPTY;
+                       break;
                }
-               if (bh)
-                       fat_brelse(dir->i_sb, bh);
        }
+       if (bh)
+               fat_brelse(dir->i_sb, bh);
+
        return result;
 }
 
@@ -444,13 +444,8 @@
         * whether it is empty.
         */
        res = -EBUSY;
-       if (!list_empty(&dentry->d_hash)) {
-#ifdef MSDOS_DEBUG
-printk("msdos_rmdir: %s/%s busy, d_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
-#endif
+       if (!list_empty(&dentry->d_hash))
                goto rmdir_done;
-       }
        res = msdos_empty(inode);
        if (res)
                goto rmdir_done;
@@ -503,14 +498,6 @@
        dir->i_nlink++;
        inode->i_nlink = 2; /* no need to mark them dirty */
 
-#ifdef whatfor
-       /*
-        * He's dead, Jim. We don't d_instantiate anymore. Should do it
-        * from the very beginning, actually.
-        */
-       MSDOS_I(inode)->i_busy = 1; /* prevent lookups */
-#endif
-
        if ((res = fat_add_cluster(inode)) < 0)
                goto mkdir_error;
        if ((res = msdos_create_entry(inode,MSDOS_DOT,1,0,&dot)) < 0)
@@ -529,9 +516,6 @@
        MSDOS_I(dot)->i_logstart = MSDOS_I(dir)->i_logstart;
        dot->i_nlink = dir->i_nlink;
        mark_inode_dirty(dot);
-#ifdef whatfor
-       MSDOS_I(inode)->i_busy = 0;
-#endif
        iput(dot);
        d_instantiate(dentry, inode);
        res = 0;
@@ -606,110 +590,9 @@
        return msdos_unlinkx (dir,dentry,0);
 }
 
-#define MSDOS_CHECK_BUSY 1
-
-/***** Rename within a directory */
-static int msdos_rename_same(struct inode *old_dir,char *old_name,
-    struct dentry *old_dentry,
-    struct inode *new_dir,char *new_name,struct dentry *new_dentry,
-    struct buffer_head *old_bh,
-    struct msdos_dir_entry *old_de, int old_ino, int is_hid)
-{
-       struct super_block *sb = old_dir->i_sb;
-       struct buffer_head *new_bh;
-       struct msdos_dir_entry *new_de;
-       struct inode *new_inode,*old_inode;
-       int new_ino, exists, error;
-
-       if (!strncmp(old_name, new_name, MSDOS_NAME))
-               goto set_hid;
-       error = -ENOENT;
-       if (*(unsigned char *) old_de->name == DELETED_FLAG)
-               goto out;
-
-       exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
-       if (exists) {
-               error = -EIO;
-               new_inode = new_dentry->d_inode;
-               /* Make sure it really exists ... */
-               if (!new_inode) {
-                       printk(KERN_ERR
-                               "msdos_rename_same: %s/%s inode NULL, ino=%d\n",
-                               new_dentry->d_parent->d_name.name,
-                               new_dentry->d_name.name, new_ino);
-                       d_drop(new_dentry);
-                       goto out_error;
-               }
-               error = S_ISDIR(new_inode->i_mode)
-                       ? (old_de->attr & ATTR_DIR)
-                               ? msdos_empty(new_inode)
-                               : -EPERM
-                       : (old_de->attr & ATTR_DIR)
-                               ? -EPERM
-                               : 0;
-               if (error)
-                       goto out_error;
-               error = -EPERM;
-               if ((old_de->attr & ATTR_SYS))
-                       goto out_error;
-
-               if (S_ISDIR(new_inode->i_mode)) {
-                       /* make sure it's empty */
-                       error = msdos_empty(new_inode);
-                       if (error)
-                               goto out_error;
-#ifdef MSDOS_CHECK_BUSY
-                       /* check for a busy dentry */
-                       error = -EBUSY;
-                       shrink_dcache_parent(new_dentry);
-                       if (new_dentry->d_count > 1) {
-printk("msdos_rename_same: %s/%s busy, count=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_dentry->d_count);
-                               goto out_error;
-                       }
-#endif
-                       new_dir->i_nlink--;
-                       mark_inode_dirty(new_dir);
-               }
-               new_inode->i_nlink = 0;
-               MSDOS_I(new_inode)->i_busy = 1;
-               mark_inode_dirty(new_inode);
-               /*
-                * Make it negative if it's not busy;
-                * otherwise let d_move() drop it.
-                */
-               if (new_dentry->d_count == 1)
-                       d_delete(new_dentry);
-
-               new_de->name[0] = DELETED_FLAG;
-               fat_mark_buffer_dirty(sb, new_bh, 1);
-               fat_brelse(sb, new_bh);
-       }
-       memcpy(old_de->name, new_name, MSDOS_NAME);
-       /* Update the dcache */
-       d_move(old_dentry, new_dentry);
-set_hid:
-       old_de->attr = is_hid
-               ? (old_de->attr | ATTR_HIDDEN)
-               : (old_de->attr &~ ATTR_HIDDEN);
-       fat_mark_buffer_dirty(sb, old_bh, 1);
-       /* update binary info for conversion, i_attrs */
-       old_inode = old_dentry->d_inode;
-       MSDOS_I(old_inode)->i_attrs = is_hid
-               ? (MSDOS_I(old_inode)->i_attrs |  ATTR_HIDDEN)
-               : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
-       error = 0;
-out:
-       return error;
-
-out_error:
-       fat_brelse(sb, new_bh);
-       goto out;
-}
-
+/* Now we could merge it with msdos_rename_same. Later */
 /***** Rename across directories - a nonphysical move */
-static int msdos_rename_diff(struct inode *old_dir, char *old_name,
+static int do_msdos_rename(struct inode *old_dir, char *old_name,
     struct dentry *old_dentry,
     struct inode *new_dir,char *new_name, struct dentry *new_dentry,
     struct buffer_head *old_bh,
@@ -718,30 +601,27 @@
        struct super_block *sb = old_dir->i_sb;
        struct buffer_head *new_bh,*free_bh,*dotdot_bh;
        struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
-       struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode;
+       struct inode *old_inode,*new_inode,*dotdot_inode;
        int new_ino,free_ino,dotdot_ino;
        int error, exists;
 
-       error = -EINVAL;
-       if (old_ino == new_dir->i_ino)
-               goto out;
-       /* prevent moving directory below itself */
-       if (is_subdir(new_dentry, old_dentry))
-               goto out;
-
+       old_inode = old_dentry->d_inode;
+       if (old_dir==new_dir && !strncmp(old_name, new_name, MSDOS_NAME))
+               goto set_hid;
        error = -ENOENT;
        if (*(unsigned char *) old_de->name == DELETED_FLAG)
                goto out;
 
        /* find free spot */
-       while ((error = fat_scan(new_dir, NULL, &free_bh, &free_de, &free_ino,
-                                       SCAN_ANY)) < 0) {
-               if (error != -ENOENT)
-                       goto out;
-               error = fat_add_cluster(new_dir);
-               if (error)
-                       goto out;
-       }
+       if (new_dir!=old_dir)
+               while ((error = fat_scan(new_dir, NULL, &free_bh, &free_de,
+                                       &free_ino, SCAN_ANY)) < 0) {
+                       if (error != -ENOENT)
+                               goto out;
+                       error = fat_add_cluster(new_dir);
+                       if (error)
+                               goto out;
+               }
 
        exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
        if (exists) {  /* Trash the old file! */
@@ -750,40 +630,17 @@
                /* Make sure it really exists ... */
                if (!new_inode) {
                        printk(KERN_ERR
-                               "msdos_rename_diff: %s/%s inode NULL, ino=%d\n",
+                               "msdos_rename: %s/%s inode NULL, ino=%d\n",
                                new_dentry->d_parent->d_name.name,
                                new_dentry->d_name.name, new_ino);
                        d_drop(new_dentry);
                        goto out_new;
                }
-               error = S_ISDIR(new_inode->i_mode)
-                       ? (old_de->attr & ATTR_DIR)
-                               ? msdos_empty(new_inode)
-                               : -EPERM
-                       : (old_de->attr & ATTR_DIR)
-                               ? -EPERM
-                               : 0;
-               if (error)
-                       goto out_new;
                error = -EPERM;
                if ((old_de->attr & ATTR_SYS))
                        goto out_new;
 
-#ifdef MSDOS_CHECK_BUSY
-               /* check for a busy dentry */
-               error = -EBUSY;
-               if (new_dentry->d_count > 1) {
-                       shrink_dcache_parent(new_dentry);
-                       if (new_dentry->d_count > 1) {
-printk("msdos_rename_diff: target %s/%s busy, count=%d\n",
-new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
-new_dentry->d_count);
-                               goto out_new;
-                       }
-               }
-#endif
                if (S_ISDIR(new_inode->i_mode)) {
-                       /* make sure it's empty */
                        error = msdos_empty(new_inode);
                        if (error)
                                goto out_new;
@@ -793,18 +650,29 @@
                new_inode->i_nlink = 0;
                MSDOS_I(new_inode)->i_busy = 1;
                mark_inode_dirty(new_inode);
-               /*
-                * Make it negative if it's not busy;
-                * otherwise let d_move() drop it.
-                */
-               if (new_dentry->d_count == 1)
-                       d_delete(new_dentry);
+
                new_de->name[0] = DELETED_FLAG;
                fat_mark_buffer_dirty(sb, new_bh, 1);
                fat_brelse(sb, new_bh);
        }
 
-       old_inode = old_dentry->d_inode;
+       if (old_dir==new_dir) {
+               memcpy(old_de->name, new_name, MSDOS_NAME);
+               /* Update the dcache */
+               if (!S_ISDIR(old_inode->i_mode))
+                       d_move(old_dentry, new_dentry);
+set_hid:
+               old_de->attr = is_hid
+                       ? (old_de->attr | ATTR_HIDDEN)
+                       : (old_de->attr &~ ATTR_HIDDEN);
+               fat_mark_buffer_dirty(sb, old_bh, 1);
+               MSDOS_I(old_inode)->i_attrs = is_hid
+                       ? (MSDOS_I(old_inode)->i_attrs |  ATTR_HIDDEN)
+                       : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
+               error = 0;
+               goto out;
+       }
+
        /* Get the dotdot inode if we'll need it ... */
        dotdot_bh = NULL;
        dotdot_inode = NULL;
@@ -824,73 +692,37 @@
                        goto out_dotdot;
        }
 
-       /* get an inode for the new name */
+       /*
+        * Potential race here. It will go away when we'll switch to
+        * sane inumbers (along with a frigging lot of other races).
+        */
+
+       /* set new entry */
        memcpy(free_de, old_de, sizeof(struct msdos_dir_entry));
        memcpy(free_de->name, new_name, MSDOS_NAME);
        free_de->attr = is_hid
                ? (free_de->attr|ATTR_HIDDEN)
                : (free_de->attr&~ATTR_HIDDEN);
 
-       error = -EIO;
-       free_inode = iget(sb, free_ino);
-       if (!free_inode)
-               goto out_iput;
-       /* make sure it's not busy! */
-       if (MSDOS_I(free_inode)->i_busy)
-               printk(KERN_ERR "msdos_rename_diff: new inode %ld busy!\n",
-                       (ino_t) free_ino);
-       if (!list_empty(&free_inode->i_dentry))
-               printk("msdos_rename_diff: free inode has aliases??\n");
-       msdos_read_inode(free_inode);
-
        /*
-        * Make sure the old dentry isn't busy,
-        * as we need to change inodes ...
+        * Now the tricky part. We need to change i_ino. icache ignores
+        * i_ino for unhashed inodes, so we'll remove inode from hash,
+        * change what we want to change and reinsert it back. NB: we
+        * don't have to invalidate FAT cache here - all we need is to
+        * flip i_ino in relevant cache entries. Later.
         */
-       error = -EBUSY;
-       if (old_dentry->d_count > 1) {
-               shrink_dcache_parent(old_dentry);
-               if (old_dentry->d_count > 1) {
-printk("msdos_rename_diff: source %s/%s busy, count=%d\n",
-old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
-old_dentry->d_count);
-                       goto out_iput;
-               }
-       }
-
-       /* keep the inode for a bit ... */
-       old_inode->i_count++;
-       d_delete(old_dentry);
-
-       free_inode->i_mode   = old_inode->i_mode;
-       free_inode->i_nlink  = old_inode->i_nlink;
-       free_inode->i_size   = old_inode->i_size;
-       free_inode->i_blocks = old_inode->i_blocks;
-       free_inode->i_mtime  = old_inode->i_mtime;
-       free_inode->i_atime  = old_inode->i_atime;
-       free_inode->i_ctime  = old_inode->i_ctime;
-       MSDOS_I(free_inode)->i_ctime_ms = MSDOS_I(old_inode)->i_ctime_ms;
-
-       MSDOS_I(free_inode)->i_start = MSDOS_I(old_inode)->i_start;
-       MSDOS_I(free_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart;
-       MSDOS_I(free_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs;
-
-       /* release the old inode's resources */
-       MSDOS_I(old_inode)->i_start = 0;
-       MSDOS_I(old_inode)->i_logstart = 0;
-       old_inode->i_nlink = 0;
-
-       /*
-        * Install the new inode ...
-        */
-       d_instantiate(old_dentry, free_inode);
+       remove_inode_hash(old_inode);
 
-       fat_mark_buffer_dirty(sb, free_bh, 1);
        fat_cache_inval_inode(old_inode);
-       mark_inode_dirty(old_inode);
+       old_inode->i_version = ++event;
+       MSDOS_I(old_inode)->i_binary =
+               is_binary(MSDOS_SB(sb)->options.conversion, free_de->ext);
+       old_inode->i_ino = free_ino;
+       fat_mark_buffer_dirty(sb, free_bh, 1);
        old_de->name[0] = DELETED_FLAG;
        fat_mark_buffer_dirty(sb, old_bh, 1);
-       iput(old_inode);
+
+       insert_inode_hash(old_inode);
 
        /* a directory? */
        if (dotdot_bh) {
@@ -909,7 +741,8 @@
        }
 
        /* Update the dcache */
-       d_move(old_dentry, new_dentry);
+       if (!S_ISDIR(old_inode->i_mode))
+               d_move(old_dentry, new_dentry);
        error = 0;
 
 rename_done:
@@ -917,14 +750,6 @@
 out:
        return error;
 
-out_iput:
-       free_de->name[0] = DELETED_FLAG;
-       /*
-        * Don't mark free_bh as dirty. Both states 
-        * are supposed to be equivalent.
-        */
-       iput(free_inode); /* may be NULL */
-       iput(dotdot_inode);
 out_dotdot:
        fat_brelse(sb, dotdot_bh);
        goto rename_done;
@@ -944,9 +769,6 @@
        int is_hid,old_hid; /* if new file and old file are hidden */
        char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
 
-       error = -EINVAL;
-       if (sb != new_dir->i_sb)
-               goto rename_done;
        error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
                                old_dentry->d_name.name, old_dentry->d_name.len,
                                old_msdos_name, 1,MSDOS_SB(sb)->options.dotsOK);
@@ -966,14 +788,9 @@
                goto rename_done;
 
        fat_lock_creation();
-       if (old_dir == new_dir)
-               error = msdos_rename_same(old_dir, old_msdos_name, old_dentry,
-                                       new_dir, new_msdos_name, new_dentry,
-                                       old_bh, old_de, (ino_t)old_ino, is_hid);
-       else
-               error = msdos_rename_diff(old_dir, old_msdos_name, old_dentry,
-                                       new_dir, new_msdos_name, new_dentry,
-                                       old_bh, old_de, (ino_t)old_ino, is_hid);
+       error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
+                               new_dir, new_msdos_name, new_dentry,
+                               old_bh, old_de, (ino_t)old_ino, is_hid);
        fat_unlock_creation();
        fat_brelse(sb, old_bh);
 
diff -urN linux-2.2.2-pre4/fs/namei.c linux.bird.rename/fs/namei.c
--- linux-2.2.2-pre4/fs/namei.c Tue Feb 16 11:53:45 1999
+++ linux.bird.rename/fs/namei.c        Tue Feb 16 11:58:17 1999
@@ -1231,15 +1231,73 @@
        return error;
 }
 
-int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
+              struct inode *new_dir, struct dentry *new_dentry)
+{
+       int error;
+       int need_rehash = 0;
+
+       if (old_dentry->d_inode == new_dentry->d_inode)
+               return 0;
+
+       error = may_delete(old_dir, old_dentry, 1);
+       if (error)
+               return error;
+
+       if (new_dir->i_dev != old_dir->i_dev)
+               return -EXDEV;
+
+       if (!new_dentry->d_inode)
+               error = may_create(new_dir, new_dentry);
+       else
+               error = may_delete(new_dir, new_dentry, 1);
+       if (error)
+               return error;
+
+       if (!old_dir->i_op || !old_dir->i_op->rename)
+               return -EPERM;
+
+       /*
+        * If we are going to change the parent - check write permissions,
+        * we'll need to flip '..'.
+        */
+       if (new_dir != old_dir) {
+               error = permission(old_dentry->d_inode, MAY_WRITE);
+       }
+       if (error)
+               return error;
+
+       DQUOT_INIT(old_dir);
+       DQUOT_INIT(new_dir);
+       down(&old_dir->i_sb->s_vfs_rename_sem);
+       error = -EINVAL;
+       if (is_subdir(new_dentry, old_dentry))
+               goto out_unlock;
+       if (new_dentry->d_inode) {
+               error = -EBUSY;
+               if (d_invalidate(new_dentry)<0)
+                       goto out_unlock;
+               need_rehash = 1;
+       }
+       error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
+       if (need_rehash)
+               d_rehash(new_dentry);
+       if (!error)
+               d_move(old_dentry,new_dentry);
+out_unlock:
+       up(&old_dir->i_sb->s_vfs_rename_sem);
+       return error;
+}
+
+int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
               struct inode *new_dir, struct dentry *new_dentry)
 {
        int error;
-       int isdir;
 
-       isdir = S_ISDIR(old_dentry->d_inode->i_mode);
+       if (old_dentry->d_inode == new_dentry->d_inode)
+               return 0;
 
-       error = may_delete(old_dir, old_dentry, isdir); /* XXX */
+       error = may_delete(old_dir, old_dentry, 0);
        if (error)
                return error;
 
@@ -1249,7 +1307,7 @@
        if (!new_dentry->d_inode)
                error = may_create(new_dir, new_dentry);
        else
-               error = may_delete(new_dir, new_dentry, isdir);
+               error = may_delete(new_dir, new_dentry, 0);
        if (error)
                return error;
 
@@ -1261,6 +1319,15 @@
        error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
 
        return error;
+}
+
+int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+              struct inode *new_dir, struct dentry *new_dentry)
+{
+       if (S_ISDIR(old_dentry->d_inode->i_mode))
+               return vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
+       else
+               return vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
 }
 
 static inline int do_rename(const char * oldname, const char * newname)
diff -urN linux-2.2.2-pre4/fs/ncpfs/dir.c linux.bird.rename/fs/ncpfs/dir.c
--- linux-2.2.2-pre4/fs/ncpfs/dir.c     Tue Feb 16 11:53:47 1999
+++ linux.bird.rename/fs/ncpfs/dir.c    Tue Feb 16 11:58:17 1999
@@ -303,6 +303,8 @@
 
         memset(&ia,0,sizeof(struct iattr));
         ia.ia_mode = old_dentry->d_inode->i_mode;
+       if (S_ISDIR(ia.ia_mode))
+               goto leave_me;
         ia.ia_mode |= NCP_SERVER(old_dir)->m.file_mode & 0222;  /* set write bits */
         ia.ia_valid = ATTR_MODE;
 
@@ -1125,7 +1127,8 @@
                                 old_dentry->d_name.name,new_dentry->d_name.name);
                         ncp_invalid_dir_cache(old_dir);
                         ncp_invalid_dir_cache(new_dir);
-                        d_move(old_dentry,new_dentry);
+                       if (!S_ISDIR(old_dentry->d_inode->i_mode))
+                               d_move(old_dentry,new_dentry);
                 }
        } else {
                if (error == 0x9E)
diff -urN linux-2.2.2-pre4/fs/nfs/dir.c linux.bird.rename/fs/nfs/dir.c
--- linux-2.2.2-pre4/fs/nfs/dir.c       Tue Feb 16 11:53:45 1999
+++ linux.bird.rename/fs/nfs/dir.c      Tue Feb 16 13:10:44 1999
@@ -624,10 +624,6 @@
        dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
                dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-       error = -ENAMETOOLONG;
-       if (dentry->d_name.len > NFS_MAXNAMLEN)
-               goto out;
-
        sattr.mode = mode;
        sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
        sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
@@ -642,7 +638,6 @@
                error = nfs_instantiate(dentry, &fhandle, &fattr);
        if (error)
                d_drop(dentry);
-out:
        return error;
 }
 
@@ -659,9 +654,6 @@
        dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
                dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-       if (dentry->d_name.len > NFS_MAXNAMLEN)
-               return -ENAMETOOLONG;
-
        sattr.mode = mode;
        sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
        if (S_ISCHR(mode) || S_ISBLK(mode))
@@ -691,10 +683,6 @@
        dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
                dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-       error = -ENAMETOOLONG;
-       if (dentry->d_name.len > NFS_MAXNAMLEN)
-               goto out;
-
        sattr.mode = mode | S_IFDIR;
        sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
        sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
@@ -709,7 +697,6 @@
        nfs_invalidate_dircache(dir);
        error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
                                dentry->d_name.name, &sattr, &fhandle, &fattr);
-out:
        return error;
 }
 
@@ -731,10 +718,6 @@
        dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
                dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-       error = -ENAMETOOLONG;
-       if (dentry->d_name.len > NFS_MAXNAMLEN)
-               goto out;
-
        error = -EBUSY;
        if (!list_empty(&dentry->d_hash))
                goto out;
@@ -964,10 +947,6 @@
        dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
                dir->i_dev, dir->i_ino, dentry->d_name.name);
 
-       error = -ENAMETOOLONG;
-       if (dentry->d_name.len > NFS_MAXNAMLEN)
-               goto out;
-
        error = nfs_sillyrename(dir, dentry);
        if (error && error != -EBUSY) {
                error = nfs_safe_remove(dentry);
@@ -975,7 +954,6 @@
                        nfs_renew_times(dentry);
                }
        }
-out:
        return error;
 }
 
@@ -989,9 +967,6 @@
                dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
 
        error = -ENAMETOOLONG;
-       if (dentry->d_name.len > NFS_MAXNAMLEN)
-               goto out;
-
        if (strlen(symname) > NFS_MAXPATHLEN)
                goto out;
 
@@ -1038,10 +1013,6 @@
                old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
                dentry->d_parent->d_name.name, dentry->d_name.name);
 
-       error = -ENAMETOOLONG;
-       if (dentry->d_name.len > NFS_MAXNAMLEN)
-               goto out;
-
        /*
         * Drop the dentry in advance to force a new lookup.
         * Since nfs_proc_link doesn't return a file handle,
@@ -1058,7 +1029,6 @@
                 */
                inode->i_nlink++;
        }
-out:
        return error;
 }
 
@@ -1099,11 +1069,6 @@
                new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
                new_dentry->d_count);
 
-       error = -ENAMETOOLONG;
-       if (old_dentry->d_name.len > NFS_MAXNAMLEN ||
-           new_dentry->d_name.len > NFS_MAXNAMLEN)
-               goto out;
-
        /*
         * First check whether the target is busy ... we can't
         * safely do _any_ rename if the target is in use.
@@ -1112,28 +1077,24 @@
         * silly-rename. If the silly-rename succeeds, the
         * copied dentry is hashed and becomes the new target.
         *
-        * For directories, prune any unused children.
+        * With directories check is done in VFS.
         */
        error = -EBUSY;
        if (new_dentry->d_count > 1 && new_inode) {
-               if (S_ISREG(new_inode->i_mode)) {
-                       int err;
-                       /* copy the target dentry's name */
-                       dentry = d_alloc(new_dentry->d_parent,
-                                        &new_dentry->d_name);
-                       if (!dentry)
-                               goto out;
-
-                       /* silly-rename the existing target ... */
-                       err = nfs_sillyrename(new_dir, new_dentry);
-                       if (!err) {
-                               new_dentry = dentry;
-                               new_inode = NULL;
-                               /* hash the replacement target */
-                               d_add(new_dentry, NULL);
-                       }
-               } else if (!list_empty(&new_dentry->d_subdirs)) {
-                       shrink_dcache_parent(new_dentry);
+               int err;
+               /* copy the target dentry's name */
+               dentry = d_alloc(new_dentry->d_parent,
+                                &new_dentry->d_name);
+               if (!dentry)
+                       goto out;
+
+               /* silly-rename the existing target ... */
+               err = nfs_sillyrename(new_dir, new_dentry);
+               if (!err) {
+                       new_dentry = dentry;
+                       new_inode = NULL;
+                       /* hash the replacement target */
+                       d_add(new_dentry, NULL);
                }
 
                /* dentry still busy? */
@@ -1208,7 +1169,7 @@
        error = nfs_proc_rename(NFS_DSERVER(old_dentry),
                        NFS_FH(old_dentry->d_parent), old_dentry->d_name.name,
                        NFS_FH(new_dentry->d_parent), new_dentry->d_name.name);
-       if (!error) {
+       if (!error && !S_ISDIR(old_inode->i_mode)) {
                /* Update the dcache if needed */
                if (rehash)
                        d_add(new_dentry, NULL);
diff -urN linux-2.2.2-pre4/fs/nfsd/vfs.c linux.bird.rename/fs/nfsd/vfs.c
--- linux-2.2.2-pre4/fs/nfsd/vfs.c      Tue Feb 16 11:53:48 1999
+++ linux.bird.rename/fs/nfsd/vfs.c     Tue Feb 16 13:03:02 1999
@@ -959,7 +959,7 @@
                goto out_unlock;
 
        err = nfserr_perm;
-       if (IS_IMMUTABLE(dest) /* || IS_APPEND(dest) */ )
+       if (IS_IMMUTABLE(dest) || IS_APPEND(dest))
                goto out_unlock;
        if (!dirp->i_op || !dirp->i_op->link)
                goto out_unlock;
diff -urN linux-2.2.2-pre4/fs/smbfs/dir.c linux.bird.rename/fs/smbfs/dir.c
--- linux-2.2.2-pre4/fs/smbfs/dir.c     Tue Feb 16 11:53:46 1999
+++ linux.bird.rename/fs/smbfs/dir.c    Tue Feb 16 13:12:03 1999
@@ -423,9 +423,6 @@
 printk("smb_create: creating %s/%s, mode=%d\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
 #endif
-       error = -ENAMETOOLONG;
-       if (dentry->d_name.len > SMB_MAXNAMELEN)
-               goto out;
 
        smb_invalid_dir_cache(dir);
        error = smb_proc_create(dentry, 0, CURRENT_TIME, &fileid);
@@ -439,7 +436,6 @@
 dentry->d_parent->d_name.name, dentry->d_name.name, error);
 #endif
        }
-out:
        return error;
 }
 
@@ -449,17 +445,12 @@
 {
        int error;
 
-       error = -ENAMETOOLONG;
-       if (dentry->d_name.len > SMB_MAXNAMELEN)
-               goto out;
-
        smb_invalid_dir_cache(dir);
        error = smb_proc_mkdir(dentry);
        if (!error)
        {
                error = smb_instantiate(dentry, 0, 0);
        }
-out:
        return error;
 }
 
@@ -514,11 +505,6 @@
 {
        int error;
 
-       error = -ENAMETOOLONG;
-       if (old_dentry->d_name.len > SMB_MAXNAMELEN ||
-           new_dentry->d_name.len > SMB_MAXNAMELEN)
-               goto out;
-
        /*
         * Close any open files, and check whether to delete the
         * target before attempting the rename.
@@ -537,6 +523,7 @@
 #endif
                        goto out;
                }
+               /* FIXME */
                d_delete(new_dentry);
        }
 
@@ -547,7 +534,8 @@
        {
                smb_renew_times(old_dentry);
                smb_renew_times(new_dentry);
-               d_move(old_dentry, new_dentry);
+               if (!S_ISDIR(old_dentry->d_inode->i_mode))
+                       d_move(old_dentry, new_dentry);
        }
 out:
        return error;
diff -urN linux-2.2.2-pre4/fs/super.c linux.bird.rename/fs/super.c
--- linux-2.2.2-pre4/fs/super.c Tue Feb 16 11:53:45 1999
+++ linux.bird.rename/fs/super.c        Tue Feb 16 11:58:17 1999
@@ -559,6 +559,7 @@
        s->s_dev = dev;
        s->s_flags = flags;
        s->s_dirt = 0;
+       sema_init(&s->s_vfs_rename_sem,1);
        /* N.B. Should lock superblock now ... */
        if (!type->read_super(s, data, silent))
                goto out_fail;
diff -urN linux-2.2.2-pre4/fs/sysv/namei.c linux.bird.rename/fs/sysv/namei.c
--- linux-2.2.2-pre4/fs/sysv/namei.c    Tue Feb 16 11:53:46 1999
+++ linux.bird.rename/fs/sysv/namei.c   Tue Feb 16 11:58:17 1999
@@ -593,8 +593,8 @@
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
-static int do_sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
-                         struct inode * new_dir, struct dentry * new_dentry)
+int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
+                 struct inode * new_dir, struct dentry * new_dentry)
 {
        struct inode * old_inode, * new_inode;
        struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -627,20 +627,8 @@
                        new_bh = NULL;
                }
        }
-       if (new_inode == old_inode) {
-               retval = 0;
-               goto end_rename;
-       }
        if (S_ISDIR(old_inode->i_mode)) {
-               retval = -EINVAL;
-               if (is_subdir(new_dentry, old_dentry))
-                       goto end_rename;
                if (new_inode) {
-                       if (new_dentry->d_count > 1)
-                               shrink_dcache_parent(new_dentry);
-                       retval = -EBUSY;
-                       if (new_dentry->d_count > 1)
-                               goto end_rename;
                        retval = -ENOTEMPTY;
                        if (!empty_dir(new_inode))
                                goto end_rename;
@@ -695,37 +683,12 @@
                        mark_inode_dirty(new_dir);
                }
        }
-       d_move(old_dentry, new_dentry);
+       if (!S_ISDIR(old_inode->i_mode))
+               d_move(old_dentry, new_dentry);
        retval = 0;
 end_rename:
        brelse(dir_bh);
        brelse(old_bh);
        brelse(new_bh);
        return retval;
-}
-
-/*
- * Ok, rename also locks out other renames, as they can change the parent of
- * a directory, and we don't want any races. Other races are checked for by
- * "do_rename()", which restarts if there are inconsistencies.
- *
- * Note that there is no race between different filesystems: it's only within
- * the same device that races occur: many renames can happen at once, as long
- * as they are on different partitions.
- */
-int sysv_rename(struct inode * old_dir, struct dentry * old_dentry,
-               struct inode * new_dir, struct dentry * new_dentry)
-{
-       static struct wait_queue * wait = NULL;
-       static int lock = 0;
-       int result;
-
-       while (lock)
-               sleep_on(&wait);
-       lock = 1;
-       result = do_sysv_rename(old_dir, old_dentry,
-                               new_dir, new_dentry);
-       lock = 0;
-       wake_up(&wait);
-       return result;
 }
diff -urN linux-2.2.2-pre4/fs/ufs/namei.c linux.bird.rename/fs/ufs/namei.c
--- linux-2.2.2-pre4/fs/ufs/namei.c     Tue Feb 16 11:53:47 1999
+++ linux.bird.rename/fs/ufs/namei.c    Tue Feb 16 13:14:40 1999
@@ -250,12 +250,6 @@
        swab = sb->u.ufs_sb.s_swab;
        uspi = sb->u.ufs_sb.s_uspi;
 
-       if (namelen > UFS_MAXNAMLEN)
-       {
-               *err = -ENAMETOOLONG;
-               return NULL;
-       }
-
        if (!namelen)
                return NULL;
        /*
@@ -469,10 +463,6 @@
        sb = dir->i_sb;
        flags = sb->u.ufs_sb.s_flags;
        swab = sb->u.ufs_sb.s_swab;
-       
-       err = -ENAMETOOLONG;
-       if (dentry->d_name.len > UFS_MAXNAMLEN)
-               goto out;
 
        inode = ufs_new_inode (dir, mode, &err);
        if (!inode)
@@ -528,10 +518,6 @@
        sb = dir->i_sb;
        flags = sb->u.ufs_sb.s_flags;
        swab = sb->u.ufs_sb.s_swab;
-       
-       err = -ENAMETOOLONG;
-       if (dentry->d_name.len > UFS_MAXNAMLEN)
-               goto out;
 
        err = -EMLINK;
        if (dir->i_nlink >= UFS_LINK_MAX)
@@ -670,10 +656,6 @@
        swab = sb->u.ufs_sb.s_swab;
                
        UFSD(("ENTER\n"))
-       
-       retval = -ENAMETOOLONG;
-       if (dentry->d_name.len > UFS_MAXNAMLEN)
-               goto out;
 
        retval = -ENOENT;
        bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
@@ -687,14 +669,12 @@
        if (SWAB32(de->d_ino) != inode->i_ino)
                goto end_rmdir;
 
+       retval = -ENOTEMPTY;
        if (!ufs_empty_dir (inode))
-               retval = -ENOTEMPTY;
-       else if (SWAB32(de->d_ino) != inode->i_ino)
-               retval = -ENOENT;
-       else {
-               retval = ufs_delete_entry (dir, de, bh);
-               dir->i_version = ++event;
-       }
+               goto end_rmdir;
+
+       retval = ufs_delete_entry (dir, de, bh);
+       dir->i_version = ++event;
        if (retval)
                goto end_rmdir;
        mark_buffer_dirty(bh, 1);
@@ -717,7 +697,6 @@
 
 end_rmdir:
        brelse (bh);
-out:
        UFSD(("EXIT\n"))
        
        return retval;
@@ -735,10 +714,6 @@
        sb = dir->i_sb;
        flags = sb->u.ufs_sb.s_flags;
        swab = sb->u.ufs_sb.s_swab;
-               
-       retval = -ENAMETOOLONG;
-       if (dentry->d_name.len > UFS_MAXNAMLEN)
-               goto out;
 
        retval = -ENOENT;
        bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
@@ -779,7 +754,6 @@
 
 end_unlink:
        brelse (bh);
-out:
        return retval;
 }
 
@@ -881,9 +855,6 @@
        if (S_ISDIR(inode->i_mode))
                return -EPERM;
 
-       if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
-               return -EPERM;
-
        if (inode->i_nlink >= UFS_LINK_MAX)
                return -EMLINK;
 
@@ -912,17 +883,10 @@
        ((struct ufs_dir_entry *) ((char *) buffer + \
        SWAB16(((struct ufs_dir_entry *) buffer)->d_reclen)))->d_ino
 /*
- * rename uses retrying to avoid race-conditions: at least they should be
- * minimal.
- * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
- * checks fail, it tries to restart itself again. Very practical - no changes
- * are done until we know everything works ok.. and then all the changes can be
- * done in one fell swoop when we have claimed all the buffers needed.
- *
  * Anybody can rename anything with this: the permission checks are left to the
  * higher-level routines.
  */
-static int do_ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
+int ufs_rename (struct inode * old_dir, struct dentry * old_dentry,
        struct inode * new_dir, struct dentry * new_dentry )
 {
        struct super_block * sb;
@@ -941,9 +905,6 @@
        old_inode = new_inode = NULL;
        old_bh = new_bh = dir_bh = NULL;
        new_de = NULL;
-       retval = -ENAMETOOLONG;
-       if (old_dentry->d_name.len > UFS_MAXNAMLEN)
-               goto end_rename;
 
        old_bh = ufs_find_entry (old_dir, old_dentry->d_name.name, 
old_dentry->d_name.len, &old_de);
        /*
@@ -967,25 +928,14 @@
                        DQUOT_INIT(new_inode);
                }
        }
-       retval = 0;
-       if (new_inode == old_inode)
-               goto end_rename;
        if (S_ISDIR(old_inode->i_mode)) {
-               retval = -EINVAL;
-               if (is_subdir(new_dentry, old_dentry))
-                       goto end_rename;
                if (new_inode) {
-                       /* Prune any children before testing for busy */
-                       if (new_dentry->d_count > 1)
-                               shrink_dcache_parent(new_dentry);
-                       retval = -EBUSY;
-                       if (new_dentry->d_count > 1)
-                               goto end_rename;
                        retval = -ENOTEMPTY;
                        if (!ufs_empty_dir (new_inode))
                                goto end_rename;
                }
 
+               retval = -EIO;
                dir_bh = ufs_bread (old_inode, 0, 0, &retval);
                if (!dir_bh)
                        goto end_rename;
@@ -1043,7 +993,8 @@
        }
 
        /* Update the dcache */
-       d_move(old_dentry, new_dentry);
+       if (!S_ISDIR(old_inode->i_mode))
+               d_move(old_dentry, new_dentry);
        retval = 0;
 end_rename:
        brelse (dir_bh);
@@ -1054,36 +1005,3 @@
        
        return retval;
 }
-
-/*
- * Ok, rename also locks out other renames, as they can change the parent of
- * a directory, and we don't want any races. Other races are checked for by
- * "do_rename()", which restarts if there are inconsistencies.
- *
- * Note that there is no race between different filesystems: it's only within
- * the same device that races occur: many renames can happen at once, as long
- * as they are on different partitions.
- *
- * In the second extended file system, we use a lock flag stored in the memory
- * super-block.  This way, we really lock other renames only if they occur
- * on the same file system
- */
-int ufs_rename (struct inode * old_dir, struct dentry *old_dentry,
-       struct inode * new_dir, struct dentry *new_dentry )
-{
-       int result;
-
-       UFSD(("ENTER\n"))
-       
-       while (old_dir->i_sb->u.ufs_sb.s_rename_lock)
-               sleep_on (&old_dir->i_sb->u.ufs_sb.s_rename_wait);
-       old_dir->i_sb->u.ufs_sb.s_rename_lock = 1;
-       result = do_ufs_rename (old_dir, old_dentry, new_dir, new_dentry);
-       old_dir->i_sb->u.ufs_sb.s_rename_lock = 0;
-       wake_up (&old_dir->i_sb->u.ufs_sb.s_rename_wait);
-       
-       UFSD(("EXIT\n"))
-       
-       return result;
-}
- 
diff -urN linux-2.2.2-pre4/fs/ufs/super.c linux.bird.rename/fs/ufs/super.c
--- linux-2.2.2-pre4/fs/ufs/super.c     Tue Feb 16 11:53:47 1999
+++ linux.bird.rename/fs/ufs/super.c    Tue Feb 16 11:58:17 1999
@@ -734,8 +734,6 @@
        
        sb->u.ufs_sb.s_flags = flags;
        sb->u.ufs_sb.s_swab = swab;
-       sb->u.ufs_sb.s_rename_lock = 0;
-       sb->u.ufs_sb.s_rename_wait = NULL;
                                                                          
        sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL);
 
diff -urN linux-2.2.2-pre4/fs/umsdos/namei.c linux.bird.rename/fs/umsdos/namei.c
--- linux-2.2.2-pre4/fs/umsdos/namei.c  Tue Feb 16 11:53:46 1999
+++ linux.bird.rename/fs/umsdos/namei.c Tue Feb 16 11:58:17 1999
@@ -6,6 +6,10 @@
  *
  * Maintain and access the --linux alternate directory file.
  */
+ /*
+  * You are in the maze of twisted functions - half of them shouldn't
+  * be here...
+  */
 
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -394,26 +398,12 @@
                goto out_unlock;
        }
 
-       /* check sticky bit on old_dir */
-       ret = -EPERM;
-       if (is_sticky(old_dir, old_info.entry.uid)) {
-printk("umsdos_rename_f: %s/%s old sticky bit, fsuid=%d, uid=%d, dir=%d\n",
-old_dentry->d_parent->d_name.name, old_info.entry.name,
-current->fsuid, old_info.entry.uid, old_dir->i_uid);
-               goto out_unlock;
-       }
-
        /*
         * Check whether the new_name already exists, and
         * if so whether we're allowed to replace it.
         */
        err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
        if (err == 0) {
-               /* Are we allowed to replace it? */
-               if (is_sticky(new_dir, new_info.entry.uid)) {
-Printk (("sticky set on new "));
-                       goto out_unlock;
-               }
                /* check whether it _really_ exists ... */
                ret = -EEXIST;
                if (new_dentry->d_inode)
@@ -468,28 +458,6 @@
                ret = -ENOENT;
                if (old->d_inode != old_inode)
                        goto out_dput;
-               /*
-                * A cross-directory move with different short and long
-                * names has nasty complications: msdos-fs will need to
-                * change inodes, so we must check whether the original
-                * dentry is busy, and if the rename succeeds the short
-                * dentry will come back with a different inode.
-                *
-                * To handle this, we drop the dentry and free the inode,
-                * and then pick up the new inode after the rename.
-                */
-               if (old_dir != new_dir) {
-                       ret = -EBUSY;
-                       if (old_dentry->d_count > 1) {
-printk("umsdos_rename_f: old dentry %s/%s busy, d_count=%d\n",
-old_dentry->d_parent->d_name.name, old_dentry->d_name.name,old_dentry->d_count);
-                               goto out_dput;
-                       }
-                       d_drop(old_dentry);
-                       d_delete(old_dentry);
-printk("umsdos_rename_f: cross-dir move, %s/%s dropped\n",
-old_dentry->d_parent->d_name.name, old_dentry->d_name.name);
-               }
        }
 
        new = umsdos_lookup_dentry(new_dentry->d_parent, new_info.fake.fname, 
@@ -596,6 +564,135 @@
        Printk ((" _ret=%d\n", ret));
        return ret;
 }
+ 
+static int umsdos_rename_d (struct inode *old_dir, struct dentry *old_dentry,
+                           struct inode *new_dir, struct dentry *new_dentry,
+                           int flags)
+{
+       struct inode *old_inode = old_dentry->d_inode;
+       struct dentry *old, *new, *old_emd, *demd;
+       int err, ret;
+       struct umsdos_info old_info;
+       struct umsdos_info new_info;
+
+       ret = -EPERM;
+       err = umsdos_parse (old_dentry->d_name.name,
+                               old_dentry->d_name.len, &old_info);
+       if (err)
+               goto out;
+       err = umsdos_parse (new_dentry->d_name.name,
+                               new_dentry->d_name.len, &new_info);
+       if (err)
+               goto out;
+
+       /* Get the EMD dentry for the old parent */
+       old_emd = umsdos_get_emd_dentry(old_dentry->d_parent);
+       ret = PTR_ERR(old_emd);
+       if (IS_ERR(old_emd))
+               goto out;
+
+       umsdos_lockcreate2 (old_dir, new_dir);
+
+       ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);
+       if (ret)
+               goto out_unlock;
+
+       err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
+       if (err == 0) {
+               /* bogus lookup? complain and fix up the EMD ... */
+               printk(KERN_WARNING
+                       "umsdos_rename_f: entry %s/%s exists, inode NULL??\n",
+                       new_dentry->d_parent->d_name.name, new_info.entry.name);
+               err = umsdos_delentry(new_dentry->d_parent, &new_info, 1);
+       }
+
+       umsdos_ren_init (&new_info, &old_info);
+       if (flags)
+               new_info.entry.flags = flags;
+       ret = umsdos_newentry (new_dentry->d_parent, &new_info);
+       if (ret)
+               goto out_unlock;
+
+       old = umsdos_lookup_dentry(old_dentry->d_parent, old_info.fake.fname, 
+                                       old_info.fake.len, 1);
+       ret = PTR_ERR(old);
+       if (IS_ERR(old))
+               goto out_unlock;
+       /* short and long name dentries match? */
+       if (old == old_dentry)
+               dput(old);
+       else {
+               /* make sure it's the same inode! */
+               ret = -ENOENT;
+               if (old->d_inode != old_inode)
+                       goto out_dput;
+       }
+
+       new = umsdos_lookup_dentry(new_dentry->d_parent, new_info.fake.fname, 
+                                       new_info.fake.len, 1);
+       ret = PTR_ERR(new);
+       if (IS_ERR(new))
+               goto out_dput;
+       if (new == new_dentry)
+               dput(new);
+       else
+               d_drop(new);
+
+       /* Do the msdos-level rename */
+       ret = msdos_rename (old_dir, old, new_dir, new);
+
+       if (new != new_dentry)
+               dput(new);
+
+       /* If the rename failed, remove the new EMD entry */
+       if (ret != 0) {
+               umsdos_delentry (new_dentry->d_parent, &new_info,1);
+               goto out_dput;
+       }
+
+       /*
+        * Rename successful ... remove the old name from the EMD.
+        * Note that we use the EMD parent here, as the old dentry
+        * may have moved to a new parent ...
+        */
+       err = umsdos_delentry (old_emd->d_parent, &old_info, 1);
+       if (err) {
+               /* Failed? Complain a bit, but don't fail the operation */
+               printk(KERN_WARNING 
+                       "umsdos_rename_f: delentry %s/%s failed, error=%d\n",
+                       old_emd->d_parent->d_name.name, old_info.entry.name,
+                       err);
+       }
+
+       /*
+        * Update f_pos so notify_change will succeed
+        * if the file was already in use.
+        */
+
+       old_inode->u.umsdos_i.i_emd_owner = 0;
+       old_inode->u.umsdos_i.pos = new_info.f_pos;
+
+       /* now check the EMD file */
+       demd = umsdos_get_emd_dentry(new_dentry->d_parent);
+       if (!IS_ERR(demd)) {
+               if (demd->d_inode)
+                       old_inode->u.umsdos_i.i_emd_owner = demd->d_inode->i_ino;
+               dput(demd);
+       }
+
+       /* dput() the dentry if we haven't already */
+out_dput:
+       if (old_dentry != old)
+               dput(old);
+
+out_unlock:
+       dput(old_emd);
+       umsdos_unlockcreate (old_dir);
+       umsdos_unlockcreate (new_dir);
+
+out:
+       return ret;
+}
 
 /*
  * Setup a Symbolic link or a (pseudo) hard link
@@ -1268,18 +1365,28 @@
        if (ret)
                goto out;
 
-       /*
-        * If the target already exists, delete it first.
-        */
-       if (new_dentry->d_inode) {
-               if (S_ISDIR(new_dentry->d_inode->i_mode))
+       if (S_ISDIR(old_dentry->d_inode->i_mode)) {
+               /*
+                * If the target already exists, delete it first.
+                */
+               if (new_dentry->d_inode) {
+                       new_dentry->d_count++;
                        ret = UMSDOS_rmdir (new_dir, new_dentry);
-               else
-                       ret = UMSDOS_unlink (new_dir, new_dentry);
+                       dput(new_dentry);
+                       if (ret)
+                               return ret;
+               }
+               d_delete(new_dentry);
+               ret = umsdos_rename_d(old_dir, old_dentry, new_dir, new_dentry, 0);
+               return ret;
+       } 
+
+
+       if (new_dentry->d_inode) {
+               ret = UMSDOS_unlink (new_dir, new_dentry);
                if (ret)
                        goto out;
        }
-
        /*
         * If we didn't get a negative dentry, make a copy and hash it.
         */
diff -urN linux-2.2.2-pre4/fs/vfat/namei.c linux.bird.rename/fs/vfat/namei.c
--- linux-2.2.2-pre4/fs/vfat/namei.c    Tue Feb 16 11:53:47 1999
+++ linux.bird.rename/fs/vfat/namei.c   Tue Feb 16 11:58:17 1999
@@ -1570,14 +1570,6 @@
                 old_dentry, old_dentry->d_inode, old_dentry->d_inode->i_ino,
                 new_dentry, new_dentry->d_inode,
                 new_dentry->d_inode ? new_dentry->d_inode->i_ino : 0));
-       /*
-        * POSIX is braindead (surprise, surprise). It requires that rename()
-        * should return 0 and do nothing if the target has the same inode as
-        * the source. Somebody, get a time machine, return to '89 and tell
-        * RMS & Co *not* to do that idiocy, FAST!
-        */
-       if (old_dentry->d_inode == new_dentry->d_inode)
-               return 0;
 
        old_bh = new_bh = NULL;
        old_inode = new_inode = NULL;
@@ -1597,16 +1589,8 @@
        old_inode = old_dentry->d_inode;
        is_dir = S_ISDIR(old_inode->i_mode);
 
-       /*
-        * Race: we can be hit by another rename after this check.
-        * For the time being use fat_lock_creation(), but it's
-        * ugly. FIXME.
-        */
-
-       fat_lock_creation(); locked = 1;
-
        if (is_dir) {
-               /* We can't use d_subdir() here. Arrgh. */
+               /* We can't use is_subdir() here. Even now. Arrgh. */
                for (walk=new_dentry;walk!=walk->d_parent;walk=walk->d_parent) {
                        if (walk->d_inode != old_dentry->d_inode)
                                continue;
@@ -1615,6 +1599,8 @@
                }
        }
 
+       fat_lock_creation(); locked = 1;
+
        if (new_dentry->d_inode) {
                /*
                 * OK, we have to remove the target. We should do it so
@@ -1639,8 +1625,6 @@
                         * be tolerated.
                         */
                        res = -EBUSY;
-                       if (d_invalidate(new_dentry) < 0)
-                               goto rename_done;
                        /*
                         * OK, let's try to get rid of other dentries.
                         * No need to do it if i_count is 1.
@@ -1727,9 +1711,9 @@
        }
 
        if (res >= 0) {
-               if (new_inode && is_dir)
-                       d_rehash(new_dentry);
-               d_move(old_dentry, new_dentry);
+               if (!is_dir) {
+                       d_move(old_dentry, new_dentry);
+               }
                res = 0;
        }
 
diff -urN linux-2.2.2-pre4/include/linux/ext2_fs_sb.h 
linux.bird.rename/include/linux/ext2_fs_sb.h
--- linux-2.2.2-pre4/include/linux/ext2_fs_sb.h Tue Feb 16 11:53:53 1999
+++ linux.bird.rename/include/linux/ext2_fs_sb.h        Tue Feb 16 12:22:34 1999
@@ -49,8 +49,6 @@
        struct buffer_head * s_inode_bitmap[EXT2_MAX_GROUP_LOADED];
        unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED];
        struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED];
-       int s_rename_lock;
-       struct wait_queue * s_rename_wait;
        unsigned long  s_mount_opt;
        unsigned short s_resuid;
        unsigned short s_resgid;
diff -urN linux-2.2.2-pre4/include/linux/fs.h linux.bird.rename/include/linux/fs.h
--- linux-2.2.2-pre4/include/linux/fs.h Tue Feb 16 11:55:45 1999
+++ linux.bird.rename/include/linux/fs.h        Tue Feb 16 12:22:44 1999
@@ -557,6 +557,11 @@
                struct qnx4_sb_info     qnx4_sb;           
                void                    *generic_sbp;
        } u;
+       /*
+        * The next field is for VFS *only*. No filesystems have any business
+        * even looking at it. You had been warned.
+        */
+       struct semaphore s_vfs_rename_sem;      /* Kludge */
 };
 
 /*
diff -urN linux-2.2.2-pre4/include/linux/ufs_fs.h 
linux.bird.rename/include/linux/ufs_fs.h
--- linux-2.2.2-pre4/include/linux/ufs_fs.h     Tue Feb 16 11:53:53 1999
+++ linux.bird.rename/include/linux/ufs_fs.h    Tue Feb 16 12:22:35 1999
@@ -203,7 +203,7 @@
 #define        UFS_MAXNAMLEN 255
 #define UFS_MAXMNTLEN 512
 #define UFS_MAXCSBUFS 31
-#define UFS_LINK_MAX EXT2_LINK_MAX
+#define UFS_LINK_MAX 32000
 
 /*
  * UFS_DIR_PAD defines the directory entries boundaries
diff -urN linux-2.2.2-pre4/include/linux/ufs_fs_sb.h 
linux.bird.rename/include/linux/ufs_fs_sb.h
--- linux-2.2.2-pre4/include/linux/ufs_fs_sb.h  Tue Feb 16 11:53:54 1999
+++ linux.bird.rename/include/linux/ufs_fs_sb.h Tue Feb 16 12:22:35 1999
@@ -116,8 +116,6 @@
 struct ufs_sb_info {
        struct ufs_sb_private_info * s_uspi;    
        struct ufs_csum * s_csp[UFS_MAXCSBUFS];
-       int s_rename_lock;
-       struct wait_queue * s_rename_wait;
        unsigned s_swab;
        unsigned s_flags;
        struct buffer_head ** s_ucg;

Reply via email to