|
@@ -69,8 +69,6 @@ static void ext4_mark_recovery_complete(struct super_block *sb,
|
|
|
static void ext4_clear_journal_err(struct super_block *sb,
|
|
|
struct ext4_super_block *es);
|
|
|
static int ext4_sync_fs(struct super_block *sb, int wait);
|
|
|
-static const char *ext4_decode_error(struct super_block *sb, int errno,
|
|
|
- char nbuf[16]);
|
|
|
static int ext4_remount(struct super_block *sb, int *flags, char *data);
|
|
|
static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf);
|
|
|
static int ext4_unfreeze(struct super_block *sb);
|
|
@@ -296,107 +294,6 @@ void ext4_itable_unused_set(struct super_block *sb,
|
|
|
}
|
|
|
|
|
|
|
|
|
-/* Just increment the non-pointer handle value */
|
|
|
-static handle_t *ext4_get_nojournal(void)
|
|
|
-{
|
|
|
- handle_t *handle = current->journal_info;
|
|
|
- unsigned long ref_cnt = (unsigned long)handle;
|
|
|
-
|
|
|
- BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT);
|
|
|
-
|
|
|
- ref_cnt++;
|
|
|
- handle = (handle_t *)ref_cnt;
|
|
|
-
|
|
|
- current->journal_info = handle;
|
|
|
- return handle;
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-/* Decrement the non-pointer handle value */
|
|
|
-static void ext4_put_nojournal(handle_t *handle)
|
|
|
-{
|
|
|
- unsigned long ref_cnt = (unsigned long)handle;
|
|
|
-
|
|
|
- BUG_ON(ref_cnt == 0);
|
|
|
-
|
|
|
- ref_cnt--;
|
|
|
- handle = (handle_t *)ref_cnt;
|
|
|
-
|
|
|
- current->journal_info = handle;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Wrappers for jbd2_journal_start/end.
|
|
|
- */
|
|
|
-handle_t *ext4_journal_start_sb(struct super_block *sb, int nblocks)
|
|
|
-{
|
|
|
- journal_t *journal;
|
|
|
-
|
|
|
- trace_ext4_journal_start(sb, nblocks, _RET_IP_);
|
|
|
- if (sb->s_flags & MS_RDONLY)
|
|
|
- return ERR_PTR(-EROFS);
|
|
|
-
|
|
|
- WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE);
|
|
|
- journal = EXT4_SB(sb)->s_journal;
|
|
|
- if (!journal)
|
|
|
- return ext4_get_nojournal();
|
|
|
- /*
|
|
|
- * Special case here: if the journal has aborted behind our
|
|
|
- * backs (eg. EIO in the commit thread), then we still need to
|
|
|
- * take the FS itself readonly cleanly.
|
|
|
- */
|
|
|
- if (is_journal_aborted(journal)) {
|
|
|
- ext4_abort(sb, "Detected aborted journal");
|
|
|
- return ERR_PTR(-EROFS);
|
|
|
- }
|
|
|
- return jbd2_journal_start(journal, nblocks);
|
|
|
-}
|
|
|
-
|
|
|
-int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle)
|
|
|
-{
|
|
|
- struct super_block *sb;
|
|
|
- int err;
|
|
|
- int rc;
|
|
|
-
|
|
|
- if (!ext4_handle_valid(handle)) {
|
|
|
- ext4_put_nojournal(handle);
|
|
|
- return 0;
|
|
|
- }
|
|
|
- sb = handle->h_transaction->t_journal->j_private;
|
|
|
- err = handle->h_err;
|
|
|
- rc = jbd2_journal_stop(handle);
|
|
|
-
|
|
|
- if (!err)
|
|
|
- err = rc;
|
|
|
- if (err)
|
|
|
- __ext4_std_error(sb, where, line, err);
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
-void ext4_journal_abort_handle(const char *caller, unsigned int line,
|
|
|
- const char *err_fn, struct buffer_head *bh,
|
|
|
- handle_t *handle, int err)
|
|
|
-{
|
|
|
- char nbuf[16];
|
|
|
- const char *errstr = ext4_decode_error(NULL, err, nbuf);
|
|
|
-
|
|
|
- BUG_ON(!ext4_handle_valid(handle));
|
|
|
-
|
|
|
- if (bh)
|
|
|
- BUFFER_TRACE(bh, "abort");
|
|
|
-
|
|
|
- if (!handle->h_err)
|
|
|
- handle->h_err = err;
|
|
|
-
|
|
|
- if (is_handle_aborted(handle))
|
|
|
- return;
|
|
|
-
|
|
|
- printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n",
|
|
|
- caller, line, errstr, err_fn);
|
|
|
-
|
|
|
- jbd2_journal_abort_handle(handle);
|
|
|
-}
|
|
|
-
|
|
|
static void __save_error_info(struct super_block *sb, const char *func,
|
|
|
unsigned int line)
|
|
|
{
|
|
@@ -582,8 +479,8 @@ void ext4_error_file(struct file *file, const char *function,
|
|
|
ext4_handle_error(inode->i_sb);
|
|
|
}
|
|
|
|
|
|
-static const char *ext4_decode_error(struct super_block *sb, int errno,
|
|
|
- char nbuf[16])
|
|
|
+const char *ext4_decode_error(struct super_block *sb, int errno,
|
|
|
+ char nbuf[16])
|
|
|
{
|
|
|
char *errstr = NULL;
|
|
|
|
|
@@ -858,6 +755,7 @@ static void ext4_put_super(struct super_block *sb)
|
|
|
ext4_abort(sb, "Couldn't clean up the journal");
|
|
|
}
|
|
|
|
|
|
+ ext4_es_unregister_shrinker(sb);
|
|
|
del_timer(&sbi->s_err_report);
|
|
|
ext4_release_system_zone(sb);
|
|
|
ext4_mb_release(sb);
|
|
@@ -939,11 +837,12 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
|
|
|
return 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);
|
|
|
ext4_es_init_tree(&ei->i_es_tree);
|
|
|
rwlock_init(&ei->i_es_lock);
|
|
|
+ INIT_LIST_HEAD(&ei->i_es_lru);
|
|
|
+ ei->i_es_lru_nr = 0;
|
|
|
ei->i_reserved_data_blocks = 0;
|
|
|
ei->i_reserved_meta_blocks = 0;
|
|
|
ei->i_allocated_meta_blocks = 0;
|
|
@@ -960,6 +859,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
|
|
|
ei->i_datasync_tid = 0;
|
|
|
atomic_set(&ei->i_ioend_count, 0);
|
|
|
atomic_set(&ei->i_unwritten, 0);
|
|
|
+ INIT_WORK(&ei->i_unwritten_work, ext4_end_io_work);
|
|
|
|
|
|
return &ei->vfs_inode;
|
|
|
}
|
|
@@ -1031,6 +931,7 @@ void ext4_clear_inode(struct inode *inode)
|
|
|
dquot_drop(inode);
|
|
|
ext4_discard_preallocations(inode);
|
|
|
ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS);
|
|
|
+ ext4_es_lru_del(inode);
|
|
|
if (EXT4_I(inode)->jinode) {
|
|
|
jbd2_journal_release_jbd_inode(EXT4_JOURNAL(inode),
|
|
|
EXT4_I(inode)->jinode);
|
|
@@ -1280,8 +1181,8 @@ static const match_table_t tokens = {
|
|
|
{Opt_stripe, "stripe=%u"},
|
|
|
{Opt_delalloc, "delalloc"},
|
|
|
{Opt_nodelalloc, "nodelalloc"},
|
|
|
- {Opt_mblk_io_submit, "mblk_io_submit"},
|
|
|
- {Opt_nomblk_io_submit, "nomblk_io_submit"},
|
|
|
+ {Opt_removed, "mblk_io_submit"},
|
|
|
+ {Opt_removed, "nomblk_io_submit"},
|
|
|
{Opt_block_validity, "block_validity"},
|
|
|
{Opt_noblock_validity, "noblock_validity"},
|
|
|
{Opt_inode_readahead_blks, "inode_readahead_blks=%u"},
|
|
@@ -1337,6 +1238,7 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
|
|
|
{
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
|
|
char *qname;
|
|
|
+ int ret = -1;
|
|
|
|
|
|
if (sb_any_quota_loaded(sb) &&
|
|
|
!sbi->s_qf_names[qtype]) {
|
|
@@ -1351,23 +1253,26 @@ static int set_qf_name(struct super_block *sb, int qtype, substring_t *args)
|
|
|
"Not enough memory for storing quotafile name");
|
|
|
return -1;
|
|
|
}
|
|
|
- if (sbi->s_qf_names[qtype] &&
|
|
|
- strcmp(sbi->s_qf_names[qtype], qname)) {
|
|
|
- ext4_msg(sb, KERN_ERR,
|
|
|
- "%s quota file already specified", QTYPE2NAME(qtype));
|
|
|
- kfree(qname);
|
|
|
- return -1;
|
|
|
+ if (sbi->s_qf_names[qtype]) {
|
|
|
+ if (strcmp(sbi->s_qf_names[qtype], qname) == 0)
|
|
|
+ ret = 1;
|
|
|
+ else
|
|
|
+ ext4_msg(sb, KERN_ERR,
|
|
|
+ "%s quota file already specified",
|
|
|
+ QTYPE2NAME(qtype));
|
|
|
+ goto errout;
|
|
|
}
|
|
|
- sbi->s_qf_names[qtype] = qname;
|
|
|
- if (strchr(sbi->s_qf_names[qtype], '/')) {
|
|
|
+ if (strchr(qname, '/')) {
|
|
|
ext4_msg(sb, KERN_ERR,
|
|
|
"quotafile must be on filesystem root");
|
|
|
- kfree(sbi->s_qf_names[qtype]);
|
|
|
- sbi->s_qf_names[qtype] = NULL;
|
|
|
- return -1;
|
|
|
+ goto errout;
|
|
|
}
|
|
|
+ sbi->s_qf_names[qtype] = qname;
|
|
|
set_opt(sb, QUOTA);
|
|
|
return 1;
|
|
|
+errout:
|
|
|
+ kfree(qname);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
static int clear_qf_name(struct super_block *sb, int qtype)
|
|
@@ -1381,10 +1286,7 @@ static int clear_qf_name(struct super_block *sb, int qtype)
|
|
|
" when quota turned on");
|
|
|
return -1;
|
|
|
}
|
|
|
- /*
|
|
|
- * The space will be released later when all options are confirmed
|
|
|
- * to be correct
|
|
|
- */
|
|
|
+ kfree(sbi->s_qf_names[qtype]);
|
|
|
sbi->s_qf_names[qtype] = NULL;
|
|
|
return 1;
|
|
|
}
|
|
@@ -1404,6 +1306,9 @@ static int clear_qf_name(struct super_block *sb, int qtype)
|
|
|
#define MOPT_QFMT MOPT_NOSUPPORT
|
|
|
#endif
|
|
|
#define MOPT_DATAJ 0x0080
|
|
|
+#define MOPT_NO_EXT2 0x0100
|
|
|
+#define MOPT_NO_EXT3 0x0200
|
|
|
+#define MOPT_EXT4_ONLY (MOPT_NO_EXT2 | MOPT_NO_EXT3)
|
|
|
|
|
|
static const struct mount_opts {
|
|
|
int token;
|
|
@@ -1414,25 +1319,31 @@ static const struct mount_opts {
|
|
|
{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_dioread_nolock, EXT4_MOUNT_DIOREAD_NOLOCK,
|
|
|
+ MOPT_EXT4_ONLY | MOPT_SET},
|
|
|
+ {Opt_dioread_lock, EXT4_MOUNT_DIOREAD_NOLOCK,
|
|
|
+ MOPT_EXT4_ONLY | 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_delalloc, EXT4_MOUNT_DELALLOC,
|
|
|
+ MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT},
|
|
|
+ {Opt_nodelalloc, EXT4_MOUNT_DELALLOC,
|
|
|
+ MOPT_EXT4_ONLY | MOPT_CLEAR | MOPT_EXPLICIT},
|
|
|
+ {Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM,
|
|
|
+ MOPT_EXT4_ONLY | MOPT_SET},
|
|
|
{Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT |
|
|
|
- EXT4_MOUNT_JOURNAL_CHECKSUM), MOPT_SET},
|
|
|
- {Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_SET},
|
|
|
+ EXT4_MOUNT_JOURNAL_CHECKSUM),
|
|
|
+ MOPT_EXT4_ONLY | MOPT_SET},
|
|
|
+ {Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_NO_EXT2 | 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_data_err_abort, EXT4_MOUNT_DATA_ERR_ABORT,
|
|
|
+ MOPT_NO_EXT2 | MOPT_SET},
|
|
|
+ {Opt_data_err_ignore, EXT4_MOUNT_DATA_ERR_ABORT,
|
|
|
+ MOPT_NO_EXT2 | 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},
|
|
@@ -1444,9 +1355,14 @@ static const struct mount_opts {
|
|
|
{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},
|
|
|
+ {Opt_resuid, 0, MOPT_GTE0},
|
|
|
+ {Opt_resgid, 0, MOPT_GTE0},
|
|
|
+ {Opt_journal_dev, 0, MOPT_GTE0},
|
|
|
+ {Opt_journal_ioprio, 0, MOPT_GTE0},
|
|
|
+ {Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_NO_EXT2 | MOPT_DATAJ},
|
|
|
+ {Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_NO_EXT2 | MOPT_DATAJ},
|
|
|
+ {Opt_data_writeback, EXT4_MOUNT_WRITEBACK_DATA,
|
|
|
+ MOPT_NO_EXT2 | MOPT_DATAJ},
|
|
|
{Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET},
|
|
|
{Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR},
|
|
|
#ifdef CONFIG_EXT4_FS_POSIX_ACL
|
|
@@ -1496,8 +1412,6 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
|
|
else if (token == Opt_offgrpjquota)
|
|
|
return clear_qf_name(sb, GRPQUOTA);
|
|
|
#endif
|
|
|
- if (args->from && match_int(args, &arg))
|
|
|
- return -1;
|
|
|
switch (token) {
|
|
|
case Opt_noacl:
|
|
|
case Opt_nouser_xattr:
|
|
@@ -1506,138 +1420,149 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
|
|
case Opt_sb:
|
|
|
return 1; /* handled by get_sb_block() */
|
|
|
case Opt_removed:
|
|
|
- ext4_msg(sb, KERN_WARNING,
|
|
|
- "Ignoring removed %s option", opt);
|
|
|
+ ext4_msg(sb, KERN_WARNING, "Ignoring removed %s option", opt);
|
|
|
+ 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_resuid:
|
|
|
+ }
|
|
|
+
|
|
|
+ for (m = ext4_mount_opts; m->token != Opt_err; m++)
|
|
|
+ if (token == m->token)
|
|
|
+ break;
|
|
|
+
|
|
|
+ if (m->token == Opt_err) {
|
|
|
+ ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" "
|
|
|
+ "or missing value", opt);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((m->flags & MOPT_NO_EXT2) && IS_EXT2_SB(sb)) {
|
|
|
+ ext4_msg(sb, KERN_ERR,
|
|
|
+ "Mount option \"%s\" incompatible with ext2", opt);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ if ((m->flags & MOPT_NO_EXT3) && IS_EXT3_SB(sb)) {
|
|
|
+ ext4_msg(sb, KERN_ERR,
|
|
|
+ "Mount option \"%s\" incompatible with ext3", opt);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (args->from && match_int(args, &arg))
|
|
|
+ return -1;
|
|
|
+ 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 && (arg > (1 << 30) || !is_power_of_2(arg))) {
|
|
|
+ ext4_msg(sb, KERN_ERR,
|
|
|
+ "EXT4-fs: inode_readahead_blks must be "
|
|
|
+ "0 or a power of 2 smaller than 2^31");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ 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_max_dir_size_kb) {
|
|
|
+ sbi->s_max_dir_size_kb = arg;
|
|
|
+ } else if (token == Opt_stripe) {
|
|
|
+ sbi->s_stripe = arg;
|
|
|
+ } else if (token == Opt_resuid) {
|
|
|
uid = make_kuid(current_user_ns(), arg);
|
|
|
if (!uid_valid(uid)) {
|
|
|
ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg);
|
|
|
return -1;
|
|
|
}
|
|
|
sbi->s_resuid = uid;
|
|
|
- return 1;
|
|
|
- case Opt_resgid:
|
|
|
+ } else if (token == Opt_resgid) {
|
|
|
gid = make_kgid(current_user_ns(), arg);
|
|
|
if (!gid_valid(gid)) {
|
|
|
ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg);
|
|
|
return -1;
|
|
|
}
|
|
|
sbi->s_resgid = gid;
|
|
|
- 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:
|
|
|
+ } else if (token == 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");
|
|
|
+ } else if (token == Opt_journal_ioprio) {
|
|
|
+ if (arg > 7) {
|
|
|
+ ext4_msg(sb, KERN_ERR, "Invalid journal IO priority"
|
|
|
+ " (must be 0-7)");
|
|
|
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)) {
|
|
|
+ *journal_ioprio =
|
|
|
+ IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 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) != m->mount_opt) {
|
|
|
ext4_msg(sb, KERN_ERR,
|
|
|
- "EXT4-fs: inode_readahead_blks"
|
|
|
- " must be a power of 2");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- 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_max_dir_size_kb) {
|
|
|
- sbi->s_max_dir_size_kb = 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) !=
|
|
|
- m->mount_opt) {
|
|
|
- ext4_msg(sb, KERN_ERR,
|
|
|
"Cannot change data mode on remount");
|
|
|
- return -1;
|
|
|
- }
|
|
|
- } else {
|
|
|
- clear_opt(sb, DATA_FLAGS);
|
|
|
- sbi->s_mount_opt |= m->mount_opt;
|
|
|
- }
|
|
|
-#ifdef CONFIG_QUOTA
|
|
|
- } else if (m->flags & MOPT_QFMT) {
|
|
|
- if (sb_any_quota_loaded(sb) &&
|
|
|
- sbi->s_jquota_fmt != m->mount_opt) {
|
|
|
- ext4_msg(sb, KERN_ERR, "Cannot "
|
|
|
- "change journaled quota options "
|
|
|
- "when quota turned on");
|
|
|
return -1;
|
|
|
}
|
|
|
- sbi->s_jquota_fmt = m->mount_opt;
|
|
|
-#endif
|
|
|
} 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;
|
|
|
- }
|
|
|
- if (arg != 0)
|
|
|
- sbi->s_mount_opt |= m->mount_opt;
|
|
|
- else
|
|
|
- sbi->s_mount_opt &= ~m->mount_opt;
|
|
|
+ clear_opt(sb, DATA_FLAGS);
|
|
|
+ sbi->s_mount_opt |= m->mount_opt;
|
|
|
}
|
|
|
- return 1;
|
|
|
+#ifdef CONFIG_QUOTA
|
|
|
+ } else if (m->flags & MOPT_QFMT) {
|
|
|
+ if (sb_any_quota_loaded(sb) &&
|
|
|
+ sbi->s_jquota_fmt != m->mount_opt) {
|
|
|
+ ext4_msg(sb, KERN_ERR, "Cannot change journaled "
|
|
|
+ "quota options when quota turned on");
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+ sbi->s_jquota_fmt = m->mount_opt;
|
|
|
+#endif
|
|
|
+ } 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;
|
|
|
+ }
|
|
|
+ if (arg != 0)
|
|
|
+ sbi->s_mount_opt |= m->mount_opt;
|
|
|
+ else
|
|
|
+ sbi->s_mount_opt &= ~m->mount_opt;
|
|
|
}
|
|
|
- ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" "
|
|
|
- "or missing value", opt);
|
|
|
- return -1;
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
static int parse_options(char *options, struct super_block *sb,
|
|
@@ -2776,7 +2701,7 @@ static int ext4_run_li_request(struct ext4_li_request *elr)
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (group == ngroups)
|
|
|
+ if (group >= ngroups)
|
|
|
ret = 1;
|
|
|
|
|
|
if (!ret) {
|
|
@@ -3016,33 +2941,34 @@ static struct ext4_li_request *ext4_li_request_new(struct super_block *sb,
|
|
|
return elr;
|
|
|
}
|
|
|
|
|
|
-static int ext4_register_li_request(struct super_block *sb,
|
|
|
- ext4_group_t first_not_zeroed)
|
|
|
+int ext4_register_li_request(struct super_block *sb,
|
|
|
+ ext4_group_t first_not_zeroed)
|
|
|
{
|
|
|
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
|
|
- struct ext4_li_request *elr;
|
|
|
+ struct ext4_li_request *elr = NULL;
|
|
|
ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
|
|
|
int ret = 0;
|
|
|
|
|
|
+ mutex_lock(&ext4_li_mtx);
|
|
|
if (sbi->s_li_request != NULL) {
|
|
|
/*
|
|
|
* Reset timeout so it can be computed again, because
|
|
|
* s_li_wait_mult might have changed.
|
|
|
*/
|
|
|
sbi->s_li_request->lr_timeout = 0;
|
|
|
- return 0;
|
|
|
+ goto out;
|
|
|
}
|
|
|
|
|
|
if (first_not_zeroed == ngroups ||
|
|
|
(sb->s_flags & MS_RDONLY) ||
|
|
|
!test_opt(sb, INIT_INODE_TABLE))
|
|
|
- return 0;
|
|
|
+ goto out;
|
|
|
|
|
|
elr = ext4_li_request_new(sb, first_not_zeroed);
|
|
|
- if (!elr)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- mutex_lock(&ext4_li_mtx);
|
|
|
+ if (!elr) {
|
|
|
+ ret = -ENOMEM;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
|
|
|
if (NULL == ext4_li_info) {
|
|
|
ret = ext4_li_info_new();
|
|
@@ -3379,7 +3305,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|
|
#ifdef CONFIG_EXT4_FS_POSIX_ACL
|
|
|
set_opt(sb, POSIX_ACL);
|
|
|
#endif
|
|
|
- set_opt(sb, MBLK_IO_SUBMIT);
|
|
|
if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA)
|
|
|
set_opt(sb, JOURNAL_DATA);
|
|
|
else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED)
|
|
@@ -3772,6 +3697,9 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|
|
sbi->s_max_writeback_mb_bump = 128;
|
|
|
sbi->s_extent_max_zeroout_kb = 32;
|
|
|
|
|
|
+ /* Register extent status tree shrinker */
|
|
|
+ ext4_es_register_shrinker(sb);
|
|
|
+
|
|
|
/*
|
|
|
* set up enough so that it can read an inode
|
|
|
*/
|
|
@@ -4008,7 +3936,7 @@ no_journal:
|
|
|
!(sb->s_flags & MS_RDONLY)) {
|
|
|
err = ext4_enable_quotas(sb);
|
|
|
if (err)
|
|
|
- goto failed_mount7;
|
|
|
+ goto failed_mount8;
|
|
|
}
|
|
|
#endif /* CONFIG_QUOTA */
|
|
|
|
|
@@ -4035,6 +3963,10 @@ cantfind_ext4:
|
|
|
ext4_msg(sb, KERN_ERR, "VFS: Can't find ext4 filesystem");
|
|
|
goto failed_mount;
|
|
|
|
|
|
+#ifdef CONFIG_QUOTA
|
|
|
+failed_mount8:
|
|
|
+ kobject_del(&sbi->s_kobj);
|
|
|
+#endif
|
|
|
failed_mount7:
|
|
|
ext4_unregister_li_request(sb);
|
|
|
failed_mount6:
|
|
@@ -4476,16 +4408,12 @@ static void ext4_clear_journal_err(struct super_block *sb,
|
|
|
int ext4_force_commit(struct super_block *sb)
|
|
|
{
|
|
|
journal_t *journal;
|
|
|
- int ret = 0;
|
|
|
|
|
|
if (sb->s_flags & MS_RDONLY)
|
|
|
return 0;
|
|
|
|
|
|
journal = EXT4_SB(sb)->s_journal;
|
|
|
- if (journal)
|
|
|
- ret = ext4_journal_force_commit(journal);
|
|
|
-
|
|
|
- return ret;
|
|
|
+ return ext4_journal_force_commit(journal);
|
|
|
}
|
|
|
|
|
|
static int ext4_sync_fs(struct super_block *sb, int wait)
|
|
@@ -4588,7 +4516,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|
|
unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO;
|
|
|
int err = 0;
|
|
|
#ifdef CONFIG_QUOTA
|
|
|
- int i;
|
|
|
+ int i, j;
|
|
|
#endif
|
|
|
char *orig_data = kstrdup(data, GFP_KERNEL);
|
|
|
|
|
@@ -4604,7 +4532,16 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|
|
#ifdef CONFIG_QUOTA
|
|
|
old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
|
|
|
for (i = 0; i < MAXQUOTAS; i++)
|
|
|
- old_opts.s_qf_names[i] = sbi->s_qf_names[i];
|
|
|
+ if (sbi->s_qf_names[i]) {
|
|
|
+ old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i],
|
|
|
+ GFP_KERNEL);
|
|
|
+ if (!old_opts.s_qf_names[i]) {
|
|
|
+ for (j = 0; j < i; j++)
|
|
|
+ kfree(old_opts.s_qf_names[j]);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+ } else
|
|
|
+ old_opts.s_qf_names[i] = NULL;
|
|
|
#endif
|
|
|
if (sbi->s_journal && sbi->s_journal->j_task->io_context)
|
|
|
journal_ioprio = sbi->s_journal->j_task->io_context->ioprio;
|
|
@@ -4737,9 +4674,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|
|
#ifdef CONFIG_QUOTA
|
|
|
/* Release old quota file names */
|
|
|
for (i = 0; i < MAXQUOTAS; i++)
|
|
|
- if (old_opts.s_qf_names[i] &&
|
|
|
- old_opts.s_qf_names[i] != sbi->s_qf_names[i])
|
|
|
- kfree(old_opts.s_qf_names[i]);
|
|
|
+ kfree(old_opts.s_qf_names[i]);
|
|
|
if (enable_quota) {
|
|
|
if (sb_any_quota_suspended(sb))
|
|
|
dquot_resume(sb, -1);
|
|
@@ -4768,9 +4703,7 @@ restore_opts:
|
|
|
#ifdef CONFIG_QUOTA
|
|
|
sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
|
|
|
for (i = 0; i < MAXQUOTAS; i++) {
|
|
|
- if (sbi->s_qf_names[i] &&
|
|
|
- old_opts.s_qf_names[i] != sbi->s_qf_names[i])
|
|
|
- kfree(sbi->s_qf_names[i]);
|
|
|
+ kfree(sbi->s_qf_names[i]);
|
|
|
sbi->s_qf_names[i] = old_opts.s_qf_names[i];
|
|
|
}
|
|
|
#endif
|
|
@@ -4835,7 +4768,7 @@ static int ext4_write_dquot(struct dquot *dquot)
|
|
|
struct inode *inode;
|
|
|
|
|
|
inode = dquot_to_inode(dquot);
|
|
|
- handle = ext4_journal_start(inode,
|
|
|
+ handle = ext4_journal_start(inode, EXT4_HT_QUOTA,
|
|
|
EXT4_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
|
|
|
if (IS_ERR(handle))
|
|
|
return PTR_ERR(handle);
|
|
@@ -4851,7 +4784,7 @@ static int ext4_acquire_dquot(struct dquot *dquot)
|
|
|
int ret, err;
|
|
|
handle_t *handle;
|
|
|
|
|
|
- handle = ext4_journal_start(dquot_to_inode(dquot),
|
|
|
+ handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA,
|
|
|
EXT4_QUOTA_INIT_BLOCKS(dquot->dq_sb));
|
|
|
if (IS_ERR(handle))
|
|
|
return PTR_ERR(handle);
|
|
@@ -4867,7 +4800,7 @@ static int ext4_release_dquot(struct dquot *dquot)
|
|
|
int ret, err;
|
|
|
handle_t *handle;
|
|
|
|
|
|
- handle = ext4_journal_start(dquot_to_inode(dquot),
|
|
|
+ handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA,
|
|
|
EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb));
|
|
|
if (IS_ERR(handle)) {
|
|
|
/* Release dquot anyway to avoid endless cycle in dqput() */
|
|
@@ -4899,7 +4832,7 @@ static int ext4_write_info(struct super_block *sb, int type)
|
|
|
handle_t *handle;
|
|
|
|
|
|
/* Data block + inode block */
|
|
|
- handle = ext4_journal_start(sb->s_root->d_inode, 2);
|
|
|
+ handle = ext4_journal_start(sb->s_root->d_inode, EXT4_HT_QUOTA, 2);
|
|
|
if (IS_ERR(handle))
|
|
|
return PTR_ERR(handle);
|
|
|
ret = dquot_commit_info(sb, type);
|
|
@@ -5005,9 +4938,9 @@ static int ext4_enable_quotas(struct super_block *sb)
|
|
|
DQUOT_USAGE_ENABLED);
|
|
|
if (err) {
|
|
|
ext4_warning(sb,
|
|
|
- "Failed to enable quota (type=%d) "
|
|
|
- "tracking. Please run e2fsck to fix.",
|
|
|
- type);
|
|
|
+ "Failed to enable quota tracking "
|
|
|
+ "(type=%d, err=%d). Please run "
|
|
|
+ "e2fsck to fix.", type, err);
|
|
|
return err;
|
|
|
}
|
|
|
}
|
|
@@ -5045,7 +4978,7 @@ static int ext4_quota_off(struct super_block *sb, int type)
|
|
|
|
|
|
/* Update modification times of quota files when userspace can
|
|
|
* start looking at them */
|
|
|
- handle = ext4_journal_start(inode, 1);
|
|
|
+ handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 1);
|
|
|
if (IS_ERR(handle))
|
|
|
goto out;
|
|
|
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|