Merge tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull ext4 updates from Ted Ts'o: "The big new feature added this time is supporting online resizing using the meta_bg feature. This allows us to resize file systems which are greater than 16TB. In addition, the speed of online resizing has been improved in general. We also fix a number of races, some of which could lead to deadlocks, in ext4's Asynchronous I/O and online defrag support, thanks to good work by Dmitry Monakhov. There are also a large number of more minor bug fixes and cleanups from a number of other ext4 contributors, quite of few of which have submitted fixes for the first time." * tag 'ext4_for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: (69 commits) ext4: fix ext4_flush_completed_IO wait semantics ext4: fix mtime update in nodelalloc mode ext4: fix ext_remove_space for punch_hole case ext4: punch_hole should wait for DIO writers ext4: serialize truncate with owerwrite DIO workers ext4: endless truncate due to nonlocked dio readers ext4: serialize unlocked dio reads with truncate ext4: serialize dio nonlocked reads with defrag workers ext4: completed_io locking cleanup ext4: fix unwritten counter leakage ext4: give i_aiodio_unwritten a more appropriate name ext4: ext4_inode_info diet ext4: convert to use leXX_add_cpu() ext4: ext4_bread usage audit fs: reserve fallocate flag codepoint ext4: remove redundant offset check in mext_check_arguments() ext4: don't clear orphan list on ro mount with errors jbd2: fix assertion failure in commit code due to lacking transaction credits ext4: release donor reference when EXT4_IOC_MOVE_EXT ioctl fails ext4: enable FITRIM ioctl on bigalloc file system ...
This commit is contained in:
@@ -420,7 +420,7 @@ static void __save_error_info(struct super_block *sb, const char *func,
|
||||
*/
|
||||
if (!es->s_error_count)
|
||||
mod_timer(&EXT4_SB(sb)->s_err_report, jiffies + 24*60*60*HZ);
|
||||
es->s_error_count = cpu_to_le32(le32_to_cpu(es->s_error_count) + 1);
|
||||
le32_add_cpu(&es->s_error_count, 1);
|
||||
}
|
||||
|
||||
static void save_error_info(struct super_block *sb, const char *func,
|
||||
@@ -850,7 +850,6 @@ static void ext4_put_super(struct super_block *sb)
|
||||
flush_workqueue(sbi->dio_unwritten_wq);
|
||||
destroy_workqueue(sbi->dio_unwritten_wq);
|
||||
|
||||
lock_super(sb);
|
||||
if (sbi->s_journal) {
|
||||
err = jbd2_journal_destroy(sbi->s_journal);
|
||||
sbi->s_journal = NULL;
|
||||
@@ -917,7 +916,6 @@ static void ext4_put_super(struct super_block *sb)
|
||||
* Now that we are completely done shutting down the
|
||||
* superblock, we need to actually destroy the kobject.
|
||||
*/
|
||||
unlock_super(sb);
|
||||
kobject_put(&sbi->s_kobj);
|
||||
wait_for_completion(&sbi->s_kobj_unregister);
|
||||
if (sbi->s_chksum_driver)
|
||||
@@ -956,11 +954,10 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
|
||||
ei->jinode = NULL;
|
||||
INIT_LIST_HEAD(&ei->i_completed_io_list);
|
||||
spin_lock_init(&ei->i_completed_io_lock);
|
||||
ei->cur_aio_dio = NULL;
|
||||
ei->i_sync_tid = 0;
|
||||
ei->i_datasync_tid = 0;
|
||||
atomic_set(&ei->i_ioend_count, 0);
|
||||
atomic_set(&ei->i_aiodio_unwritten, 0);
|
||||
atomic_set(&ei->i_unwritten, 0);
|
||||
|
||||
return &ei->vfs_inode;
|
||||
}
|
||||
@@ -1224,6 +1221,7 @@ enum {
|
||||
Opt_inode_readahead_blks, Opt_journal_ioprio,
|
||||
Opt_dioread_nolock, Opt_dioread_lock,
|
||||
Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable,
|
||||
Opt_max_dir_size_kb,
|
||||
};
|
||||
|
||||
static const match_table_t tokens = {
|
||||
@@ -1297,6 +1295,7 @@ static const match_table_t tokens = {
|
||||
{Opt_init_itable, "init_itable=%u"},
|
||||
{Opt_init_itable, "init_itable"},
|
||||
{Opt_noinit_itable, "noinit_itable"},
|
||||
{Opt_max_dir_size_kb, "max_dir_size_kb=%u"},
|
||||
{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 */
|
||||
@@ -1477,6 +1476,7 @@ static const struct mount_opts {
|
||||
{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_max_dir_size_kb, 0, MOPT_GTE0},
|
||||
{Opt_err, 0, 0}
|
||||
};
|
||||
|
||||
@@ -1592,6 +1592,8 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
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) {
|
||||
@@ -1664,7 +1666,7 @@ static int parse_options(char *options, struct super_block *sb,
|
||||
* Initialize args struct so we know whether arg was
|
||||
* found; some options take optional arguments.
|
||||
*/
|
||||
args[0].to = args[0].from = 0;
|
||||
args[0].to = args[0].from = NULL;
|
||||
token = match_token(p, tokens, args);
|
||||
if (handle_mount_opt(sb, p, token, args, journal_devnum,
|
||||
journal_ioprio, is_remount) < 0)
|
||||
@@ -1740,7 +1742,7 @@ static inline void ext4_show_quota_options(struct seq_file *seq,
|
||||
|
||||
static const char *token2str(int token)
|
||||
{
|
||||
static const struct match_token *t;
|
||||
const struct match_token *t;
|
||||
|
||||
for (t = tokens; t->token != Opt_err; t++)
|
||||
if (t->token == token && !strchr(t->pattern, '='))
|
||||
@@ -1823,6 +1825,8 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
|
||||
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);
|
||||
if (nodefs || sbi->s_max_dir_size_kb)
|
||||
SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb);
|
||||
|
||||
ext4_show_quota_options(seq, sb);
|
||||
return 0;
|
||||
@@ -1914,15 +1918,45 @@ done:
|
||||
return res;
|
||||
}
|
||||
|
||||
int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
struct flex_groups *new_groups;
|
||||
int size;
|
||||
|
||||
if (!sbi->s_log_groups_per_flex)
|
||||
return 0;
|
||||
|
||||
size = ext4_flex_group(sbi, ngroup - 1) + 1;
|
||||
if (size <= sbi->s_flex_groups_allocated)
|
||||
return 0;
|
||||
|
||||
size = roundup_pow_of_two(size * sizeof(struct flex_groups));
|
||||
new_groups = ext4_kvzalloc(size, GFP_KERNEL);
|
||||
if (!new_groups) {
|
||||
ext4_msg(sb, KERN_ERR, "not enough memory for %d flex groups",
|
||||
size / (int) sizeof(struct flex_groups));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (sbi->s_flex_groups) {
|
||||
memcpy(new_groups, sbi->s_flex_groups,
|
||||
(sbi->s_flex_groups_allocated *
|
||||
sizeof(struct flex_groups)));
|
||||
ext4_kvfree(sbi->s_flex_groups);
|
||||
}
|
||||
sbi->s_flex_groups = new_groups;
|
||||
sbi->s_flex_groups_allocated = size / sizeof(struct flex_groups);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ext4_fill_flex_info(struct super_block *sb)
|
||||
{
|
||||
struct ext4_sb_info *sbi = EXT4_SB(sb);
|
||||
struct ext4_group_desc *gdp = NULL;
|
||||
ext4_group_t flex_group_count;
|
||||
ext4_group_t flex_group;
|
||||
unsigned int groups_per_flex = 0;
|
||||
size_t size;
|
||||
int i;
|
||||
int i, err;
|
||||
|
||||
sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex;
|
||||
if (sbi->s_log_groups_per_flex < 1 || sbi->s_log_groups_per_flex > 31) {
|
||||
@@ -1931,17 +1965,9 @@ static int ext4_fill_flex_info(struct super_block *sb)
|
||||
}
|
||||
groups_per_flex = 1 << sbi->s_log_groups_per_flex;
|
||||
|
||||
/* We allocate both existing and potentially added groups */
|
||||
flex_group_count = ((sbi->s_groups_count + groups_per_flex - 1) +
|
||||
((le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) + 1) <<
|
||||
EXT4_DESC_PER_BLOCK_BITS(sb))) / groups_per_flex;
|
||||
size = flex_group_count * sizeof(struct flex_groups);
|
||||
sbi->s_flex_groups = ext4_kvzalloc(size, GFP_KERNEL);
|
||||
if (sbi->s_flex_groups == NULL) {
|
||||
ext4_msg(sb, KERN_ERR, "not enough memory for %u flex groups",
|
||||
flex_group_count);
|
||||
err = ext4_alloc_flex_bg_array(sb, sbi->s_groups_count);
|
||||
if (err)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
for (i = 0; i < sbi->s_groups_count; i++) {
|
||||
gdp = ext4_get_group_desc(sb, i, NULL);
|
||||
@@ -2144,10 +2170,12 @@ static void ext4_orphan_cleanup(struct super_block *sb,
|
||||
}
|
||||
|
||||
if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) {
|
||||
if (es->s_last_orphan)
|
||||
/* don't clear list on RO mount w/ errors */
|
||||
if (es->s_last_orphan && !(s_flags & MS_RDONLY)) {
|
||||
jbd_debug(1, "Errors on filesystem, "
|
||||
"clearing orphan list.\n");
|
||||
es->s_last_orphan = 0;
|
||||
es->s_last_orphan = 0;
|
||||
}
|
||||
jbd_debug(1, "Skipping orphan recovery on fs with errors.\n");
|
||||
return;
|
||||
}
|
||||
@@ -2528,6 +2556,7 @@ EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs);
|
||||
EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request);
|
||||
EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc);
|
||||
EXT4_RW_ATTR_SBI_UI(max_writeback_mb_bump, s_max_writeback_mb_bump);
|
||||
EXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb);
|
||||
EXT4_ATTR(trigger_fs_error, 0200, NULL, trigger_test_error);
|
||||
|
||||
static struct attribute *ext4_attrs[] = {
|
||||
@@ -2543,6 +2572,7 @@ static struct attribute *ext4_attrs[] = {
|
||||
ATTR_LIST(mb_stream_req),
|
||||
ATTR_LIST(mb_group_prealloc),
|
||||
ATTR_LIST(max_writeback_mb_bump),
|
||||
ATTR_LIST(extent_max_zeroout_kb),
|
||||
ATTR_LIST(trigger_fs_error),
|
||||
NULL,
|
||||
};
|
||||
@@ -2550,10 +2580,12 @@ static struct attribute *ext4_attrs[] = {
|
||||
/* Features this copy of ext4 supports */
|
||||
EXT4_INFO_ATTR(lazy_itable_init);
|
||||
EXT4_INFO_ATTR(batched_discard);
|
||||
EXT4_INFO_ATTR(meta_bg_resize);
|
||||
|
||||
static struct attribute *ext4_feat_attrs[] = {
|
||||
ATTR_LIST(lazy_itable_init),
|
||||
ATTR_LIST(batched_discard),
|
||||
ATTR_LIST(meta_bg_resize),
|
||||
NULL,
|
||||
};
|
||||
|
||||
@@ -3374,7 +3406,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
* enable delayed allocation by default
|
||||
* Use -o nodelalloc to turn it off
|
||||
*/
|
||||
if (!IS_EXT3_SB(sb) &&
|
||||
if (!IS_EXT3_SB(sb) && !IS_EXT2_SB(sb) &&
|
||||
((def_mount_opts & EXT4_DEFM_NODELALLOC) == 0))
|
||||
set_opt(sb, DELALLOC);
|
||||
|
||||
@@ -3743,6 +3775,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
|
||||
sbi->s_stripe = ext4_get_stripe_size(sbi);
|
||||
sbi->s_max_writeback_mb_bump = 128;
|
||||
sbi->s_extent_max_zeroout_kb = 32;
|
||||
|
||||
/*
|
||||
* set up enough so that it can read an inode
|
||||
@@ -4519,11 +4552,9 @@ static int ext4_unfreeze(struct super_block *sb)
|
||||
if (sb->s_flags & MS_RDONLY)
|
||||
return 0;
|
||||
|
||||
lock_super(sb);
|
||||
/* Reset the needs_recovery flag before the fs is unlocked. */
|
||||
EXT4_SET_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
|
||||
ext4_commit_super(sb, 1);
|
||||
unlock_super(sb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4559,7 +4590,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
||||
char *orig_data = kstrdup(data, GFP_KERNEL);
|
||||
|
||||
/* Store the original options */
|
||||
lock_super(sb);
|
||||
old_sb_flags = sb->s_flags;
|
||||
old_opts.s_mount_opt = sbi->s_mount_opt;
|
||||
old_opts.s_mount_opt2 = sbi->s_mount_opt2;
|
||||
@@ -4701,7 +4731,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
||||
if (sbi->s_journal == NULL)
|
||||
ext4_commit_super(sb, 1);
|
||||
|
||||
unlock_super(sb);
|
||||
#ifdef CONFIG_QUOTA
|
||||
/* Release old quota file names */
|
||||
for (i = 0; i < MAXQUOTAS; i++)
|
||||
@@ -4714,10 +4743,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
||||
else if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
|
||||
EXT4_FEATURE_RO_COMPAT_QUOTA)) {
|
||||
err = ext4_enable_quotas(sb);
|
||||
if (err) {
|
||||
lock_super(sb);
|
||||
if (err)
|
||||
goto restore_opts;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -4744,7 +4771,6 @@ restore_opts:
|
||||
sbi->s_qf_names[i] = old_opts.s_qf_names[i];
|
||||
}
|
||||
#endif
|
||||
unlock_super(sb);
|
||||
kfree(orig_data);
|
||||
return err;
|
||||
}
|
||||
@@ -5269,8 +5295,10 @@ static int __init ext4_init_fs(void)
|
||||
if (err)
|
||||
goto out6;
|
||||
ext4_kset = kset_create_and_add("ext4", NULL, fs_kobj);
|
||||
if (!ext4_kset)
|
||||
if (!ext4_kset) {
|
||||
err = -ENOMEM;
|
||||
goto out5;
|
||||
}
|
||||
ext4_proc_root = proc_mkdir("fs/ext4", NULL);
|
||||
|
||||
err = ext4_init_feat_adverts();
|
||||
|
Reference in New Issue
Block a user