Skip to content

Commit 477e31f

Browse files
committed
Merge tag 'erofs-for-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs
Pull erofs updates from Gao Xiang: - Fix a WARNING caused by a recent FSDAX misdetection regression - Fix the filesystem stacking limit for file-backed mounts - Print more informative diagnostics on decompression errors - Switch the on-disk definition `erofs_fs.h` to the MIT license - Minor cleanups * tag 'erofs-for-6.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs: erofs: switch on-disk header `erofs_fs.h` to MIT license erofs: get rid of raw bi_end_io() usage erofs: enable error reporting for z_erofs_fixup_insize() erofs: enable error reporting for z_erofs_stream_switch_bufs() erofs: improve Zstd, LZMA and DEFLATE error strings erofs: improve decompression error reporting erofs: tidy up z_erofs_lz4_handle_overlap() erofs: limit the level of fs stacking for file-backed mounts erofs: correct FSDAX detection
2 parents ca010e2 + 0bdbf89 commit 477e31f

11 files changed

Lines changed: 178 additions & 148 deletions

fs/erofs/compress.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ struct z_erofs_decompress_req {
2323
struct z_erofs_decompressor {
2424
int (*config)(struct super_block *sb, struct erofs_super_block *dsb,
2525
void *data, int size);
26-
int (*decompress)(struct z_erofs_decompress_req *rq,
27-
struct page **pagepool);
26+
const char *(*decompress)(struct z_erofs_decompress_req *rq,
27+
struct page **pagepool);
2828
int (*init)(void);
2929
void (*exit)(void);
3030
char *name;
@@ -70,10 +70,10 @@ struct z_erofs_stream_dctx {
7070
bool bounced; /* is the bounce buffer used now? */
7171
};
7272

73-
int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
74-
void **src, struct page **pgpl);
75-
int z_erofs_fixup_insize(struct z_erofs_decompress_req *rq, const char *padbuf,
76-
unsigned int padbufsize);
73+
const char *z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx,
74+
void **dst, void **src, struct page **pgpl);
75+
const char *z_erofs_fixup_insize(struct z_erofs_decompress_req *rq,
76+
const char *padbuf, unsigned int padbufsize);
7777
int __init z_erofs_init_decompressor(void);
7878
void z_erofs_exit_decompressor(void);
7979
int z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,

fs/erofs/decompressor.c

Lines changed: 75 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -105,94 +105,102 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_decompress_req *rq,
105105
return kaddr ? 1 : 0;
106106
}
107107

