]> Gentwo Git Trees - linux/.git/commitdiff
erofs: improve decompression error reporting
authorGao Xiang <hsiangkao@linux.alibaba.com>
Thu, 27 Nov 2025 07:31:19 +0000 (15:31 +0800)
committerGao Xiang <hsiangkao@linux.alibaba.com>
Fri, 28 Nov 2025 14:00:07 +0000 (22:00 +0800)
Change the return type of decompress() from `int` to `const char *` to
provide more informative error diagnostics:

 - A NULL return indicates successful decompression;

 - If IS_ERR(ptr) is true, the return value encodes a standard negative
   errno (e.g., -ENOMEM, -EOPNOTSUPP) identifying the specific error;

 - Otherwise, a non-NULL return points to a human-readable error string,
   and the corresponding error code should be treated as -EFSCORRUPTED.

Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
fs/erofs/compress.h
fs/erofs/decompressor.c
fs/erofs/decompressor_deflate.c
fs/erofs/decompressor_lzma.c
fs/erofs/decompressor_zstd.c
fs/erofs/zdata.c

index 510e922c51931a57b0b1352c315dd80bf3069218..1ee4ad934c1fabb8a6eba5045605eed5faeee849 100644 (file)
@@ -23,8 +23,8 @@ struct z_erofs_decompress_req {
 struct z_erofs_decompressor {
        int (*config)(struct super_block *sb, struct erofs_super_block *dsb,
                      void *data, int size);
-       int (*decompress)(struct z_erofs_decompress_req *rq,
-                         struct page **pagepool);
+       const char *(*decompress)(struct z_erofs_decompress_req *rq,
+                                 struct page **pagepool);
        int (*init)(void);
        void (*exit)(void);
        char *name;
index 2f4cef67cf6403fce99d18c9dd29c82e32b490a5..f9d29f43666f69331ea10c457572b874ccaaff74 100644 (file)
@@ -235,8 +235,6 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst
                                          rq->inputsize, rq->outputsize);
 
        if (ret != rq->outputsize) {
-               erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]",
-                         ret, rq->inputsize, inputmargin, rq->outputsize);
                if (ret >= 0)
                        memset(out + ret, 0, rq->outputsize - ret);
                ret = -EFSCORRUPTED;
@@ -257,8 +255,8 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst
        return ret;
 }
 
-static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
-                                 struct page **pagepool)
+static const char *z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
+                                         struct page **pagepool)
 {
        unsigned int dst_maptype;
        void *dst;
@@ -273,14 +271,14 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
                /* general decoding path which can be used for all cases */
                ret = z_erofs_lz4_prepare_dstpages(rq, pagepool);
                if (ret < 0)
-                       return ret;
+                       return ERR_PTR(ret);
                if (ret > 0) {
                        dst = page_address(*rq->out);
                        dst_maptype = 1;
                } else {
                        dst = erofs_vm_map_ram(rq->out, rq->outpages);
                        if (!dst)
-                               return -ENOMEM;
+                               return ERR_PTR(-ENOMEM);
                        dst_maptype = 2;
                }
        }
@@ -289,11 +287,11 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
                kunmap_local(dst);
        else if (dst_maptype == 2)
                vm_unmap_ram(dst, rq->outpages);
-       return ret;
+       return ERR_PTR(ret);
 }
 
-static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
-                                  struct page **pagepool)
+static const char *z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
+                                          struct page **pagepool)
 {
        const unsigned int nrpages_in = rq->inpages, nrpages_out = rq->outpages;
        const unsigned int bs = rq->sb->s_blocksize;
@@ -301,7 +299,7 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
        u8 *kin;
 
        if (rq->outputsize > rq->inputsize)
-               return -EOPNOTSUPP;
+               return ERR_PTR(-EOPNOTSUPP);
        if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
                cur = bs - (rq->pageofs_out & (bs - 1));
                pi = (rq->pageofs_in + rq->inputsize - cur) & ~PAGE_MASK;
@@ -341,7 +339,7 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
                kunmap_local(kin);
        }
        DBG_BUGON(ni > nrpages_in);
-       return 0;
+       return NULL;
 }
 
 int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
index 6909b2d529c7a270c4179521edc4af2bc68718b7..e9c4b740ef89262274f0b4831656e8a1c2cc4eef 100644 (file)
@@ -157,8 +157,6 @@ static int __z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
                                break;
                        if (zerr == Z_STREAM_END && !rq->outputsize)
                                break;
-                       erofs_err(sb, "failed to decompress %d in[%u] out[%u]",
-                                 zerr, rq->inputsize, rq->outputsize);
                        err = -EFSCORRUPTED;
                        break;
                }
@@ -178,8 +176,8 @@ static int __z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
        return err;
 }
 
-static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
-                                     struct page **pgpl)
+static const char *z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
+                                             struct page **pgpl)
 {
 #ifdef CONFIG_EROFS_FS_ZIP_ACCEL
        int err;
@@ -187,11 +185,11 @@ static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
        if (!rq->partial_decoding) {
                err = z_erofs_crypto_decompress(rq, pgpl);
                if (err != -EOPNOTSUPP)
-                       return err;
+                       return ERR_PTR(err);
 
        }
 #endif
-       return __z_erofs_deflate_decompress(rq, pgpl);
+       return ERR_PTR(__z_erofs_deflate_decompress(rq, pgpl));
 }
 
 const struct z_erofs_decompressor z_erofs_deflate_decomp = {
index 832cffb83a6622a88088a64223a72179c6585ce2..7784ced901456d86ca303769a8257a1051e92e00 100644 (file)
@@ -146,8 +146,8 @@ static int z_erofs_load_lzma_config(struct super_block *sb,
        return err;
 }
 
-static int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
-                                  struct page **pgpl)
+static const char *z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
+                                          struct page **pgpl)
 {
        struct super_block *sb = rq->sb;
        struct z_erofs_stream_dctx dctx = { .rq = rq, .no = -1, .ni = 0 };
@@ -162,7 +162,7 @@ static int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
                        min(rq->inputsize, sb->s_blocksize - rq->pageofs_in));
        if (err) {
                kunmap_local(dctx.kin);
-               return err;
+               return ERR_PTR(err);
        }
 
        /* 2. get an available lzma context */
