Messages in this thread Patch in this message | | | Date | Sat, 13 Feb 1999 16:02:57 -0500 (EST) | From | Alexander Viro <> | Subject | [Call For Testers][VFS] Rename stuff - new version. |
| |
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/
| |