108-
static void *z_erofs_lz4_handle_overlap(struct z_erofs_decompress_req *rq,
108+
static void *z_erofs_lz4_handle_overlap(const struct z_erofs_decompress_req *rq,
109109
void *inpage, void *out, unsigned int *inputmargin,
110110
int *maptype, bool may_inplace)
111111
{
112-
unsigned int oend, omargin, total, i;
112+
unsigned int oend, omargin, cnt, i;
113113
struct page **in;
114-
void *src, *tmp;
115-
116-
if (rq->inplace_io) {
117-
oend = rq->pageofs_out + rq->outputsize;
118-
omargin = PAGE_ALIGN(oend) - oend;
119-
if (rq->partial_decoding || !may_inplace ||
120-
omargin < LZ4_DECOMPRESS_INPLACE_MARGIN(rq->inputsize))
121-
goto docopy;
114+
void *src;
122115

116+
/*
117+
* If in-place I/O isn't used, for example, the bounce compressed cache
118+
* can hold data for incomplete read requests. Just map the compressed
119+
* buffer as well and decompress directly.
120+
*/
121+
if (!rq->inplace_io) {
122+
if (rq->inpages <= 1) {
123+
*maptype = 0;
124+
return inpage;
125+
}
126+
kunmap_local(inpage);
127+
src = erofs_vm_map_ram(rq->in, rq->inpages);
128+
if (!src)
129+
return ERR_PTR(-ENOMEM);
130+
*maptype = 1;
131+
return src;
132+
}
133+
/*
134+
* Then, deal with in-place I/Os. The reasons why in-place I/O is useful
135+
* are: (1) It minimizes memory footprint during the I/O submission,
136+
* which is useful for slow storage (including network devices and
137+
* low-end HDDs/eMMCs) but with a lot inflight I/Os; (2) If in-place
138+
* decompression can also be applied, it will reuse the unique buffer so
139+
* that no extra CPU D-cache is polluted with temporary compressed data
140+
* for extreme performance.
141+
*/
142+
oend = rq->pageofs_out + rq->outputsize;
143+
omargin = PAGE_ALIGN(oend) - oend;
144+
if (!rq->partial_decoding && may_inplace &&
145+
omargin >= LZ4_DECOMPRESS_INPLACE_MARGIN(rq->inputsize)) {
123146
for (i = 0; i < rq->inpages; ++i)
124147
if (rq->out[rq->outpages - rq->inpages + i] !=
125148
rq->in[i])
126-
goto docopy;
127-
kunmap_local(inpage);
128-
*maptype = 3;
129-
return out + ((rq->outpages - rq->inpages) << PAGE_SHIFT);
130-
}
131-
132-
if (rq->inpages <= 1) {
133-
*maptype = 0;
134-
return inpage;
149+
break;
150+
if (i >= rq->inpages) {
151+
kunmap_local(inpage);
152+
*maptype = 3;
153+
return out + ((rq->outpages - rq->inpages) << PAGE_SHIFT);
154+
}
135155
}
136-
kunmap_local(inpage);
137-
src = erofs_vm_map_ram(rq->in, rq->inpages);
138-
if (!src)
139-
return ERR_PTR(-ENOMEM);
140-
*maptype = 1;
141-
return src;
142-
143-
docopy:
144-
/* Or copy compressed data which can be overlapped to per-CPU buffer */
145-
in = rq->in;
156+
/*
157+
* If in-place decompression can't be applied, copy compressed data that
158+
* may potentially overlap during decompression to a per-CPU buffer.
159+
*/
146160
src = z_erofs_get_gbuf(rq->inpages);
147161
if (!src) {
148162
DBG_BUGON(1);
149163
kunmap_local(inpage);
150164
return ERR_PTR(-EFAULT);
151165
}
152166

153-
tmp = src;
154-
total = rq->inputsize;
155-
while (total) {
156-
unsigned int page_copycnt =
157-
min_t(unsigned int, total, PAGE_SIZE - *inputmargin);
158-
167+
for (i = 0, in = rq->in; i < rq->inputsize; i += cnt, ++in) {
168+
cnt = min_t(u32, rq->inputsize - i, PAGE_SIZE - *inputmargin);
159169
if (!inpage)
160170
inpage = kmap_local_page(*in);
161-
memcpy(tmp, inpage + *inputmargin, page_copycnt);
171+
memcpy(src + i, inpage + *inputmargin, cnt);
162172
kunmap_local(inpage);
163173
inpage = NULL;
164-
tmp += page_copycnt;
165-
total -= page_copycnt;
166-
++in;
167174
*inputmargin = 0;
168175
}
169176
*maptype = 2;
170177
return src;
171178
}
172179

173180
/*
174-
* Get the exact inputsize with zero_padding feature.
175-
* - For LZ4, it should work if zero_padding feature is on (5.3+);
176-
* - For MicroLZMA, it'd be enabled all the time.
181+
* Get the exact on-disk size of the compressed data:
182+
* - For LZ4, it should apply if the zero_padding feature is on (5.3+);
183+
* - For others, zero_padding is enabled all the time.
177184
*/
178-
int z_erofs_fixup_insize(struct z_erofs_decompress_req *rq, const char *padbuf,
179-
unsigned int padbufsize)
185+
const char *z_erofs_fixup_insize(struct z_erofs_decompress_req *rq,
186+
const char *padbuf, unsigned int padbufsize)
180187
{
181188
const char *padend;
182189

183190
padend = memchr_inv(padbuf, 0, padbufsize);
184191
if (!padend)
185-
return -EFSCORRUPTED;
192+
return "compressed data start not found";
186193
rq->inputsize -= padend - padbuf;
187194
rq->pageofs_in += padend - padbuf;
188-
return 0;
195+
return NULL;
189196
}
190197

191198
static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst)
192199
{
193200
bool support_0padding = false, may_inplace = false;
194201
unsigned int inputmargin;
195202
u8 *out, *headpage, *src;
203+
const char *reason;
196204
int ret, maptype;
197205

198206
DBG_BUGON(*rq->in == NULL);
@@ -201,12 +209,12 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst
201209
/* LZ4 decompression inplace is only safe if zero_padding is enabled */
202210
if (erofs_sb_has_zero_padding(EROFS_SB(rq->sb))) {
203211
support_0padding = true;
204-
ret = z_erofs_fixup_insize(rq, headpage + rq->pageofs_in,
212+
reason = z_erofs_fixup_insize(rq, headpage + rq->pageofs_in,
205213
min_t(unsigned int, rq->inputsize,
206214
rq->sb->s_blocksize - rq->pageofs_in));
207-
if (ret) {
215+
if (reason) {
208216
kunmap_local(headpage);
209-
return ret;
217+
return IS_ERR(reason) ? PTR_ERR(reason) : -EFSCORRUPTED;
210218
}
211219
may_inplace = !((rq->pageofs_in + rq->inputsize) &
212220
(rq->sb->s_blocksize - 1));
@@ -228,8 +236,6 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst
228236
rq->inputsize, rq->outputsize);
229237

230238
if (ret != rq->outputsize) {
231-
erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]",
232-
ret, rq->inputsize, inputmargin, rq->outputsize);
233239
if (ret >= 0)
234240
memset(out + ret, 0, rq->outputsize - ret);
235241
ret = -EFSCORRUPTED;
@@ -250,8 +256,8 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *dst
250256
return ret;
251257
}
252258

253-
static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
254-
struct page **pagepool)
259+
static const char *z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
260+
struct page **pagepool)
255261
{
256262
unsigned int dst_maptype;
257263
void *dst;
@@ -266,14 +272,14 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
266272
/* general decoding path which can be used for all cases */
267273
ret = z_erofs_lz4_prepare_dstpages(rq, pagepool);
268274
if (ret < 0)
269-
return ret;
275+
return ERR_PTR(ret);
270276
if (ret > 0) {
271277
dst = page_address(*rq->out);
272278
dst_maptype = 1;
273279
} else {
274280
dst = erofs_vm_map_ram(rq->out, rq->outpages);
275281
if (!dst)
276-
return -ENOMEM;
282+
return ERR_PTR(-ENOMEM);
277283
dst_maptype = 2;
278284
}
279285
}
@@ -282,19 +288,19 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
282288
kunmap_local(dst);
283289
else if (dst_maptype == 2)
284290
vm_unmap_ram(dst, rq->outpages);
285-
return ret;
291+
return ERR_PTR(ret);
286292
}
287293

