[PATCH 2/2] erofs-utils: mkfs: support lc,lp,pb properties for LZMA
Gao Xiang
hsiangkao at linux.alibaba.com
Tue Feb 17 01:39:18 AEDT 2026
Add support for specifying LZMA compression parameters lc (literal
context bits), lp (literal position bits), and pb (position bits)
via mkfs.erofs command-line options.
Note that these are all advanced parameters: Default values are used
if not specified. Users are advised to keep defaults unless they
understand their impact.
Signed-off-by: Gao Xiang <hsiangkao at linux.alibaba.com>
---
include/erofs/internal.h | 1 +
lib/compress.c | 15 +++++--
lib/compressor.c | 70 ++++++++++++++++++++----------
lib/compressor.h | 4 +-
lib/compressor_liblzma.c | 93 ++++++++++++++++++++++++++++++----------
mkfs/main.c | 20 ++++++++-
6 files changed, 150 insertions(+), 53 deletions(-)
diff --git a/include/erofs/internal.h b/include/erofs/internal.h
index 3ccae0c7ac86..0a5f6beeb14c 100644
--- a/include/erofs/internal.h
+++ b/include/erofs/internal.h
@@ -438,6 +438,7 @@ struct z_erofs_paramset {
char *alg;
int clevel;
u32 dict_size;
+ char *extraopts;
};
int liberofs_global_init(void);
diff --git a/lib/compress.c b/lib/compress.c
index 1c4aa115641d..bbbf0e43d3fb 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -1457,10 +1457,11 @@ void *z_erofs_mt_wq_tls_free(struct erofs_workqueue *wq, void *priv)
struct erofs_compress_wq_tls *tls = priv;
int i;
- for (i = 0; i < EROFS_MAX_COMPR_CFGS; i++)
- if (tls->ccfg[i].enable)
- erofs_compressor_exit(&tls->ccfg[i].handle);
-
+ for (i = 0; i < EROFS_MAX_COMPR_CFGS; i++) {
+ if (!tls->ccfg[i].enable)
+ continue;
+ erofs_compressor_exit(&tls->ccfg[i].handle);
+ }
free(tls->ccfg);
free(tls->destbuf);
free(tls->queue);
@@ -2163,6 +2164,11 @@ int z_erofs_compress_init(struct erofs_importer *im)
ccfg->zset.alg = strdup(zset->alg);
if (!ccfg->zset.alg)
return -ENOMEM;
+ if (zset->extraopts) {
+ ccfg->zset.extraopts = strdup(zset->extraopts);
+ if (!ccfg->zset.extraopts)
+ return -ENOMEM;
+ }
ret = erofs_compressor_init(sbi, c, &ccfg->zset,
pclustersize_max);
@@ -2264,6 +2270,7 @@ int z_erofs_compress_exit(struct erofs_sb_info *sbi)
if (ret)
return ret;
free(sbi->zmgr->ccfg[i].zset.alg);
+ free(sbi->zmgr->ccfg[i].zset.extraopts);
}
free(sbi->zmgr);
return 0;
diff --git a/lib/compressor.c b/lib/compressor.c
index 79d80372968e..cf55abcf5359 100644
--- a/lib/compressor.c
+++ b/lib/compressor.c
@@ -96,6 +96,13 @@ int erofs_compress(const struct erofs_compress *c,
return c->alg->c->compress(c, src, srcsize, dst, dstcapacity);
}
+int erofs_compressor_exit(struct erofs_compress *c)
+{
+ if (c->alg && c->alg->c->exit)
+ return c->alg->c->exit(c);
+ return 0;
+}
+
int erofs_compressor_init(struct erofs_sb_info *sbi, struct erofs_compress *c,
const struct z_erofs_paramset *zset,
u32 pclustersize_max)
@@ -117,17 +124,36 @@ int erofs_compressor_init(struct erofs_sb_info *sbi, struct erofs_compress *c,
if (!erofs_algs[i].c)
continue;
+ if (!erofs_algs[i].c->setlevel && zset->clevel >= 0) {
+ erofs_err("compression level %d is not supported for %s",
+ zset->clevel, zset->alg);
+ return -EINVAL;
+ }
+
+ if (!erofs_algs[i].c->setdictsize && zset->dict_size) {
+ erofs_err("unsupported dict size for %s", zset->alg);
+ return -EINVAL;
+ }
+
+ if (!erofs_algs[i].c->setextraopts && zset->extraopts) {
+ erofs_err("invalid compression option %s for %s",
+ zset->extraopts, zset->alg);
+ return -EINVAL;
+ }
+
+ if (erofs_algs[i].c->preinit) {
+ ret = erofs_algs[i].c->preinit(c);
+ if (ret)
+ return ret;
+ }
+
if (erofs_algs[i].c->setlevel) {
ret = erofs_algs[i].c->setlevel(c, zset->clevel);
if (ret) {
erofs_err("failed to set compression level %d for %s",
zset->clevel, zset->alg);
- return ret;
+ goto fail;
}
- } else if (zset->clevel >= 0) {
- erofs_err("compression level %d is not supported for %s",
- zset->clevel, zset->alg);
- return -EINVAL;
}
if (erofs_algs[i].c->setdictsize) {
@@ -136,32 +162,30 @@ int erofs_compressor_init(struct erofs_sb_info *sbi, struct erofs_compress *c,
if (ret) {
erofs_err("failed to set dict size %u for %s",
zset->dict_size, zset->alg);
- return ret;
+ goto fail;
}
- } else if (zset->dict_size) {
- erofs_err("dict size is not supported for %s",
- zset->alg);
- return -EINVAL;
}
- ret = erofs_algs[i].c->init(c);
- if (ret)
- return ret;
+ if (zset->extraopts && erofs_algs[i].c->setextraopts) {
+ ret = erofs_algs[i].c->setextraopts(c, zset->extraopts);
+ if (ret)
+ goto fail;
+ }
- if (!ret) {
- c->alg = &erofs_algs[i];
- return 0;
+ if (erofs_algs[i].c->init) {
+ ret = erofs_algs[i].c->init(c);
+ if (ret)
+ goto fail;
}
+ c->alg = &erofs_algs[i];
+ return 0;
}
erofs_err("Cannot find a valid compressor %s", zset->alg);
return ret;
-}
-
-int erofs_compressor_exit(struct erofs_compress *c)
-{
- if (c->alg && c->alg->c->exit)
- return c->alg->c->exit(c);
- return 0;
+fail:
+ if (erofs_algs[i].c->preinit && erofs_algs[i].c->exit)
+ erofs_algs[i].c->exit(c);
+ return ret;
}
void erofs_compressor_reset(struct erofs_compress *c)
diff --git a/lib/compressor.h b/lib/compressor.h
index c679466759d3..86b45a759874 100644
--- a/lib/compressor.h
+++ b/lib/compressor.h
@@ -17,12 +17,14 @@ struct erofs_compressor {
u32 default_dictsize;
u32 max_dictsize;
- int (*init)(struct erofs_compress *c);
+ int (*preinit)(struct erofs_compress *c);
int (*exit)(struct erofs_compress *c);
void (*reset)(struct erofs_compress *c);
int (*setlevel)(struct erofs_compress *c, int compression_level);
int (*setdictsize)(struct erofs_compress *c, u32 dict_size,
u32 pclustersize_max);
+ int (*setextraopts)(struct erofs_compress *c, const char *extraopts);
+ int (*init)(struct erofs_compress *c);
int (*compress_destsize)(const struct erofs_compress *c,
const void *src, unsigned int *srcsize,
diff --git a/lib/compressor_liblzma.c b/lib/compressor_liblzma.c
index e6026b26bc58..49a90a23525a 100644
--- a/lib/compressor_liblzma.c
+++ b/lib/compressor_liblzma.c
@@ -50,19 +50,43 @@ static int erofs_compressor_liblzma_exit(struct erofs_compress *c)
lzma_end(&ctx->strm);
free(ctx);
+ c->private_data = NULL;
+ return 0;
+}
+
+static int erofs_compressor_liblzma_preinit(struct erofs_compress *c)
+{
+ struct erofs_liblzma_context *ctx;
+
+ ctx = malloc(sizeof(*ctx));
+ if (!ctx)
+ return -ENOMEM;
+ ctx->strm = (lzma_stream)LZMA_STREAM_INIT;
+ DBG_BUGON(c->private_data);
+ c->private_data = ctx;
return 0;
}
static int erofs_compressor_liblzma_setlevel(struct erofs_compress *c,
int compression_level)
{
- if (compression_level < 0)
- compression_level = erofs_compressor_lzma.default_level;
+ struct erofs_liblzma_context *ctx = c->private_data;
+ u32 preset;
if (compression_level > erofs_compressor_lzma.best_level) {
erofs_err("invalid compression level %d", compression_level);
return -EINVAL;
}
+
+ if (compression_level < 0)
+ preset = LZMA_PRESET_DEFAULT;
+ else if (compression_level >= 100)
+ preset = (compression_level - 100) | LZMA_PRESET_EXTREME;
+ else
+ preset = compression_level;
+
+ if (lzma_lzma_preset(&ctx->opt, preset))
+ return -EINVAL;
c->compression_level = compression_level;
return 0;
}
@@ -70,6 +94,8 @@ static int erofs_compressor_liblzma_setlevel(struct erofs_compress *c,
static int erofs_compressor_liblzma_setdictsize(struct erofs_compress *c,
u32 dict_size, u32 pclustersize_max)
{
+ struct erofs_liblzma_context *ctx = c->private_data;
+
if (!dict_size) {
if (erofs_compressor_lzma.default_dictsize) {
dict_size = erofs_compressor_lzma.default_dictsize;
@@ -85,32 +111,52 @@ static int erofs_compressor_liblzma_setdictsize(struct erofs_compress *c,
erofs_err("invalid dictionary size %u", dict_size);
return -EINVAL;
}
- c->dict_size = dict_size;
+ ctx->opt.dict_size = c->dict_size = dict_size;
return 0;
}
-static int erofs_compressor_liblzma_init(struct erofs_compress *c)
+static int erofs_compressor_liblzma_setextraopts(struct erofs_compress *c,
+ const char *extraopts)
{
- struct erofs_liblzma_context *ctx;
- u32 preset;
-
- ctx = malloc(sizeof(*ctx));
- if (!ctx)
- return -ENOMEM;
- ctx->strm = (lzma_stream)LZMA_STREAM_INIT;
-
- if (c->compression_level < 0)
- preset = LZMA_PRESET_DEFAULT;
- else if (c->compression_level >= 100)
- preset = (c->compression_level - 100) | LZMA_PRESET_EXTREME;
- else
- preset = c->compression_level;
+ struct erofs_liblzma_context *ctx = c->private_data;
+ const char *token, *next;
+
+ for (token = extraopts; *token != '\0'; token = next) {
+ const char *p = strchr(token, ',');
+ const char *rhs;
+ char *endptr;
+ unsigned long val;
+ uint32_t *key;
+
+ next = NULL;
+ if (p) {
+ next = p + 1;
+ } else {
+ p = token + strlen(token);
+ next = p;
+ }
- if (lzma_lzma_preset(&ctx->opt, preset))
- return -EINVAL;
- ctx->opt.dict_size = c->dict_size;
+ if (!strncmp(token, "lc=", sizeof("lc=") - 1)) {
+ key = &ctx->opt.lc;
+ rhs = token + sizeof("lc=") - 1;
+ } else if (!strncmp(token, "lp=", sizeof("lp=") - 1)) {
+ key = &ctx->opt.lp;
+ rhs = token + sizeof("lp=") - 1;
+ } else if (!strncmp(token, "pb=", sizeof("pb=") - 1)) {
+ key = &ctx->opt.pb;
+ rhs = token + sizeof("pb=") - 1;
+ } else {
+ erofs_err("unknown extra options %s", extraopts);
+ return -EINVAL;
+ }
- c->private_data = ctx;
+ val = strtoul(rhs, &endptr, 0);
+ if (val == ULONG_MAX || endptr != p) {
+ erofs_err("invalid option %.*s", p - token, token);
+ return -EINVAL;
+ }
+ *key = val;
+ }
return 0;
}
@@ -118,10 +164,11 @@ const struct erofs_compressor erofs_compressor_lzma = {
.default_level = LZMA_PRESET_DEFAULT,
.best_level = 109,
.max_dictsize = Z_EROFS_LZMA_MAX_DICT_SIZE,
- .init = erofs_compressor_liblzma_init,
+ .preinit = erofs_compressor_liblzma_preinit,
.exit = erofs_compressor_liblzma_exit,
.setlevel = erofs_compressor_liblzma_setlevel,
.setdictsize = erofs_compressor_liblzma_setdictsize,
+ .setextraopts = erofs_compressor_liblzma_setextraopts,
.compress_destsize = erofs_liblzma_compress_destsize,
};
#endif
diff --git a/mkfs/main.c b/mkfs/main.c
index 326c332d37af..ee23944f3ebd 100644
--- a/mkfs/main.c
+++ b/mkfs/main.c
@@ -166,6 +166,12 @@ static void usage(int argc, char **argv)
printf("%s [,dictsize=<dictsize>]\t(default=<auto>, max=%u)\n",
spaces, s->c->max_dictsize);
}
+ if (!strcmp(s->name, "lzma")) {
+ printf("\n%s LZMA advanced options (do not specify if unsure):\n", spaces);
+ printf("%s [,lc=<n>] n = number of literal context bits\n", spaces);
+ printf("%s [,lp=<n>] n = number of literal position bits\n", spaces);
+ printf("%s [,pb=<n>] n = number of position bits\n", spaces);
+ }
}
printf(
" -C# specify the size of compress physical cluster in bytes\n"
@@ -845,7 +851,9 @@ unsigned int erofs_mkfs_total_ccfgs;
static int mkfs_parse_one_compress_alg(char *alg)
{
struct z_erofs_paramset *zset = mkfscfg.zcfgs + mkfscfg.total_zcfgs;
+ char extraopts[48];
char *p, *q, *opt, *endptr;
+ int i, j;
if (zset >= erofs_mkfs_zparams + ARRAY_SIZE(erofs_mkfs_zparams)) {
erofs_err("too many algorithm types");
@@ -854,6 +862,7 @@ static int mkfs_parse_one_compress_alg(char *alg)
zset->clevel = -1;
zset->dict_size = 0;
+ i = 0;
p = strchr(alg, ',');
if (!p) {
zset->alg = alg;
@@ -891,13 +900,20 @@ static int mkfs_parse_one_compress_alg(char *alg)
return -EINVAL;
}
} else {
- erofs_err("invalid compression option %s", opt);
- return -EINVAL;
+ if (i)
+ j = snprintf(extraopts + i, sizeof(extraopts) - i, ",%s", opt);
+ else
+ j = snprintf(extraopts, sizeof(extraopts), "%s", opt);
+ if (j < 0)
+ return -ERANGE;
+ i += j;
}
opt = q ? q + 1 : NULL;
}
}
}
+ if (i)
+ zset->extraopts = strdup(extraopts);
return mkfscfg.total_zcfgs++;
}
--
2.43.5
More information about the Linux-erofs
mailing list