Skip to content

Commit 0507d25

Browse files
committed
Merge tag 'erofs-for-6.8-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs
Pull erofs updates from Gao Xiang: "In this cycle, we'd like to enable basic sub-page compressed data support for Android ecosystem (for vendors to try out 16k page size with 4k-block images in their compatibility mode) as well as container images (so that 4k-block images can be parsed on arm64 cloud servers using 64k page size.) In addition, there are several bugfixes and cleanups as usual. All commits have been in -next for a while and no potential merge conflict is observed. Summary: - Add basic sub-page compressed data support - Fix a memory leak on MicroLZMA and DEFLATE compression - Fix a rare LZ4 inplace decompression issue on recent x86 CPUs - Fix a KASAN issue reported by syzbot around crafted images - Some cleanups" * tag 'erofs-for-6.8-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs: erofs: make erofs_{err,info}() support NULL sb parameter erofs: avoid debugging output for (de)compressed data erofs: allow partially filled compressed bvecs erofs: enable sub-page compressed block support erofs: refine z_erofs_transform_plain() for sub-page block support erofs: fix ztailpacking for subpage compressed blocks erofs: fix up compacted indexes for block size < 4096 erofs: record `pclustersize` in bytes instead of pages erofs: support I/O submission for sub-page compressed blocks erofs: fix lz4 inplace decompression erofs: fix memory leak on short-lived bounced pages
2 parents 17b9e38 + aa12a79 commit 0507d25

File tree

6 files changed

+211
-226
lines changed

6 files changed

+211
-226
lines changed

fs/erofs/decompressor.c

Lines changed: 65 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,11 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_lz4_decompress_ctx *ctx,
121121
}
122122

123123
static void *z_erofs_lz4_handle_overlap(struct z_erofs_lz4_decompress_ctx *ctx,
124-
void *inpage, unsigned int *inputmargin, int *maptype,
125-
bool may_inplace)
124+
void *inpage, void *out, unsigned int *inputmargin,
125+
int *maptype, bool may_inplace)
126126
{
127127
struct z_erofs_decompress_req *rq = ctx->rq;
128-
unsigned int omargin, total, i, j;
128+
unsigned int omargin, total, i;
129129
struct page **in;
130130
void *src, *tmp;
131131

@@ -135,20 +135,20 @@ static void *z_erofs_lz4_handle_overlap(struct z_erofs_lz4_decompress_ctx *ctx,
135135
omargin < LZ4_DECOMPRESS_INPLACE_MARGIN(rq->inputsize))
136136
goto docopy;
137137

138-
for (i = 0; i < ctx->inpages; ++i) {
139-
DBG_BUGON(rq->in[i] == NULL);
140-
for (j = 0; j < ctx->outpages - ctx->inpages + i; ++j)
141-
if (rq->out[j] == rq->in[i])
142-
goto docopy;
143-
}
138+
for (i = 0; i < ctx->inpages; ++i)
139+
if (rq->out[ctx->outpages - ctx->inpages + i] !=
140+
rq->in[i])
141+
goto docopy;
142+
kunmap_local(inpage);
143+
*maptype = 3;
144+
return out + ((ctx->outpages - ctx->inpages) << PAGE_SHIFT);
144145
}
145146

146147
if (ctx->inpages <= 1) {
147148
*maptype = 0;
148149
return inpage;
149150
}
150151
kunmap_local(inpage);
151-
might_sleep();
152152
src = erofs_vm_map_ram(rq->in, ctx->inpages);
153153
if (!src)
154154
return ERR_PTR(-ENOMEM);
@@ -204,12 +204,12 @@ int z_erofs_fixup_insize(struct z_erofs_decompress_req *rq, const char *padbuf,
204204
}
205205

206206
static int z_erofs_lz4_decompress_mem(struct z_erofs_lz4_decompress_ctx *ctx,
207-
u8 *out)
207+
u8 *dst)
208208
{
209209
struct z_erofs_decompress_req *rq = ctx->rq;
210210
bool support_0padding = false, may_inplace = false;
211211
unsigned int inputmargin;
212-
u8 *headpage, *src;
212+
u8 *out, *headpage, *src;
213213
int ret, maptype;
214214

215215
DBG_BUGON(*rq->in == NULL);
@@ -230,11 +230,12 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_lz4_decompress_ctx *ctx,
230230
}
231231

