diff options
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/balloc.c | 66 | ||||
-rw-r--r-- | fs/ext4/bitmap.c | 2 | ||||
-rw-r--r-- | fs/ext4/dir.c | 2 | ||||
-rw-r--r-- | fs/ext4/ialloc.c | 17 | ||||
-rw-r--r-- | fs/ext4/resize.c | 4 | ||||
-rw-r--r-- | fs/ext4/super.c | 107 |
6 files changed, 153 insertions, 45 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index e53b4af..b74bf43 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -100,6 +100,15 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, return desc; } +static inline int +block_in_use(ext4_fsblk_t block, struct super_block *sb, unsigned char *map) +{ + ext4_grpblk_t offset; + + ext4_get_group_no_and_offset(sb, block, NULL, &offset); + return ext4_test_bit (offset, map); +} + /** * read_block_bitmap() * @sb: super block @@ -113,21 +122,53 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, static struct buffer_head * read_block_bitmap(struct super_block *sb, unsigned int block_group) { + int i; struct ext4_group_desc * desc; struct buffer_head * bh = NULL; + ext4_fsblk_t bitmap_blk; desc = ext4_get_group_desc (sb, block_group, NULL); if (!desc) - goto error_out; - bh = sb_bread(sb, ext4_block_bitmap(sb, desc)); + return NULL; + bitmap_blk = ext4_block_bitmap(sb, desc); + bh = sb_bread(sb, bitmap_blk); if (!bh) - ext4_error (sb, "read_block_bitmap", + ext4_error (sb, __FUNCTION__, "Cannot read block bitmap - " "block_group = %d, block_bitmap = %llu", - block_group, - ext4_block_bitmap(sb, desc)); -error_out: + block_group, bitmap_blk); + + /* check whether block bitmap block number is set */ + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + + /* check whether the inode bitmap block number is set */ + bitmap_blk = ext4_inode_bitmap(sb, desc); + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + /* check whether the inode table block number is set */ + bitmap_blk = ext4_inode_table(sb, desc); + for (i = 0; i < EXT4_SB(sb)->s_itb_per_group; i++, bitmap_blk++) { + if (!block_in_use(bitmap_blk, sb, bh->b_data)) { + /* bad block bitmap */ + goto error_out; + } + } + return bh; + +error_out: + brelse(bh); + ext4_error(sb, __FUNCTION__, + "Invalid block bitmap - " + "block_group = %d, block = %llu", + block_group, bitmap_blk); + return NULL; + } /* * The reservation window structure operations @@ -587,7 +628,7 @@ do_more: cpu_to_le16(le16_to_cpu(desc->bg_free_blocks_count) + group_freed); spin_unlock(sb_bgl_lock(sbi, block_group)); - percpu_counter_mod(&sbi->s_freeblocks_counter, count); + percpu_counter_add(&sbi->s_freeblocks_counter, count); /* We dirtied the bitmap block */ BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); @@ -1647,7 +1688,7 @@ allocated: gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)-num); spin_unlock(sb_bgl_lock(sbi, group_no)); - percpu_counter_mod(&sbi->s_freeblocks_counter, -num); + percpu_counter_sub(&sbi->s_freeblocks_counter, num); BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); err = ext4_journal_dirty_metadata(handle, gdp_bh); @@ -1747,15 +1788,6 @@ ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb) #endif } -static inline int -block_in_use(ext4_fsblk_t block, struct super_block *sb, unsigned char *map) -{ - ext4_grpblk_t offset; - - ext4_get_group_no_and_offset(sb, block, NULL, &offset); - return ext4_test_bit (offset, map); -} - static inline int test_root(int a, int b) { int num = b; diff --git a/fs/ext4/bitmap.c b/fs/ext4/bitmap.c index 11e93c1..420554f 100644 --- a/fs/ext4/bitmap.c +++ b/fs/ext4/bitmap.c @@ -13,7 +13,7 @@ #ifdef EXT4FS_DEBUG -static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; +static const int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; unsigned long ext4_count_free (struct buffer_head * map, unsigned int numchars) { diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index e11890a..0fb1e62 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c @@ -210,7 +210,7 @@ revalidate: * not the directory has been modified * during the copy operation. */ - unsigned long version = filp->f_version; + u64 version = filp->f_version; error = filldir(dirent, de->name, de->name_len, diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 427f830..d0c7793 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -204,14 +204,13 @@ static int find_group_dir(struct super_block *sb, struct inode *parent) int ngroups = EXT4_SB(sb)->s_groups_count; unsigned int freei, avefreei; struct ext4_group_desc *desc, *best_desc = NULL; - struct buffer_head *bh; int group, best_group = -1; freei = percpu_counter_read_positive(&EXT4_SB(sb)->s_freeinodes_counter); avefreei = freei / ngroups; for (group = 0; group < ngroups; group++) { - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) @@ -269,7 +268,6 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) ext4_grpblk_t min_blocks; int group = -1, i; struct ext4_group_desc *desc; - struct buffer_head *bh; freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); avefreei = freei / ngroups; @@ -287,7 +285,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) parent_group = (unsigned)group % ngroups; for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) @@ -322,7 +320,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) @@ -337,7 +335,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent) fallback: for (i = 0; i < ngroups; i++) { group = (parent_group + i) % ngroups; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (!desc || !desc->bg_free_inodes_count) continue; if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) @@ -361,14 +359,13 @@ static int find_group_other(struct super_block *sb, struct inode *parent) int parent_group = EXT4_I(parent)->i_block_group; int ngroups = EXT4_SB(sb)->s_groups_count; struct ext4_group_desc *desc; - struct buffer_head *bh; int group, i; /* * Try to place the inode in its parent directory */ group = parent_group; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) return group; @@ -392,7 +389,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) group += i; if (group >= ngroups) group -= ngroups; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count) && le16_to_cpu(desc->bg_free_blocks_count)) return group; @@ -406,7 +403,7 @@ static int find_group_other(struct super_block *sb, struct inode *parent) for (i = 0; i < ngroups; i++) { if (++group >= ngroups) group = 0; - desc = ext4_get_group_desc (sb, group, &bh); + desc = ext4_get_group_desc (sb, group, NULL); if (desc && le16_to_cpu(desc->bg_free_inodes_count)) return group; } diff --git a/fs/ext4/resize.c b/fs/ext4/resize.c index aa11d7d..472fc0d 100644 --- a/fs/ext4/resize.c +++ b/fs/ext4/resize.c @@ -893,9 +893,9 @@ int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) input->reserved_blocks); /* Update the free space counts */ - percpu_counter_mod(&sbi->s_freeblocks_counter, + percpu_counter_add(&sbi->s_freeblocks_counter, input->free_blocks_count); - percpu_counter_mod(&sbi->s_freeinodes_counter, + percpu_counter_add(&sbi->s_freeinodes_counter, EXT4_INODES_PER_GROUP(sb)); ext4_journal_dirty_metadata(handle, sbi->s_sbh); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 3c1397f..4c8d31c 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -523,7 +523,7 @@ static void ext4_destroy_inode(struct inode *inode) kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); } -static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) +static void init_once(struct kmem_cache *cachep, void *foo) { struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; @@ -596,9 +596,80 @@ static inline void ext4_show_quota_options(struct seq_file *seq, struct super_bl #endif } +/* + * Show an option if + * - it's set to a non-default value OR + * - if the per-sb default is different from the global default + */ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs) { struct super_block *sb = vfs->mnt_sb; + struct ext4_sb_info *sbi = EXT4_SB(sb); + struct ext4_super_block *es = sbi->s_es; + unsigned long def_mount_opts; + + def_mount_opts = le32_to_cpu(es->s_default_mount_opts); + + if (sbi->s_sb_block != 1) + seq_printf(seq, ",sb=%llu", sbi->s_sb_block); + if (test_opt(sb, MINIX_DF)) + seq_puts(seq, ",minixdf"); + if (test_opt(sb, GRPID)) + seq_puts(seq, ",grpid"); + if (!test_opt(sb, GRPID) && (def_mount_opts & EXT4_DEFM_BSDGROUPS)) + seq_puts(seq, ",nogrpid"); + if (sbi->s_resuid != EXT4_DEF_RESUID || + le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) { + seq_printf(seq, ",resuid=%u", sbi->s_resuid); + } + if (sbi->s_resgid != EXT4_DEF_RESGID || + le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) { + seq_printf(seq, ",resgid=%u", sbi->s_resgid); + } + if (test_opt(sb, ERRORS_CONT)) { + int def_errors = le16_to_cpu(es->s_errors); + + if (def_errors == EXT4_ERRORS_PANIC || + def_errors == EXT4_ERRORS_RO) { + seq_puts(seq, ",errors=continue"); + } + } + if (test_opt(sb, ERRORS_RO)) + seq_puts(seq, ",errors=remount-ro"); + if (test_opt(sb, ERRORS_PANIC)) + seq_puts(seq, ",errors=panic"); + if (test_opt(sb, NO_UID32)) + seq_puts(seq, ",nouid32"); + if (test_opt(sb, DEBUG)) + seq_puts(seq, ",debug"); + if (test_opt(sb, OLDALLOC)) + seq_puts(seq, ",oldalloc"); +#ifdef CONFIG_EXT4_FS_XATTR + if (test_opt(sb, XATTR_USER)) + seq_puts(seq, ",user_xattr"); + if (!test_opt(sb, XATTR_USER) && + (def_mount_opts & EXT4_DEFM_XATTR_USER)) { + seq_puts(seq, ",nouser_xattr"); + } +#endif +#ifdef CONFIG_EXT4_FS_POSIX_ACL + if (test_opt(sb, POSIX_ACL)) + seq_puts(seq, ",acl"); + if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL)) + seq_puts(seq, ",noacl"); +#endif + if (!test_opt(sb, RESERVATION)) + seq_puts(seq, ",noreservation"); + if (sbi->s_commit_interval) { + seq_printf(seq, ",commit=%u", + (unsigned) (sbi->s_commit_interval / HZ)); + } + if (test_opt(sb, BARRIER)) + seq_puts(seq, ",barrier=1"); + if (test_opt(sb, NOBH)) + seq_puts(seq, ",nobh"); + if (!test_opt(sb, EXTENTS)) + seq_puts(seq, ",noextents"); if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) seq_puts(seq, ",data=journal"); @@ -1415,8 +1486,6 @@ static void ext4_orphan_cleanup (struct super_block * sb, sb->s_flags = s_flags; /* Restore MS_RDONLY status */ } -#define log2(n) ffz(~(n)) - /* * Maximal file size. There is a direct, and {,double-,triple-}indirect * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. @@ -1479,6 +1548,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) int needs_recovery; __le32 features; __u64 blocks_count; + int err; sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); if (!sbi) @@ -1487,6 +1557,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) sbi->s_mount_opt = 0; sbi->s_resuid = EXT4_DEF_RESUID; sbi->s_resgid = EXT4_DEF_RESGID; + sbi->s_sb_block = sb_block; unlock_kernel(); @@ -1667,7 +1738,7 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_64BIT)) { if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT || sbi->s_desc_size > EXT4_MAX_DESC_SIZE || - sbi->s_desc_size & (sbi->s_desc_size - 1)) { + !is_power_of_2(sbi->s_desc_size)) { printk(KERN_ERR "EXT4-fs: unsupported descriptor size %lu\n", sbi->s_desc_size); @@ -1688,8 +1759,8 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) sbi->s_desc_per_block = blocksize / EXT4_DESC_SIZE(sb); sbi->s_sbh = bh; sbi->s_mount_state = le16_to_cpu(es->s_state); - sbi->s_addr_per_block_bits = log2(EXT4_ADDR_PER_BLOCK(sb)); - sbi->s_desc_per_block_bits = log2(EXT4_DESC_PER_BLOCK(sb)); + sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); + sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb)); for (i=0; i < 4; i++) sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); sbi->s_def_hash_version = es->s_def_hash_version; @@ -1759,12 +1830,20 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) get_random_bytes(&sbi->s_next_generation, sizeof(u32)); spin_lock_init(&sbi->s_next_gen_lock); - percpu_counter_init(&sbi->s_freeblocks_counter, - ext4_count_free_blocks(sb)); - percpu_counter_init(&sbi->s_freeinodes_counter, - ext4_count_free_inodes(sb)); - percpu_counter_init(&sbi->s_dirs_counter, - ext4_count_dirs(sb)); + err = percpu_counter_init(&sbi->s_freeblocks_counter, + ext4_count_free_blocks(sb)); + if (!err) { + err = percpu_counter_init(&sbi->s_freeinodes_counter, + ext4_count_free_inodes(sb)); + } + if (!err) { + err = percpu_counter_init(&sbi->s_dirs_counter, + ext4_count_dirs(sb)); + } + if (err) { + printk(KERN_ERR "EXT4-fs: insufficient memory\n"); + goto failed_mount3; + } /* per fileystem reservation list head & lock */ spin_lock_init(&sbi->s_rsv_window_lock); @@ -2592,13 +2671,13 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf) buf->f_type = EXT4_SUPER_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last; - buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); + buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter); es->s_free_blocks_count = cpu_to_le32(buf->f_bfree); buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); if (buf->f_bfree < ext4_r_blocks_count(es)) buf->f_bavail = 0; buf->f_files = le32_to_cpu(es->s_inodes_count); - buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); + buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); es->s_free_inodes_count = cpu_to_le32(buf->f_ffree); buf->f_namelen = EXT4_NAME_LEN; fsid = le64_to_cpup((void *)es->s_uuid) ^ |