diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-06-19 22:45:37 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-06-19 22:45:37 +0000 |
commit | 6d403070f28cd44860fdb3a53be5da0275c65cf4 (patch) | |
tree | 0d0e7fe7b5fb7568d19e11d7d862b77a866ce081 /fs/ext2 | |
parent | ecf1bf5f6c2e668d03b0a9fb026db7aa41e292e1 (diff) |
Merge with 2.4.0-test1-ac21 + pile of MIPS cleanups to make merging
possible. Chainsawed RM200 kernel to compile again. Jazz machine
status unknown.
Diffstat (limited to 'fs/ext2')
-rw-r--r-- | fs/ext2/balloc.c | 7 | ||||
-rw-r--r-- | fs/ext2/dir.c | 2 | ||||
-rw-r--r-- | fs/ext2/file.c | 3 | ||||
-rw-r--r-- | fs/ext2/fsync.c | 133 | ||||
-rw-r--r-- | fs/ext2/ialloc.c | 26 | ||||
-rw-r--r-- | fs/ext2/inode.c | 44 | ||||
-rw-r--r-- | fs/ext2/namei.c | 17 | ||||
-rw-r--r-- | fs/ext2/super.c | 1 | ||||
-rw-r--r-- | fs/ext2/truncate.c | 4 |
9 files changed, 61 insertions, 176 deletions
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index a3f8ae4ce..97fb703e1 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -473,11 +473,8 @@ repeat: if (i >= sb->u.ext2_sb.s_groups_count) i = 0; gdp = ext2_get_group_desc (sb, i, &bh2); - if (!gdp) { - *err = -EIO; - unlock_super (sb); - return 0; - } + if (!gdp) + goto io_error; if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) break; } diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 3a18b375c..cd62f058d 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -26,7 +26,7 @@ struct file_operations ext2_dir_operations = { read: generic_read_dir, readdir: ext2_readdir, ioctl: ext2_ioctl, - fsync: ext2_sync_file, + fsync: ext2_fsync_file, }; int ext2_check_dir_entry (const char * function, struct inode * dir, diff --git a/fs/ext2/file.c b/fs/ext2/file.c index d2c137e2c..130013e50 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -91,6 +91,7 @@ static int ext2_open_file (struct inode * inode, struct file * filp) return 0; } + /* * We have mostly NULL's here: the current defaults are ok for * the ext2 filesystem. @@ -103,7 +104,7 @@ struct file_operations ext2_file_operations = { mmap: generic_file_mmap, open: ext2_open_file, release: ext2_release_file, - fsync: ext2_sync_file, + fsync: ext2_fsync_file, }; struct inode_operations ext2_file_inode_operations = { diff --git a/fs/ext2/fsync.c b/fs/ext2/fsync.c index 52ffd6138..5b58f6cad 100644 --- a/fs/ext2/fsync.c +++ b/fs/ext2/fsync.c @@ -27,131 +27,28 @@ #include <linux/smp_lock.h> -#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb)) -#define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb)) - -static int sync_indirect(struct inode * inode, u32 * block, int wait) -{ - struct buffer_head * bh; - - if (!*block) - return 0; - bh = get_hash_table(inode->i_dev, le32_to_cpu(*block), blocksize); - if (!bh) - return 0; - if (wait && buffer_req(bh) && !buffer_uptodate(bh)) { - /* There can be a parallell read(2) that started read-I/O - on the buffer so we can't assume that there's been - an I/O error without first waiting I/O completation. */ - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - { - brelse (bh); - return -1; - } - } - if (wait || !buffer_uptodate(bh) || !buffer_dirty(bh)) { - if (wait) - /* when we return from fsync all the blocks - must be _just_ stored on disk */ - wait_on_buffer(bh); - brelse(bh); - return 0; - } - ll_rw_block(WRITE, 1, &bh); - atomic_dec(&bh->b_count); - return 0; -} - -static int sync_iblock(struct inode * inode, u32 * iblock, - struct buffer_head ** bh, int wait) -{ - int rc, tmp; - - *bh = NULL; - tmp = le32_to_cpu(*iblock); - if (!tmp) - return 0; - rc = sync_indirect(inode, iblock, wait); - if (rc) - return rc; - *bh = bread(inode->i_dev, tmp, blocksize); - if (!*bh) - return -1; - return 0; -} - -static int sync_dindirect(struct inode * inode, u32 * diblock, int wait) -{ - int i; - struct buffer_head * dind_bh; - int rc, err = 0; - - rc = sync_iblock(inode, diblock, &dind_bh, wait); - if (rc || !dind_bh) - return rc; - - for (i = 0; i < addr_per_block; i++) { - rc = sync_indirect(inode, ((u32 *) dind_bh->b_data) + i, wait); - if (rc) - err = rc; - } - brelse(dind_bh); - return err; -} - -static int sync_tindirect(struct inode * inode, u32 * tiblock, int wait) -{ - int i; - struct buffer_head * tind_bh; - int rc, err = 0; - - rc = sync_iblock(inode, tiblock, &tind_bh, wait); - if (rc || !tind_bh) - return rc; - - for (i = 0; i < addr_per_block; i++) { - rc = sync_dindirect(inode, ((u32 *) tind_bh->b_data) + i, wait); - if (rc) - err = rc; - } - brelse(tind_bh); - return err; -} - /* * File may be NULL when we are called. Perhaps we shouldn't * even pass file to fsync ? */ -int ext2_sync_file(struct file * file, struct dentry *dentry) +int ext2_fsync_file(struct file * file, struct dentry *dentry, int datasync) { - int wait, err = 0; struct inode *inode = dentry->d_inode; + return ext2_fsync_inode(inode, datasync); +} - lock_kernel(); - if (S_ISLNK(inode->i_mode) && !(inode->i_blocks)) - /* - * Don't sync fast links! - */ - goto skip; - - err = generic_buffer_fdatasync(inode, 0, ~0UL); - - for (wait=0; wait<=1; wait++) - { - err |= sync_indirect(inode, - inode->u.ext2_i.i_data+EXT2_IND_BLOCK, - wait); - err |= sync_dindirect(inode, - inode->u.ext2_i.i_data+EXT2_DIND_BLOCK, - wait); - err |= sync_tindirect(inode, - inode->u.ext2_i.i_data+EXT2_TIND_BLOCK, - wait); - } -skip: - err |= ext2_sync_inode (inode); - unlock_kernel(); +int ext2_fsync_inode(struct inode *inode, int datasync) +{ + int err; + + err = fsync_inode_buffers(inode); + if (!(inode->i_state & I_DIRTY)) + return err; + if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) + return err; + + err |= ext2_sync_inode(inode); return err ? -EIO : 0; } + diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 277562ec7..cbc806cda 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -186,24 +186,6 @@ void ext2_free_inode (struct inode * inode) struct ext2_group_desc * gdp; struct ext2_super_block * es; - if (!inode->i_dev) { - printk ("ext2_free_inode: inode has no device\n"); - return; - } - if (inode->i_count > 1) { - printk ("ext2_free_inode: inode has count=%d\n", inode->i_count); - return; - } - if (inode->i_nlink) { - printk ("ext2_free_inode: inode has nlink=%d\n", - inode->i_nlink); - return; - } - if (!sb) { - printk("ext2_free_inode: inode on nonexistent device\n"); - return; - } - ino = inode->i_ino; ext2_debug ("freeing inode %lu\n", ino); @@ -305,7 +287,6 @@ struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err) repeat: gdp = NULL; i=0; - *err = -ENOSPC; if (S_ISDIR(mode)) { avefreei = le32_to_cpu(es->s_free_inodes_count) / sb->u.ext2_sb.s_groups_count; @@ -387,6 +368,7 @@ repeat: if (!gdp) { unlock_super (sb); iput(inode); + *err = -ENOSPC; return NULL; } bitmap_nr = load_inode_bitmap (sb, i); @@ -416,9 +398,8 @@ repeat: ext2_error (sb, "ext2_new_inode", "Free inodes count corrupted in group %d", i); - unlock_super (sb); - iput (inode); - return NULL; + /* If we continue recover from this case */ + gdp->bg_free_inodes_count = 0; } goto repeat; } @@ -429,6 +410,7 @@ repeat: "block_group = %d,inode=%d", i, j); unlock_super (sb); iput (inode); + *err = EIO; /* Should never happen */ return NULL; } gdp->bg_free_inodes_count = diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 7e5263fb1..d3abb7cb2 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -117,7 +117,7 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err) inode->u.ext2_i.i_prealloc_count--; ext2_debug ("preallocation hit (%lu/%lu).\n", ++alloc_hits, ++alloc_attempts); - + *err = 0; } else { ext2_discard_prealloc (inode); ext2_debug ("preallocation miss (%lu/%lu).\n", @@ -200,6 +200,7 @@ out: return ret; } +/* returns NULL and sets *err on error */ static struct buffer_head * inode_getblk (struct inode * inode, int nr, int new_block, int * err, int metadata, long *phys, int *new) { @@ -223,7 +224,6 @@ repeat: return NULL; } } - *err = -EFBIG; /* Check file limits.. */ { @@ -311,7 +311,7 @@ repeat: * can fail due to: - not present * - out of space * - * NULL return in the data case is mandatory. + * NULL return in the data case, or an error, is mandatory. */ static struct buffer_head * block_getblk (struct inode * inode, struct buffer_head * bh, int nr, @@ -341,6 +341,7 @@ repeat: if (tmp == le32_to_cpu(*p)) goto out; brelse (result); + result = NULL; goto repeat; } else { *phys = tmp; @@ -402,11 +403,9 @@ repeat: *new = 1; } *p = le32_to_cpu(tmp); - mark_buffer_dirty(bh, 1); - if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) { + mark_buffer_dirty_inode(bh, 1, inode); + if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) ll_rw_block (WRITE, 1, &bh); - wait_on_buffer (bh); - } inode->i_ctime = CURRENT_TIME; inode->i_blocks += blocksize/512; mark_inode_dirty(inode); @@ -487,9 +486,9 @@ static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head * #define GET_INODE_PTR(x) \ inode_getblk(inode, x, iblock, &err, 1, NULL, NULL) #define GET_INDIRECT_DATABLOCK(x) \ - block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new); + block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new) #define GET_INDIRECT_PTR(x) \ - block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL); + block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL) if (ptr < direct_blocks) { bh = GET_INODE_DATABLOCK(ptr); @@ -547,13 +546,11 @@ abort_too_big: struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err) { struct buffer_head dummy; - int error; dummy.b_state = 0; dummy.b_blocknr = -1000; - error = ext2_get_block(inode, block, &dummy, create); - *err = error; - if (!error && buffer_mapped(&dummy)) { + *err = ext2_get_block(inode, block, &dummy, create); + if (!*err && buffer_mapped(&dummy)) { struct buffer_head *bh; bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize); if (buffer_new(&dummy)) { @@ -881,8 +878,23 @@ static int ext2_update_inode(struct inode * inode, int do_sync) raw_inode->i_file_acl = cpu_to_le32(inode->u.ext2_i.i_file_acl); if (S_ISDIR(inode->i_mode)) raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl); - else + else { raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32); + if (inode->i_size >> 31) { + struct super_block *sb = inode->i_sb; + struct ext2_super_block *es = sb->u.ext2_sb.s_es; + if (!(es->s_feature_ro_compat & cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE))) { + /* If this is the first large file + * created, add a flag to the superblock + * SMP Note: we're currently protected by the + * big kernel lock here, so this will need + * to be changed if that's no longer true. + */ + es->s_feature_ro_compat |= cpu_to_le32(EXT2_FEATURE_RO_COMPAT_LARGE_FILE); + ext2_write_super(sb); + } + } + } raw_inode->i_generation = cpu_to_le32(inode->i_generation); if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) @@ -904,10 +916,10 @@ static int ext2_update_inode(struct inode * inode, int do_sync) return err; } -void ext2_write_inode (struct inode * inode) +void ext2_write_inode (struct inode * inode, int wait) { lock_kernel(); - ext2_update_inode (inode, 0); + ext2_update_inode (inode, wait); unlock_kernel(); } diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 3e471f42b..116b4852f 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -366,12 +366,9 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode) struct inode * inode; int err; - /* - * N.B. Several error exits in ext2_new_inode don't set err. - */ inode = ext2_new_inode (dir, mode, &err); if (!inode) - return -EIO; + return err; inode->i_op = &ext2_file_inode_operations; inode->i_fop = &ext2_file_operations; @@ -397,7 +394,7 @@ static int ext2_mknod (struct inode * dir, struct dentry *dentry, int mode, int inode = ext2_new_inode (dir, mode, &err); if (!inode) - return -EIO; + return err; inode->i_uid = current->fsuid; init_special_inode(inode, mode, rdev); @@ -428,7 +425,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) inode = ext2_new_inode (dir, S_IFDIR, &err); if (!inode) - return -EIO; + return err; inode->i_op = &ext2_dir_inode_operations; inode->i_fop = &ext2_dir_operations; @@ -454,7 +451,7 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, int mode) strcpy (de->name, ".."); ext2_set_de_type(dir->i_sb, de, S_IFDIR); inode->i_nlink = 2; - mark_buffer_dirty(dir_block, 1); + mark_buffer_dirty_inode(dir_block, 1, dir); brelse (dir_block); inode->i_mode = S_IFDIR | mode; if (dir->i_mode & S_ISGID) @@ -634,7 +631,7 @@ static int ext2_symlink (struct inode * dir, struct dentry *dentry, const char * return -ENAMETOOLONG; if (!(inode = ext2_new_inode (dir, S_IFLNK, &err))) - return -EIO; + return err; inode->i_mode = S_IFLNK | S_IRWXUGO; @@ -685,7 +682,7 @@ static int ext2_link (struct dentry * old_dentry, inode->i_nlink++; inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); - inode->i_count++; + atomic_inc(&inode->i_count); d_instantiate(dentry, inode); return 0; } @@ -791,7 +788,7 @@ static int ext2_rename (struct inode * old_dir, struct dentry *old_dentry, 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); + mark_buffer_dirty_inode(dir_bh, 1, old_inode); old_dir->i_nlink--; mark_inode_dirty(old_dir); if (new_inode) { diff --git a/fs/ext2/super.c b/fs/ext2/super.c index aa6a599fc..d3af3b992 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -593,7 +593,6 @@ struct super_block * ext2_read_super (struct super_block * sb, void * data, /* * set up enough so that it can read an inode */ - sb->s_dev = dev; sb->s_op = &ext2_sops; sb->s_root = d_alloc_root(iget(sb, EXT2_ROOT_INO)); if (!sb->s_root) { diff --git a/fs/ext2/truncate.c b/fs/ext2/truncate.c index ba8397196..1c05cc09f 100644 --- a/fs/ext2/truncate.c +++ b/fs/ext2/truncate.c @@ -211,7 +211,7 @@ static int trunc_indirect (struct inode * inode, int offset, u32 * p, struct buf inode->i_ino, tmp); *p = 0; if (dind_bh) - mark_buffer_dirty(dind_bh, 1); + mark_buffer_dirty_inode(dind_bh, 1, inode); else mark_inode_dirty(inode); return 0; @@ -279,7 +279,7 @@ static int trunc_dindirect (struct inode * inode, int offset, u32 * p, inode->i_ino, tmp); *p = 0; if (tind_bh) - mark_buffer_dirty(tind_bh, 1); + mark_buffer_dirty_inode(tind_bh, 1, inode); else mark_inode_dirty(inode); return 0; |