File-level compression fallback is control flow, not a real error.
Return an erofs-specific status code for it instead of overloading
-ENOSPC, which can also report real space failures.
Keep the global compression context reusable for that fallback while
preserving the fatal state for real errors.
Fixes: a729584ef975 ("erofs-utils: mkfs: avoid hanging if fragment is on and
tmpdir is full")
Reported-by: Bastian Schmitz <[email protected]>
Closes: https://github.com/erofs/erofs-utils/issues/50
Assisted-by: Codex:GPT-5.5
Signed-off-by: Yifan Zhao <[email protected]>
---
include/erofs/err.h | 1 +
lib/compress.c | 10 +++++++---
lib/inode.c | 6 +++---
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/include/erofs/err.h b/include/erofs/err.h
index 7dacc91..ef882c9 100644
--- a/include/erofs/err.h
+++ b/include/erofs/err.h
@@ -29,6 +29,7 @@ static inline const char *erofs_strerror(int err)
}
#define MAX_ERRNO (4095)
+#define EROFS_ERRNO_COMPR_FALLBACK (MAX_ERRNO + 1)
#define IS_ERR_VALUE(x)
\
((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO)
diff --git a/lib/compress.c b/lib/compress.c
index ea07409..edc29ed 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -1375,7 +1375,7 @@ int erofs_commit_compressed_file(struct
z_erofs_compress_ictx *ictx,
legacymetasize >= inode->i_size) {
z_erofs_dedupe_ext_commit(true);
z_erofs_dedupe_commit(true);
- ret = -ENOSPC;
+ ret = -EROFS_ERRNO_COMPR_FALLBACK;
goto err_free_meta;
}
z_erofs_dedupe_ext_commit(false);
@@ -2031,7 +2031,11 @@ err_free_idata:
out:
#ifdef EROFS_MT_ENABLED
pthread_mutex_lock(&ictx->mutex);
- ictx->seg_num = ret < 0 ? INT_MAX : 0;
+ if (ret < 0 && ret != -EROFS_ERRNO_COMPR_FALLBACK)
+ /* mark as failed to avoid further processing */
+ ictx->seg_num = INT_MAX;
+ else
+ ictx->seg_num = 0;
pthread_cond_signal(&ictx->cond);
pthread_mutex_unlock(&ictx->mutex);
#endif
@@ -2044,7 +2048,7 @@ int erofs_begin_compress_dir(struct erofs_importer *im,
{
if (!im->params->compress_dir ||
inode->i_size < Z_EROFS_LEGACY_MAP_HEADER_SIZE)
- return -ENOSPC;
+ return -EROFS_ERRNO_COMPR_FALLBACK;
inode->z_advise |= Z_EROFS_ADVISE_FRAGMENT_PCLUSTER;
erofs_sb_set_fragments(inode->sbi);
diff --git a/lib/inode.c b/lib/inode.c
index c225faa..9f3d7e6 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -1507,7 +1507,7 @@ static int erofs_mkfs_job_write_file(struct
erofs_mkfs_job_ndir_ctx *ctx)
if (ctx->ictx) {
ret = erofs_write_compressed_file(ctx->ictx);
- if (ret != -ENOSPC)
+ if (ret != -EROFS_ERRNO_COMPR_FALLBACK)
goto out;
if (lseek(ctx->fd, ctx->fpos, SEEK_SET) < 0) {
ret = -errno;
@@ -1594,7 +1594,7 @@ static int erofs_mkfs_create_directory(const struct
erofs_mkfs_btctx *ctx,
inode->datalayout = EROFS_INODE_FLAT_INLINE;
ret = erofs_begin_compress_dir(ctx->im, inode);
- if (ret && ret != -ENOSPC)
+ if (ret && ret != -EROFS_ERRNO_COMPR_FALLBACK)
return ret;
} else {
DBG_BUGON(inode->datalayout != EROFS_INODE_FLAT_PLAIN);
@@ -2391,7 +2391,7 @@ struct erofs_inode
*erofs_mkfs_build_special_from_fd(struct erofs_importer *im,
ret = erofs_write_compressed_file(ictx);
if (!ret)
goto out;
- if (ret != -ENOSPC)
+ if (ret != -EROFS_ERRNO_COMPR_FALLBACK)
return ERR_PTR(ret);
ret = lseek(fd, 0, SEEK_SET);
--
2.47.3