232232
inputmargin = rq->pageofs_in;
233-
src = z_erofs_lz4_handle_overlap(ctx, headpage, &inputmargin,
233+
src = z_erofs_lz4_handle_overlap(ctx, headpage, dst, &inputmargin,
234234
&maptype, may_inplace);
235235
if (IS_ERR(src))
236236
return PTR_ERR(src);
237237

238+
out = dst + rq->pageofs_out;
238239
/* legacy format could compress extra data in a pcluster. */
239240
if (rq->partial_decoding || !support_0padding)
240241
ret = LZ4_decompress_safe_partial(src + inputmargin, out,
@@ -246,15 +247,9 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_lz4_decompress_ctx *ctx,
246247
if (ret != rq->outputsize) {
247248
erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]",
248249
ret, rq->inputsize, inputmargin, rq->outputsize);
249-
250-
print_hex_dump(KERN_DEBUG, "[ in]: ", DUMP_PREFIX_OFFSET,
251-
16, 1, src + inputmargin, rq->inputsize, true);
252-
print_hex_dump(KERN_DEBUG, "[out]: ", DUMP_PREFIX_OFFSET,
253-
16, 1, out, rq->outputsize, true);
254-
255250
if (ret >= 0)
256251
memset(out + ret, 0, rq->outputsize - ret);
257-
ret = -EIO;
252+
ret = -EFSCORRUPTED;
258253
} else {
259254
ret = 0;
260255
}
@@ -265,7 +260,7 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_lz4_decompress_ctx *ctx,
265260
vm_unmap_ram(src, ctx->inpages);
266261
} else if (maptype == 2) {
267262
erofs_put_pcpubuf(src);
268-
} else {
263+
} else if (maptype != 3) {
269264
DBG_BUGON(1);
270265
return -EFAULT;
271266
}
@@ -308,7 +303,7 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
308303
}
309304

310305
dstmap_out:
311-
ret = z_erofs_lz4_decompress_mem(&ctx, dst + rq->pageofs_out);
306+
ret = z_erofs_lz4_decompress_mem(&ctx, dst);
312307
if (!dst_maptype)
313308
kunmap_local(dst);
314309
else if (dst_maptype == 2)
@@ -319,43 +314,58 @@ static int z_erofs_lz4_decompress(struct z_erofs_decompress_req *rq,
319314
static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
320315
struct page **pagepool)
321316
{
322-
const unsigned int inpages = PAGE_ALIGN(rq->inputsize) >> PAGE_SHIFT;
323-
const unsigned int outpages =
317+
const unsigned int nrpages_in =
318+
PAGE_ALIGN(rq->pageofs_in + rq->inputsize) >> PAGE_SHIFT;
319+
const unsigned int nrpages_out =
324320
PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
325-
const unsigned int righthalf = min_t(unsigned int, rq->outputsize,
326-
PAGE_SIZE - rq->pageofs_out);
327-
const unsigned int lefthalf = rq->outputsize - righthalf;
328-
const unsigned int interlaced_offset =
329-
rq->alg == Z_EROFS_COMPRESSION_SHIFTED ? 0 : rq->pageofs_out;
330-
u8 *src;
331-
332-
if (outpages > 2 && rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
333-
DBG_BUGON(1);
334-
return -EFSCORRUPTED;
335-
}
336-
337-
if (rq->out[0] == *rq->in) {
338-
DBG_BUGON(rq->pageofs_out);
339-
return 0;
321+
const unsigned int bs = rq->sb->s_blocksize;
322+
unsigned int cur = 0, ni = 0, no, pi, po, insz, cnt;
323+
u8 *kin;
324+
325+
DBG_BUGON(rq->outputsize > rq->inputsize);
326+
if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
327+
cur = bs - (rq->pageofs_out & (bs - 1));
328+
pi = (rq->pageofs_in + rq->inputsize - cur) & ~PAGE_MASK;
329+
cur = min(cur, rq->outputsize);
330+
if (cur && rq->out[0]) {
331+
kin = kmap_local_page(rq->in[nrpages_in - 1]);
332+
if (rq->out[0] == rq->in[nrpages_in - 1]) {
333+
memmove(kin + rq->pageofs_out, kin + pi, cur);
334+
flush_dcache_page(rq->out[0]);
335+
} else {
336+
memcpy_to_page(rq->out[0], rq->pageofs_out,
337+
kin + pi, cur);
338+
}
339+
kunmap_local(kin);
340+
}
341+
rq->outputsize -= cur;
340342
}
341343

342-
src = kmap_local_page(rq->in[inpages - 1]) + rq->pageofs_in;
343-
if (rq->out[0])
344-
memcpy_to_page(rq->out[0], rq->pageofs_out,
345-
src + interlaced_offset, righthalf);
346-
347-
if (outpages > inpages) {
348-
DBG_BUGON(!rq->out[outpages - 1]);
349-
if (rq->out[outpages - 1] != rq->in[inpages - 1]) {
350-
memcpy_to_page(rq->out[outpages - 1], 0, src +
351-
(interlaced_offset ? 0 : righthalf),
352-
lefthalf);
353-
} else if (!interlaced_offset) {
354-
memmove(src, src + righthalf, lefthalf);
355-
flush_dcache_page(rq->in[inpages - 1]);
356-
}
344+
for (; rq->outputsize; rq->pageofs_in = 0, cur += PAGE_SIZE, ni++) {
345+
insz = min(PAGE_SIZE - rq->pageofs_in, rq->outputsize);
346+
rq->outputsize -= insz;
347+
if (!rq->in[ni])
348+
continue;
349+
kin = kmap_local_page(rq->in[ni]);
350+
pi = 0;
351+
do {
352+
no = (rq->pageofs_out + cur + pi) >> PAGE_SHIFT;
353+
po = (rq->pageofs_out + cur + pi) & ~PAGE_MASK;
354+
DBG_BUGON(no >= nrpages_out);
355+
cnt = min(insz - pi, PAGE_SIZE - po);
356+
if (rq->out[no] == rq->in[ni]) {
357+
memmove(kin + po,
358+
kin + rq->pageofs_in + pi, cnt);
359+
flush_dcache_page(rq->out[no]);
360+
} else if (rq->out[no]) {
361+
memcpy_to_page(rq->out[no], po,
362+
kin + rq->pageofs_in + pi, cnt);
363+
}
364+
pi += cnt;
365+
} while (pi < insz);
366+
kunmap_local(kin);
357367
}
358-
kunmap_local(src);
368+
DBG_BUGON(ni > nrpages_in);
359369
return 0;
360370
}
361371

fs/erofs/decompressor_deflate.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ int __init z_erofs_deflate_init(void)
7070
return 0;
7171

7272
out_failed:
73-
pr_err("failed to allocate zlib workspace\n");
73+
erofs_err(NULL, "failed to allocate zlib workspace");
7474
z_erofs_deflate_exit();
7575
return -ENOMEM;
7676
}

