lkml.org 
[lkml]   [1999]   [Feb]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[Call For Testers][VFS] Rename stuff.
	OK, folks. Preliminary version of rename patch is here. It's
against 2.2.2-pre2. Help in testing is extermely welcome - I don't have
access to many filesystems, so I can't test them myself. I'm very
suspicious about UMSDOS and HFS parts. I can (and will) test UMSDOS, but
HFS is out of reach for me. WARNING: CONFIG_NCPFS_STRONG ON SMBFS WILL NOT
WORK WITH rename() IN THIS VERSION. Everything else should (in theory)
work. Yup, it's my turn to get those brown paperbags. Please, test the
thing. Most likely it will break. More than in one place. Eating your
data, letting the magic smoke out of your harddisk, driving your dog mad
and causing global warming. You are warned. At least it compiles and
manages to boot (from ext2).
Anyway, in process I've caught quite a collection of bugs of varied
nastiness in nearly all *_rename() methods. At least something...
Patch is attached. Random stuff below being the list of changes /
comments. Ufff...
Al


include/linux/fs.h: added a semaphore to the end of struct super.
fs/super.c: added initialization of semaphore.
fs/namei.c: Divided vfs_rename into vfs_rename_dir and vfs_rename_other
Had put locking / checks into vfs_rename_dir().
Now, for filesystems:
adfs: no rename().
affs: wow. No rename/rename race prevention. OK, fixed the thing. BTW, where
does it flip '..'?
autofs: no rename().
coda: no rename/rename protection, no is_subdir. Mommy, server will do the
right thing, certainly it will not screw me up, why would it?
devpts: no rename().
ext2: Removed unneeded checks. BTW, if in case of directory move reading
the first block of source (for "..") failed it returned either
-EINVAL (if target was negative) or -EBUSY (if positive). Sheesh...
Changed to -EIO. Removed internal ext2 rename serialization (super.c,
ext2_fs_sb.h)
fat: Not a filesystem.
hfs: Hell knows how it works. No visible checks for *anything*. Oh well, did
minimal change (conditional d_move). HFS folks: you'ld better check
your stuff. Really. Sorry, I'm unable to read it. At least some
comments on *how* it works are in order, IMHO.
hpfs: no rename.
isofs: no rename.
lockd: not a filesystem.
minix: Way too rough serialization. Removed unneeded checks. I'm still not sure
that retries in {minix,sysv}_rename do not give a race. Later.
ncpfs: no checks at all. No serialization. Odd stuff with CONFIG_NCPFS_STRONG.
WARNING: support of NCPFS_STRONG is broken right now. FIXME!!!
nfs: no checks, no nothing. Fixed.
nfsd: not a filesystem.
nls: not a filesystem.
ntfs: no rename().
proc: no rename().
qnx4: no rename().
romfs: no rename().
smbfs: no checks at all. Fixed, except the POSIX breakage (target becoming
negative for a while).
sysv: Removed unneeded checks. Serialization was too rough.
ufs: same picture as with ext2.
vfat: Removed unneeded checks. Alas, not all of them went away. Darn aliases.
msdos: Fixed. Another change: now we don't flip inodes under dentry.
Finally. Sorry, but without that there was no way to fix umsdos
and remain even remotely sane.
umsdos: PERKELE! I have some opinion on the current state of this piece of
kernel, but it's completely unsuitable for family reading.
IOW: bloody mess. IMNSHO the *only* way to fix the thing goes through
support of layers on dcache level. Attempt to save on the number of
active dentries and fit two inodes into one leads to completely broken
code. To start with, it does a mind-boggling number of dcache lookups
and, what's worse, EMD lookups. What it will give in conjunction with
loop device or, heaven forbid, knfsd is, erm, unpleasant. Not to mention
the fact that the thing is hardly readable and does very odd things with
locking (deadlocks *are* there). Idea of symlinks having ->readpage()
is, to put it politely, unorthodoxal, but that's relatively minor
offence. Manipulations with struct file inside of the beast are very
interesting. Unfortunately they are very fragile too.
It's *not* a flame towards Matija - I'm amazed how one can
keep sanity working with such code. But dentry stuff in UMSDOS
really should be replaced by proper implementation of stackable
filesystem support in VFS. It would help in other places too, but
that's another story. I'll look whether it can be done without breaking
compatibility. I hope it is possible, at least for subset needed by
UMSDOS.
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 Tue Feb 9 10:17:17 1999
+++ linux.bird.rename/fs/affs/namei.c Tue Feb 9 09:23:19 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 Tue Feb 9 10:17:18 1999
+++ linux.bird.rename/fs/coda/dir.c Tue Feb 9 08:40:22 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 Tue Feb 9 10:17:15 1999
+++ linux.bird.rename/fs/ext2/namei.c Tue Feb 9 08:01:02 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 Tue Feb 9 10:17:15 1999
+++ linux.bird.rename/fs/ext2/super.c Sun Feb 7 00:00:47 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 Tue Feb 9 10:17:19 1999
+++ linux.bird.rename/fs/hfs/dir.c Mon Feb 8 23:33: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 Tue Feb 9 10:17:15 1999
+++ linux.bird.rename/fs/minix/namei.c Tue Feb 9 08:43:32 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 Tue Feb 9 10:17:15 1999
+++ linux.bird.rename/fs/msdos/namei.c Tue Feb 9 06:42:07 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;
@@ -640,47 +624,20 @@
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);
@@ -688,7 +645,8 @@
}
memcpy(old_de->name, new_name, MSDOS_NAME);
/* Update the dcache */
- d_move(old_dentry, new_dentry);
+ 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)
@@ -708,6 +666,7 @@
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,
struct dentry *old_dentry,
@@ -718,16 +677,13 @@
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;

