Skip to content

Commit 84a2cee

Browse files
committed
erofs: tidy up stream decompressors
Just use a generic helper to prepare buffers for all supported stream decompressors, eliminating similar logic. Signed-off-by: Gao Xiang <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 5a7cce8 commit 84a2cee

File tree

5 files changed

+209
-304
lines changed

5 files changed

+209
-304
lines changed

fs/erofs/compress.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,21 @@ extern const struct z_erofs_decompressor z_erofs_deflate_decomp;
8888
extern const struct z_erofs_decompressor z_erofs_zstd_decomp;
8989
extern const struct z_erofs_decompressor *z_erofs_decomp[];
9090

91+
struct z_erofs_stream_dctx {
92+
struct z_erofs_decompress_req *rq;
93+
unsigned int inpages, outpages; /* # of {en,de}coded pages */
94+
int no, ni; /* the current {en,de}coded page # */
95+
96+
unsigned int avail_out; /* remaining bytes in the decoded buffer */
97+
unsigned int inbuf_pos, inbuf_sz;
98+
/* current status of the encoded buffer */
99+
u8 *kin, *kout; /* buffer mapped pointers */
100+
void *bounce; /* bounce buffer for inplace I/Os */
101+
bool bounced; /* is the bounce buffer used now? */
102+
};
103+
104+
int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
105+
void **src, struct page **pgpl);
91106
int z_erofs_fixup_insize(struct z_erofs_decompress_req *rq, const char *padbuf,
92107
unsigned int padbufsize);
93108
int __init z_erofs_init_decompressor(void);

fs/erofs/decompressor.c

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,89 @@ static int z_erofs_transform_plain(struct z_erofs_decompress_req *rq,
372372
return 0;
373373
}
374374

