diff options
Diffstat (limited to 'fs/ext4/super.c')
| -rw-r--r-- | fs/ext4/super.c | 1073 | 
1 files changed, 463 insertions, 610 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 933900909ed..ceebaf853be 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -62,6 +62,7 @@ static struct ext4_features *ext4_feat;  static int ext4_load_journal(struct super_block *, struct ext4_super_block *,  			     unsigned long journal_devnum); +static int ext4_show_options(struct seq_file *seq, struct dentry *root);  static int ext4_commit_super(struct super_block *sb, int sync);  static void ext4_mark_recovery_complete(struct super_block *sb,  					struct ext4_super_block *es); @@ -375,7 +376,7 @@ void ext4_journal_abort_handle(const char *caller, unsigned int line,  	if (is_handle_aborted(handle))  		return; -	printk(KERN_ERR "%s:%d: aborting transaction: %s in %s\n", +	printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",  	       caller, line, errstr, err_fn);  	jbd2_journal_abort_handle(handle); @@ -431,6 +432,22 @@ static int block_device_ejected(struct super_block *sb)  	return bdi->dev == NULL;  } +static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn) +{ +	struct super_block		*sb = journal->j_private; +	struct ext4_sb_info		*sbi = EXT4_SB(sb); +	int				error = is_journal_aborted(journal); +	struct ext4_journal_cb_entry	*jce, *tmp; + +	spin_lock(&sbi->s_md_lock); +	list_for_each_entry_safe(jce, tmp, &txn->t_private_list, jce_list) { +		list_del_init(&jce->jce_list); +		spin_unlock(&sbi->s_md_lock); +		jce->jce_func(sb, jce, error); +		spin_lock(&sbi->s_md_lock); +	} +	spin_unlock(&sbi->s_md_lock); +}  /* Deal with the reporting of failure conditions on a filesystem such as   * inconsistencies detected or read IO failures. @@ -498,11 +515,16 @@ void ext4_error_inode(struct inode *inode, const char *function,  	va_start(args, fmt);  	vaf.fmt = fmt;  	vaf.va = &args; -	printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: inode #%lu: ", -	       inode->i_sb->s_id, function, line, inode->i_ino);  	if (block) -		printk(KERN_CONT "block %llu: ", block); -	printk(KERN_CONT "comm %s: %pV\n", current->comm, &vaf); +		printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: " +		       "inode #%lu: block %llu: comm %s: %pV\n", +		       inode->i_sb->s_id, function, line, inode->i_ino, +		       block, current->comm, &vaf); +	else +		printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: " +		       "inode #%lu: comm %s: %pV\n", +		       inode->i_sb->s_id, function, line, inode->i_ino, +		       current->comm, &vaf);  	va_end(args);  	ext4_handle_error(inode->i_sb); @@ -524,15 +546,21 @@ void ext4_error_file(struct file *file, const char *function,  	path = d_path(&(file->f_path), pathname, sizeof(pathname));  	if (IS_ERR(path))  		path = "(unknown)"; -	printk(KERN_CRIT -	       "EXT4-fs error (device %s): %s:%d: inode #%lu: ", -	       inode->i_sb->s_id, function, line, inode->i_ino); -	if (block) -		printk(KERN_CONT "block %llu: ", block);  	va_start(args, fmt);  	vaf.fmt = fmt;  	vaf.va = &args; -	printk(KERN_CONT "comm %s: path %s: %pV\n", current->comm, path, &vaf); +	if (block) +		printk(KERN_CRIT +		       "EXT4-fs error (device %s): %s:%d: inode #%lu: " +		       "block %llu: comm %s: path %s: %pV\n", +		       inode->i_sb->s_id, function, line, inode->i_ino, +		       block, current->comm, path, &vaf); +	else +		printk(KERN_CRIT +		       "EXT4-fs error (device %s): %s:%d: inode #%lu: " +		       "comm %s: path %s: %pV\n", +		       inode->i_sb->s_id, function, line, inode->i_ino, +		       current->comm, path, &vaf);  	va_end(args);  	ext4_handle_error(inode->i_sb); @@ -808,9 +836,6 @@ static void ext4_put_super(struct super_block *sb)  	destroy_workqueue(sbi->dio_unwritten_wq);  	lock_super(sb); -	if (sb->s_dirt) -		ext4_commit_super(sb, 1); -  	if (sbi->s_journal) {  		err = jbd2_journal_destroy(sbi->s_journal);  		sbi->s_journal = NULL; @@ -827,9 +852,12 @@ static void ext4_put_super(struct super_block *sb)  	if (!(sb->s_flags & MS_RDONLY)) {  		EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);  		es->s_state = cpu_to_le16(sbi->s_mount_state); -		ext4_commit_super(sb, 1);  	} +	if (sb->s_dirt || !(sb->s_flags & MS_RDONLY)) +		ext4_commit_super(sb, 1); +  	if (sbi->s_proc) { +		remove_proc_entry("options", sbi->s_proc);  		remove_proc_entry(sb->s_id, ext4_proc_root);  	}  	kobject_del(&sbi->s_kobj); @@ -990,180 +1018,6 @@ void ext4_clear_inode(struct inode *inode)  	}  } -static inline void ext4_show_quota_options(struct seq_file *seq, -					   struct super_block *sb) -{ -#if defined(CONFIG_QUOTA) -	struct ext4_sb_info *sbi = EXT4_SB(sb); - -	if (sbi->s_jquota_fmt) { -		char *fmtname = ""; - -		switch (sbi->s_jquota_fmt) { -		case QFMT_VFS_OLD: -			fmtname = "vfsold"; -			break; -		case QFMT_VFS_V0: -			fmtname = "vfsv0"; -			break; -		case QFMT_VFS_V1: -			fmtname = "vfsv1"; -			break; -		} -		seq_printf(seq, ",jqfmt=%s", fmtname); -	} - -	if (sbi->s_qf_names[USRQUOTA]) -		seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]); - -	if (sbi->s_qf_names[GRPQUOTA]) -		seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); - -	if (test_opt(sb, USRQUOTA)) -		seq_puts(seq, ",usrquota"); - -	if (test_opt(sb, GRPQUOTA)) -		seq_puts(seq, ",grpquota"); -#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 dentry *root) -{ -	int def_errors; -	unsigned long def_mount_opts; -	struct super_block *sb = root->d_sb; -	struct ext4_sb_info *sbi = EXT4_SB(sb); -	struct ext4_super_block *es = sbi->s_es; - -	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) && !(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"); -	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_RO)) { -		if (def_errors == EXT4_ERRORS_PANIC || -		    def_errors == EXT4_ERRORS_CONTINUE) { -			seq_puts(seq, ",errors=remount-ro"); -		} -	} -	if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE) -		seq_puts(seq, ",errors=continue"); -	if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC) -		seq_puts(seq, ",errors=panic"); -	if (test_opt(sb, NO_UID32) && !(def_mount_opts & EXT4_DEFM_UID16)) -		seq_puts(seq, ",nouid32"); -	if (test_opt(sb, DEBUG) && !(def_mount_opts & EXT4_DEFM_DEBUG)) -		seq_puts(seq, ",debug"); -#ifdef CONFIG_EXT4_FS_XATTR -	if (test_opt(sb, XATTR_USER)) -		seq_puts(seq, ",user_xattr"); -	if (!test_opt(sb, XATTR_USER)) -		seq_puts(seq, ",nouser_xattr"); -#endif -#ifdef CONFIG_EXT4_FS_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"); -#endif -	if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) { -		seq_printf(seq, ",commit=%u", -			   (unsigned) (sbi->s_commit_interval / HZ)); -	} -	if (sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME) { -		seq_printf(seq, ",min_batch_time=%u", -			   (unsigned) sbi->s_min_batch_time); -	} -	if (sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME) { -		seq_printf(seq, ",max_batch_time=%u", -			   (unsigned) sbi->s_max_batch_time); -	} - -	/* -	 * We're changing the default of barrier mount option, so -	 * let's always display its mount state so it's clear what its -	 * status is. -	 */ -	seq_puts(seq, ",barrier="); -	seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0"); -	if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) -		seq_puts(seq, ",journal_async_commit"); -	else if (test_opt(sb, JOURNAL_CHECKSUM)) -		seq_puts(seq, ",journal_checksum"); -	if (test_opt(sb, I_VERSION)) -		seq_puts(seq, ",i_version"); -	if (!test_opt(sb, DELALLOC) && -	    !(def_mount_opts & EXT4_DEFM_NODELALLOC)) -		seq_puts(seq, ",nodelalloc"); - -	if (!test_opt(sb, MBLK_IO_SUBMIT)) -		seq_puts(seq, ",nomblk_io_submit"); -	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=ordered"); -	else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) -		seq_puts(seq, ",data=writeback"); - -	if (sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS) -		seq_printf(seq, ",inode_readahead_blks=%u", -			   sbi->s_inode_readahead_blks); - -	if (test_opt(sb, DATA_ERR_ABORT)) -		seq_puts(seq, ",data_err=abort"); - -	if (test_opt(sb, NO_AUTO_DA_ALLOC)) -		seq_puts(seq, ",noauto_da_alloc"); - -	if (test_opt(sb, DISCARD) && !(def_mount_opts & EXT4_DEFM_DISCARD)) -		seq_puts(seq, ",discard"); - -	if (test_opt(sb, NOLOAD)) -		seq_puts(seq, ",norecovery"); - -	if (test_opt(sb, DIOREAD_NOLOCK)) -		seq_puts(seq, ",dioread_nolock"); - -	if (test_opt(sb, BLOCK_VALIDITY) && -	    !(def_mount_opts & EXT4_DEFM_BLOCK_VALIDITY)) -		seq_puts(seq, ",block_validity"); - -	if (!test_opt(sb, INIT_INODE_TABLE)) -		seq_puts(seq, ",noinit_itable"); -	else if (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT) -		seq_printf(seq, ",init_itable=%u", -			   (unsigned) sbi->s_li_wait_mult); - -	ext4_show_quota_options(seq, sb); - -	return 0; -} -  static struct inode *ext4_nfs_get_inode(struct super_block *sb,  					u64 ino, u32 generation)  { @@ -1316,18 +1170,17 @@ static const struct export_operations ext4_export_ops = {  enum {  	Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,  	Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, -	Opt_nouid32, Opt_debug, Opt_oldalloc, Opt_orlov, +	Opt_nouid32, Opt_debug, Opt_removed,  	Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, -	Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload, Opt_nobh, Opt_bh, +	Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload,  	Opt_commit, Opt_min_batch_time, Opt_max_batch_time, -	Opt_journal_update, Opt_journal_dev, -	Opt_journal_checksum, Opt_journal_async_commit, +	Opt_journal_dev, Opt_journal_checksum, Opt_journal_async_commit,  	Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,  	Opt_data_err_abort, Opt_data_err_ignore,  	Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,  	Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota, -	Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, -	Opt_resize, Opt_usrquota, Opt_grpquota, Opt_i_version, +	Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, +	Opt_usrquota, Opt_grpquota, Opt_i_version,  	Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit,  	Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity,  	Opt_inode_readahead_blks, Opt_journal_ioprio, @@ -1350,20 +1203,19 @@ static const match_table_t tokens = {  	{Opt_err_ro, "errors=remount-ro"},  	{Opt_nouid32, "nouid32"},  	{Opt_debug, "debug"}, -	{Opt_oldalloc, "oldalloc"}, -	{Opt_orlov, "orlov"}, +	{Opt_removed, "oldalloc"}, +	{Opt_removed, "orlov"},  	{Opt_user_xattr, "user_xattr"},  	{Opt_nouser_xattr, "nouser_xattr"},  	{Opt_acl, "acl"},  	{Opt_noacl, "noacl"}, -	{Opt_noload, "noload"},  	{Opt_noload, "norecovery"}, -	{Opt_nobh, "nobh"}, -	{Opt_bh, "bh"}, +	{Opt_noload, "noload"}, +	{Opt_removed, "nobh"}, +	{Opt_removed, "bh"},  	{Opt_commit, "commit=%u"},  	{Opt_min_batch_time, "min_batch_time=%u"},  	{Opt_max_batch_time, "max_batch_time=%u"}, -	{Opt_journal_update, "journal=update"},  	{Opt_journal_dev, "journal_dev=%u"},  	{Opt_journal_checksum, "journal_checksum"},  	{Opt_journal_async_commit, "journal_async_commit"}, @@ -1389,7 +1241,6 @@ static const match_table_t tokens = {  	{Opt_nobarrier, "nobarrier"},  	{Opt_i_version, "i_version"},  	{Opt_stripe, "stripe=%u"}, -	{Opt_resize, "resize"},  	{Opt_delalloc, "delalloc"},  	{Opt_nodelalloc, "nodelalloc"},  	{Opt_mblk_io_submit, "mblk_io_submit"}, @@ -1408,6 +1259,11 @@ static const match_table_t tokens = {  	{Opt_init_itable, "init_itable=%u"},  	{Opt_init_itable, "init_itable"},  	{Opt_noinit_itable, "noinit_itable"}, +	{Opt_removed, "check=none"},	/* mount option from ext2/3 */ +	{Opt_removed, "nocheck"},	/* mount option from ext2/3 */ +	{Opt_removed, "reservation"},	/* mount option from ext2/3 */ +	{Opt_removed, "noreservation"}, /* mount option from ext2/3 */ +	{Opt_removed, "journal=%u"},	/* mount option from ext2/3 */  	{Opt_err, NULL},  }; @@ -1496,420 +1352,273 @@ static int clear_qf_name(struct super_block *sb, int qtype)  }  #endif -static int parse_options(char *options, struct super_block *sb, -			 unsigned long *journal_devnum, -			 unsigned int *journal_ioprio, -			 ext4_fsblk_t *n_blocks_count, int is_remount) -{ -	struct ext4_sb_info *sbi = EXT4_SB(sb); -	char *p; -	substring_t args[MAX_OPT_ARGS]; -	int data_opt = 0; -	int option; +#define MOPT_SET	0x0001 +#define MOPT_CLEAR	0x0002 +#define MOPT_NOSUPPORT	0x0004 +#define MOPT_EXPLICIT	0x0008 +#define MOPT_CLEAR_ERR	0x0010 +#define MOPT_GTE0	0x0020  #ifdef CONFIG_QUOTA -	int qfmt; +#define MOPT_Q		0 +#define MOPT_QFMT	0x0040 +#else +#define MOPT_Q		MOPT_NOSUPPORT +#define MOPT_QFMT	MOPT_NOSUPPORT  #endif +#define MOPT_DATAJ	0x0080 -	if (!options) -		return 1; - -	while ((p = strsep(&options, ",")) != NULL) { -		int token; -		if (!*p) -			continue; - -		/* -		 * Initialize args struct so we know whether arg was -		 * found; some options take optional arguments. -		 */ -		args[0].to = args[0].from = NULL; -		token = match_token(p, tokens, args); -		switch (token) { -		case Opt_bsd_df: -			ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38"); -			clear_opt(sb, MINIX_DF); -			break; -		case Opt_minix_df: -			ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38"); -			set_opt(sb, MINIX_DF); - -			break; -		case Opt_grpid: -			ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38"); -			set_opt(sb, GRPID); - -			break; -		case Opt_nogrpid: -			ext4_msg(sb, KERN_WARNING, deprecated_msg, p, "2.6.38"); -			clear_opt(sb, GRPID); - -			break; -		case Opt_resuid: -			if (match_int(&args[0], &option)) -				return 0; -			sbi->s_resuid = option; -			break; -		case Opt_resgid: -			if (match_int(&args[0], &option)) -				return 0; -			sbi->s_resgid = option; -			break; -		case Opt_sb: -			/* handled by get_sb_block() instead of here */ -			/* *sb_block = match_int(&args[0]); */ -			break; -		case Opt_err_panic: -			clear_opt(sb, ERRORS_CONT); -			clear_opt(sb, ERRORS_RO); -			set_opt(sb, ERRORS_PANIC); -			break; -		case Opt_err_ro: -			clear_opt(sb, ERRORS_CONT); -			clear_opt(sb, ERRORS_PANIC); -			set_opt(sb, ERRORS_RO); -			break; -		case Opt_err_cont: -			clear_opt(sb, ERRORS_RO); -			clear_opt(sb, ERRORS_PANIC); -			set_opt(sb, ERRORS_CONT); -			break; -		case Opt_nouid32: -			set_opt(sb, NO_UID32); -			break; -		case Opt_debug: -			set_opt(sb, DEBUG); -			break; -		case Opt_oldalloc: -			ext4_msg(sb, KERN_WARNING, -				 "Ignoring deprecated oldalloc option"); -			break; -		case Opt_orlov: -			ext4_msg(sb, KERN_WARNING, -				 "Ignoring deprecated orlov option"); -			break; +static const struct mount_opts { +	int	token; +	int	mount_opt; +	int	flags; +} ext4_mount_opts[] = { +	{Opt_minix_df, EXT4_MOUNT_MINIX_DF, MOPT_SET}, +	{Opt_bsd_df, EXT4_MOUNT_MINIX_DF, MOPT_CLEAR}, +	{Opt_grpid, EXT4_MOUNT_GRPID, MOPT_SET}, +	{Opt_nogrpid, EXT4_MOUNT_GRPID, MOPT_CLEAR}, +	{Opt_mblk_io_submit, EXT4_MOUNT_MBLK_IO_SUBMIT, MOPT_SET}, +	{Opt_nomblk_io_submit, EXT4_MOUNT_MBLK_IO_SUBMIT, MOPT_CLEAR}, +	{Opt_block_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_SET}, +	{Opt_noblock_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_CLEAR}, +	{Opt_dioread_nolock, EXT4_MOUNT_DIOREAD_NOLOCK, MOPT_SET}, +	{Opt_dioread_lock, EXT4_MOUNT_DIOREAD_NOLOCK, MOPT_CLEAR}, +	{Opt_discard, EXT4_MOUNT_DISCARD, MOPT_SET}, +	{Opt_nodiscard, EXT4_MOUNT_DISCARD, MOPT_CLEAR}, +	{Opt_delalloc, EXT4_MOUNT_DELALLOC, MOPT_SET | MOPT_EXPLICIT}, +	{Opt_nodelalloc, EXT4_MOUNT_DELALLOC, MOPT_CLEAR | MOPT_EXPLICIT}, +	{Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM, MOPT_SET}, +	{Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT | +				    EXT4_MOUNT_JOURNAL_CHECKSUM), MOPT_SET}, +	{Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_SET}, +	{Opt_err_panic, EXT4_MOUNT_ERRORS_PANIC, MOPT_SET | MOPT_CLEAR_ERR}, +	{Opt_err_ro, EXT4_MOUNT_ERRORS_RO, MOPT_SET | MOPT_CLEAR_ERR}, +	{Opt_err_cont, EXT4_MOUNT_ERRORS_CONT, MOPT_SET | MOPT_CLEAR_ERR}, +	{Opt_data_err_abort, EXT4_MOUNT_DATA_ERR_ABORT, MOPT_SET}, +	{Opt_data_err_ignore, EXT4_MOUNT_DATA_ERR_ABORT, MOPT_CLEAR}, +	{Opt_barrier, EXT4_MOUNT_BARRIER, MOPT_SET}, +	{Opt_nobarrier, EXT4_MOUNT_BARRIER, MOPT_CLEAR}, +	{Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET}, +	{Opt_auto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_CLEAR}, +	{Opt_noinit_itable, EXT4_MOUNT_INIT_INODE_TABLE, MOPT_CLEAR}, +	{Opt_commit, 0, MOPT_GTE0}, +	{Opt_max_batch_time, 0, MOPT_GTE0}, +	{Opt_min_batch_time, 0, MOPT_GTE0}, +	{Opt_inode_readahead_blks, 0, MOPT_GTE0}, +	{Opt_init_itable, 0, MOPT_GTE0}, +	{Opt_stripe, 0, MOPT_GTE0}, +	{Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_DATAJ}, +	{Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_DATAJ}, +	{Opt_data_writeback, EXT4_MOUNT_WRITEBACK_DATA, MOPT_DATAJ},  #ifdef CONFIG_EXT4_FS_XATTR -		case Opt_user_xattr: -			set_opt(sb, XATTR_USER); -			break; -		case Opt_nouser_xattr: -			clear_opt(sb, XATTR_USER); -			break; +	{Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET}, +	{Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR},  #else -		case Opt_user_xattr: -		case Opt_nouser_xattr: -			ext4_msg(sb, KERN_ERR, "(no)user_xattr options not supported"); -			break; +	{Opt_user_xattr, 0, MOPT_NOSUPPORT}, +	{Opt_nouser_xattr, 0, MOPT_NOSUPPORT},  #endif  #ifdef CONFIG_EXT4_FS_POSIX_ACL -		case Opt_acl: -			set_opt(sb, POSIX_ACL); -			break; -		case Opt_noacl: -			clear_opt(sb, POSIX_ACL); -			break; +	{Opt_acl, EXT4_MOUNT_POSIX_ACL, MOPT_SET}, +	{Opt_noacl, EXT4_MOUNT_POSIX_ACL, MOPT_CLEAR},  #else -		case Opt_acl: -		case Opt_noacl: -			ext4_msg(sb, KERN_ERR, "(no)acl options not supported"); -			break; +	{Opt_acl, 0, MOPT_NOSUPPORT}, +	{Opt_noacl, 0, MOPT_NOSUPPORT},  #endif -		case Opt_journal_update: -			/* @@@ FIXME */ -			/* Eventually we will want to be able to create -			   a journal file here.  For now, only allow the -			   user to specify an existing inode to be the -			   journal file. */ -			if (is_remount) { -				ext4_msg(sb, KERN_ERR, -					 "Cannot specify journal on remount"); -				return 0; -			} -			set_opt(sb, UPDATE_JOURNAL); -			break; -		case Opt_journal_dev: -			if (is_remount) { +	{Opt_nouid32, EXT4_MOUNT_NO_UID32, MOPT_SET}, +	{Opt_debug, EXT4_MOUNT_DEBUG, MOPT_SET}, +	{Opt_quota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, MOPT_SET | MOPT_Q}, +	{Opt_usrquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, +							MOPT_SET | MOPT_Q}, +	{Opt_grpquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_GRPQUOTA, +							MOPT_SET | MOPT_Q}, +	{Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA | +		       EXT4_MOUNT_GRPQUOTA), MOPT_CLEAR | MOPT_Q}, +	{Opt_usrjquota, 0, MOPT_Q}, +	{Opt_grpjquota, 0, MOPT_Q}, +	{Opt_offusrjquota, 0, MOPT_Q}, +	{Opt_offgrpjquota, 0, MOPT_Q}, +	{Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT}, +	{Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT}, +	{Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT}, +	{Opt_err, 0, 0} +}; + +static int handle_mount_opt(struct super_block *sb, char *opt, int token, +			    substring_t *args, unsigned long *journal_devnum, +			    unsigned int *journal_ioprio, int is_remount) +{ +	struct ext4_sb_info *sbi = EXT4_SB(sb); +	const struct mount_opts *m; +	int arg = 0; + +	if (args->from && match_int(args, &arg)) +		return -1; +	switch (token) { +	case Opt_noacl: +	case Opt_nouser_xattr: +		ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5"); +		break; +	case Opt_sb: +		return 1;	/* handled by get_sb_block() */ +	case Opt_removed: +		ext4_msg(sb, KERN_WARNING, +			 "Ignoring removed %s option", opt); +		return 1; +	case Opt_resuid: +		sbi->s_resuid = arg; +		return 1; +	case Opt_resgid: +		sbi->s_resgid = arg; +		return 1; +	case Opt_abort: +		sbi->s_mount_flags |= EXT4_MF_FS_ABORTED; +		return 1; +	case Opt_i_version: +		sb->s_flags |= MS_I_VERSION; +		return 1; +	case Opt_journal_dev: +		if (is_remount) { +			ext4_msg(sb, KERN_ERR, +				 "Cannot specify journal on remount"); +			return -1; +		} +		*journal_devnum = arg; +		return 1; +	case Opt_journal_ioprio: +		if (arg < 0 || arg > 7) +			return -1; +		*journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg); +		return 1; +	} + +	for (m = ext4_mount_opts; m->token != Opt_err; m++) { +		if (token != m->token) +			continue; +		if (args->from && (m->flags & MOPT_GTE0) && (arg < 0)) +			return -1; +		if (m->flags & MOPT_EXPLICIT) +			set_opt2(sb, EXPLICIT_DELALLOC); +		if (m->flags & MOPT_CLEAR_ERR) +			clear_opt(sb, ERRORS_MASK); +		if (token == Opt_noquota && sb_any_quota_loaded(sb)) { +			ext4_msg(sb, KERN_ERR, "Cannot change quota " +				 "options when quota turned on"); +			return -1; +		} + +		if (m->flags & MOPT_NOSUPPORT) { +			ext4_msg(sb, KERN_ERR, "%s option not supported", opt); +		} else if (token == Opt_commit) { +			if (arg == 0) +				arg = JBD2_DEFAULT_MAX_COMMIT_AGE; +			sbi->s_commit_interval = HZ * arg; +		} else if (token == Opt_max_batch_time) { +			if (arg == 0) +				arg = EXT4_DEF_MAX_BATCH_TIME; +			sbi->s_max_batch_time = arg; +		} else if (token == Opt_min_batch_time) { +			sbi->s_min_batch_time = arg; +		} else if (token == Opt_inode_readahead_blks) { +			if (arg > (1 << 30)) +				return -1; +			if (arg && !is_power_of_2(arg)) {  				ext4_msg(sb, KERN_ERR, -					"Cannot specify journal on remount"); -				return 0; +					 "EXT4-fs: inode_readahead_blks" +					 " must be a power of 2"); +				return -1;  			} -			if (match_int(&args[0], &option)) -				return 0; -			*journal_devnum = option; -			break; -		case Opt_journal_checksum: -			set_opt(sb, JOURNAL_CHECKSUM); -			break; -		case Opt_journal_async_commit: -			set_opt(sb, JOURNAL_ASYNC_COMMIT); -			set_opt(sb, JOURNAL_CHECKSUM); -			break; -		case Opt_noload: -			set_opt(sb, NOLOAD); -			break; -		case Opt_commit: -			if (match_int(&args[0], &option)) -				return 0; -			if (option < 0) -				return 0; -			if (option == 0) -				option = JBD2_DEFAULT_MAX_COMMIT_AGE; -			sbi->s_commit_interval = HZ * option; -			break; -		case Opt_max_batch_time: -			if (match_int(&args[0], &option)) -				return 0; -			if (option < 0) -				return 0; -			if (option == 0) -				option = EXT4_DEF_MAX_BATCH_TIME; -			sbi->s_max_batch_time = option; -			break; -		case Opt_min_batch_time: -			if (match_int(&args[0], &option)) -				return 0; -			if (option < 0) -				return 0; -			sbi->s_min_batch_time = option; -			break; -		case Opt_data_journal: -			data_opt = EXT4_MOUNT_JOURNAL_DATA; -			goto datacheck; -		case Opt_data_ordered: -			data_opt = EXT4_MOUNT_ORDERED_DATA; -			goto datacheck; -		case Opt_data_writeback: -			data_opt = EXT4_MOUNT_WRITEBACK_DATA; -		datacheck: +			sbi->s_inode_readahead_blks = arg; +		} else if (token == Opt_init_itable) { +			set_opt(sb, INIT_INODE_TABLE); +			if (!args->from) +				arg = EXT4_DEF_LI_WAIT_MULT; +			sbi->s_li_wait_mult = arg; +		} else if (token == Opt_stripe) { +			sbi->s_stripe = arg; +		} else if (m->flags & MOPT_DATAJ) {  			if (is_remount) {  				if (!sbi->s_journal)  					ext4_msg(sb, KERN_WARNING, "Remounting file system with no journal so ignoring journalled data option"); -				else if (test_opt(sb, DATA_FLAGS) != data_opt) { +				else if (test_opt(sb, DATA_FLAGS) != +					 m->mount_opt) {  					ext4_msg(sb, KERN_ERR, -						"Cannot change data mode on remount"); -					return 0; +					 "Cannot change data mode on remount"); +					return -1;  				}  			} else {  				clear_opt(sb, DATA_FLAGS); -				sbi->s_mount_opt |= data_opt; +				sbi->s_mount_opt |= m->mount_opt;  			} -			break; -		case Opt_data_err_abort: -			set_opt(sb, DATA_ERR_ABORT); -			break; -		case Opt_data_err_ignore: -			clear_opt(sb, DATA_ERR_ABORT); -			break;  #ifdef CONFIG_QUOTA -		case Opt_usrjquota: +		} else if (token == Opt_usrjquota) {  			if (!set_qf_name(sb, USRQUOTA, &args[0])) -				return 0; -			break; -		case Opt_grpjquota: +				return -1; +		} else if (token == Opt_grpjquota) {  			if (!set_qf_name(sb, GRPQUOTA, &args[0])) -				return 0; -			break; -		case Opt_offusrjquota: +				return -1; +		} else if (token == Opt_offusrjquota) {  			if (!clear_qf_name(sb, USRQUOTA)) -				return 0; -			break; -		case Opt_offgrpjquota: +				return -1; +		} else if (token == Opt_offgrpjquota) {  			if (!clear_qf_name(sb, GRPQUOTA)) -				return 0; -			break; - -		case Opt_jqfmt_vfsold: -			qfmt = QFMT_VFS_OLD; -			goto set_qf_format; -		case Opt_jqfmt_vfsv0: -			qfmt = QFMT_VFS_V0; -			goto set_qf_format; -		case Opt_jqfmt_vfsv1: -			qfmt = QFMT_VFS_V1; -set_qf_format: +				return -1; +		} else if (m->flags & MOPT_QFMT) {  			if (sb_any_quota_loaded(sb) && -			    sbi->s_jquota_fmt != qfmt) { -				ext4_msg(sb, KERN_ERR, "Cannot change " -					"journaled quota options when " -					"quota turned on"); -				return 0; -			} -			sbi->s_jquota_fmt = qfmt; -			break; -		case Opt_quota: -		case Opt_usrquota: -			set_opt(sb, QUOTA); -			set_opt(sb, USRQUOTA); -			break; -		case Opt_grpquota: -			set_opt(sb, QUOTA); -			set_opt(sb, GRPQUOTA); -			break; -		case Opt_noquota: -			if (sb_any_quota_loaded(sb)) { -				ext4_msg(sb, KERN_ERR, "Cannot change quota " -					"options when quota turned on"); -				return 0; +			    sbi->s_jquota_fmt != m->mount_opt) { +				ext4_msg(sb, KERN_ERR, "Cannot " +					 "change journaled quota options " +					 "when quota turned on"); +				return -1;  			} -			clear_opt(sb, QUOTA); -			clear_opt(sb, USRQUOTA); -			clear_opt(sb, GRPQUOTA); -			break; -#else -		case Opt_quota: -		case Opt_usrquota: -		case Opt_grpquota: -			ext4_msg(sb, KERN_ERR, -				"quota options not supported"); -			break; -		case Opt_usrjquota: -		case Opt_grpjquota: -		case Opt_offusrjquota: -		case Opt_offgrpjquota: -		case Opt_jqfmt_vfsold: -		case Opt_jqfmt_vfsv0: -		case Opt_jqfmt_vfsv1: -			ext4_msg(sb, KERN_ERR, -				"journaled quota options not supported"); -			break; -		case Opt_noquota: -			break; +			sbi->s_jquota_fmt = m->mount_opt;  #endif -		case Opt_abort: -			sbi->s_mount_flags |= EXT4_MF_FS_ABORTED; -			break; -		case Opt_nobarrier: -			clear_opt(sb, BARRIER); -			break; -		case Opt_barrier: -			if (args[0].from) { -				if (match_int(&args[0], &option)) -					return 0; -			} else -				option = 1;	/* No argument, default to 1 */ -			if (option) -				set_opt(sb, BARRIER); -			else -				clear_opt(sb, BARRIER); -			break; -		case Opt_ignore: -			break; -		case Opt_resize: -			if (!is_remount) { -				ext4_msg(sb, KERN_ERR, -					"resize option only available " -					"for remount"); -				return 0; -			} -			if (match_int(&args[0], &option) != 0) -				return 0; -			*n_blocks_count = option; -			break; -		case Opt_nobh: -			ext4_msg(sb, KERN_WARNING, -				 "Ignoring deprecated nobh option"); -			break; -		case Opt_bh: -			ext4_msg(sb, KERN_WARNING, -				 "Ignoring deprecated bh option"); -			break; -		case Opt_i_version: -			set_opt(sb, I_VERSION); -			sb->s_flags |= MS_I_VERSION; -			break; -		case Opt_nodelalloc: -			clear_opt(sb, DELALLOC); -			clear_opt2(sb, EXPLICIT_DELALLOC); -			break; -		case Opt_mblk_io_submit: -			set_opt(sb, MBLK_IO_SUBMIT); -			break; -		case Opt_nomblk_io_submit: -			clear_opt(sb, MBLK_IO_SUBMIT); -			break; -		case Opt_stripe: -			if (match_int(&args[0], &option)) -				return 0; -			if (option < 0) -				return 0; -			sbi->s_stripe = option; -			break; -		case Opt_delalloc: -			set_opt(sb, DELALLOC); -			set_opt2(sb, EXPLICIT_DELALLOC); -			break; -		case Opt_block_validity: -			set_opt(sb, BLOCK_VALIDITY); -			break; -		case Opt_noblock_validity: -			clear_opt(sb, BLOCK_VALIDITY); -			break; -		case Opt_inode_readahead_blks: -			if (match_int(&args[0], &option)) -				return 0; -			if (option < 0 || option > (1 << 30)) -				return 0; -			if (option && !is_power_of_2(option)) { -				ext4_msg(sb, KERN_ERR, -					 "EXT4-fs: inode_readahead_blks" -					 " must be a power of 2"); -				return 0; +		} else { +			if (!args->from) +				arg = 1; +			if (m->flags & MOPT_CLEAR) +				arg = !arg; +			else if (unlikely(!(m->flags & MOPT_SET))) { +				ext4_msg(sb, KERN_WARNING, +					 "buggy handling of option %s", opt); +				WARN_ON(1); +				return -1;  			} -			sbi->s_inode_readahead_blks = option; -			break; -		case Opt_journal_ioprio: -			if (match_int(&args[0], &option)) -				return 0; -			if (option < 0 || option > 7) -				break; -			*journal_ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, -							    option); -			break; -		case Opt_noauto_da_alloc: -			set_opt(sb, NO_AUTO_DA_ALLOC); -			break; -		case Opt_auto_da_alloc: -			if (args[0].from) { -				if (match_int(&args[0], &option)) -					return 0; -			} else -				option = 1;	/* No argument, default to 1 */ -			if (option) -				clear_opt(sb, NO_AUTO_DA_ALLOC); +			if (arg != 0) +				sbi->s_mount_opt |= m->mount_opt;  			else -				set_opt(sb,NO_AUTO_DA_ALLOC); -			break; -		case Opt_discard: -			set_opt(sb, DISCARD); -			break; -		case Opt_nodiscard: -			clear_opt(sb, DISCARD); -			break; -		case Opt_dioread_nolock: -			set_opt(sb, DIOREAD_NOLOCK); -			break; -		case Opt_dioread_lock: -			clear_opt(sb, DIOREAD_NOLOCK); -			break; -		case Opt_init_itable: -			set_opt(sb, INIT_INODE_TABLE); -			if (args[0].from) { -				if (match_int(&args[0], &option)) -					return 0; -			} else -				option = EXT4_DEF_LI_WAIT_MULT; -			if (option < 0) -				return 0; -			sbi->s_li_wait_mult = option; -			break; -		case Opt_noinit_itable: -			clear_opt(sb, INIT_INODE_TABLE); -			break; -		default: -			ext4_msg(sb, KERN_ERR, -			       "Unrecognized mount option \"%s\" " -			       "or missing value", p); -			return 0; +				sbi->s_mount_opt &= ~m->mount_opt;  		} +		return 1; +	} +	ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" " +		 "or missing value", opt); +	return -1; +} + +static int parse_options(char *options, struct super_block *sb, +			 unsigned long *journal_devnum, +			 unsigned int *journal_ioprio, +			 int is_remount) +{ +	struct ext4_sb_info *sbi = EXT4_SB(sb); +	char *p; +	substring_t args[MAX_OPT_ARGS]; +	int token; + +	if (!options) +		return 1; + +	while ((p = strsep(&options, ",")) != NULL) { +		if (!*p) +			continue; +		/* +		 * Initialize args struct so we know whether arg was +		 * found; some options take optional arguments. +		 */ +		args[0].to = args[0].from = 0; +		token = match_token(p, tokens, args); +		if (handle_mount_opt(sb, p, token, args, journal_devnum, +				     journal_ioprio, is_remount) < 0) +			return 0;  	}  #ifdef CONFIG_QUOTA  	if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) { @@ -1942,6 +1651,160 @@ set_qf_format:  	return 1;  } +static inline void ext4_show_quota_options(struct seq_file *seq, +					   struct super_block *sb) +{ +#if defined(CONFIG_QUOTA) +	struct ext4_sb_info *sbi = EXT4_SB(sb); + +	if (sbi->s_jquota_fmt) { +		char *fmtname = ""; + +		switch (sbi->s_jquota_fmt) { +		case QFMT_VFS_OLD: +			fmtname = "vfsold"; +			break; +		case QFMT_VFS_V0: +			fmtname = "vfsv0"; +			break; +		case QFMT_VFS_V1: +			fmtname = "vfsv1"; +			break; +		} +		seq_printf(seq, ",jqfmt=%s", fmtname); +	} + +	if (sbi->s_qf_names[USRQUOTA]) +		seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]); + +	if (sbi->s_qf_names[GRPQUOTA]) +		seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); + +	if (test_opt(sb, USRQUOTA)) +		seq_puts(seq, ",usrquota"); + +	if (test_opt(sb, GRPQUOTA)) +		seq_puts(seq, ",grpquota"); +#endif +} + +static const char *token2str(int token) +{ +	static const struct match_token *t; + +	for (t = tokens; t->token != Opt_err; t++) +		if (t->token == token && !strchr(t->pattern, '=')) +			break; +	return t->pattern; +} + +/* + * 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 super_block *sb, +			      int nodefs) +{ +	struct ext4_sb_info *sbi = EXT4_SB(sb); +	struct ext4_super_block *es = sbi->s_es; +	int def_errors, def_mount_opt = nodefs ? 0 : sbi->s_def_mount_opt; +	const struct mount_opts *m; +	char sep = nodefs ? '\n' : ','; + +#define SEQ_OPTS_PUTS(str) seq_printf(seq, "%c" str, sep) +#define SEQ_OPTS_PRINT(str, arg) seq_printf(seq, "%c" str, sep, arg) + +	if (sbi->s_sb_block != 1) +		SEQ_OPTS_PRINT("sb=%llu", sbi->s_sb_block); + +	for (m = ext4_mount_opts; m->token != Opt_err; m++) { +		int want_set = m->flags & MOPT_SET; +		if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) || +		    (m->flags & MOPT_CLEAR_ERR)) +			continue; +		if (!(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt))) +			continue; /* skip if same as the default */ +		if ((want_set && +		     (sbi->s_mount_opt & m->mount_opt) != m->mount_opt) || +		    (!want_set && (sbi->s_mount_opt & m->mount_opt))) +			continue; /* select Opt_noFoo vs Opt_Foo */ +		SEQ_OPTS_PRINT("%s", token2str(m->token)); +	} + +	if (nodefs || sbi->s_resuid != EXT4_DEF_RESUID || +	    le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) +		SEQ_OPTS_PRINT("resuid=%u", sbi->s_resuid); +	if (nodefs || sbi->s_resgid != EXT4_DEF_RESGID || +	    le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) +		SEQ_OPTS_PRINT("resgid=%u", sbi->s_resgid); +	def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors); +	if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO) +		SEQ_OPTS_PUTS("errors=remount-ro"); +	if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE) +		SEQ_OPTS_PUTS("errors=continue"); +	if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC) +		SEQ_OPTS_PUTS("errors=panic"); +	if (nodefs || sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) +		SEQ_OPTS_PRINT("commit=%lu", sbi->s_commit_interval / HZ); +	if (nodefs || sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME) +		SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time); +	if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME) +		SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time); +	if (sb->s_flags & MS_I_VERSION) +		SEQ_OPTS_PUTS("i_version"); +	if (nodefs || sbi->s_stripe) +		SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe); +	if (EXT4_MOUNT_DATA_FLAGS & (sbi->s_mount_opt ^ def_mount_opt)) { +		if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) +			SEQ_OPTS_PUTS("data=journal"); +		else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) +			SEQ_OPTS_PUTS("data=ordered"); +		else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) +			SEQ_OPTS_PUTS("data=writeback"); +	} +	if (nodefs || +	    sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS) +		SEQ_OPTS_PRINT("inode_readahead_blks=%u", +			       sbi->s_inode_readahead_blks); + +	if (nodefs || (test_opt(sb, INIT_INODE_TABLE) && +		       (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT))) +		SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult); + +	ext4_show_quota_options(seq, sb); +	return 0; +} + +static int ext4_show_options(struct seq_file *seq, struct dentry *root) +{ +	return _ext4_show_options(seq, root->d_sb, 0); +} + +static int options_seq_show(struct seq_file *seq, void *offset) +{ +	struct super_block *sb = seq->private; +	int rc; + +	seq_puts(seq, (sb->s_flags & MS_RDONLY) ? "ro" : "rw"); +	rc = _ext4_show_options(seq, sb, 1); +	seq_puts(seq, "\n"); +	return rc; +} + +static int options_open_fs(struct inode *inode, struct file *file) +{ +	return single_open(file, options_seq_show, PDE(inode)->data); +} + +static const struct file_operations ext4_seq_options_fops = { +	.owner = THIS_MODULE, +	.open = options_open_fs, +	.read = seq_read, +	.llseek = seq_lseek, +	.release = single_release, +}; +  static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,  			    int read_only)  { @@ -2945,7 +2808,7 @@ static int ext4_run_lazyinit_thread(void)  		ext4_clear_request_list();  		kfree(ext4_li_info);  		ext4_li_info = NULL; -		printk(KERN_CRIT "EXT4: error %d creating inode table " +		printk(KERN_CRIT "EXT4-fs: error %d creating inode table "  				 "initialization thread\n",  				 err);  		return err; @@ -3183,11 +3046,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)  	set_opt(sb, INIT_INODE_TABLE);  	if (def_mount_opts & EXT4_DEFM_DEBUG)  		set_opt(sb, DEBUG); -	if (def_mount_opts & EXT4_DEFM_BSDGROUPS) { -		ext4_msg(sb, KERN_WARNING, deprecated_msg, "bsdgroups", -			"2.6.38"); +	if (def_mount_opts & EXT4_DEFM_BSDGROUPS)  		set_opt(sb, GRPID); -	}  	if (def_mount_opts & EXT4_DEFM_UID16)  		set_opt(sb, NO_UID32);  	/* xattr user namespace & acls are now defaulted on */ @@ -3240,13 +3100,14 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)  	sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT;  	if (!parse_options((char *) sbi->s_es->s_mount_opts, sb, -			   &journal_devnum, &journal_ioprio, NULL, 0)) { +			   &journal_devnum, &journal_ioprio, 0)) {  		ext4_msg(sb, KERN_WARNING,  			 "failed to parse options in superblock: %s",  			 sbi->s_es->s_mount_opts);  	} +	sbi->s_def_mount_opt = sbi->s_mount_opt;  	if (!parse_options((char *) data, sb, &journal_devnum, -			   &journal_ioprio, NULL, 0)) +			   &journal_ioprio, 0))  		goto failed_mount;  	if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { @@ -3416,7 +3277,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)  #else  		es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH);  #endif -		sb->s_dirt = 1;  	}  	/* Handle clustersize */ @@ -3540,6 +3400,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)  	if (ext4_proc_root)  		sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root); +	if (sbi->s_proc) +		proc_create_data("options", S_IRUGO, sbi->s_proc, +				 &ext4_seq_options_fops, sb); +  	bgl_lock_init(sbi->s_blockgroup_lock);  	for (i = 0; i < db_count; i++) { @@ -3694,6 +3558,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)  	}  	set_task_ioprio(sbi->s_journal->j_task, journal_ioprio); +	sbi->s_journal->j_commit_callback = ext4_journal_commit_callback; +  	/*  	 * The journal may have updated the bg summary counts, so we  	 * need to update the global counters. @@ -3861,6 +3727,7 @@ failed_mount2:  	ext4_kvfree(sbi->s_group_desc);  failed_mount:  	if (sbi->s_proc) { +		remove_proc_entry("options", sbi->s_proc);  		remove_proc_entry(sb->s_id, ext4_proc_root);  	}  #ifdef CONFIG_QUOTA @@ -4090,15 +3957,6 @@ static int ext4_load_journal(struct super_block *sb,  	if (!(journal->j_flags & JBD2_BARRIER))  		ext4_msg(sb, KERN_INFO, "barriers disabled"); -	if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) { -		err = jbd2_journal_update_format(journal); -		if (err)  { -			ext4_msg(sb, KERN_ERR, "error updating journal"); -			jbd2_journal_destroy(journal); -			return err; -		} -	} -  	if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER))  		err = jbd2_journal_wipe(journal, !really_read_only);  	if (!err) { @@ -4385,7 +4243,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)  {  	struct ext4_super_block *es;  	struct ext4_sb_info *sbi = EXT4_SB(sb); -	ext4_fsblk_t n_blocks_count = 0;  	unsigned long old_sb_flags;  	struct ext4_mount_options old_opts;  	int enable_quota = 0; @@ -4418,8 +4275,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)  	/*  	 * Allow the "check" option to be passed as a remount option.  	 */ -	if (!parse_options(data, sb, NULL, &journal_ioprio, -			   &n_blocks_count, 1)) { +	if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) {  		err = -EINVAL;  		goto restore_opts;  	} @@ -4437,8 +4293,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)  		set_task_ioprio(sbi->s_journal->j_task, journal_ioprio);  	} -	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || -		n_blocks_count > ext4_blocks_count(es)) { +	if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) {  		if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) {  			err = -EROFS;  			goto restore_opts; @@ -4513,8 +4368,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)  			if (sbi->s_journal)  				ext4_clear_journal_err(sb, es);  			sbi->s_mount_state = le16_to_cpu(es->s_state); -			if ((err = ext4_group_extend(sb, es, n_blocks_count))) -				goto restore_opts;  			if (!ext4_setup_super(sb, es, 0))  				sb->s_flags &= ~MS_RDONLY;  			if (EXT4_HAS_INCOMPAT_FEATURE(sb,  |