[RFC PATCH 2/4] ext4: add dax_fc_bytelog mount option

Li Chen posted 4 patches 1 month, 1 week ago
[RFC PATCH 2/4] ext4: add dax_fc_bytelog mount option
Posted by Li Chen 1 month, 1 week ago
Add dax_fc_bytelog={off,on,force} to control the DAX ByteLog fast commit
backend.
Initialize the ByteLog ring before fast commit replay and release it on
unmount.

Signed-off-by: Li Chen <me@linux.beauty>
---
 fs/ext4/super.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 76 insertions(+), 1 deletion(-)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 504148b2142b..3645456a61dd 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1368,6 +1368,7 @@ static void ext4_put_super(struct super_block *sb)
 	sbi->s_ea_block_cache = NULL;
 
 	ext4_stop_mmpd(sbi);
+	ext4_fc_bytelog_release(sb);
 
 	brelse(sbi->s_sbh);
 	sb->s_fs_info = NULL;
@@ -1685,6 +1686,8 @@ enum {
 	Opt_max_dir_size_kb, Opt_nojournal_checksum, Opt_nombcache,
 	Opt_no_prefetch_block_bitmaps, Opt_mb_optimize_scan,
 	Opt_errors, Opt_data, Opt_data_err, Opt_jqfmt, Opt_dax_type,
+	Opt_dax_fc_bytelog, Opt_dax_fc_bytelog_off, Opt_dax_fc_bytelog_on,
+	Opt_dax_fc_bytelog_force,
 #ifdef CONFIG_EXT4_DEBUG
 	Opt_fc_debug_max_replay, Opt_fc_debug_force
 #endif
@@ -1724,6 +1727,13 @@ static const struct constant_table ext4_param_dax[] = {
 	{}
 };
 
+static const struct constant_table ext4_param_dax_fc_bytelog[] = {
+	{"off",		Opt_dax_fc_bytelog_off},
+	{"on",		Opt_dax_fc_bytelog_on},
+	{"force",	Opt_dax_fc_bytelog_force},
+	{}
+};
+
 /*
  * Mount option specification
  * We don't use fsparam_flag_no because of the way we set the
@@ -1780,6 +1790,8 @@ static const struct fs_parameter_spec ext4_param_specs[] = {
 	fsparam_flag	("i_version",		Opt_removed),
 	fsparam_flag	("dax",			Opt_dax),
 	fsparam_enum	("dax",			Opt_dax_type, ext4_param_dax),
+	fsparam_enum("dax_fc_bytelog", Opt_dax_fc_bytelog,
+		     ext4_param_dax_fc_bytelog),
 	fsparam_u32	("stripe",		Opt_stripe),
 	fsparam_flag	("delalloc",		Opt_delalloc),
 	fsparam_flag	("nodelalloc",		Opt_nodelalloc),
@@ -1965,6 +1977,7 @@ ext4_sb_read_encoding(const struct ext4_super_block *es)
 #define EXT4_SPEC_s_fc_debug_max_replay		(1 << 17)
 #define EXT4_SPEC_s_sb_block			(1 << 18)
 #define EXT4_SPEC_mb_optimize_scan		(1 << 19)
+#define EXT4_SPEC_s_dax_fc_bytelog		BIT(20)
 
 struct ext4_fs_context {
 	char		*s_qf_names[EXT4_MAXQUOTAS];
@@ -2370,6 +2383,26 @@ static int ext4_parse_param(struct fs_context *fc, struct fs_parameter *param)
 		ext4_msg(NULL, KERN_INFO, "dax option not supported");
 		return -EINVAL;
 #endif
+	case Opt_dax_fc_bytelog:
+		switch (result.uint_32) {
+		case Opt_dax_fc_bytelog_off:
+			ctx_clear_mount_opt2(ctx, EXT4_MOUNT2_DAX_FC_BYTELOG);
+			ctx_clear_mount_opt2(ctx,
+					     EXT4_MOUNT2_DAX_FC_BYTELOG_FORCE);
+			break;
+		case Opt_dax_fc_bytelog_on:
+			ctx_set_mount_opt2(ctx, EXT4_MOUNT2_DAX_FC_BYTELOG);
+			ctx_clear_mount_opt2(ctx,
+					     EXT4_MOUNT2_DAX_FC_BYTELOG_FORCE);
+			break;
+		case Opt_dax_fc_bytelog_force:
+			ctx_set_mount_opt2(ctx, EXT4_MOUNT2_DAX_FC_BYTELOG);
+			ctx_set_mount_opt2(ctx,
+					   EXT4_MOUNT2_DAX_FC_BYTELOG_FORCE);
+			break;
+		}
+		ctx->spec |= EXT4_SPEC_s_dax_fc_bytelog;
+		return 0;
 	case Opt_data_err:
 		if (result.uint_32 == Opt_data_err_abort)
 			ctx_set_mount_opt(ctx, m->mount_opt);
@@ -2819,7 +2852,22 @@ static int ext4_check_opt_consistency(struct fs_context *fc,
 			    !(sbi->s_mount_opt2 & EXT4_MOUNT2_DAX_INODE))) {
 			goto fail_dax_change_remount;
 		}
-	}
+
+		if (ctx->spec & EXT4_SPEC_s_dax_fc_bytelog) {
+			bool new_on = ctx_test_mount_opt2(ctx,
+					EXT4_MOUNT2_DAX_FC_BYTELOG);
+			bool new_force = ctx_test_mount_opt2(ctx,
+					EXT4_MOUNT2_DAX_FC_BYTELOG_FORCE);
+			bool cur_on = test_opt2(sb, DAX_FC_BYTELOG);
+			bool cur_force = test_opt2(sb, DAX_FC_BYTELOG_FORCE);
+
+				if (new_on != cur_on || new_force != cur_force) {
+					ext4_msg(NULL, KERN_ERR,
+						 "can't change dax_fc_bytelog mount option while remounting");
+					return -EINVAL;
+				}
+			}
+		}
 
 	return ext4_check_quota_consistency(fc, sb);
 }
@@ -3038,6 +3086,12 @@ static int _ext4_show_options(struct seq_file *seq, struct super_block *sb,
 	} else if (test_opt2(sb, DAX_INODE)) {
 		SEQ_OPTS_PUTS("dax=inode");
 	}
+	if (test_opt2(sb, DAX_FC_BYTELOG)) {
+		if (test_opt2(sb, DAX_FC_BYTELOG_FORCE))
+			SEQ_OPTS_PUTS("dax_fc_bytelog=force");
+		else
+			SEQ_OPTS_PUTS("dax_fc_bytelog=on");
+	}
 
 	if (sbi->s_groups_count >= MB_DEFAULT_LINEAR_SCAN_THRESHOLD &&
 			!test_opt2(sb, MB_OPTIMIZE_SCAN)) {
@@ -4950,6 +5004,8 @@ static int ext4_load_and_init_journal(struct super_block *sb,
 			"Failed to set fast commit journal feature");
 		goto out;
 	}
+	if (test_opt2(sb, JOURNAL_FAST_COMMIT))
+		ext4_fc_bytelog_init(sb, sbi->s_journal);
 
 	/* We have now updated the journal if required, so we can
 	 * validate the data journaling mode. */
@@ -6124,10 +6180,29 @@ static int ext4_load_journal(struct super_block *sb,
 		char *save = kmalloc(EXT4_S_ERR_LEN, GFP_KERNEL);
 		__le16 orig_state;
 		bool changed = false;
+		int fc_err;
 
 		if (save)
 			memcpy(save, ((char *) es) +
 			       EXT4_S_ERR_START, EXT4_S_ERR_LEN);
+
+		/*
+		 * Map the ByteLog ring before fast-commit replay so that
+		 * EXT4_FC_TAG_DAX_BYTELOG_ANCHOR records can be processed
+		 * during jbd2_journal_load().
+		 *
+		 * For filesystems with the INCOMPAT_DAX_FC_BYTELOG feature
+		 * bit set, failing to initialize the ByteLog ring must be
+		 * treated as fatal.
+		 */
+		if (test_opt2(sb, JOURNAL_FAST_COMMIT)) {
+			fc_err = ext4_fc_bytelog_init(sb, journal);
+			if (fc_err && ext4_has_feature_dax_fc_bytelog(sb)) {
+				kfree(save);
+				err = fc_err;
+				goto err_out;
+			}
+		}
 		err = jbd2_journal_load(journal);
 		if (save && memcmp(((char *) es) + EXT4_S_ERR_START,
 				   save, EXT4_S_ERR_LEN)) {
-- 
2.52.0