[PATCH 2/2] erofs-utils: mkfs: validate source and dataimport mode combinations

Yifan Zhao zhaoyifan28 at huawei.com
Fri Feb 13 18:32:41 AEDT 2026


This patch adds validation for all combinations of source mode and
dataimport mode, and prints corresponding error/warning messages.
It should have no impact on external behavior.

Signed-off-by: Yifan Zhao <zhaoyifan28 at huawei.com>
---
 mkfs/main.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 131 insertions(+), 13 deletions(-)

diff --git a/mkfs/main.c b/mkfs/main.c
index a948b2e..e369347 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -169,7 +169,7 @@ static void usage(int argc, char **argv)
 	}
 	printf(
 		" -C#                    specify the size of compress physical cluster in bytes\n"
-		" -EX[,...]              X=extended options\n"
+		" -EX[,...]              X=extended options, see mkfs.erofs(1) manual for details\n"
 		" -L volume-label        set the volume label (maximum 15 bytes)\n"
 		" -m#[:X]                enable metadata compression (# = physical cluster size in bytes;\n"
 		"                                                     X = another compression algorithm for metadata)\n"
@@ -300,6 +300,10 @@ static struct ocierofs_config ocicfg;
 static bool mkfs_oci_tarindex_mode;
 
 enum {
+	/* XXX: the "DEFAULT" mode is actually source-dependent,
+	 * meaning BLOB_INDEX for rebuild mode and FULLDATA for others.
+	 * Consider refactoring this...
+	 */
 	EROFS_MKFS_DATA_IMPORT_DEFAULT,
 	EROFS_MKFS_DATA_IMPORT_FULLDATA,
 	EROFS_MKFS_DATA_IMPORT_RVSP,
@@ -314,6 +318,118 @@ static enum {
 	EROFS_MKFS_SOURCE_REBUILD,
 } source_mode;
 
+static int erofs_mkfs_validate_source_datamode(void)
+{
+	int status;
+	enum {
+		EROFS_MKFS_CLEAN_MODE = 0,
+		EROFS_MKFS_INCREMENTAL_MODE = 1
+	};
+	const char *SOURCE_NAME[] = {
+		[EROFS_MKFS_SOURCE_LOCALDIR] = "localdir source",
+		[EROFS_MKFS_SOURCE_TAR] = "tarball source",
+		[EROFS_MKFS_SOURCE_S3] = "S3-compatible object store source",
+		[EROFS_MKFS_SOURCE_OCI] = "OCI remote source",
+		[EROFS_MKFS_SOURCE_REBUILD] = "rebuilding from existing EROFS image(s)",
+	};
+	const char *DATAIMPORT_NAME[] = {
+		[EROFS_MKFS_DATA_IMPORT_DEFAULT] = "default", // placeholder
+		[EROFS_MKFS_DATA_IMPORT_FULLDATA] = "data",
+		[EROFS_MKFS_DATA_IMPORT_RVSP] = "rvsp",
+		[EROFS_MKFS_DATA_IMPORT_ZEROFILL] = "0",
+	};
+	enum {
+		INVALID = 0, // INVALID must be 0 for static initialization
+		NOP = 1,
+		SUPPORTED = 2,
+	};
+	static const int support[EROFS_MKFS_SOURCE_REBUILD + 1][EROFS_MKFS_INCREMENTAL_MODE + 1][EROFS_MKFS_DATA_IMPORT_ZEROFILL + 1] = {
+		[EROFS_MKFS_SOURCE_LOCALDIR] = {
+			[EROFS_MKFS_CLEAN_MODE] = {
+				[EROFS_MKFS_DATA_IMPORT_FULLDATA] = SUPPORTED,
+				[EROFS_MKFS_DATA_IMPORT_RVSP] = NOP,
+				[EROFS_MKFS_DATA_IMPORT_ZEROFILL] = NOP
+			},
+			[EROFS_MKFS_INCREMENTAL_MODE] = {
+				[EROFS_MKFS_DATA_IMPORT_FULLDATA] = SUPPORTED,
+				[EROFS_MKFS_DATA_IMPORT_RVSP] = NOP,
+				[EROFS_MKFS_DATA_IMPORT_ZEROFILL] = NOP
+			},
+		},
+		[EROFS_MKFS_SOURCE_TAR] = {
+			[EROFS_MKFS_CLEAN_MODE] = {
+				[EROFS_MKFS_DATA_IMPORT_FULLDATA] = SUPPORTED,
+				[EROFS_MKFS_DATA_IMPORT_RVSP] = SUPPORTED,
+				[EROFS_MKFS_DATA_IMPORT_ZEROFILL] = NOP
+			},
+			[EROFS_MKFS_INCREMENTAL_MODE] = {
+				[EROFS_MKFS_DATA_IMPORT_FULLDATA] = SUPPORTED,
+				[EROFS_MKFS_DATA_IMPORT_RVSP] = SUPPORTED,
+				[EROFS_MKFS_DATA_IMPORT_ZEROFILL] = NOP
+			},
+		},
+		[EROFS_MKFS_SOURCE_S3] = {
+			[EROFS_MKFS_CLEAN_MODE] = {
+				[EROFS_MKFS_DATA_IMPORT_FULLDATA] = SUPPORTED,
+				[EROFS_MKFS_DATA_IMPORT_ZEROFILL] = SUPPORTED,
+			},
+		},
+		[EROFS_MKFS_SOURCE_OCI] = {
+			[EROFS_MKFS_CLEAN_MODE] = {
+				[EROFS_MKFS_DATA_IMPORT_FULLDATA] = SUPPORTED
+			},
+		},
+		[EROFS_MKFS_SOURCE_REBUILD] = {
+			[EROFS_MKFS_CLEAN_MODE] = {
+				[EROFS_MKFS_DATA_IMPORT_DEFAULT] = SUPPORTED,
+				/* XXX: FULLDATA rebuild mode doesn't work actually, let's keep
+				 * its behavior until v1.9 is released to avoid breaking anyone who
+				 * might rely on it...
+				 */
+				[EROFS_MKFS_DATA_IMPORT_FULLDATA] = SUPPORTED,
+				[EROFS_MKFS_DATA_IMPORT_RVSP] = SUPPORTED,
+			},
+			[EROFS_MKFS_INCREMENTAL_MODE] = {
+				[EROFS_MKFS_DATA_IMPORT_DEFAULT] = SUPPORTED,
+				/* XXX: FULLDATA rebuild mode doesn't work actually, let's keep
+				 * its behavior until v1.9 is released to avoid breaking anyone who
+				 * might rely on it...
+				 */
+				[EROFS_MKFS_DATA_IMPORT_FULLDATA] = SUPPORTED,
+				[EROFS_MKFS_DATA_IMPORT_RVSP] = SUPPORTED,
+			},
+		},
+	};
+	int real_dataimport_mode = dataimport_mode;
+	if (real_dataimport_mode == EROFS_MKFS_DATA_IMPORT_DEFAULT)
+		real_dataimport_mode = (source_mode == EROFS_MKFS_SOURCE_REBUILD) ?
+			EROFS_MKFS_DATA_IMPORT_DEFAULT : EROFS_MKFS_DATA_IMPORT_FULLDATA;
+
+	if (source_mode < 0 || source_mode > EROFS_MKFS_SOURCE_REBUILD)
+		return -EINVAL;
+
+	if (real_dataimport_mode < EROFS_MKFS_DATA_IMPORT_DEFAULT ||
+	    real_dataimport_mode > EROFS_MKFS_DATA_IMPORT_ZEROFILL)
+		return -EINVAL;
+
+	status = support[source_mode][incremental_mode ? EROFS_MKFS_INCREMENTAL_MODE : EROFS_MKFS_CLEAN_MODE][real_dataimport_mode];
+	if (status == SUPPORTED) {
+		return 0;
+	} else if (status == NOP) {
+		erofs_warn("datamode '%s' under %s mode is a no-op for %s.",
+			   DATAIMPORT_NAME[real_dataimport_mode],
+			   incremental_mode ? "incremental" : "clean",
+			   SOURCE_NAME[source_mode]);
+		return 0;
+	} else {
+		erofs_err("datamode '%s' under %s mode is not supported for %s.",
+			  DATAIMPORT_NAME[real_dataimport_mode],
+			  incremental_mode ? "incremental" : "clean",
+			  SOURCE_NAME[source_mode]);
+		return -EOPNOTSUPP;
+	}
+}
+
 static unsigned int rebuild_src_count, total_ccfgs;
 static LIST_HEAD(rebuild_src_list);
 static u8 fixeduuid[16];
@@ -1570,6 +1686,10 @@ static int mkfs_parse_options_cfg(struct erofs_importer_params *params,
 
 	if (has_timestamp && cfg.c_timeinherit == TIMESTAMP_UNSPECIFIED)
 		cfg.c_timeinherit = TIMESTAMP_FIXED;
+
+	err = erofs_mkfs_validate_source_datamode();
+	if (err)
+		return err;
 	return 0;
 }
 
@@ -1631,11 +1751,16 @@ static int erofs_mkfs_rebuild_load_trees(struct erofs_inode *root)
 		datamode = EROFS_REBUILD_DATA_BLOB_INDEX;
 		break;
 	case EROFS_MKFS_DATA_IMPORT_FULLDATA:
+		/* XXX: fulldata rebuild is unsupported, but let's keep this behavior
+		 * in case anyone relies on it until v1.9 is released...
+		 */
 		datamode = EROFS_REBUILD_DATA_FULL;
 		break;
 	case EROFS_MKFS_DATA_IMPORT_RVSP:
 		datamode = EROFS_REBUILD_DATA_RESVSP;
 		break;
+	case EROFS_MKFS_DATA_IMPORT_ZEROFILL:
+		return -EOPNOTSUPP;
 	default:
 		return -EINVAL;
 	}
@@ -1786,6 +1911,8 @@ int main(int argc, char **argv)
 	if (source_mode == EROFS_MKFS_SOURCE_TAR) {
 		if (dataimport_mode == EROFS_MKFS_DATA_IMPORT_RVSP)
 			erofstar.rvsp_mode = true;
+		if (erofstar.index_mode && erofstar.rvsp_mode)
+			erofs_warn("rvsp mode takes precedence and tar index mode is ignored");
 		erofstar.dev = rebuild_src_count + 1;
 
 		if (erofstar.mapfile) {
@@ -1950,12 +2077,8 @@ int main(int argc, char **argv)
 			s3cfg.secret_key[S3_SECRET_KEY_LEN] = '\0';
 		}
 
-		if (incremental_mode ||
-		    dataimport_mode == EROFS_MKFS_DATA_IMPORT_RVSP)
-			err = -EOPNOTSUPP;
-		else
-			err = s3erofs_build_trees(&importer, &s3cfg,
-						  cfg.c_src_path,
+		err = s3erofs_build_trees(&importer, &s3cfg,
+					  cfg.c_src_path,
 				dataimport_mode == EROFS_MKFS_DATA_IMPORT_ZEROFILL);
 #endif
 #ifdef OCIEROFS_ENABLED
@@ -1966,12 +2089,7 @@ int main(int argc, char **argv)
 			if (!ocicfg.zinfo_path)
 				ocicfg.zinfo_path = mkfs_aws_zinfo_file;
 
-			if (incremental_mode ||
-			    dataimport_mode == EROFS_MKFS_DATA_IMPORT_RVSP ||
-			    dataimport_mode == EROFS_MKFS_DATA_IMPORT_ZEROFILL)
-				err = -EOPNOTSUPP;
-			else
-				err = ocierofs_build_trees(&importer, &ocicfg);
+			err = ocierofs_build_trees(&importer, &ocicfg);
 			if (err)
 				goto exit;
 #endif
-- 
2.47.3



More information about the Linux-erofs mailing list