375+
int z_erofs_stream_switch_bufs(struct z_erofs_stream_dctx *dctx, void **dst,
376+
void **src, struct page **pgpl)
377+
{
378+
struct z_erofs_decompress_req *rq = dctx->rq;
379+
struct super_block *sb = rq->sb;
380+
struct page **pgo, *tmppage;
381+
unsigned int j;
382+
383+
if (!dctx->avail_out) {
384+
if (++dctx->no >= dctx->outpages || !rq->outputsize) {
385+
erofs_err(sb, "insufficient space for decompressed data");
386+
return -EFSCORRUPTED;
387+
}
388+
389+
if (dctx->kout)
390+
kunmap_local(dctx->kout);
391+
dctx->avail_out = min(rq->outputsize, PAGE_SIZE - rq->pageofs_out);
392+
rq->outputsize -= dctx->avail_out;
393+
pgo = &rq->out[dctx->no];
394+
if (!*pgo && rq->fillgaps) { /* deduped */
395+
*pgo = erofs_allocpage(pgpl, rq->gfp);
396+
if (!*pgo) {
397+
dctx->kout = NULL;
398+
return -ENOMEM;
399+
}
400+
set_page_private(*pgo, Z_EROFS_SHORTLIVED_PAGE);
401+
}
402+
if (*pgo) {
403+
dctx->kout = kmap_local_page(*pgo);
404+
*dst = dctx->kout + rq->pageofs_out;
405+
} else {
406+
*dst = dctx->kout = NULL;
407+
}
408+
rq->pageofs_out = 0;
409+
}
410+
411+
if (dctx->inbuf_pos == dctx->inbuf_sz && rq->inputsize) {
412+
if (++dctx->ni >= dctx->inpages) {
413+
erofs_err(sb, "invalid compressed data");
414+
return -EFSCORRUPTED;
415+
}
416+
if (dctx->kout) /* unlike kmap(), take care of the orders */
417+
kunmap_local(dctx->kout);
418+
kunmap_local(dctx->kin);
419+
420+
dctx->inbuf_sz = min_t(u32, rq->inputsize, PAGE_SIZE);
421+
rq->inputsize -= dctx->inbuf_sz;
422+
dctx->kin = kmap_local_page(rq->in[dctx->ni]);
423+
*src = dctx->kin;
424+
dctx->bounced = false;
425+
if (dctx->kout) {
426+
j = (u8 *)*dst - dctx->kout;
427+
dctx->kout = kmap_local_page(rq->out[dctx->no]);
428+
*dst = dctx->kout + j;
429+
}
430+
dctx->inbuf_pos = 0;
431+
}
432+
433+
/*
434+
* Handle overlapping: Use the given bounce buffer if the input data is
435+
* under processing; Or utilize short-lived pages from the on-stack page
436+
* pool, where pages are shared among the same request. Note that only
437+
* a few inplace I/O pages need to be doubled.
438+
*/
439+
if (!dctx->bounced && rq->out[dctx->no] == rq->in[dctx->ni]) {
440+
memcpy(dctx->bounce, *src, dctx->inbuf_sz);
441+
*src = dctx->bounce;
442+
dctx->bounced = true;
443+
}
444+
445+
for (j = dctx->ni + 1; j < dctx->inpages; ++j) {
446+
if (rq->out[dctx->no] != rq->in[j])
447+
continue;
448+
tmppage = erofs_allocpage(pgpl, rq->gfp);
449+
if (!tmppage)
450+
return -ENOMEM;
451+
set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE);
452+
copy_highpage(tmppage, rq->in[j]);
453+
rq->in[j] = tmppage;
454+
}
455+
return 0;
456+
}
457+
375458
const struct z_erofs_decompressor *z_erofs_decomp[] = {
376459
[Z_EROFS_COMPRESSION_SHIFTED] = &(const struct z_erofs_decompressor) {
377460
.decompress = z_erofs_transform_plain,

fs/erofs/decompressor_deflate.c

Lines changed: 31 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -100,24 +100,23 @@ static int z_erofs_load_deflate_config(struct super_block *sb,
100100
static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
101101
struct page **pgpl)
102102
{
103-
const unsigned int nrpages_out =
104-
PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT;
105-
const unsigned int nrpages_in =
106-
PAGE_ALIGN(rq->inputsize) >> PAGE_SHIFT;
107103
struct super_block *sb = rq->sb;
108-
unsigned int insz, outsz, pofs;
104+
struct z_erofs_stream_dctx dctx = {
105+
.rq = rq,
106+
.inpages = PAGE_ALIGN(rq->inputsize) >> PAGE_SHIFT,
107+
.outpages = PAGE_ALIGN(rq->pageofs_out + rq->outputsize)
108+
>> PAGE_SHIFT,
109+
.no = -1, .ni = 0,
110+
};
109111
struct z_erofs_deflate *strm;
110-
u8 *kin, *kout = NULL;
111-
bool bounced = false;
112-
int no = -1, ni = 0, j = 0, zerr, err;
112+
int zerr, err;
113113

114114
/* 1. get the exact DEFLATE compressed size */
115-
kin = kmap_local_page(*rq->in);
116-
err = z_erofs_fixup_insize(rq, kin + rq->pageofs_in,
117-
min_t(unsigned int, rq->inputsize,
118-
sb->s_blocksize - rq->pageofs_in));
115+
dctx.kin = kmap_local_page(*rq->in);
116+
err = z_erofs_fixup_insize(rq, dctx.kin + rq->pageofs_in,
117+
min(rq->inputsize, sb->s_blocksize - rq->pageofs_in));
119118
if (err) {
120-
kunmap_local(kin);
119+
kunmap_local(dctx.kin);
121120
return err;
122121
}
123122

@@ -134,116 +133,48 @@ static int z_erofs_deflate_decompress(struct z_erofs_decompress_req *rq,
134133
spin_unlock(&z_erofs_deflate_lock);
135134

136135
/* 3. multi-call decompress */
137-
insz = rq->inputsize;
138-
outsz = rq->outputsize;
139136
zerr = zlib_inflateInit2(&strm->z, -MAX_WBITS);
140137
if (zerr != Z_OK) {
141138
err = -EIO;
142139
goto failed_zinit;
143140
}
144141

145-
pofs = rq->pageofs_out;
146-
strm->z.avail_in = min_t(u32, insz, PAGE_SIZE - rq->pageofs_in);
147-
insz -= strm->z.avail_in;
148-
strm->z.next_in = kin + rq->pageofs_in;
142+
rq->fillgaps = true; /* DEFLATE doesn't support NULL output buffer */
143+
strm->z.avail_in = min(rq->inputsize, PAGE_SIZE - rq->pageofs_in);
144+
rq->inputsize -= strm->z.avail_in;
145+
strm->z.next_in = dctx.kin + rq->pageofs_in;
149146
strm->z.avail_out = 0;
147+
dctx.bounce = strm->bounce;
150148

151149
while (1) {
152-
if (!strm->z.avail_out) {
153-
if (++no >= nrpages_out || !outsz) {
154-
erofs_err(sb, "insufficient space for decompressed data");
155-
err = -EFSCORRUPTED;
156-
break;
157-
}
158-
159-
if (kout)
160-
kunmap_local(kout);
161-
strm->z.avail_out = min_t(u32, outsz, PAGE_SIZE - pofs);
162-
outsz -= strm->z.avail_out;
163-
if (!rq->out[no]) {
164-
rq->out[no] = erofs_allocpage(pgpl, rq->gfp);
165-
if (!rq->out[no]) {
166-
kout = NULL;
167-
err = -ENOMEM;
168-
break;
169-
}
170-
set_page_private(rq->out[no],
171-
Z_EROFS_SHORTLIVED_PAGE);
172-
}
173-
kout = kmap_local_page(rq->out[no]);
174-
strm->z.next_out = kout + pofs;
175-
pofs = 0;
176-
}
177-
178-
if (!strm->z.avail_in && insz) {
179-
if (++ni >= nrpages_in) {
180-
erofs_err(sb, "invalid compressed data");
181-
err = -EFSCORRUPTED;
182-
break;
183-
}
184-
185-
if (kout) { /* unlike kmap(), take care of the orders */
186-
j = strm->z.next_out - kout;
187-
kunmap_local(kout);
188-
}
189-
kunmap_local(kin);
190-
strm->z.avail_in = min_t(u32, insz, PAGE_SIZE);
191-
insz -= strm->z.avail_in;
192-
kin = kmap_local_page(rq->in[ni]);
193-
strm->z.next_in = kin;
194-
bounced = false;
195-
if (kout) {
196-
kout = kmap_local_page(rq->out[no]);
197-
strm->z.next_out = kout + j;
198-
}
199-
}
200-
201-
/*
202-
* Handle overlapping: Use bounced buffer if the compressed
203-
* data is under processing; Or use short-lived pages from the
204-
* on-stack pagepool where pages share among the same request
205-
* and not _all_ inplace I/O pages are needed to be doubled.
206-
*/
207-
if (!bounced && rq->out[no] == rq->in[ni]) {
208-
memcpy(strm->bounce, strm->z.next_in, strm->z.avail_in);
209-
strm->z.next_in = strm->bounce;
210-
bounced = true;
211-
}
212-
213-
for (j = ni + 1; j < nrpages_in; ++j) {
214-
struct page *tmppage;
215-
216-
if (rq->out[no] != rq->in[j])
217-
continue;
218-
tmppage = erofs_allocpage(pgpl, rq->gfp);
219-
if (!tmppage) {
220-
err = -ENOMEM;
221-
goto failed;
222-
}
223-
set_page_private(tmppage, Z_EROFS_SHORTLIVED_PAGE);
224-
copy_highpage(tmppage, rq->in[j]);
225-
rq->in[j] = tmppage;
226-
}
150+
dctx.avail_out = strm->z.avail_out;
151+
dctx.inbuf_sz = strm->z.avail_in;
152+
err = z_erofs_stream_switch_bufs(&dctx,
153+
(void **)&strm->z.next_out,
154+
(void **)&strm->z.next_in, pgpl);
155+
if (err)
156+
break;
157+
strm->z.avail_out = dctx.avail_out;
158+
strm->z.avail_in = dctx.inbuf_sz;
227159

228160
zerr = zlib_inflate(&strm->z, Z_SYNC_FLUSH);
229-
if (zerr != Z_OK || !(outsz + strm->z.avail_out)) {
161+
if (zerr != Z_OK || !(rq->outputsize + strm->z.avail_out)) {
230162
if (zerr == Z_OK && rq->partial_decoding)
231163
break;
232-
if (zerr == Z_STREAM_END && !outsz)
164+
if (zerr == Z_STREAM_END && !rq->outputsize)
233165
break;
234166
erofs_err(sb, "failed to decompress %d in[%u] out[%u]",
235167
zerr, rq->inputsize, rq->outputsize);
236168
err = -EFSCORRUPTED;
237169
break;
238170
}
239171
}
240-
failed:
241172
if (zlib_inflateEnd(&strm->z) != Z_OK && !err)
242173
err = -EIO;
243-
if (kout)
244-
kunmap_local(kout);
174+
if (dctx.kout)
175+
kunmap_local(dctx.kout);
245176
failed_zinit:
246-
kunmap_local(kin);
177+
kunmap_local(dctx.kin);
247178
/* 4. push back DEFLATE stream context to the global list */
248179
spin_lock(&z_erofs_deflate_lock);
249180
strm->next = z_erofs_deflate_head;

0 commit comments

Comments
 (0)