erofs-utils: mkfs: add `--zfeature-bits` option
authorGao Xiang <hsiangkao@linux.alibaba.com>
Fri, 17 May 2024 09:00:48 +0000 (17:00 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Tue, 4 Jun 2024 08:59:26 +0000 (16:59 +0800)
Thus, we could traverse all compression features with continuous
numbers easily in the testcases.

Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
Link: https://lore.kernel.org/r/20240517090048.3039594-1-hsiangkao@linux.alibaba.com
mkfs/main.c

index c26cb56b72118a710fc4b0480286e7b38af623d6..347efe6a45f57a9f881c8556214cba5c36bca45f 100644 (file)
@@ -81,6 +81,7 @@ static struct option long_options[] = {
 #ifdef EROFS_MT_ENABLED
        {"workers", required_argument, NULL, 520},
 #endif
+       {"zfeature-bits", required_argument, NULL, 521},
        {0, 0, 0, 0},
 };
 
@@ -166,6 +167,7 @@ static void usage(int argc, char **argv)
                " --gid-offset=#        add offset # to all file gids (# = id offset)\n"
                " --ignore-mtime        use build time instead of strict per-file modification time\n"
                " --max-extent-bytes=#  set maximum decompressed extent size # in bytes\n"
+               " --mount-point=X       X=prefix of target fs path (default: /)\n"
                " --preserve-mtime      keep per-file modification time strictly\n"
                " --offset=#            skip # bytes at the beginning of IMAGE.\n"
                " --aufs                replace aufs special files with overlayfs metadata\n"
@@ -190,7 +192,7 @@ static void usage(int argc, char **argv)
                " --workers=#           set the number of worker threads to # (default: %u)\n"
 #endif
                " --xattr-prefix=X      X=extra xattr name prefix\n"
-               " --mount-point=X       X=prefix of target fs path (default: /)\n"
+               " --zfeature-bits=#     toggle filesystem compression features according to given bits #\n"
 #ifdef WITH_ANDROID
                "\n"
                "Android-specific options:\n"
@@ -220,10 +222,81 @@ static bool tar_mode, rebuild_mode;
 static unsigned int rebuild_src_count;
 static LIST_HEAD(rebuild_src_list);
 
+static int erofs_mkfs_feat_set_legacy_compress(bool en, const char *val,
+                                              unsigned int vallen)
+{
+       if (vallen)
+               return -EINVAL;
+       /* disable compacted indexes and 0padding */
+       cfg.c_legacy_compress = en;
+       return 0;
+}
+
+static int erofs_mkfs_feat_set_ztailpacking(bool en, const char *val,
+                                           unsigned int vallen)
+{
+       if (vallen)
+               return -EINVAL;
+       cfg.c_ztailpacking = en;
+       return 0;
+}
+
+static int erofs_mkfs_feat_set_fragments(bool en, const char *val,
+                                        unsigned int vallen)
+{
+       if (!en) {
+               if (vallen)
+                       return -EINVAL;
+               cfg.c_fragments = false;
+               return 0;
+       }
+
+       if (vallen) {
+               char *endptr;
+               u64 i = strtoull(val, &endptr, 0);
+
+               if (endptr - val != vallen) {
+                       erofs_err("invalid pcluster size %s for the packed file %s", val);
+                       return -EINVAL;
+               }
+               pclustersize_packed = i;
+       }
+       cfg.c_fragments = true;
+       return 0;
+}
+
+static int erofs_mkfs_feat_set_all_fragments(bool en, const char *val,
+                                            unsigned int vallen)
+{
+       cfg.c_all_fragments = en;
+       return erofs_mkfs_feat_set_fragments(en, val, vallen);
+}
+
+static int erofs_mkfs_feat_set_dedupe(bool en, const char *val,
+                                     unsigned int vallen)
+{
+       if (vallen)
+               return -EINVAL;
+       cfg.c_dedupe = en;
+       return 0;
+}
+
+static struct {
+       char *feat;
+       int (*set)(bool en, const char *val, unsigned int len);
+} z_erofs_mkfs_features[] = {
+       {"legacy-compress", erofs_mkfs_feat_set_legacy_compress},
+       {"ztailpacking", erofs_mkfs_feat_set_ztailpacking},
+       {"fragments", erofs_mkfs_feat_set_fragments},
+       {"all-fragments", erofs_mkfs_feat_set_all_fragments},
+       {"dedupe", erofs_mkfs_feat_set_dedupe},
+       {NULL, NULL},
+};
+
 static int parse_extended_opts(const char *opts)
 {
 #define MATCH_EXTENTED_OPT(opt, token, keylen) \
-       (keylen == sizeof(opt) - 1 && !memcmp(token, opt, sizeof(opt) - 1))
+       (keylen == strlen(opt) && !memcmp(token, opt, keylen))
 
        const char *token, *next, *tokenend, *value __maybe_unused;
        unsigned int keylen, vallen;
@@ -262,12 +335,7 @@ static int parse_extended_opts(const char *opts)
                        clear = true;
                }
 
-               if (MATCH_EXTENTED_OPT("legacy-compress", token, keylen)) {
-                       if (vallen)
-                               return -EINVAL;
-                       /* disable compacted indexes and 0padding */
-                       cfg.c_legacy_compress = true;
-               } else if (MATCH_EXTENTED_OPT("force-inode-compact", token, keylen)) {
+               if (MATCH_EXTENTED_OPT("force-inode-compact", token, keylen)) {
                        if (vallen)
                                return -EINVAL;
                        cfg.c_force_inodeversion = FORCE_INODE_COMPACT;
@@ -296,41 +364,51 @@ static int parse_extended_opts(const char *opts)
                        if (vallen)
                                return -EINVAL;
                        cfg.c_force_chunkformat = FORCE_INODE_CHUNK_INDEXES;
-               } else if (MATCH_EXTENTED_OPT("ztailpacking", token, keylen)) {
-                       if (vallen)
-                               return -EINVAL;
-                       cfg.c_ztailpacking = !clear;
-               } else if (MATCH_EXTENTED_OPT("all-fragments", token, keylen)) {
-                       cfg.c_all_fragments = true;
-                       goto handle_fragment;
-               } else if (MATCH_EXTENTED_OPT("fragments", token, keylen)) {
-                       char *endptr;
-                       u64 i;
-
-handle_fragment:
-                       cfg.c_fragments = true;
-                       if (vallen) {
-                               i = strtoull(value, &endptr, 0);
-                               if (endptr - value != vallen) {
-                                       erofs_err("invalid pcluster size for the packed file %s",
-                                                 next);
-                                       return -EINVAL;
-                               }
-                               pclustersize_packed = i;
-                       }
-               } else if (MATCH_EXTENTED_OPT("dedupe", token, keylen)) {
-                       if (vallen)
-                               return -EINVAL;
-                       cfg.c_dedupe = !clear;
                } else if (MATCH_EXTENTED_OPT("xattr-name-filter", token, keylen)) {
                        if (vallen)
                                return -EINVAL;
                        cfg.c_xattr_name_filter = !clear;
                } else {
-                       erofs_err("unknown extended option %.*s",
-                                 p - token, token);
+                       int i, err;
+
+                       for (i = 0; z_erofs_mkfs_features[i].feat; ++i) {
+                               if (!MATCH_EXTENTED_OPT(z_erofs_mkfs_features[i].feat,
+                                                       token, keylen))
+                                       continue;
+                               err = z_erofs_mkfs_features[i].set(!clear, value, vallen);
+                               if (err)
+                                       return err;
+                               break;
+                       }
+
+                       if (!z_erofs_mkfs_features[i].feat) {
+                               erofs_err("unknown extended option %.*s",
+                                         p - token, token);
+                               return -EINVAL;
+                       }
+               }
+       }
+       return 0;
+}
+
+static int mkfs_apply_zfeature_bits(uintmax_t bits)
+{
+       int i;
+
+       for (i = 0; bits; ++i) {
+               int err;
+
+               if (!z_erofs_mkfs_features[i].feat) {
+                       erofs_err("unsupported zfeature bit %u", i);
                        return -EINVAL;
                }
+               err = z_erofs_mkfs_features[i].set(bits & 1, NULL, 0);
+               if (err) {
+                       erofs_err("failed to apply zfeature %s",
+                                 z_erofs_mkfs_features[i].feat);
+                       return err;
+               }
+               bits >>= 1;
        }
        return 0;
 }
@@ -690,6 +768,16 @@ static int mkfs_parse_options_cfg(int argc, char *argv[])
                        break;
                }
 #endif
+               case 521:
+                       i = strtol(optarg, &endptr, 0);
+                       if (errno || *endptr != '\0') {
+                               erofs_err("invalid zfeature bits %s", optarg);
+                               return -EINVAL;
+                       }
+                       err = mkfs_apply_zfeature_bits(i);
+                       if (err)
+                               return err;
+                       break;
                case 'V':
                        version();
                        exit(0);