struct ext4_super_block *es = sbi->s_es;
int i;
+ ext4_mb_release(sb);
ext4_ext_release(sb);
ext4_xattr_put_super(sb);
jbd2_journal_destroy(sbi->s_journal);
ei->i_block_alloc_info = NULL;
ei->vfs_inode.i_version = 1;
memset(&ei->i_cached_extent, 0, sizeof(struct ext4_ext_cache));
+ INIT_LIST_HEAD(&ei->i_prealloc_list);
+ spin_lock_init(&ei->i_prealloc_lock);
return &ei->vfs_inode;
}
*/
static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
{
+ int def_errors;
+ unsigned long def_mount_opts;
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);
+ def_errors = le16_to_cpu(es->s_errors);
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))
+ if (test_opt(sb, GRPID) && !(def_mount_opts & EXT4_DEFM_BSDGROUPS))
seq_puts(seq, ",grpid");
if (!test_opt(sb, GRPID) && (def_mount_opts & EXT4_DEFM_BSDGROUPS))
seq_puts(seq, ",nogrpid");
seq_printf(seq, ",resgid=%u", sbi->s_resgid);
}
if (test_opt(sb, ERRORS_RO)) {
- int def_errors = le16_to_cpu(es->s_errors);
-
if (def_errors == EXT4_ERRORS_PANIC ||
def_errors == EXT4_ERRORS_CONTINUE) {
seq_puts(seq, ",errors=remount-ro");
}
}
- if (test_opt(sb, ERRORS_CONT))
+ if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE)
seq_puts(seq, ",errors=continue");
- if (test_opt(sb, ERRORS_PANIC))
+ if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC)
seq_puts(seq, ",errors=panic");
- if (test_opt(sb, NO_UID32))
+ if (test_opt(sb, NO_UID32) && !(def_mount_opts & EXT4_DEFM_UID16))
seq_puts(seq, ",nouid32");
- if (test_opt(sb, DEBUG))
+ if (test_opt(sb, DEBUG) && !(def_mount_opts & EXT4_DEFM_DEBUG))
seq_puts(seq, ",debug");
if (test_opt(sb, OLDALLOC))
seq_puts(seq, ",oldalloc");
#ifdef CONFIG_EXT4DEV_FS_XATTR
- if (test_opt(sb, XATTR_USER))
+ if (test_opt(sb, XATTR_USER) &&
+ !(def_mount_opts & EXT4_DEFM_XATTR_USER))
seq_puts(seq, ",user_xattr");
if (!test_opt(sb, XATTR_USER) &&
(def_mount_opts & EXT4_DEFM_XATTR_USER)) {
}
#endif
#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL
- if (test_opt(sb, POSIX_ACL))
+ if (test_opt(sb, POSIX_ACL) && !(def_mount_opts & EXT4_DEFM_ACL))
seq_puts(seq, ",acl");
if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT4_DEFM_ACL))
seq_puts(seq, ",noacl");
seq_puts(seq, ",nobh");
if (!test_opt(sb, EXTENTS))
seq_puts(seq, ",noextents");
+ if (!test_opt(sb, MBALLOC))
+ seq_puts(seq, ",nomballoc");
+ if (test_opt(sb, I_VERSION))
+ seq_puts(seq, ",i_version");
+ if (sbi->s_stripe)
+ seq_printf(seq, ",stripe=%lu", sbi->s_stripe);
+ /*
+ * journal mode get enabled in different ways
+ * So just print the value even if we didn't specify it
+ */
if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA)
seq_puts(seq, ",data=journal");
else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA)
seq_puts(seq, ",data=writeback");
ext4_show_quota_options(seq, sb);
-
return 0;
}
* Currently we don't know the generation for parent directory, so
* a generation of 0 means "accept any"
*/
- inode = iget(sb, ino);
- if (inode == NULL)
- return ERR_PTR(-ENOMEM);
- if (is_bad_inode(inode) ||
- (generation && inode->i_generation != generation)) {
+ inode = ext4_iget(sb, ino);
+ if (IS_ERR(inode))
+ return ERR_CAST(inode);
+ if (generation && inode->i_generation != generation) {
iput(inode);
return ERR_PTR(-ESTALE);
}
static const struct super_operations ext4_sops = {
.alloc_inode = ext4_alloc_inode,
.destroy_inode = ext4_destroy_inode,
- .read_inode = ext4_read_inode,
.write_inode = ext4_write_inode,
.dirty_inode = ext4_dirty_inode,
.delete_inode = ext4_delete_inode,
Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
+ Opt_journal_checksum, Opt_journal_async_commit,
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota,
- Opt_grpquota, Opt_extents, Opt_noextents,
+ Opt_grpquota, Opt_extents, Opt_noextents, Opt_i_version,
+ Opt_mballoc, Opt_nomballoc, Opt_stripe,
};
static match_table_t tokens = {
{Opt_journal_update, "journal=update"},
{Opt_journal_inum, "journal=%u"},
{Opt_journal_dev, "journal_dev=%u"},
+ {Opt_journal_checksum, "journal_checksum"},
+ {Opt_journal_async_commit, "journal_async_commit"},
{Opt_abort, "abort"},
{Opt_data_journal, "data=journal"},
{Opt_data_ordered, "data=ordered"},
{Opt_barrier, "barrier=%u"},
{Opt_extents, "extents"},
{Opt_noextents, "noextents"},
+ {Opt_i_version, "i_version"},
+ {Opt_mballoc, "mballoc"},
+ {Opt_nomballoc, "nomballoc"},
+ {Opt_stripe, "stripe=%u"},
{Opt_err, NULL},
{Opt_resize, "resize"},
};
return 0;
*journal_devnum = option;
break;
+ case Opt_journal_checksum:
+ set_opt(sbi->s_mount_opt, JOURNAL_CHECKSUM);
+ break;
+ case Opt_journal_async_commit:
+ set_opt(sbi->s_mount_opt, JOURNAL_ASYNC_COMMIT);
+ set_opt(sbi->s_mount_opt, JOURNAL_CHECKSUM);
+ break;
case Opt_noload:
set_opt (sbi->s_mount_opt, NOLOAD);
break;
case Opt_noextents:
clear_opt (sbi->s_mount_opt, EXTENTS);
break;
+ case Opt_i_version:
+ set_opt(sbi->s_mount_opt, I_VERSION);
+ sb->s_flags |= MS_I_VERSION;
+ break;
+ case Opt_mballoc:
+ set_opt(sbi->s_mount_opt, MBALLOC);
+ break;
+ case Opt_nomballoc:
+ clear_opt(sbi->s_mount_opt, MBALLOC);
+ break;
+ case Opt_stripe:
+ if (match_int(&args[0], &option))
+ return 0;
+ if (option < 0)
+ return 0;
+ sbi->s_stripe = option;
+ break;
default:
printk (KERN_ERR
"EXT4-fs: Unrecognized mount option \"%s\" "
}
/* Called at mount-time, super-block is locked */
-static int ext4_check_descriptors (struct super_block * sb)
+static int ext4_check_descriptors(struct super_block *sb)
{
struct ext4_sb_info *sbi = EXT4_SB(sb);
ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
ext4_fsblk_t block_bitmap;
ext4_fsblk_t inode_bitmap;
ext4_fsblk_t inode_table;
- struct ext4_group_desc * gdp = NULL;
- int desc_block = 0;
int flexbg_flag = 0;
ext4_group_t i;
ext4_debug ("Checking group descriptors");
- for (i = 0; i < sbi->s_groups_count; i++)
- {
+ for (i = 0; i < sbi->s_groups_count; i++) {
+ struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL);
+
if (i == sbi->s_groups_count - 1 || flexbg_flag)
last_block = ext4_blocks_count(sbi->s_es) - 1;
else
last_block = first_block +
(EXT4_BLOCKS_PER_GROUP(sb) - 1);
- if ((i % EXT4_DESC_PER_BLOCK(sb)) == 0)
- gdp = (struct ext4_group_desc *)
- sbi->s_group_desc[desc_block++]->b_data;
block_bitmap = ext4_block_bitmap(sb, gdp);
if (block_bitmap < first_block || block_bitmap > last_block)
{
}
if (!flexbg_flag)
first_block += EXT4_BLOCKS_PER_GROUP(sb);
- gdp = (struct ext4_group_desc *)
- ((__u8 *)gdp + EXT4_DESC_SIZE(sb));
}
ext4_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
return (has_super + ext4_group_first_block_no(sb, bg));
}
+/**
+ * ext4_get_stripe_size: Get the stripe size.
+ * @sbi: In memory super block info
+ *
+ * If we have specified it via mount option, then
+ * use the mount option value. If the value specified at mount time is
+ * greater than the blocks per group use the super block value.
+ * If the super block value is greater than blocks per group return 0.
+ * Allocator needs it be less than blocks per group.
+ *
+ */
+static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi)
+{
+ unsigned long stride = le16_to_cpu(sbi->s_es->s_raid_stride);
+ unsigned long stripe_width =
+ le32_to_cpu(sbi->s_es->s_raid_stripe_width);
+
+ if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group)
+ return sbi->s_stripe;
+
+ if (stripe_width <= sbi->s_blocks_per_group)
+ return stripe_width;
+
+ if (stride <= sbi->s_blocks_per_group)
+ return stride;
+
+ return 0;
+}
static int ext4_fill_super (struct super_block *sb, void *data, int silent)
__releases(kernel_sem)
unsigned long journal_devnum = 0;
unsigned long def_mount_opts;
struct inode *root;
+ int ret = -EINVAL;
int blocksize;
- int hblock;
int db_count;
int i;
int needs_recovery;
* User -o noextents to turn it off
*/
set_opt(sbi->s_mount_opt, EXTENTS);
+ /*
+ * turn on mballoc feature by default in ext4 filesystem
+ * User -o nomballoc to turn it off
+ */
+ set_opt(sbi->s_mount_opt, MBALLOC);
if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum,
NULL, 0))
goto failed_mount;
}
- hblock = bdev_hardsect_size(sb->s_bdev);
if (sb->s_blocksize != blocksize) {
- /*
- * Make sure the blocksize for the filesystem is larger
- * than the hardware sectorsize for the machine.
- */
- if (blocksize < hblock) {
- printk(KERN_ERR "EXT4-fs: blocksize %d too small for "
- "device blocksize %d.\n", blocksize, hblock);
+
+ /* Validate the filesystem blocksize */
+ if (!sb_set_blocksize(sb, blocksize)) {
+ printk(KERN_ERR "EXT4-fs: bad block size %d.\n",
+ blocksize);
goto failed_mount;
}
brelse (bh);
- sb_set_blocksize(sb, blocksize);
logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE;
offset = do_div(logical_sb_block, blocksize);
bh = sb_bread(sb, logical_sb_block);
sbi->s_rsv_window_head.rsv_goal_size = 0;
ext4_rsv_window_add(sb, &sbi->s_rsv_window_head);
+ sbi->s_stripe = ext4_get_stripe_size(sbi);
+
/*
* set up enough so that it can read an inode
*/
goto failed_mount4;
}
+ if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
+ jbd2_journal_set_features(sbi->s_journal,
+ JBD2_FEATURE_COMPAT_CHECKSUM, 0,
+ JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
+ } else if (test_opt(sb, JOURNAL_CHECKSUM)) {
+ jbd2_journal_set_features(sbi->s_journal,
+ JBD2_FEATURE_COMPAT_CHECKSUM, 0, 0);
+ jbd2_journal_clear_features(sbi->s_journal, 0, 0,
+ JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
+ } else {
+ jbd2_journal_clear_features(sbi->s_journal,
+ JBD2_FEATURE_COMPAT_CHECKSUM, 0,
+ JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT);
+ }
+
/* We have now updated the journal if required, so we can
* validate the data journaling mode. */
switch (test_opt(sb, DATA_FLAGS)) {
* so we can safely mount the rest of the filesystem now.
*/
- root = iget(sb, EXT4_ROOT_INO);
- sb->s_root = d_alloc_root(root);
- if (!sb->s_root) {
+ root = ext4_iget(sb, EXT4_ROOT_INO);
+ if (IS_ERR(root)) {
printk(KERN_ERR "EXT4-fs: get root inode failed\n");
- iput(root);
+ ret = PTR_ERR(root);
goto failed_mount4;
}
if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) {
- dput(sb->s_root);
- sb->s_root = NULL;
+ iput(root);
printk(KERN_ERR "EXT4-fs: corrupt root inode, run e2fsck\n");
goto failed_mount4;
}
+ sb->s_root = d_alloc_root(root);
+ if (!sb->s_root) {
+ printk(KERN_ERR "EXT4-fs: get root dentry failed\n");
+ iput(root);
+ ret = -ENOMEM;
+ goto failed_mount4;
+ }
ext4_setup_super (sb, es, sb->s_flags & MS_RDONLY);
"writeback");
ext4_ext_init(sb);
+ ext4_mb_init(sb, needs_recovery);
lock_kernel();
return 0;
sb->s_fs_info = NULL;
kfree(sbi);
lock_kernel();
- return -EINVAL;
+ return ret;
}
/*
* things happen if we iget() an unused inode, as the subsequent
* iput() will try to delete it. */
- journal_inode = iget(sb, journal_inum);
- if (!journal_inode) {
+ journal_inode = ext4_iget(sb, journal_inum);
+ if (IS_ERR(journal_inode)) {
printk(KERN_ERR "EXT4-fs: no journal found.\n");
return NULL;
}
jbd_debug(2, "Journal inode found at %p: %Ld bytes\n",
journal_inode, journal_inode->i_size);
- if (is_bad_inode(journal_inode) || !S_ISREG(journal_inode->i_mode)) {
+ if (!S_ISREG(journal_inode->i_mode)) {
printk(KERN_ERR "EXT4-fs: invalid journal inode.\n");
iput(journal_inode);
return NULL;
i_size_write(inode, off+len-towrite);
EXT4_I(inode)->i_disksize = inode->i_size;
}
- inode->i_version++;
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
ext4_mark_inode_dirty(handle, inode);
mutex_unlock(&inode->i_mutex);
static int __init init_ext4_fs(void)
{
- int err = init_ext4_xattr();
+ int err;
+
+ err = init_ext4_mballoc();
if (err)
return err;
+
+ err = init_ext4_xattr();
+ if (err)
+ goto out2;
err = init_inodecache();
if (err)
goto out1;
destroy_inodecache();
out1:
exit_ext4_xattr();
+out2:
+ exit_ext4_mballoc();
return err;
}
unregister_filesystem(&ext4dev_fs_type);
destroy_inodecache();
exit_ext4_xattr();
+ exit_ext4_mballoc();
}
MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others");