Merge tag 'ext4-for-linus-5.8-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4
Pull more ext4 updates from Ted Ts'o: "This is the second round of ext4 commits for 5.8 merge window [1]. It includes the per-inode DAX support, which was dependant on the DAX infrastructure which came in via the XFS tree, and a number of regression and bug fixes; most notably the "BUG: using smp_processor_id() in preemptible code in ext4_mb_new_blocks" reported by syzkaller" [1] The pull request actually came in 15 minutes after I had tagged the rc1 release. Tssk, tssk, late.. - Linus * tag 'ext4-for-linus-5.8-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4: ext4, jbd2: ensure panic by fix a race between jbd2 abort and ext4 error handlers ext4: support xattr gnu.* namespace for the Hurd ext4: mballoc: Use this_cpu_read instead of this_cpu_ptr ext4: avoid utf8_strncasecmp() with unstable name ext4: stop overwrite the errcode in ext4_setup_super ext4: fix partial cluster initialization when splitting extent ext4: avoid race conditions when remounting with options that change dax Documentation/dax: Update DAX enablement for ext4 fs/ext4: Introduce DAX inode flag fs/ext4: Remove jflag variable fs/ext4: Make DAX mount option a tri-state fs/ext4: Only change S_DAX on inode load fs/ext4: Update ext4_should_use_dax() fs/ext4: Change EXT4_MOUNT_DAX to EXT4_MOUNT_DAX_ALWAYS fs/ext4: Disallow verity if inode is DAX fs/ext4: Narrow scope of DAX check in setflags
This commit is contained in:
124
fs/ext4/super.c
124
fs/ext4/super.c
@@ -522,9 +522,6 @@ static void ext4_handle_error(struct super_block *sb)
|
||||
smp_wmb();
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
} else if (test_opt(sb, ERRORS_PANIC)) {
|
||||
if (EXT4_SB(sb)->s_journal &&
|
||||
!(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
|
||||
return;
|
||||
panic("EXT4-fs (device %s): panic forced after error\n",
|
||||
sb->s_id);
|
||||
}
|
||||
@@ -725,23 +722,20 @@ void __ext4_abort(struct super_block *sb, const char *function,
|
||||
va_end(args);
|
||||
|
||||
if (sb_rdonly(sb) == 0) {
|
||||
ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
|
||||
EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
|
||||
if (EXT4_SB(sb)->s_journal)
|
||||
jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
|
||||
|
||||
ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
|
||||
/*
|
||||
* Make sure updated value of ->s_mount_flags will be visible
|
||||
* before ->s_flags update
|
||||
*/
|
||||
smp_wmb();
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
if (EXT4_SB(sb)->s_journal)
|
||||
jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
|
||||
}
|
||||
if (test_opt(sb, ERRORS_PANIC) && !system_going_down()) {
|
||||
if (EXT4_SB(sb)->s_journal &&
|
||||
!(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
|
||||
return;
|
||||
if (test_opt(sb, ERRORS_PANIC) && !system_going_down())
|
||||
panic("EXT4-fs panic from previous error\n");
|
||||
}
|
||||
}
|
||||
|
||||
void __ext4_msg(struct super_block *sb,
|
||||
@@ -1324,6 +1318,9 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
|
||||
if (WARN_ON_ONCE(IS_DAX(inode) && i_size_read(inode)))
|
||||
return -EINVAL;
|
||||
|
||||
if (ext4_test_inode_flag(inode, EXT4_INODE_DAX))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
res = ext4_convert_inline_data(inode);
|
||||
if (res)
|
||||
return res;
|
||||
@@ -1349,7 +1346,7 @@ static int ext4_set_context(struct inode *inode, const void *ctx, size_t len,
|
||||
* Update inode->i_flags - S_ENCRYPTED will be enabled,
|
||||
* S_DAX may be disabled
|
||||
*/
|
||||
ext4_set_inode_flags(inode);
|
||||
ext4_set_inode_flags(inode, false);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -1376,7 +1373,7 @@ retry:
|
||||
* Update inode->i_flags - S_ENCRYPTED will be enabled,
|
||||
* S_DAX may be disabled
|
||||
*/
|
||||
ext4_set_inode_flags(inode);
|
||||
ext4_set_inode_flags(inode, false);
|
||||
res = ext4_mark_inode_dirty(handle, inode);
|
||||
if (res)
|
||||
EXT4_ERROR_INODE(inode, "Failed to mark inode dirty");
|
||||
@@ -1514,7 +1511,8 @@ enum {
|
||||
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
|
||||
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
|
||||
Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err,
|
||||
Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version, Opt_dax,
|
||||
Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version,
|
||||
Opt_dax, Opt_dax_always, Opt_dax_inode, Opt_dax_never,
|
||||
Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_warn_on_error,
|
||||
Opt_nowarn_on_error, Opt_mblk_io_submit,
|
||||
Opt_lazytime, Opt_nolazytime, Opt_debug_want_extra_isize,
|
||||
@@ -1581,6 +1579,9 @@ static const match_table_t tokens = {
|
||||
{Opt_nobarrier, "nobarrier"},
|
||||
{Opt_i_version, "i_version"},
|
||||
{Opt_dax, "dax"},
|
||||
{Opt_dax_always, "dax=always"},
|
||||
{Opt_dax_inode, "dax=inode"},
|
||||
{Opt_dax_never, "dax=never"},
|
||||
{Opt_stripe, "stripe=%u"},
|
||||
{Opt_delalloc, "delalloc"},
|
||||
{Opt_warn_on_error, "warn_on_error"},
|
||||
@@ -1729,6 +1730,7 @@ static int clear_qf_name(struct super_block *sb, int qtype)
|
||||
#define MOPT_NO_EXT3 0x0200
|
||||
#define MOPT_EXT4_ONLY (MOPT_NO_EXT2 | MOPT_NO_EXT3)
|
||||
#define MOPT_STRING 0x0400
|
||||
#define MOPT_SKIP 0x0800
|
||||
|
||||
static const struct mount_opts {
|
||||
int token;
|
||||
@@ -1778,7 +1780,13 @@ static const struct mount_opts {
|
||||
{Opt_min_batch_time, 0, MOPT_GTE0},
|
||||
{Opt_inode_readahead_blks, 0, MOPT_GTE0},
|
||||
{Opt_init_itable, 0, MOPT_GTE0},
|
||||
{Opt_dax, EXT4_MOUNT_DAX, MOPT_SET},
|
||||
{Opt_dax, EXT4_MOUNT_DAX_ALWAYS, MOPT_SET | MOPT_SKIP},
|
||||
{Opt_dax_always, EXT4_MOUNT_DAX_ALWAYS,
|
||||
MOPT_EXT4_ONLY | MOPT_SET | MOPT_SKIP},
|
||||
{Opt_dax_inode, EXT4_MOUNT2_DAX_INODE,
|
||||
MOPT_EXT4_ONLY | MOPT_SET | MOPT_SKIP},
|
||||
{Opt_dax_never, EXT4_MOUNT2_DAX_NEVER,
|
||||
MOPT_EXT4_ONLY | MOPT_SET | MOPT_SKIP},
|
||||
{Opt_stripe, 0, MOPT_GTE0},
|
||||
{Opt_resuid, 0, MOPT_GTE0},
|
||||
{Opt_resgid, 0, MOPT_GTE0},
|
||||
@@ -2123,13 +2131,56 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
||||
}
|
||||
sbi->s_jquota_fmt = m->mount_opt;
|
||||
#endif
|
||||
} else if (token == Opt_dax) {
|
||||
} else if (token == Opt_dax || token == Opt_dax_always ||
|
||||
token == Opt_dax_inode || token == Opt_dax_never) {
|
||||
#ifdef CONFIG_FS_DAX
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
|
||||
sbi->s_mount_opt |= m->mount_opt;
|
||||
switch (token) {
|
||||
case Opt_dax:
|
||||
case Opt_dax_always:
|
||||
if (is_remount &&
|
||||
(!(sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) ||
|
||||
(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER))) {
|
||||
fail_dax_change_remount:
|
||||
ext4_msg(sb, KERN_ERR, "can't change "
|
||||
"dax mount option while remounting");
|
||||
return -1;
|
||||
}
|
||||
if (is_remount &&
|
||||
(test_opt(sb, DATA_FLAGS) ==
|
||||
EXT4_MOUNT_JOURNAL_DATA)) {
|
||||
ext4_msg(sb, KERN_ERR, "can't mount with "
|
||||
"both data=journal and dax");
|
||||
return -1;
|
||||
}
|
||||
ext4_msg(sb, KERN_WARNING,
|
||||
"DAX enabled. Warning: EXPERIMENTAL, use at your own risk");
|
||||
sbi->s_mount_opt |= EXT4_MOUNT_DAX_ALWAYS;
|
||||
sbi->s_mount_opt2 &= ~EXT4_MOUNT2_DAX_NEVER;
|
||||
break;
|
||||
case Opt_dax_never:
|
||||
if (is_remount &&
|
||||
(!(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER) ||
|
||||
(sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS)))
|
||||
goto fail_dax_change_remount;
|
||||
sbi->s_mount_opt2 |= EXT4_MOUNT2_DAX_NEVER;
|
||||
sbi->s_mount_opt &= ~EXT4_MOUNT_DAX_ALWAYS;
|
||||
break;
|
||||
case Opt_dax_inode:
|
||||
if (is_remount &&
|
||||
((sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) ||
|
||||
(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_NEVER) ||
|
||||
!(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_INODE)))
|
||||
goto fail_dax_change_remount;
|
||||
sbi->s_mount_opt &= ~EXT4_MOUNT_DAX_ALWAYS;
|
||||
sbi->s_mount_opt2 &= ~EXT4_MOUNT2_DAX_NEVER;
|
||||
/* Strictly for printing options */
|
||||
sbi->s_mount_opt2 |= EXT4_MOUNT2_DAX_INODE;
|
||||
break;
|
||||
}
|
||||
#else
|
||||
ext4_msg(sb, KERN_INFO, "dax option not supported");
|
||||
sbi->s_mount_opt2 |= EXT4_MOUNT2_DAX_NEVER;
|
||||
sbi->s_mount_opt &= ~EXT4_MOUNT_DAX_ALWAYS;
|
||||
return -1;
|
||||
#endif
|
||||
} else if (token == Opt_data_err_abort) {
|
||||
@@ -2293,7 +2344,7 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
|
||||
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))
|
||||
(m->flags & MOPT_CLEAR_ERR) || m->flags & MOPT_SKIP)
|
||||
continue;
|
||||
if (!nodefs && !(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt)))
|
||||
continue; /* skip if same as the default */
|
||||
@@ -2353,6 +2404,17 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
|
||||
|
||||
fscrypt_show_test_dummy_encryption(seq, sep, sb);
|
||||
|
||||
if (test_opt(sb, DAX_ALWAYS)) {
|
||||
if (IS_EXT2_SB(sb))
|
||||
SEQ_OPTS_PUTS("dax");
|
||||
else
|
||||
SEQ_OPTS_PUTS("dax=always");
|
||||
} else if (test_opt2(sb, DAX_NEVER)) {
|
||||
SEQ_OPTS_PUTS("dax=never");
|
||||
} else if (test_opt2(sb, DAX_INODE)) {
|
||||
SEQ_OPTS_PUTS("dax=inode");
|
||||
}
|
||||
|
||||
ext4_show_quota_options(seq, sb);
|
||||
return 0;
|
||||
}
|
||||
@@ -2383,6 +2445,7 @@ static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es,
|
||||
ext4_msg(sb, KERN_ERR, "revision level too high, "
|
||||
"forcing read-only mode");
|
||||
err = -EROFS;
|
||||
goto done;
|
||||
}
|
||||
if (read_only)
|
||||
goto done;
|
||||
@@ -4017,7 +4080,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
"both data=journal and delalloc");
|
||||
goto failed_mount;
|
||||
}
|
||||
if (test_opt(sb, DAX)) {
|
||||
if (test_opt(sb, DAX_ALWAYS)) {
|
||||
ext4_msg(sb, KERN_ERR, "can't mount with "
|
||||
"both data=journal and dax");
|
||||
goto failed_mount;
|
||||
@@ -4127,13 +4190,16 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||
goto failed_mount;
|
||||
}
|
||||
|
||||
if (sbi->s_mount_opt & EXT4_MOUNT_DAX) {
|
||||
if (bdev_dax_supported(sb->s_bdev, blocksize))
|
||||
set_bit(EXT4_FLAGS_BDEV_IS_DAX, &sbi->s_ext4_flags);
|
||||
|
||||
if (sbi->s_mount_opt & EXT4_MOUNT_DAX_ALWAYS) {
|
||||
if (ext4_has_feature_inline_data(sb)) {
|
||||
ext4_msg(sb, KERN_ERR, "Cannot use DAX on a filesystem"
|
||||
" that may contain inline data");
|
||||
goto failed_mount;
|
||||
}
|
||||
if (!bdev_dax_supported(sb->s_bdev, blocksize)) {
|
||||
if (!test_bit(EXT4_FLAGS_BDEV_IS_DAX, &sbi->s_ext4_flags)) {
|
||||
ext4_msg(sb, KERN_ERR,
|
||||
"DAX unsupported by block device.");
|
||||
goto failed_mount;
|
||||
@@ -5447,12 +5513,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
||||
err = -EINVAL;
|
||||
goto restore_opts;
|
||||
}
|
||||
if (test_opt(sb, DAX)) {
|
||||
ext4_msg(sb, KERN_ERR, "can't mount with "
|
||||
"both data=journal and dax");
|
||||
err = -EINVAL;
|
||||
goto restore_opts;
|
||||
}
|
||||
} else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) {
|
||||
if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) {
|
||||
ext4_msg(sb, KERN_ERR, "can't mount with "
|
||||
@@ -5468,12 +5528,6 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
||||
goto restore_opts;
|
||||
}
|
||||
|
||||
if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_DAX) {
|
||||
ext4_msg(sb, KERN_WARNING, "warning: refusing change of "
|
||||
"dax flag with busy inodes while remounting");
|
||||
sbi->s_mount_opt ^= EXT4_MOUNT_DAX;
|
||||
}
|
||||
|
||||
if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
|
||||
ext4_abort(sb, EXT4_ERR_ESHUTDOWN, "Abort forced by user");
|
||||
|
||||
|
Reference in New Issue
Block a user