@@ -207,8 +207,6 @@ static int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
                if (xz_err != XZ_OK) {
                        if (xz_err == XZ_STREAM_END && !rq->outputsize)
                                break;
-                       erofs_err(sb, "failed to decompress %d in[%u] out[%u]",
-                                 xz_err, rq->inputsize, rq->outputsize);
                        err = -EFSCORRUPTED;
                        break;
                }
@@ -223,7 +221,7 @@ static int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
        z_erofs_lzma_head = strm;
        spin_unlock(&z_erofs_lzma_lock);
        wake_up(&z_erofs_lzma_wq);
-       return err;
+       return ERR_PTR(err);
 }
 
 const struct z_erofs_decompressor z_erofs_lzma_decomp = {
index e38d93bb21048f9b298c7790daed52a53ff5b403..50fadff89cbc109813e98b5b743f569ceb76bdcf 100644 (file)
@@ -135,8 +135,8 @@ static int z_erofs_load_zstd_config(struct super_block *sb,
        return strm ? -ENOMEM : 0;
 }
 
-static int z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
-                                  struct page **pgpl)
+static const char *z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
+                                          struct page **pgpl)
 {
        struct super_block *sb = rq->sb;
        struct z_erofs_stream_dctx dctx = { .rq = rq, .no = -1, .ni = 0 };
@@ -152,7 +152,7 @@ static int z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
                        min(rq->inputsize, sb->s_blocksize - rq->pageofs_in));
        if (err) {
                kunmap_local(dctx.kin);
-               return err;
+               return ERR_PTR(err);
        }
 
        /* 2. get an available ZSTD context */
@@ -191,10 +191,6 @@ static int z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
                if (zstd_is_error(zerr) ||
                    ((rq->outputsize + dctx.avail_out) && (!zerr || (zerr > 0 &&
                                !(rq->inputsize + in_buf.size - in_buf.pos))))) {
-                       erofs_err(sb, "failed to decompress in[%u] out[%u]: %s",
-                                 rq->inputsize, rq->outputsize,
-                                 zstd_is_error(zerr) ? zstd_get_error_name(zerr) :
-                                       "unexpected end of stream");
                        err = -EFSCORRUPTED;
                        break;
                }
@@ -210,7 +206,7 @@ static int z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
        z_erofs_zstd_head = strm;
        spin_unlock(&z_erofs_zstd_lock);
        wake_up(&z_erofs_zstd_wq);
-       return err;
+       return ERR_PTR(err);
 }
 
 const struct z_erofs_decompressor z_erofs_zstd_decomp = {
index bc80cfe482f73bdb4ac5a8810c39e95c5089f4ff..461a929e0825859cf17a031ec7c8895175e76f4c 100644 (file)
@@ -1267,12 +1267,13 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, int err)
        struct erofs_sb_info *const sbi = EROFS_SB(be->sb);
        struct z_erofs_pcluster *pcl = be->pcl;
        unsigned int pclusterpages = z_erofs_pclusterpages(pcl);
-       const struct z_erofs_decompressor *decomp =
+       const struct z_erofs_decompressor *alg =
                                z_erofs_decomp[pcl->algorithmformat];
+       bool try_free = true;
        int i, j, jtop, err2;
        struct page *page;
        bool overlapped;
-       bool try_free = true;
+       const char *reason;
 
        mutex_lock(&pcl->lock);
        be->nr_pages = PAGE_ALIGN(pcl->length + pcl->pageofs_out) >> PAGE_SHIFT;
@@ -1304,8 +1305,8 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, int err)
        err2 = z_erofs_parse_in_bvecs(be, &overlapped);
        if (err2)
                err = err2;
-       if (!err)
-               err = decomp->decompress(&(struct z_erofs_decompress_req) {
+       if (!err) {
+               reason = alg->decompress(&(struct z_erofs_decompress_req) {
                                        .sb = be->sb,
                                        .in = be->compressed_pages,
                                        .out = be->decompressed_pages,
@@ -1322,6 +1323,18 @@ static int z_erofs_decompress_pcluster(struct z_erofs_backend *be, int err)
                                        .gfp = pcl->besteffort ? GFP_KERNEL :
                                                GFP_NOWAIT | __GFP_NORETRY
                                 }, be->pagepool);
+               if (IS_ERR(reason)) {
+                       erofs_err(be->sb, "failed to decompress (%s) %ld @ pa %llu size %u => %u",
+                                 alg->name, PTR_ERR(reason), pcl->pos,
+                                 pcl->pclustersize, pcl->length);
+                       err = PTR_ERR(reason);
+               } else if (unlikely(reason)) {
+                       erofs_err(be->sb, "failed to decompress (%s) %s @ pa %llu size %u => %u",
+                                 alg->name, reason, pcl->pos,
+                                 pcl->pclustersize, pcl->length);
+                       err = -EFSCORRUPTED;
+               }
+       }
 
        /* must handle all compressed pages before actual file pages */
        if (pcl->from_meta) {