diff options
Diffstat (limited to 'fs/ext3')
-rw-r--r-- | fs/ext3/acl.c | 2 | ||||
-rw-r--r-- | fs/ext3/dir.c | 14 | ||||
-rw-r--r-- | fs/ext3/inode.c | 2 | ||||
-rw-r--r-- | fs/ext3/ioctl.c | 6 | ||||
-rw-r--r-- | fs/ext3/namei.c | 10 | ||||
-rw-r--r-- | fs/ext3/super.c | 54 |
6 files changed, 63 insertions, 25 deletions
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c index 1e5038d9a01b..d34e9967430a 100644 --- a/fs/ext3/acl.c +++ b/fs/ext3/acl.c @@ -489,7 +489,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value, if (!test_opt(inode->i_sb, POSIX_ACL)) return -EOPNOTSUPP; - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + if (!is_owner_or_cap(inode)) return -EPERM; if (value) { diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 852869840f24..c00723a99f44 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c @@ -136,12 +136,14 @@ static int ext3_readdir(struct file * filp, err = ext3_get_blocks_handle(NULL, inode, blk, 1, &map_bh, 0, 0); if (err > 0) { - page_cache_readahead(sb->s_bdev->bd_inode->i_mapping, - &filp->f_ra, - filp, - map_bh.b_blocknr >> - (PAGE_CACHE_SHIFT - inode->i_blkbits), - 1); + pgoff_t index = map_bh.b_blocknr >> + (PAGE_CACHE_SHIFT - inode->i_blkbits); + if (!ra_has_index(&filp->f_ra, index)) + page_cache_sync_readahead( + sb->s_bdev->bd_inode->i_mapping, + &filp->f_ra, filp, + index, 1); + filp->f_ra.prev_index = index; bh = ext3_bread(NULL, inode, blk, 0, &err); } diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 2a85ddee4740..de4e3161e479 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -3195,7 +3195,7 @@ int ext3_change_inode_journal_flag(struct inode *inode, int val) */ journal = EXT3_JOURNAL(inode); - if (is_journal_aborted(journal) || IS_RDONLY(inode)) + if (is_journal_aborted(journal)) return -EROFS; journal_lock_updates(journal); diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index 965006dba6be..4a2a02c95bf9 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c @@ -41,7 +41,7 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, if (IS_RDONLY(inode)) return -EROFS; - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + if (!is_owner_or_cap(inode)) return -EACCES; if (get_user(flags, (int __user *) arg)) @@ -122,7 +122,7 @@ flags_err: __u32 generation; int err; - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + if (!is_owner_or_cap(inode)) return -EPERM; if (IS_RDONLY(inode)) return -EROFS; @@ -181,7 +181,7 @@ flags_err: if (IS_RDONLY(inode)) return -EROFS; - if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) + if (!is_owner_or_cap(inode)) return -EACCES; if (get_user(rsv_window_size, (int __user *)arg)) diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 9bb046df827a..1586807b8177 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1019,6 +1019,11 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str if (!inode) return ERR_PTR(-EACCES); + + if (is_bad_inode(inode)) { + iput(inode); + return ERR_PTR(-ENOENT); + } } return d_splice_alias(inode, dentry); } @@ -1054,6 +1059,11 @@ struct dentry *ext3_get_parent(struct dentry *child) if (!inode) return ERR_PTR(-EACCES); + if (is_bad_inode(inode)) { + iput(inode); + return ERR_PTR(-ENOENT); + } + parent = d_alloc_anon(inode); if (!parent) { iput(inode); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 6e3062913a92..f0614e3f1fe8 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -29,12 +29,14 @@ #include <linux/parser.h> #include <linux/smp_lock.h> #include <linux/buffer_head.h> +#include <linux/exportfs.h> #include <linux/vfs.h> #include <linux/random.h> #include <linux/mount.h> #include <linux/namei.h> #include <linux/quotaops.h> #include <linux/seq_file.h> +#include <linux/log2.h> #include <asm/uaccess.h> @@ -459,6 +461,14 @@ static struct inode *ext3_alloc_inode(struct super_block *sb) static void ext3_destroy_inode(struct inode *inode) { + if (!list_empty(&(EXT3_I(inode)->i_orphan))) { + printk("EXT3 Inode %p: orphan list check failed!\n", + EXT3_I(inode)); + print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4, + EXT3_I(inode), sizeof(struct ext3_inode_info), + false); + dump_stack(); + } kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); } @@ -480,7 +490,7 @@ static int init_inodecache(void) sizeof(struct ext3_inode_info), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), - init_once, NULL); + init_once); if (ext3_inode_cachep == NULL) return -ENOMEM; return 0; @@ -1566,7 +1576,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) sbi->s_inode_size = le16_to_cpu(es->s_inode_size); sbi->s_first_ino = le32_to_cpu(es->s_first_ino); if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) || - (sbi->s_inode_size & (sbi->s_inode_size - 1)) || + (!is_power_of_2(sbi->s_inode_size)) || (sbi->s_inode_size > blocksize)) { printk (KERN_ERR "EXT3-fs: unsupported inode size: %d\n", @@ -2075,6 +2085,7 @@ static int ext3_create_journal(struct super_block * sb, unsigned int journal_inum) { journal_t *journal; + int err; if (sb->s_flags & MS_RDONLY) { printk(KERN_ERR "EXT3-fs: readonly filesystem when trying to " @@ -2082,13 +2093,15 @@ static int ext3_create_journal(struct super_block * sb, return -EROFS; } - if (!(journal = ext3_get_journal(sb, journal_inum))) + journal = ext3_get_journal(sb, journal_inum); + if (!journal) return -EINVAL; printk(KERN_INFO "EXT3-fs: creating new journal on inode %u\n", journal_inum); - if (journal_create(journal)) { + err = journal_create(journal); + if (err) { printk(KERN_ERR "EXT3-fs: error creating journal.\n"); journal_destroy(journal); return -EIO; @@ -2139,12 +2152,14 @@ static void ext3_mark_recovery_complete(struct super_block * sb, journal_lock_updates(journal); journal_flush(journal); + lock_super(sb); if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) && sb->s_flags & MS_RDONLY) { EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); sb->s_dirt = 0; ext3_commit_super(sb, es, 1); } + unlock_super(sb); journal_unlock_updates(journal); } @@ -2333,7 +2348,13 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) (sbi->s_mount_state & EXT3_VALID_FS)) es->s_state = cpu_to_le16(sbi->s_mount_state); + /* + * We have to unlock super so that we can wait for + * transactions. + */ + unlock_super(sb); ext3_mark_recovery_complete(sb, es); + lock_super(sb); } else { __le32 ret; if ((ret = EXT3_HAS_RO_COMPAT_FEATURE(sb, @@ -2406,19 +2427,19 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) struct super_block *sb = dentry->d_sb; struct ext3_sb_info *sbi = EXT3_SB(sb); struct ext3_super_block *es = sbi->s_es; - ext3_fsblk_t overhead; - int i; u64 fsid; - if (test_opt (sb, MINIX_DF)) - overhead = 0; - else { - unsigned long ngroups; - ngroups = EXT3_SB(sb)->s_groups_count; + if (test_opt(sb, MINIX_DF)) { + sbi->s_overhead_last = 0; + } else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) { + unsigned long ngroups = sbi->s_groups_count, i; + ext3_fsblk_t overhead = 0; smp_rmb(); /* - * Compute the overhead (FS structures) + * Compute the overhead (FS structures). This is constant + * for a given filesystem unless the number of block groups + * changes so we cache the previous value until it does. */ /* @@ -2442,18 +2463,23 @@ static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) * Every block group has an inode bitmap, a block * bitmap, and an inode table. */ - overhead += (ngroups * (2 + EXT3_SB(sb)->s_itb_per_group)); + overhead += ngroups * (2 + sbi->s_itb_per_group); + sbi->s_overhead_last = overhead; + smp_wmb(); + sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count); } buf->f_type = EXT3_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; - buf->f_blocks = le32_to_cpu(es->s_blocks_count) - overhead; + buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last; buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); + es->s_free_blocks_count = cpu_to_le32(buf->f_bfree); buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count); if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count)) buf->f_bavail = 0; buf->f_files = le32_to_cpu(es->s_inodes_count); buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); + es->s_free_inodes_count = cpu_to_le32(buf->f_ffree); buf->f_namelen = EXT3_NAME_LEN; fsid = le64_to_cpup((void *)es->s_uuid) ^ le64_to_cpup((void *)es->s_uuid + sizeof(u64)); |