fs/erofs/inode.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,10 @@ static int erofs_fill_inode(struct inode *inode)
259259

260260
if (erofs_inode_is_data_compressed(vi->datalayout)) {
261261
#ifdef CONFIG_EROFS_FS_ZIP
262-
if (!erofs_is_fscache_mode(inode->i_sb) &&
263-
inode->i_sb->s_blocksize_bits == PAGE_SHIFT) {
262+
if (!erofs_is_fscache_mode(inode->i_sb)) {
263+
DO_ONCE_LITE_IF(inode->i_sb->s_blocksize != PAGE_SIZE,
264+
erofs_info, inode->i_sb,
265+
"EXPERIMENTAL EROFS subpage compressed block support in use. Use at your own risk!");
264266
inode->i_mapping->a_ops = &z_erofs_aops;
265267
err = 0;
266268
goto out_unlock;

fs/erofs/super.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ void _erofs_err(struct super_block *sb, const char *func, const char *fmt, ...)
2727
vaf.fmt = fmt;
2828
vaf.va = &args;
2929

30-
pr_err("(device %s): %s: %pV", sb->s_id, func, &vaf);
30+
if (sb)
31+
pr_err("(device %s): %s: %pV", sb->s_id, func, &vaf);
32+
else
33+
pr_err("%s: %pV", func, &vaf);
3134
va_end(args);
3235
}
3336

@@ -41,7 +44,10 @@ void _erofs_info(struct super_block *sb, const char *func, const char *fmt, ...)
4144
vaf.fmt = fmt;
4245
vaf.va = &args;
4346

44-
pr_info("(device %s): %pV", sb->s_id, &vaf);
47+
if (sb)
48+
pr_info("(device %s): %pV", sb->s_id, &vaf);
49+
else
50+
pr_info("%pV", &vaf);
4551
va_end(args);
4652
}
4753

0 commit comments

Comments
 (0)