diff options
Diffstat (limited to 'fs/ext2')
-rw-r--r-- | fs/ext2/balloc.c | 6 | ||||
-rw-r--r-- | fs/ext2/dir.c | 6 | ||||
-rw-r--r-- | fs/ext2/file.c | 5 | ||||
-rw-r--r-- | fs/ext2/ialloc.c | 56 | ||||
-rw-r--r-- | fs/ext2/inode.c | 21 | ||||
-rw-r--r-- | fs/ext2/ioctl.c | 4 | ||||
-rw-r--r-- | fs/ext2/namei.c | 416 | ||||
-rw-r--r-- | fs/ext2/super.c | 10 | ||||
-rw-r--r-- | fs/ext2/symlink.c | 37 | ||||
-rw-r--r-- | fs/ext2/truncate.c | 209 |
10 files changed, 287 insertions, 483 deletions
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 4d2b561ee..7e159e7d2 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -291,7 +291,7 @@ int ext2_new_block (const struct inode * inode, unsigned long goal, printk ("ext2_new_block: nonexistent device"); return 0; } -retry: + lock_super (sb); es = sb->u.ext2_sb.s_es; if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) && @@ -299,8 +299,6 @@ retry: (sb->u.ext2_sb.s_resgid == 0 || !in_group_p (sb->u.ext2_sb.s_resgid)))) { unlock_super (sb); - if(sb->s_ibasket && free_ibasket(sb)) - goto retry; return 0; } @@ -392,8 +390,6 @@ repeat: } if (k >= sb->u.ext2_sb.s_groups_count) { unlock_super (sb); - if(sb->s_ibasket && free_ibasket(sb)) - goto retry; return 0; } bitmap_nr = load_block_bitmap (sb, i); diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index d9b1957e3..b75acdef5 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -65,6 +65,7 @@ struct inode_operations ext2_dir_inode_operations = { ext2_mknod, /* mknod */ ext2_rename, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -211,9 +212,6 @@ revalidate: offset = 0; brelse (bh); } - if (DO_UPDATE_ATIME(inode)) { - inode->i_atime = CURRENT_TIME; - inode->i_dirt = 1; - } + UPDATE_ATIME(inode); return 0; } diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 1627f5cee..d632133f1 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -72,6 +72,7 @@ struct inode_operations ext2_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ ext2_bmap, /* bmap */ @@ -121,7 +122,7 @@ static inline void remove_suid(struct inode *inode) mode &= inode->i_mode; if (mode && !suser()) { inode->i_mode &= ~mode; - inode->i_dirt = 1; + mark_inode_dirty(inode); } } @@ -250,7 +251,7 @@ static long ext2_file_write (struct inode * inode, struct file * filp, inode->u.ext2_i.i_osync--; inode->i_ctime = inode->i_mtime = CURRENT_TIME; filp->f_pos = pos; - inode->i_dirt = 1; + mark_inode_dirty(inode); return written; } diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index a486679f9..bc16722e4 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -154,8 +154,26 @@ static int load_inode_bitmap (struct super_block * sb, return 0; } +/* + * NOTE! When we get the inode, we're the only people + * that have access to it, and as such there are no + * race conditions we have to worry about. The inode + * is not on the hash-lists, and it cannot be reached + * through the filesystem because the directory entry + * has been deleted earlier. + * + * HOWEVER: we must make sure that we get no aliases, + * which means that we have to call "clear_inode()" + * _before_ we mark the inode not in use in the inode + * bitmaps. Otherwise a newly created file might use + * the same inode number (not actually the same pointer + * though), and then we'd have two inodes sharing the + * same inode number and space on the harddisk. + */ void ext2_free_inode (struct inode * inode) { + int is_directory; + unsigned long ino; struct super_block * sb; struct buffer_head * bh; struct buffer_head * bh2; @@ -171,9 +189,8 @@ void ext2_free_inode (struct inode * inode) printk ("ext2_free_inode: inode has no device\n"); return; } - if (atomic_read(&inode->i_count) > 1) { - printk ("ext2_free_inode: inode has count=%d\n", - atomic_read(&inode->i_count)); + if (inode->i_count > 1) { + printk ("ext2_free_inode: inode has count=%d\n", inode->i_count); return; } if (inode->i_nlink) { @@ -186,47 +203,53 @@ void ext2_free_inode (struct inode * inode) return; } - ext2_debug ("freeing inode %lu\n", inode->i_ino); + ino = inode->i_ino; + ext2_debug ("freeing inode %lu\n", ino); sb = inode->i_sb; lock_super (sb); - if (inode->i_ino < EXT2_FIRST_INO(sb) || - inode->i_ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) { + if (ino < EXT2_FIRST_INO(sb) || + ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) { ext2_error (sb, "free_inode", "reserved inode or nonexistent inode"); unlock_super (sb); return; } es = sb->u.ext2_sb.s_es; - block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb); - bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb); + block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb); + bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb); bitmap_nr = load_inode_bitmap (sb, block_group); bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; + + is_directory = S_ISDIR(inode->i_mode); + + /* Do this BEFORE marking the inode not in use */ + if (sb->dq_op) + sb->dq_op->free_inode (inode, 1); + clear_inode (inode); + + /* Ok, now we can actually update the inode bitmaps.. */ if (!ext2_clear_bit (bit, bh->b_data)) ext2_warning (sb, "ext2_free_inode", - "bit already cleared for inode %lu", inode->i_ino); + "bit already cleared for inode %lu", ino); else { gdp = get_group_desc (sb, block_group, &bh2); gdp->bg_free_inodes_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1); - if (S_ISDIR(inode->i_mode)) + if (is_directory) gdp->bg_used_dirs_count = cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1); mark_buffer_dirty(bh2, 1); es->s_free_inodes_count = cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1); mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1); - inode->i_dirt = 0; } mark_buffer_dirty(bh, 1); if (sb->s_flags & MS_SYNCHRONOUS) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); } - if (sb->dq_op) - sb->dq_op->free_inode (inode, 1); sb->s_dirt = 1; - clear_inode (inode); unlock_super (sb); } @@ -240,7 +263,7 @@ static void inc_inode_version (struct inode * inode, int mode) { inode->u.ext2_i.i_version++; - inode->i_dirt = 1; + mark_inode_dirty(inode); return; } @@ -404,7 +427,6 @@ repeat: sb->s_dirt = 1; inode->i_mode = mode; inode->i_sb = sb; - atomic_set(&inode->i_count, 1); inode->i_nlink = 1; inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; @@ -416,7 +438,7 @@ repeat: mode |= S_ISGID; } else inode->i_gid = current->fsgid; - inode->i_dirt = 1; + mark_inode_dirty(inode); inode->i_ino = j; inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */ inode->i_blocks = 0; diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index f2dbff2d1..0fa14cfe1 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -31,14 +31,24 @@ static int ext2_update_inode(struct inode * inode, int do_sync); +/* + * Called at each iput() + */ void ext2_put_inode (struct inode * inode) { ext2_discard_prealloc (inode); - if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO || +} + +/* + * Called at the last iput() if i_nlink is zero. + */ +void ext2_delete_inode (struct inode * inode) +{ + if (inode->i_ino == EXT2_ACL_IDX_INO || inode->i_ino == EXT2_ACL_DATA_INO) return; inode->u.ext2_i.i_dtime = CURRENT_TIME; - inode->i_dirt = 1; + mark_inode_dirty(inode); ext2_update_inode(inode, IS_SYNC(inode)); inode->i_size = 0; if (inode->i_blocks) @@ -248,7 +258,7 @@ repeat: if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) ext2_sync_inode (inode); else - inode->i_dirt = 1; + mark_inode_dirty(inode); return result; } @@ -322,7 +332,7 @@ repeat: } inode->i_ctime = CURRENT_TIME; inode->i_blocks += blocks; - inode->i_dirt = 1; + mark_inode_dirty(inode); inode->u.ext2_i.i_next_alloc_block = new_block; inode->u.ext2_i.i_next_alloc_goal = tmp; brelse (bh); @@ -591,7 +601,6 @@ static int ext2_update_inode(struct inode * inode, int do_sync) else for (block = 0; block < EXT2_N_BLOCKS; block++) raw_inode->i_block[block] = cpu_to_le32(inode->u.ext2_i.i_data[block]); mark_buffer_dirty(bh, 1); - inode->i_dirt = 0; if (do_sync) { ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); @@ -671,7 +680,7 @@ int ext2_notify_change(struct inode *inode, struct iattr *iattr) inode->i_flags &= ~S_IMMUTABLE; inode->u.ext2_i.i_flags &= ~EXT2_IMMUTABLE_FL; } - inode->i_dirt = 1; + mark_inode_dirty(inode); return 0; } diff --git a/fs/ext2/ioctl.c b/fs/ext2/ioctl.c index 387600bbf..c0514c01e 100644 --- a/fs/ext2/ioctl.c +++ b/fs/ext2/ioctl.c @@ -62,7 +62,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, else inode->i_flags &= ~MS_NOATIME; inode->i_ctime = CURRENT_TIME; - inode->i_dirt = 1; + mark_inode_dirty(inode); return 0; case EXT2_IOC_GETVERSION: return put_user(inode->u.ext2_i.i_version, (int *) arg); @@ -74,7 +74,7 @@ int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, if (get_user(inode->u.ext2_i.i_version, (int *) arg)) return -EFAULT; inode->i_ctime = CURRENT_TIME; - inode->i_dirt = 1; + mark_inode_dirty(inode); return 0; default: return -ENOTTY; diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 421393581..2a7c42bff 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -27,6 +27,7 @@ #include <linux/string.h> #include <linux/locks.h> + /* * define how far ahead to read directories while searching them. */ @@ -154,36 +155,26 @@ failure: return NULL; } -int ext2_lookup (struct inode * dir, const char * name, int len, - struct inode ** result) +int ext2_lookup(struct inode * dir, struct dentry *dentry) { - unsigned long ino; + struct inode * inode; struct ext2_dir_entry * de; struct buffer_head * bh; - *result = NULL; - if (!dir) - return -ENOENT; - if (!S_ISDIR(dir->i_mode)) { - iput (dir); - return -ENOTDIR; - } - if (len > EXT2_NAME_LEN) { - iput (dir); + if (dentry->d_name.len > EXT2_NAME_LEN) return -ENAMETOOLONG; + + bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); + inode = NULL; + if (bh) { + unsigned long ino = le32_to_cpu(de->inode); + brelse (bh); + inode = iget(dir->i_sb, ino); + + if (!inode) + return -EACCES; } - ino = dir->i_version; - if (!(bh = ext2_find_entry (dir, name, len, &de))) { - iput (dir); - return -ENOENT; - } - ino = le32_to_cpu(de->inode); - brelse (bh); - if (!(*result = iget (dir->i_sb, ino))) { - iput (dir); - return -EACCES; - } - iput (dir); + d_add(dentry, inode); return 0; } @@ -256,7 +247,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, de->inode = le32_to_cpu(0); de->rec_len = le16_to_cpu(sb->s_blocksize); dir->i_size = offset + sb->s_blocksize; - dir->i_dirt = 1; + mark_inode_dirty(dir); } else { ext2_debug ("skipping to next block\n"); @@ -301,7 +292,7 @@ static struct buffer_head * ext2_add_entry (struct inode * dir, * and/or different from the directory change time. */ dir->i_mtime = dir->i_ctime = CURRENT_TIME; - dir->i_dirt = 1; + mark_inode_dirty(dir); dir->i_version = ++event; mark_buffer_dirty(bh, 1); *res_dir = de; @@ -347,31 +338,35 @@ static int ext2_delete_entry (struct ext2_dir_entry * dir, return -ENOENT; } -int ext2_create (struct inode * dir,const char * name, int len, int mode, - struct inode ** result) +/* + * By the time this is called, we already have created + * the directory cache entry for the new file, but it + * is so far negative - it has no inode. + * + * If the create succeeds, we fill in the inode information + * with d_instantiate(). + */ +int ext2_create (struct inode * dir, struct dentry * dentry, int mode) { struct inode * inode; struct buffer_head * bh; struct ext2_dir_entry * de; int err; - *result = NULL; if (!dir) return -ENOENT; inode = ext2_new_inode (dir, mode, &err); - if (!inode) { - iput (dir); + if (!inode) return err; - } + inode->i_op = &ext2_file_inode_operations; inode->i_mode = mode; - inode->i_dirt = 1; - bh = ext2_add_entry (dir, name, len, &de, &err); + mark_inode_dirty(inode); + bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); if (!bh) { inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput (inode); - iput (dir); return err; } de->inode = cpu_to_le32(inode->i_ino); @@ -382,13 +377,11 @@ int ext2_create (struct inode * dir,const char * name, int len, int mode, wait_on_buffer (bh); } brelse (bh); - iput (dir); - *result = inode; + d_instantiate(dentry, inode); return 0; } -int ext2_mknod (struct inode * dir, const char * name, int len, int mode, - int rdev) +int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev) { struct inode * inode; struct buffer_head * bh; @@ -398,21 +391,13 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode, if (!dir) return -ENOENT; - if (len > EXT2_NAME_LEN) { - iput (dir); + if (dentry->d_name.len > EXT2_NAME_LEN) return -ENAMETOOLONG; - } - bh = ext2_find_entry (dir, name, len, &de); - if (bh) { - brelse (bh); - iput (dir); - return -EEXIST; - } + inode = ext2_new_inode (dir, mode, &err); - if (!inode) { - iput (dir); + if (!inode) return err; - } + inode->i_uid = current->fsuid; inode->i_mode = mode; inode->i_op = NULL; @@ -433,13 +418,12 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode, init_fifo(inode); if (S_ISBLK(mode) || S_ISCHR(mode)) inode->i_rdev = to_kdev_t(rdev); - inode->i_dirt = 1; - bh = ext2_add_entry (dir, name, len, &de, &err); + mark_inode_dirty(inode); + bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); if (!bh) { inode->i_nlink--; - inode->i_dirt = 1; - iput (inode); - iput (dir); + mark_inode_dirty(inode); + iput(inode); return err; } de->inode = cpu_to_le32(inode->i_ino); @@ -449,47 +433,34 @@ int ext2_mknod (struct inode * dir, const char * name, int len, int mode, ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); } - brelse (bh); - iput (dir); - iput (inode); + brelse(bh); + d_instantiate(dentry, inode); return 0; } -int ext2_mkdir (struct inode * dir, const char * name, int len, int mode) +int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) { struct inode * inode; struct buffer_head * bh, * dir_block; struct ext2_dir_entry * de; int err; - if (!dir) - return -ENOENT; - if (len > EXT2_NAME_LEN) { - iput (dir); + if (dentry->d_name.len > EXT2_NAME_LEN) return -ENAMETOOLONG; - } - bh = ext2_find_entry (dir, name, len, &de); - if (bh) { - brelse (bh); - iput (dir); - return -EEXIST; - } - if (dir->i_nlink >= EXT2_LINK_MAX) { - iput (dir); + + if (dir->i_nlink >= EXT2_LINK_MAX) return -EMLINK; - } + inode = ext2_new_inode (dir, S_IFDIR, &err); - if (!inode) { - iput (dir); + if (!inode) return err; - } + inode->i_op = &ext2_dir_inode_operations; inode->i_size = inode->i_sb->s_blocksize; dir_block = ext2_bread (inode, 0, 1, &err); if (!dir_block) { - iput (dir); inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput (inode); return err; } @@ -510,12 +481,11 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode) inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask); if (dir->i_mode & S_ISGID) inode->i_mode |= S_ISGID; - inode->i_dirt = 1; - bh = ext2_add_entry (dir, name, len, &de, &err); + mark_inode_dirty(inode); + bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); if (!bh) { - iput (dir); inode->i_nlink = 0; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput (inode); return err; } @@ -527,9 +497,8 @@ int ext2_mkdir (struct inode * dir, const char * name, int len, int mode) wait_on_buffer (bh); } dir->i_nlink++; - dir->i_dirt = 1; - iput (dir); - iput (inode); + mark_inode_dirty(dir); + d_instantiate(dentry, inode); brelse (bh); return 0; } @@ -593,58 +562,53 @@ static int empty_dir (struct inode * inode) return 1; } -int ext2_rmdir (struct inode * dir, const char * name, int len) +int ext2_rmdir (struct inode * dir, struct dentry *dentry) { int retval; struct inode * inode; struct buffer_head * bh; struct ext2_dir_entry * de; -repeat: if (!dir) return -ENOENT; inode = NULL; - if (len > EXT2_NAME_LEN) { - iput (dir); + if (dentry->d_name.len > EXT2_NAME_LEN) return -ENAMETOOLONG; - } - bh = ext2_find_entry (dir, name, len, &de); + + bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); retval = -ENOENT; if (!bh) goto end_rmdir; retval = -EPERM; - if (!(inode = iget (dir->i_sb, le32_to_cpu(de->inode)))) - goto end_rmdir; + inode = dentry->d_inode; + if (inode->i_sb->dq_op) inode->i_sb->dq_op->initialize (inode, -1); - if (inode->i_dev != dir->i_dev) { - retval = -EBUSY; - goto end_rmdir; - } - if (le32_to_cpu(de->inode) != inode->i_ino) { - iput(inode); - brelse(bh); - current->counter = 0; - schedule(); - goto repeat; - } + if ((dir->i_mode & S_ISVTX) && !fsuser() && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid) goto end_rmdir; if (inode == dir) /* we may not delete ".", but "../dir" is ok */ goto end_rmdir; - if (!S_ISDIR(inode->i_mode)) { - retval = -ENOTDIR; + + retval = -ENOTDIR; + if (!S_ISDIR(inode->i_mode)) goto end_rmdir; - } + + retval = -EIO; + if (inode->i_dev != dir->i_dev) + goto end_rmdir; + if (le32_to_cpu(de->inode) != inode->i_ino) + goto end_rmdir; + down(&inode->i_sem); if (!empty_dir (inode)) retval = -ENOTEMPTY; else if (le32_to_cpu(de->inode) != inode->i_ino) retval = -ENOENT; else { - if (atomic_read(&inode->i_count) > 1) { + if (inode->i_count > 1) { /* * Are we deleting the last instance of a busy directory? * Better clean up if so. @@ -671,56 +635,51 @@ repeat: (int) inode->i_nlink); inode->i_version = ++event; inode->i_nlink = 0; - inode->i_dirt = 1; + mark_inode_dirty(inode); dir->i_nlink--; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_dirt = 1; + mark_inode_dirty(dir); + d_delete(dentry); + end_rmdir: - iput (dir); - iput (inode); brelse (bh); return retval; } -int ext2_unlink (struct inode * dir, const char * name, int len) +int ext2_unlink(struct inode * dir, struct dentry *dentry) { int retval; struct inode * inode; struct buffer_head * bh; struct ext2_dir_entry * de; -repeat: - if (!dir) - return -ENOENT; retval = -ENOENT; inode = NULL; - if (len > EXT2_NAME_LEN) { - iput (dir); + if (dentry->d_name.len > EXT2_NAME_LEN) return -ENAMETOOLONG; - } - bh = ext2_find_entry (dir, name, len, &de); + + bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); if (!bh) goto end_unlink; - if (!(inode = iget (dir->i_sb, le32_to_cpu(de->inode)))) - goto end_unlink; + + inode = dentry->d_inode; if (inode->i_sb->dq_op) inode->i_sb->dq_op->initialize (inode, -1); + retval = -EPERM; if (S_ISDIR(inode->i_mode)) goto end_unlink; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) goto end_unlink; - if (le32_to_cpu(de->inode) != inode->i_ino) { - iput(inode); - brelse(bh); - current->counter = 0; - schedule(); - goto repeat; - } if ((dir->i_mode & S_ISVTX) && !fsuser() && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid) goto end_unlink; + + retval = -EIO; + if (le32_to_cpu(de->inode) != inode->i_ino) + goto end_unlink; + if (!inode->i_nlink) { ext2_warning (inode->i_sb, "ext2_unlink", "Deleting nonexistent file (%lu), %d", @@ -737,20 +696,19 @@ repeat: wait_on_buffer (bh); } dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_dirt = 1; + mark_inode_dirty(dir); inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); inode->i_ctime = dir->i_ctime; retval = 0; + d_delete(dentry); /* This also frees the inode */ + end_unlink: brelse (bh); - iput (inode); - iput (dir); return retval; } -int ext2_symlink (struct inode * dir, const char * name, int len, - const char * symname) +int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * symname) { struct ext2_dir_entry * de; struct inode * inode = NULL; @@ -761,7 +719,6 @@ int ext2_symlink (struct inode * dir, const char * name, int len, char c; if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) { - iput (dir); return err; } inode->i_mode = S_IFLNK | S_IRWXUGO; @@ -775,9 +732,8 @@ int ext2_symlink (struct inode * dir, const char * name, int len, name_block = ext2_bread (inode, 0, 1, &err); if (!name_block) { - iput (dir); inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput (inode); return err; } @@ -797,23 +753,13 @@ int ext2_symlink (struct inode * dir, const char * name, int len, brelse (name_block); } inode->i_size = i; - inode->i_dirt = 1; + mark_inode_dirty(inode); - bh = ext2_find_entry (dir, name, len, &de); - if (bh) { - inode->i_nlink--; - inode->i_dirt = 1; - iput (inode); - brelse (bh); - iput (dir); - return -EEXIST; - } - bh = ext2_add_entry (dir, name, len, &de, &err); + bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); if (!bh) { inode->i_nlink--; - inode->i_dirt = 1; + mark_inode_dirty(inode); iput (inode); - iput (dir); return err; } de->inode = cpu_to_le32(inode->i_ino); @@ -824,47 +770,30 @@ int ext2_symlink (struct inode * dir, const char * name, int len, wait_on_buffer (bh); } brelse (bh); - iput (dir); - iput (inode); + d_instantiate(dentry, inode); return 0; } -int ext2_link (struct inode * oldinode, struct inode * dir, - const char * name, int len) +int ext2_link (struct inode * inode, struct inode * dir, struct dentry *dentry) { struct ext2_dir_entry * de; struct buffer_head * bh; int err; - if (S_ISDIR(oldinode->i_mode)) { - iput (oldinode); - iput (dir); + if (S_ISDIR(inode->i_mode)) return -EPERM; - } - if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) { - iput (oldinode); - iput (dir); + + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return -EPERM; - } - if (oldinode->i_nlink >= EXT2_LINK_MAX) { - iput (oldinode); - iput (dir); + + if (inode->i_nlink >= EXT2_LINK_MAX) return -EMLINK; - } - bh = ext2_find_entry (dir, name, len, &de); - if (bh) { - brelse (bh); - iput (dir); - iput (oldinode); - return -EEXIST; - } - bh = ext2_add_entry (dir, name, len, &de, &err); - if (!bh) { - iput (dir); - iput (oldinode); + + bh = ext2_add_entry (dir, dentry->d_name.name, dentry->d_name.len, &de, &err); + if (!bh) return err; - } - de->inode = cpu_to_le32(oldinode->i_ino); + + de->inode = cpu_to_le32(inode->i_ino); dir->i_version = ++event; mark_buffer_dirty(bh, 1); if (IS_SYNC(dir)) { @@ -872,35 +801,33 @@ int ext2_link (struct inode * oldinode, struct inode * dir, wait_on_buffer (bh); } brelse (bh); - iput (dir); - oldinode->i_nlink++; - oldinode->i_ctime = CURRENT_TIME; - oldinode->i_dirt = 1; - iput (oldinode); + inode->i_nlink++; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + inode->i_count++; + d_instantiate(dentry, inode); return 0; } -static int subdir (struct inode * new_inode, struct inode * old_inode) +/* + * Trivially implemented using the dcache structure + */ +static int subdir (struct dentry * new_dentry, struct dentry * old_dentry) { - int ino; int result; - atomic_inc(&new_inode->i_count); result = 0; for (;;) { - if (new_inode == old_inode) { - result = 1; - break; + if (new_dentry != old_dentry) { + struct dentry * parent = new_dentry->d_parent; + if (parent == new_dentry) + break; + new_dentry = parent; + continue; } - if (new_inode->i_dev != old_inode->i_dev) - break; - ino = new_inode->i_ino; - if (ext2_lookup (new_inode, "..", 2, &new_inode)) - break; - if (new_inode->i_ino == ino) - break; + result = 1; + break; } - iput (new_inode); return result; } @@ -908,10 +835,6 @@ static int subdir (struct inode * new_inode, struct inode * old_inode) ((struct ext2_dir_entry *) ((char *) buffer + \ le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->inode -#define PARENT_NAME(buffer) \ - ((struct ext2_dir_entry *) ((char *) buffer + \ - le16_to_cpu(((struct ext2_dir_entry *) buffer)->rec_len)))->name - /* * rename uses retrying to avoid race-conditions: at least they should be * minimal. @@ -923,43 +846,27 @@ static int subdir (struct inode * new_inode, struct inode * old_inode) * 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, const char * old_name, - int old_len, struct inode * new_dir, - const char * new_name, int new_len) +static int do_ext2_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; struct ext2_dir_entry * old_de, * new_de; int retval; - goto start_up; -try_again: - if (new_bh && new_de) { - ext2_delete_entry(new_de, new_bh); - new_dir->i_version = ++event; - } - brelse (old_bh); - brelse (new_bh); - brelse (dir_bh); - iput (old_inode); - iput (new_inode); - current->counter = 0; - schedule (); -start_up: old_inode = new_inode = NULL; old_bh = new_bh = dir_bh = NULL; new_de = NULL; retval = -ENAMETOOLONG; - if (old_len > EXT2_NAME_LEN) + if (old_dentry->d_name.len > EXT2_NAME_LEN) goto end_rename; - old_bh = ext2_find_entry (old_dir, old_name, old_len, &old_de); + old_bh = ext2_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de); retval = -ENOENT; if (!old_bh) goto end_rename; - old_inode = __iget (old_dir->i_sb, le32_to_cpu(old_de->inode), 0); /* don't cross mnt-points */ - if (!old_inode) - goto end_rename; + old_inode = old_dentry->d_inode; + retval = -EPERM; if ((old_dir->i_mode & S_ISVTX) && current->fsuid != old_inode->i_uid && @@ -967,9 +874,10 @@ start_up: goto end_rename; if (IS_APPEND(old_inode) || IS_IMMUTABLE(old_inode)) goto end_rename; - new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de); + + new_inode = new_dentry->d_inode; + new_bh = ext2_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de); if (new_bh) { - new_inode = __iget (new_dir->i_sb, le32_to_cpu(new_de->inode), 0); /* no mntp cross */ if (!new_inode) { brelse (new_bh); new_bh = NULL; @@ -987,13 +895,13 @@ start_up: if (!S_ISDIR(old_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir (new_dir, old_inode)) + if (subdir(new_dentry, old_dentry)) goto end_rename; retval = -ENOTEMPTY; if (!empty_dir (new_inode)) goto end_rename; retval = -EBUSY; - if (atomic_read(&new_inode->i_count) > 1) + if (new_inode->i_count > 1) goto end_rename; } retval = -EPERM; @@ -1006,7 +914,7 @@ start_up: if (new_inode && !S_ISDIR(new_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir (new_dir, old_inode)) + if (subdir(new_dentry, old_dentry)) goto end_rename; dir_bh = ext2_bread (old_inode, 0, 0, &retval); if (!dir_bh) @@ -1018,48 +926,37 @@ start_up: goto end_rename; } if (!new_bh) - new_bh = ext2_add_entry (new_dir, new_name, new_len, &new_de, + new_bh = ext2_add_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len, &new_de, &retval); if (!new_bh) goto end_rename; new_dir->i_version = ++event; - /* - * sanity checking before doing the rename - avoid races - */ - if (new_inode && (le32_to_cpu(new_de->inode) != new_inode->i_ino)) - goto try_again; - if (le32_to_cpu(new_de->inode) && !new_inode) - goto try_again; - if (le32_to_cpu(old_de->inode) != old_inode->i_ino) - goto try_again; + /* * ok, that's it */ new_de->inode = le32_to_cpu(old_inode->i_ino); - retval = ext2_delete_entry (old_de, old_bh); - if (retval == -ENOENT) - goto try_again; - if (retval) - goto end_rename; + ext2_delete_entry (old_de, old_bh); + old_dir->i_version = ++event; if (new_inode) { new_inode->i_nlink--; new_inode->i_ctime = CURRENT_TIME; - new_inode->i_dirt = 1; + mark_inode_dirty(new_inode); } old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; - old_dir->i_dirt = 1; + mark_inode_dirty(old_dir); if (dir_bh) { PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino); mark_buffer_dirty(dir_bh, 1); old_dir->i_nlink--; - old_dir->i_dirt = 1; + mark_inode_dirty(old_dir); if (new_inode) { new_inode->i_nlink--; - new_inode->i_dirt = 1; + mark_inode_dirty(new_inode); } else { new_dir->i_nlink++; - new_dir->i_dirt = 1; + mark_inode_dirty(new_dir); } } mark_buffer_dirty(old_bh, 1); @@ -1072,15 +969,15 @@ start_up: ll_rw_block (WRITE, 1, &new_bh); wait_on_buffer (new_bh); } + + /* Update the dcache */ + d_move(old_dentry, new_dentry->d_parent, &new_dentry->d_name); + d_delete(new_dentry); retval = 0; end_rename: brelse (dir_bh); brelse (old_bh); brelse (new_bh); - iput (old_inode); - iput (new_inode); - iput (old_dir); - iput (new_dir); return retval; } @@ -1097,16 +994,15 @@ end_rename: * 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, const char * old_name, int old_len, - struct inode * new_dir, const char * new_name, int new_len) +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_name, old_len, new_dir, - new_name, new_len); + 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 --git a/fs/ext2/super.c b/fs/ext2/super.c index 635a45692..1adc82185 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -133,9 +133,10 @@ void ext2_put_super (struct super_block * sb) static struct super_operations ext2_sops = { ext2_read_inode, - NULL, ext2_write_inode, ext2_put_inode, + ext2_delete_inode, + NULL, ext2_put_super, ext2_write_super, ext2_statfs, @@ -632,7 +633,8 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, */ sb->s_dev = dev; sb->s_op = &ext2_sops; - if (!(sb->s_mounted = iget (sb, EXT2_ROOT_INO))) { + sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO), NULL); + if (!sb->s_root) { sb->s_dev = 0; for (i = 0; i < db_count; i++) if (sb->u.ext2_sb.s_group_desc[i]) @@ -761,7 +763,7 @@ void cleanup_module(void) #endif -void ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz) +int ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz) { unsigned long overhead; unsigned long overhead_per_group; @@ -792,5 +794,5 @@ void ext2_statfs (struct super_block * sb, struct statfs * buf, int bufsiz) tmp.f_files = le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count); tmp.f_ffree = ext2_count_free_inodes (sb); tmp.f_namelen = EXT2_NAME_LEN; - copy_to_user(buf, &tmp, bufsiz); + return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; } diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c index 4d5a5cada..781f9165d 100644 --- a/fs/ext2/symlink.c +++ b/fs/ext2/symlink.c @@ -25,6 +25,7 @@ #include <linux/stat.h> static int ext2_readlink (struct inode *, char *, int); +static struct dentry *ext2_follow_link(struct inode *, struct dentry *); /* * symlinks can't do much... @@ -41,6 +42,7 @@ struct inode_operations ext2_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ ext2_readlink, /* readlink */ + ext2_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ @@ -49,37 +51,54 @@ struct inode_operations ext2_symlink_inode_operations = { NULL /* smap */ }; +static struct dentry * ext2_follow_link(struct inode * inode, struct dentry *base) +{ + int error; + struct buffer_head * bh = NULL; + char * link; + + link = (char *) inode->u.ext2_i.i_data; + if (inode->i_blocks) { + if (!(bh = ext2_bread (inode, 0, 0, &error))) { + dput(base); + return ERR_PTR(-EIO); + } + link = bh->b_data; + } + UPDATE_ATIME(inode); + base = lookup_dentry(link, base, 1); + if (bh) + brelse(bh); + return base; +} + static int ext2_readlink (struct inode * inode, char * buffer, int buflen) { struct buffer_head * bh = NULL; char * link; - int i, err; + int i; if (buflen > inode->i_sb->s_blocksize - 1) buflen = inode->i_sb->s_blocksize - 1; + + link = (char *) inode->u.ext2_i.i_data; if (inode->i_blocks) { + int err; bh = ext2_bread (inode, 0, 0, &err); if (!bh) { - iput (inode); if(err < 0) /* indicate type of error */ return err; return 0; } link = bh->b_data; } - else - link = (char *) inode->u.ext2_i.i_data; i = 0; while (i < buflen && link[i]) i++; if (copy_to_user(buffer, link, i)) i = -EFAULT; - if (DO_UPDATE_ATIME(inode)) { - inode->i_atime = CURRENT_TIME; - inode->i_dirt = 1; - } - iput (inode); + UPDATE_ATIME(inode); if (bh) brelse (bh); return i; diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c index a9e59ca00..5933ff77c 100644 --- a/fs/ext2/truncate.c +++ b/fs/ext2/truncate.c @@ -91,7 +91,7 @@ repeat: } *p = 0; inode->i_blocks -= blocks; - inode->i_dirt = 1; + mark_inode_dirty(inode); bforget(bh); if (free_count == 0) { block_to_free = tmp; @@ -110,7 +110,8 @@ repeat: return retry; } -static int trunc_indirect (struct inode * inode, int offset, u32 * p) +static int trunc_indirect (struct inode * inode, int offset, u32 * p, + int in_inode) { int i, tmp; struct buffer_head * bh; @@ -124,103 +125,16 @@ static int trunc_indirect (struct inode * inode, int offset, u32 * p) #define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset) int indirect_block = INDIRECT_BLOCK; - tmp = *p; + tmp = in_inode ? *p : le32_to_cpu(*p); if (!tmp) return 0; ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); - if (tmp != *p) { - brelse (ind_bh); - return 1; - } - if (!ind_bh) { - *p = 0; - return 0; - } -repeat: - for (i = indirect_block ; i < addr_per_block ; i++) { - if (i < 0) - i = 0; - if (i < indirect_block) - goto repeat; - ind = i + (u32 *) ind_bh->b_data; - tmp = le32_to_cpu(*ind); - if (!tmp) - continue; - bh = get_hash_table (inode->i_dev, tmp, - inode->i_sb->s_blocksize); - if (i < indirect_block) { - brelse (bh); - goto repeat; - } - if ((bh && bh->b_count != 1) || tmp != le32_to_cpu(*ind)) { - retry = 1; - brelse (bh); - continue; - } - *ind = cpu_to_le32(0); - mark_buffer_dirty(ind_bh, 1); - bforget(bh); - if (free_count == 0) { - block_to_free = tmp; - free_count++; - } else if (free_count > 0 && block_to_free == tmp - free_count) - free_count++; - else { - ext2_free_blocks (inode, block_to_free, free_count); - block_to_free = tmp; - free_count = 1; - } -/* ext2_free_blocks (inode, tmp, 1); */ - inode->i_blocks -= blocks; - inode->i_dirt = 1; - } - if (free_count > 0) - ext2_free_blocks (inode, block_to_free, free_count); - ind = (u32 *) ind_bh->b_data; - for (i = 0; i < addr_per_block; i++) - if (le32_to_cpu(*(ind++))) - break; - if (i >= addr_per_block) - if (ind_bh->b_count != 1) - retry = 1; - else { - tmp = *p; - *p = 0; - inode->i_blocks -= blocks; - inode->i_dirt = 1; - ext2_free_blocks (inode, tmp, 1); - } - if (IS_SYNC(inode) && buffer_dirty(ind_bh)) { - ll_rw_block (WRITE, 1, &ind_bh); - wait_on_buffer (ind_bh); - } - brelse (ind_bh); - return retry; -} - -static int trunc_indirect_swab32 (struct inode * inode, int offset, u32 * p) -{ - int i, tmp; - struct buffer_head * bh; - struct buffer_head * ind_bh; - u32 * ind; - unsigned long block_to_free = 0; - unsigned long free_count = 0; - int retry = 0; - int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - int blocks = inode->i_sb->s_blocksize / 512; - int indirect_block = INDIRECT_BLOCK; - - tmp = le32_to_cpu(*p); - if (!tmp) - return 0; - ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); - if (tmp != le32_to_cpu(*p)) { + if (tmp != (in_inode ? *p : le32_to_cpu(*p))) { brelse (ind_bh); return 1; } if (!ind_bh) { - *p = cpu_to_le32(0); + *p = in_inode ? 0 : cpu_to_le32(0); return 0; } repeat: @@ -259,7 +173,7 @@ repeat: } /* ext2_free_blocks (inode, tmp, 1); */ inode->i_blocks -= blocks; - inode->i_dirt = 1; + mark_inode_dirty(inode); } if (free_count > 0) ext2_free_blocks (inode, block_to_free, free_count); @@ -271,13 +185,15 @@ repeat: if (ind_bh->b_count != 1) retry = 1; else { - tmp = le32_to_cpu(*p); - *p = cpu_to_le32(0); + tmp = in_inode ? *p : le32_to_cpu(*p); + *p = in_inode ? 0 : cpu_to_le32(0); inode->i_blocks -= blocks; - inode->i_dirt = 1; + mark_inode_dirty(inode); ext2_free_blocks (inode, tmp, 1); + bforget(ind_bh); + ind_bh = NULL; } - if (IS_SYNC(inode) && buffer_dirty(ind_bh)) { + if (IS_SYNC(inode) && ind_bh && buffer_dirty(ind_bh)) { ll_rw_block (WRITE, 1, &ind_bh); wait_on_buffer (ind_bh); } @@ -286,7 +202,7 @@ repeat: } static int trunc_dindirect (struct inode * inode, int offset, - u32 * p) + u32 * p, int in_inode) { int i, tmp; struct buffer_head * dind_bh; @@ -297,75 +213,16 @@ static int trunc_dindirect (struct inode * inode, int offset, #define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block) int dindirect_block = DINDIRECT_BLOCK; - tmp = *p; - if (!tmp) - return 0; - dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); - if (tmp != *p) { - brelse (dind_bh); - return 1; - } - if (!dind_bh) { - *p = 0; - return 0; - } -repeat: - for (i = dindirect_block ; i < addr_per_block ; i++) { - if (i < 0) - i = 0; - if (i < dindirect_block) - goto repeat; - dind = i + (u32 *) dind_bh->b_data; - tmp = le32_to_cpu(*dind); - if (!tmp) - continue; - retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block), - dind); - mark_buffer_dirty(dind_bh, 1); - } - dind = (u32 *) dind_bh->b_data; - for (i = 0; i < addr_per_block; i++) - if (le32_to_cpu(*(dind++))) - break; - if (i >= addr_per_block) - if (dind_bh->b_count != 1) - retry = 1; - else { - tmp = *p; - *p = 0; - inode->i_blocks -= blocks; - inode->i_dirt = 1; - ext2_free_blocks (inode, tmp, 1); - } - if (IS_SYNC(inode) && buffer_dirty(dind_bh)) { - ll_rw_block (WRITE, 1, &dind_bh); - wait_on_buffer (dind_bh); - } - brelse (dind_bh); - return retry; -} - -static int trunc_dindirect_swab32 (struct inode * inode, int offset, - u32 * p) -{ - int i, tmp; - struct buffer_head * dind_bh; - u32 * dind; - int retry = 0; - int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - int blocks = inode->i_sb->s_blocksize / 512; - int dindirect_block = DINDIRECT_BLOCK; - - tmp = le32_to_cpu(*p); + tmp = in_inode ? *p : le32_to_cpu(*p); if (!tmp) return 0; dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); - if (tmp != le32_to_cpu(*p)) { + if (tmp != (in_inode ? *p : le32_to_cpu(*p))) { brelse (dind_bh); return 1; } if (!dind_bh) { - *p = cpu_to_le32(0); + *p = in_inode ? 0 : cpu_to_le32(0); return 0; } repeat: @@ -378,8 +235,8 @@ repeat: tmp = le32_to_cpu(*dind); if (!tmp) continue; - retry |= trunc_indirect_swab32 (inode, offset + (i * addr_per_block), - dind); + retry |= trunc_indirect(inode, offset + (i * addr_per_block), + dind, 0); mark_buffer_dirty(dind_bh, 1); } dind = (u32 *) dind_bh->b_data; @@ -390,13 +247,15 @@ repeat: if (dind_bh->b_count != 1) retry = 1; else { - tmp = le32_to_cpu(*p); - *p = cpu_to_le32(0); + tmp = in_inode ? *p : le32_to_cpu(*p); + *p = in_inode ? 0 : cpu_to_le32(0); inode->i_blocks -= blocks; - inode->i_dirt = 1; + mark_inode_dirty(inode); ext2_free_blocks (inode, tmp, 1); + bforget(dind_bh); + dind_bh = 0; } - if (IS_SYNC(inode) && buffer_dirty(dind_bh)) { + if (IS_SYNC(inode) && dind_bh && buffer_dirty(dind_bh)) { ll_rw_block (WRITE, 1, &dind_bh); wait_on_buffer (dind_bh); } @@ -436,9 +295,9 @@ repeat: if (i < tindirect_block) goto repeat; tind = i + (u32 *) tind_bh->b_data; - retry |= trunc_dindirect_swab32(inode, EXT2_NDIR_BLOCKS + + retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS + addr_per_block + (i + 1) * addr_per_block * addr_per_block, - tind); + tind, 0); mark_buffer_dirty(tind_bh, 1); } tind = (u32 *) tind_bh->b_data; @@ -452,10 +311,12 @@ repeat: tmp = *p; *p = 0; inode->i_blocks -= blocks; - inode->i_dirt = 1; + mark_inode_dirty(inode); ext2_free_blocks (inode, tmp, 1); + bforget(tind_bh); + tind_bh = 0; } - if (IS_SYNC(inode) && buffer_dirty(tind_bh)) { + if (IS_SYNC(inode) && tind_bh && buffer_dirty(tind_bh)) { ll_rw_block (WRITE, 1, &tind_bh); wait_on_buffer (tind_bh); } @@ -479,14 +340,14 @@ void ext2_truncate (struct inode * inode) while (1) { retry = trunc_direct(inode); retry |= trunc_indirect (inode, EXT2_IND_BLOCK, - (u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]); + (u32 *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK], 1); retry |= trunc_dindirect (inode, EXT2_IND_BLOCK + EXT2_ADDR_PER_BLOCK(inode->i_sb), - (u32 *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]); + (u32 *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK], 1); retry |= trunc_tindirect (inode); if (!retry) break; - if (IS_SYNC(inode) && inode->i_dirt) + if (IS_SYNC(inode) && test_bit(I_DIRTY, &inode->i_state)) ext2_sync_inode (inode); current->counter = 0; schedule (); @@ -510,5 +371,5 @@ void ext2_truncate (struct inode * inode) } } inode->i_mtime = inode->i_ctime = CURRENT_TIME; - inode->i_dirt = 1; + mark_inode_dirty(inode); } |