[Call For Testers][VFS] Rename stuff - new version.

Alexander Viro (viro@math.psu.edu)
Sat, 13 Feb 1999 16:02:57 -0500 (EST)


Folks, here's the new version of rename patch. Please help to test
it - I don't have any access to HFS, SMBFS and AFFS, so... Difference from
the previous one - NCPFS_STRONG fixed (kudos to NCPFS maintainer ;-),
MSDOS part somewhat cleaned up. Still not POSIX-compliant ones - UMSDOS
and SMBFS (rename("foo","bar") makes "bar" negative for a while (for
files, directories are OK now). d_delete() in foo_rename() is wrong,
unless you care to unhash the target and d_rehash() it immediately before
d_move(). Patch (against 2.2.2-pre2) follows. Please, help with testing.
TIA,
Al

diff -urN linux-2.2.2-pre2/fs/affs/namei.c linux.bird.rename/fs/affs/namei.c
--- linux-2.2.2-pre2/fs/affs/namei.c Sat Feb 13 12:55:14 1999
+++ linux.bird.rename/fs/affs/namei.c Tue Feb 9 21:53:25 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-pre2/fs/coda/dir.c linux.bird.rename/fs/coda/dir.c
--- linux-2.2.2-pre2/fs/coda/dir.c Sat Feb 13 12:55:15 1999
+++ linux.bird.rename/fs/coda/dir.c Tue Feb 9 21:53:25 1999
@@ -565,21 +565,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 +584,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-pre2/fs/ext2/namei.c linux.bird.rename/fs/ext2/namei.c
--- linux-2.2.2-pre2/fs/ext2/namei.c Sat Feb 13 12:55:12 1999
+++ linux.bird.rename/fs/ext2/namei.c Tue Feb 9 21:53:25 1999
@@ -851,17 +851,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;
@@ -897,24 +890,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 +960,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 +969,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-pre2/fs/ext2/super.c linux.bird.rename/fs/ext2/super.c
--- linux-2.2.2-pre2/fs/ext2/super.c Sat Feb 13 12:55:12 1999
+++ linux.bird.rename/fs/ext2/super.c Tue Feb 9 21:53:25 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-pre2/fs/hfs/dir.c linux.bird.rename/fs/hfs/dir.c
--- linux-2.2.2-pre2/fs/hfs/dir.c Sat Feb 13 12:55:17 1999
+++ linux.bird.rename/fs/hfs/dir.c Tue Feb 9 21:53:25 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-pre2/fs/minix/namei.c linux.bird.rename/fs/minix/namei.c
--- linux-2.2.2-pre2/fs/minix/namei.c Sat Feb 13 12:55:12 1999
+++ linux.bird.rename/fs/minix/namei.c Tue Feb 9 21:53:25 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-pre2/fs/msdos/namei.c linux.bird.rename/fs/msdos/namei.c
--- linux-2.2.2-pre2/fs/msdos/namei.c Sat Feb 13 12:55:11 1999
+++ linux.bird.rename/fs/msdos/namei..c Wed Feb 10 01:19:31 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,26 @@
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;
-
+ 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 +629,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 +649,30 @@
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_dentry->d_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) {
@@ -908,8 +740,10 @@
fat_brelse(sb, dotdot_bh);
}

+out_ok:
/* 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 +751,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 +770,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 +789,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-pre2/fs/namei.c linux.bird.rename/fs/namei.c
--- linux-2.2.2-pre2/fs/namei.c Sat Feb 13 12:55:11 1999
+++ linux.bird.rename/fs/namei.c Tue Feb 9 21:53:25 1999
@@ -1231,7 +1231,55 @@
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;
+
+ error = may_delete(old_dir, old_dentry, 1); /* XXX */
+ 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 (old_dentry->d_inode == new_dentry->d_inode)
+ return 0;
+
+ 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;
@@ -1239,7 +1287,7 @@

isdir = S_ISDIR(old_dentry->d_inode->i_mode);

- error = may_delete(old_dir, old_dentry, isdir); /* XXX */
+ error = may_delete(old_dir, old_dentry, 0);
if (error)
return error;

@@ -1249,18 +1297,30 @@
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;

if (!old_dir->i_op || !old_dir->i_op->rename)
return -EPERM;