error = -ENOENT;
if (*(unsigned char *) old_de->name == DELETED_FLAG)
@@ -756,34 +712,11 @@
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,12 +726,7 @@
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);
@@ -824,73 +752,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;
+ remove_inode_hash(old_inode);

- /*
- * Install the new inode ...
- */
- d_instantiate(old_dentry, free_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 +801,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 +810,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 +829,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);
diff -urN linux-2.2.2-pre2/fs/namei.c linux.bird.rename/fs/namei.c
--- linux-2.2.2-pre2/fs/namei.c Tue Feb 9 10:17:15 1999
+++ linux.bird.rename/fs/namei.c Tue Feb 9 08:10:50 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 Tue Feb 9 10:17:16 1999
+++ linux.bird.rename/fs/ncpfs/dir.c Tue Feb 9 09:12:24 1999
@@ -1125,7 +1125,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 Tue Feb 9 10:17:15 1999
+++ linux.bird.rename/fs/nfs/dir.c Tue Feb 9 08:55:29 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 Tue Feb 9 10:17:16 1999
+++ linux.bird.rename/fs/smbfs/dir.c Tue Feb 9 09:09:42 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 Tue Feb 9 10:17:15 1999
+++ linux.bird.rename/fs/super.c Tue Feb 9 08:07:02 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 Tue Feb 9 10:17:16 1999
+++ linux.bird.rename/fs/sysv/namei.c Tue Feb 9 09:06:01 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 Tue Feb 9 10:17:17 1999
+++ linux.bird.rename/fs/ufs/namei.c Tue Feb 9 09:06:37 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 Tue Feb 9 10:17:17 1999
+++ linux.bird.rename/fs/ufs/super.c Tue Feb 9 09:18:07 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 Tue Feb 9 10:17:15 1999
+++ linux.bird.rename/fs/umsdos/namei.c Tue Feb 9 09:02:24 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 Tue Feb 9 10:17:16 1999
+++ linux.bird.rename/fs/vfat/namei.c Tue Feb 9 00:58:55 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 Tue Feb 9 10:17:23 1999
+++ linux.bird.rename/include/linux/ext2_fs_sb.h Tue Feb 9 07:47:14 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 Tue Feb 9 10:17:22 1999
+++ linux.bird.rename/include/linux/fs.h Tue Feb 9 07:47:14 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 Tue Feb 9 10:17:23 1999
+++ linux.bird.rename/include/linux/ufs_fs.h Tue Feb 9 07:47:14 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 Tue Feb 9 10:17:23 1999
+++ linux.bird.rename/include/linux/ufs_fs_sb.h Tue Feb 9 07:47:14 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;
\
 
 \ /
  Last update: 2005-03-22 13:50    [W:0.298 / U:0.080 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site