288-
static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
289-
struct page **pagepool)
294+
static const char *z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
295+
struct page **pagepool)
290296
{
291297
const unsigned int nrpages_in = rq->inpages, nrpages_out = rq->outpages;
292298
const unsigned int bs = rq->sb->s_blocksize;
293299
unsigned int cur = 0, ni = 0, no, pi, po, insz, cnt;
294300
u8 *kin;
295301

296302
if (rq->outputsize > rq->inputsize)
297-
return -EOPNOTSUPP;
303+
return ERR_PTR(-EOPNOTSUPP);
298304
if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
299305
cur = bs - (rq->pageofs_out & (bs - 1));
300306
pi = (rq->pageofs_in + rq->inputsize - cur) & ~PAGE_MASK;
@@ -334,22 +340,19 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
334340
kunmap_local(kin);
335341
}
336342
DBG_BUGON(ni > nrpages_in);
337-
return 0;
343+
return NULL;
338344
}
339345

340-
int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
341-
void **src, struct page **pgpl)
346+
const char *z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx,
347+
void **dst, void **src, struct page **pgpl)
342348
{
343349
struct z_erofs_decompress_req *rq = dctx->rq;
344-
struct super_block *sb = rq->sb;
345350
struct page **pgo, *tmppage;
346351
unsigned int j;
347352

348353
if (!dctx->avail_out) {
349-
if (++dctx->no >= rq->outpages || !rq->outputsize) {
350-
erofs_err(sb, "insufficient space for decompressed data");
351-
return -EFSCORRUPTED;
352-
}
354+
if (++dctx->no >= rq->outpages || !rq->outputsize)
355+
return "insufficient space for decompressed data";
353356

354357
if (dctx->kout)
355358
kunmap_local(dctx->kout);
@@ -360,7 +363,7 @@ int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
360363
*pgo = erofs_allocpage(pgpl, rq->gfp);
361364
if (!*pgo) {
362365
dctx->kout = NULL;
363-
return -ENOMEM;
366+
return ERR_PTR(-ENOMEM);
364367
}
365368
set_page_private(*pgo, Z_EROFS_SHORTLIVED_PAGE);
366369
}
@@ -374,10 +377,8 @@ int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
374377
}
375378

376379
if (dctx->inbuf_pos == dctx->inbuf_sz && rq->inputsize) {
377-
if (++dctx->ni >= rq->inpages) {
378-
erofs_err(sb, "invalid compressed data");
379-
return -EFSCORRUPTED;
380-
}
380+
if (++dctx->ni >= rq->inpages)
381+
return "invalid compressed data";
381382
if (dctx->kout) /* unlike kmap(), take care of the orders */
382383
kunmap_local(dctx->kout);
383384
kunmap_local(dctx->kin);
@@ -412,12 +413,12 @@ int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
412413
continue;
413414
tmppage = erofs_allocpage(pgpl, rq->gfp);
414415
if (!tmppage)
415-
return -ENOMEM;
416+
return ERR_PTR(-ENOMEM);
416417
set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE);
417418
copy_highpage(tmppage, rq->in[j]);
418419
rq->in[j] = tmppage;
419420
}
420-
return 0;
421+
return NULL;
421422
}
422423

423424
const struct z_erofs_decompressor *z_erofs_decomp[] = {

fs/erofs/decompressor_crypto.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@ static int __z_erofs_crypto_decompress(struct z_erofs_decompress_req *rq,
99
struct sg_table st_src, st_dst;
1010
struct acomp_req *req;
1111
struct crypto_wait wait;
12+
const char *reason;
1213
u8 *headpage;
1314
int ret;
1415

1516
headpage = kmap_local_page(*rq->in);
16-
ret = z_erofs_fixup_insize(rq, headpage + rq->pageofs_in,
17+
reason = z_erofs_fixup_insize(rq, headpage + rq->pageofs_in,
1718
min_t(unsigned int, rq->inputsize,
1819
rq->sb->s_blocksize - rq->pageofs_in));
1920
kunmap_local(headpage);
20-
if (ret)
21-
return ret;
21+
if (reason)
22+
return IS_ERR(reason) ? PTR_ERR(reason) : -EFSCORRUPTED;
2223

2324
req = acomp_request_alloc(tfm);
2425
if (!req)

0 commit comments

Comments
 (0)