+ if (old_dentry->d_inode == new_dentry->d_inode)
+ return 0;
+
DQUOT_INIT(old_dir);
DQUOT_INIT(new_dir);
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-pre2/fs/ncpfs/dir.c linux.bird.rename/fs/ncpfs/dir.c
--- linux-2.2.2-pre2/fs/ncpfs/dir.c Sat Feb 13 12:55:13 1999
+++ linux.bird.rename/fs/ncpfs/dir.c Tue Feb 9 21:55:21 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-pre2/fs/nfs/dir.c linux.bird.rename/fs/nfs/dir.c
--- linux-2.2.2-pre2/fs/nfs/dir.c Sat Feb 13 12:55:12 1999
+++ linux.bird.rename/fs/nfs/dir.c Tue Feb 9 21:53:25 1999
@@ -1112,28 +1112,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 +1204,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-pre2/fs/smbfs/dir.c linux.bird.rename/fs/smbfs/dir.c
--- linux-2.2.2-pre2/fs/smbfs/dir.c Sat Feb 13 12:55:13 1999
+++ linux.bird.rename/fs/smbfs/dir.c Tue Feb 9 21:53:25 1999
@@ -537,6 +537,7 @@
#endif
goto out;
}
+ /* FIXME */
d_delete(new_dentry);
}

@@ -547,7 +548,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-pre2/fs/super.c linux.bird.rename/fs/super.c
--- linux-2.2.2-pre2/fs/super.c Sat Feb 13 12:55:11 1999
+++ linux.bird.rename/fs/super.c Tue Feb 9 21:53:25 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-pre2/fs/sysv/namei.c linux.bird.rename/fs/sysv/namei.c
--- linux-2.2.2-pre2/fs/sysv/namei.c Sat Feb 13 12:55:13 1999
+++ linux.bird.rename/fs/sysv/namei.c Tue Feb 9 21:53:25 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-pre2/fs/ufs/namei.c linux.bird.rename/fs/ufs/namei.c
--- linux-2.2.2-pre2/fs/ufs/namei.c Sat Feb 13 12:55:14 1999
+++ linux.bird.rename/fs/ufs/namei.c Tue Feb 9 21:53:25 1999
@@ -912,17 +912,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;
@@ -967,25 +960,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 +1025,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 +1037,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-pre2/fs/ufs/super.c linux.bird.rename/fs/ufs/super.c
--- linux-2.2.2-pre2/fs/ufs/super.c Sat Feb 13 12:55:14 1999
+++ linux.bird.rename/fs/ufs/super.c Tue Feb 9 21:53:25 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-pre2/fs/umsdos/namei.c linux.bird.rename/fs/umsdos/namei.c
--- linux-2.2.2-pre2/fs/umsdos/namei.c Sat Feb 13 12:55:12 1999
+++ linux.bird.rename/fs/umsdos/namei.c Tue Feb 9 21:53:26 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-pre2/fs/vfat/namei.c linux.bird.rename/fs/vfat/namei.c
--- linux-2.2.2-pre2/fs/vfat/namei.c Sat Feb 13 12:55:13 1999
+++ linux.bird.rename/fs/vfat/namei.c Tue Feb 9 21:53:26 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-pre2/include/linux/ext2_fs_sb.h linux.bird.rename/include/linux/ext2_fs_sb.h
--- linux-2.2.2-pre2/include/linux/ext2_fs_sb.h Sat Feb 13 12:55:20 1999
+++ linux.bird.rename/include/linux/ext2_fs_sb.h Thu Feb 11 23:40:31 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-pre2/include/linux/fs.h linux.bird.rename/include/linux/fs.h
--- linux-2.2..2-pre2/include/linux/fs.h Sat Feb 13 12:55:20 1999
+++ linux.bird.rename/include/linux/fs.h Thu Feb 11 23:40:44 1999
@@ -556,6 +556,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-pre2/include/linux/ufs_fs.h linux.bird.rename/include/linux/ufs_fs.h
--- linux-2.2.2-pre2/include/linux/ufs_fs.h Sat Feb 13 12:55:20 1999
+++ linux.bird.rename/include/linux/ufs_fs.h Thu Feb 11 23:40:31 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-pre2/include/linux/ufs_fs_sb.h linux.bird.rename/include/linux/ufs_fs_sb.h
--- linux-2.2.2-pre2/include/linux/ufs_fs_sb.h Sat Feb 13 12:55:21 1999
+++ linux.bird.rename/include/linux/ufs_fs_sb.h Thu Feb 11 23:40:31 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;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/