mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 10:04:04 +02:00
erofs: improve decompression error reporting
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>
This commit is contained in:
parent
9ae77198d4
commit
831faabed8
|
|
@ -23,8 +23,8 @@ struct z_erofs_decompress_req {
|
||||||
struct z_erofs_decompressor {
|
struct z_erofs_decompressor {
|
||||||
int (*config)(struct super_block *sb, struct erofs_super_block *dsb,
|
int (*config)(struct super_block *sb, struct erofs_super_block *dsb,
|
||||||
void *data, int size);
|
void *data, int size);
|
||||||
int (*decompress)(struct z_erofs_decompress_req *rq,
|
const char *(*decompress)(struct z_erofs_decompress_req *rq,
|
||||||
struct page **pagepool);
|
struct page **pagepool);
|
||||||
int (*init)(void);
|
int (*init)(void);
|
||||||
void (*exit)(void);
|
void (*exit)(void);
|
||||||
char *name;
|
char *name;
|
||||||
|
|
|
||||||
|
|
@ -235,8 +235,6 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst
|
||||||
rq->inputsize, rq->outputsize);
|
rq->inputsize, rq->outputsize);
|
||||||
|
|
||||||
if (ret != 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)
|
if (ret >= 0)
|
||||||
memset(out + ret, 0, rq->outputsize - ret);
|
memset(out + ret, 0, rq->outputsize - ret);
|
||||||
ret = -EFSCORRUPTED;
|
ret = -EFSCORRUPTED;
|
||||||
|
|
@ -257,8 +255,8 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
|
static const char *z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
|
||||||
struct page **pagepool)
|
struct page **pagepool)
|
||||||
{
|
{
|
||||||
unsigned int dst_maptype;
|
unsigned int dst_maptype;
|
||||||
void *dst;
|
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 */
|
/* general decoding path which can be used for all cases */
|
||||||
ret = z_erofs_lz4_prepare_dstpages(rq, pagepool);
|
ret = z_erofs_lz4_prepare_dstpages(rq, pagepool);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ERR_PTR(ret);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
dst = page_address(*rq->out);
|
dst = page_address(*rq->out);
|
||||||
dst_maptype = 1;
|
dst_maptype = 1;
|
||||||
} else {
|
} else {
|
||||||
dst = erofs_vm_map_ram(rq->out, rq->outpages);
|
dst = erofs_vm_map_ram(rq->out, rq->outpages);
|
||||||
if (!dst)
|
if (!dst)
|
||||||
return -ENOMEM;
|
return ERR_PTR(-ENOMEM);
|
||||||
dst_maptype = 2;
|
dst_maptype = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -289,11 +287,11 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
|
||||||
kunmap_local(dst);
|
kunmap_local(dst);
|
||||||
else if (dst_maptype == 2)
|
else if (dst_maptype == 2)
|
||||||
vm_unmap_ram(dst, rq->outpages);
|
vm_unmap_ram(dst, rq->outpages);
|
||||||
return ret;
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
|
static const char *z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
|
||||||
struct page **pagepool)
|
struct page **pagepool)
|
||||||
{
|
{
|
||||||
const unsigned int nrpages_in = rq->inpages, nrpages_out = rq->outpages;
|
const unsigned int nrpages_in = rq->inpages, nrpages_out = rq->outpages;
|
||||||
const unsigned int bs = rq->sb->s_blocksize;
|
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;
|
u8 *kin;
|
||||||
|
|
||||||
if (rq->outputsize > rq->inputsize)
|
if (rq->outputsize > rq->inputsize)
|
||||||
return -EOPNOTSUPP;
|
return ERR_PTR(-EOPNOTSUPP);
|
||||||
if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
|
if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
|
||||||
cur = bs - (rq->pageofs_out & (bs - 1));
|
cur = bs - (rq->pageofs_out & (bs - 1));
|
||||||
pi = (rq->pageofs_in + rq->inputsize - cur) & ~PAGE_MASK;
|
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);
|
kunmap_local(kin);
|
||||||
}
|
}
|
||||||
DBG_BUGON(ni > nrpages_in);
|
DBG_BUGON(ni > nrpages_in);
|
||||||
return 0;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
|
int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
|
||||||
|
|
|
||||||
|
|
@ -157,8 +157,6 @@ static int __z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
|
||||||
break;
|
break;
|
||||||
if (zerr == Z_STREAM_END && !rq->outputsize)
|
if (zerr == Z_STREAM_END && !rq->outputsize)
|
||||||
break;
|
break;
|
||||||
erofs_err(sb, "failed to decompress %d in[%u] out[%u]",
|
|
||||||
zerr, rq->inputsize, rq->outputsize);
|
|
||||||
err = -EFSCORRUPTED;
|
err = -EFSCORRUPTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -178,8 +176,8 @@ static int __z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
|
static const char *z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
|
||||||
struct page **pgpl)
|
struct page **pgpl)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_EROFS_FS_ZIP_ACCEL
|
#ifdef CONFIG_EROFS_FS_ZIP_ACCEL
|
||||||
int err;
|
int err;
|
||||||
|
|
@ -187,11 +185,11 @@ static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
|
||||||
if (!rq->partial_decoding) {
|
if (!rq->partial_decoding) {
|
||||||
err = z_erofs_crypto_decompress(rq, pgpl);
|
err = z_erofs_crypto_decompress(rq, pgpl);
|
||||||
if (err != -EOPNOTSUPP)
|
if (err != -EOPNOTSUPP)
|
||||||
return err;
|
return ERR_PTR(err);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#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 = {
|
const struct z_erofs_decompressor z_erofs_deflate_decomp = {
|
||||||
|
|
|
||||||
|
|
@ -146,8 +146,8 @@ static int z_erofs_load_lzma_config(struct super_block *sb,
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
|
static const char *z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
|
||||||
struct page **pgpl)
|
struct page **pgpl)
|
||||||
{
|
{
|
||||||
struct super_block *sb = rq->sb;
|
struct super_block *sb = rq->sb;
|
||||||
struct z_erofs_stream_dctx dctx = { .rq = rq, .no = -1, .ni = 0 };
|
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));
|
min(rq->inputsize, sb->s_blocksize - rq->pageofs_in));
|
||||||
if (err) {
|
if (err) {
|
||||||
kunmap_local(dctx.kin);
|
kunmap_local(dctx.kin);
|
||||||
return err;
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2. get an available lzma context */
|
/* 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_OK) {
|
||||||
if (xz_err == XZ_STREAM_END && !rq->outputsize)
|
if (xz_err == XZ_STREAM_END && !rq->outputsize)
|
||||||
break;
|
break;
|
||||||
erofs_err(sb, "failed to decompress %d in[%u] out[%u]",
|
|
||||||
xz_err, rq->inputsize, rq->outputsize);
|
|
||||||
err = -EFSCORRUPTED;
|
err = -EFSCORRUPTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -223,7 +221,7 @@ static int z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
|
||||||
z_erofs_lzma_head = strm;
|
z_erofs_lzma_head = strm;
|
||||||
spin_unlock(&z_erofs_lzma_lock);
|
spin_unlock(&z_erofs_lzma_lock);
|
||||||
wake_up(&z_erofs_lzma_wq);
|
wake_up(&z_erofs_lzma_wq);
|
||||||
return err;
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct z_erofs_decompressor z_erofs_lzma_decomp = {
|
const struct z_erofs_decompressor z_erofs_lzma_decomp = {
|
||||||
|
|
|
||||||
|
|
@ -135,8 +135,8 @@ static int z_erofs_load_zstd_config(struct super_block *sb,
|
||||||
return strm ? -ENOMEM : 0;
|
return strm ? -ENOMEM : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
|
static const char *z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
|
||||||
struct page **pgpl)
|
struct page **pgpl)
|
||||||
{
|
{
|
||||||
struct super_block *sb = rq->sb;
|
struct super_block *sb = rq->sb;
|
||||||
struct z_erofs_stream_dctx dctx = { .rq = rq, .no = -1, .ni = 0 };
|
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));
|
min(rq->inputsize, sb->s_blocksize - rq->pageofs_in));
|
||||||
if (err) {
|
if (err) {
|
||||||
kunmap_local(dctx.kin);
|
kunmap_local(dctx.kin);
|
||||||
return err;
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 2. get an available ZSTD context */
|
/* 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) ||
|
if (zstd_is_error(zerr) ||
|
||||||
((rq->outputsize + dctx.avail_out) && (!zerr || (zerr > 0 &&
|
((rq->outputsize + dctx.avail_out) && (!zerr || (zerr > 0 &&
|
||||||
!(rq->inputsize + in_buf.size - in_buf.pos))))) {
|
!(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;
|
err = -EFSCORRUPTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -210,7 +206,7 @@ static int z_erofs_zstd_decompress(struct z_erofs_decompress_req *rq,
|
||||||
z_erofs_zstd_head = strm;
|
z_erofs_zstd_head = strm;
|
||||||
spin_unlock(&z_erofs_zstd_lock);
|
spin_unlock(&z_erofs_zstd_lock);
|
||||||
wake_up(&z_erofs_zstd_wq);
|
wake_up(&z_erofs_zstd_wq);
|
||||||
return err;
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct z_erofs_decompressor z_erofs_zstd_decomp = {
|
const struct z_erofs_decompressor z_erofs_zstd_decomp = {
|
||||||
|
|
|
||||||
|
|
@ -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 erofs_sb_info *const sbi = EROFS_SB(be->sb);
|
||||||
struct z_erofs_pcluster *pcl = be->pcl;
|
struct z_erofs_pcluster *pcl = be->pcl;
|
||||||
unsigned int pclusterpages = z_erofs_pclusterpages(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];
|
z_erofs_decomp[pcl->algorithmformat];
|
||||||
|
bool try_free = true;
|
||||||
int i, j, jtop, err2;
|
int i, j, jtop, err2;
|
||||||
struct page *page;
|
struct page *page;
|
||||||
bool overlapped;
|
bool overlapped;
|
||||||
bool try_free = true;
|
const char *reason;
|
||||||
|
|
||||||
mutex_lock(&pcl->lock);
|
mutex_lock(&pcl->lock);
|
||||||
be->nr_pages = PAGE_ALIGN(pcl->length + pcl->pageofs_out) >> PAGE_SHIFT;
|
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);
|
err2 = z_erofs_parse_in_bvecs(be, &overlapped);
|
||||||
if (err2)
|
if (err2)
|
||||||
err = err2;
|
err = err2;
|
||||||
if (!err)
|
if (!err) {
|
||||||
err = decomp->decompress(&(struct z_erofs_decompress_req) {
|
reason = alg->decompress(&(struct z_erofs_decompress_req) {
|
||||||
.sb = be->sb,
|
.sb = be->sb,
|
||||||
.in = be->compressed_pages,
|
.in = be->compressed_pages,
|
||||||
.out = be->decompressed_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 = pcl->besteffort ? GFP_KERNEL :
|
||||||
GFP_NOWAIT | __GFP_NORETRY
|
GFP_NOWAIT | __GFP_NORETRY
|
||||||
}, be->pagepool);
|
}, 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 */
|
/* must handle all compressed pages before actual file pages */
|
||||||
if (pcl->from_meta) {
|
if (pcl->from_meta) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user