1*33b1fccfSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2*33b1fccfSAndroid Build Coastguard Worker /*
3*33b1fccfSAndroid Build Coastguard Worker * Copyright (C), 2008-2020, OPPO Mobile Comm Corp., Ltd.
4*33b1fccfSAndroid Build Coastguard Worker * Created by Huang Jianan <[email protected]>
5*33b1fccfSAndroid Build Coastguard Worker */
6*33b1fccfSAndroid Build Coastguard Worker #include <stdlib.h>
7*33b1fccfSAndroid Build Coastguard Worker
8*33b1fccfSAndroid Build Coastguard Worker #include "erofs/decompress.h"
9*33b1fccfSAndroid Build Coastguard Worker #include "erofs/err.h"
10*33b1fccfSAndroid Build Coastguard Worker #include "erofs/print.h"
11*33b1fccfSAndroid Build Coastguard Worker
z_erofs_fixup_insize(const u8 * padbuf,unsigned int padbufsize)12*33b1fccfSAndroid Build Coastguard Worker static unsigned int z_erofs_fixup_insize(const u8 *padbuf, unsigned int padbufsize)
13*33b1fccfSAndroid Build Coastguard Worker {
14*33b1fccfSAndroid Build Coastguard Worker unsigned int inputmargin;
15*33b1fccfSAndroid Build Coastguard Worker
16*33b1fccfSAndroid Build Coastguard Worker for (inputmargin = 0; inputmargin < padbufsize &&
17*33b1fccfSAndroid Build Coastguard Worker !padbuf[inputmargin]; ++inputmargin);
18*33b1fccfSAndroid Build Coastguard Worker return inputmargin;
19*33b1fccfSAndroid Build Coastguard Worker }
20*33b1fccfSAndroid Build Coastguard Worker
21*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBZSTD
22*33b1fccfSAndroid Build Coastguard Worker #include <zstd.h>
23*33b1fccfSAndroid Build Coastguard Worker #include <zstd_errors.h>
24*33b1fccfSAndroid Build Coastguard Worker
25*33b1fccfSAndroid Build Coastguard Worker /* also a very preliminary userspace version */
z_erofs_decompress_zstd(struct z_erofs_decompress_req * rq)26*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_decompress_zstd(struct z_erofs_decompress_req *rq)
27*33b1fccfSAndroid Build Coastguard Worker {
28*33b1fccfSAndroid Build Coastguard Worker int ret = 0;
29*33b1fccfSAndroid Build Coastguard Worker char *dest = rq->out;
30*33b1fccfSAndroid Build Coastguard Worker char *src = rq->in;
31*33b1fccfSAndroid Build Coastguard Worker char *buff = NULL;
32*33b1fccfSAndroid Build Coastguard Worker unsigned int inputmargin = 0;
33*33b1fccfSAndroid Build Coastguard Worker unsigned long long total;
34*33b1fccfSAndroid Build Coastguard Worker
35*33b1fccfSAndroid Build Coastguard Worker inputmargin = z_erofs_fixup_insize((u8 *)src, rq->inputsize);
36*33b1fccfSAndroid Build Coastguard Worker if (inputmargin >= rq->inputsize)
37*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
38*33b1fccfSAndroid Build Coastguard Worker
39*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_ZSTD_GETFRAMECONTENTSIZE
40*33b1fccfSAndroid Build Coastguard Worker total = ZSTD_getFrameContentSize(src + inputmargin,
41*33b1fccfSAndroid Build Coastguard Worker rq->inputsize - inputmargin);
42*33b1fccfSAndroid Build Coastguard Worker if (total == ZSTD_CONTENTSIZE_UNKNOWN ||
43*33b1fccfSAndroid Build Coastguard Worker total == ZSTD_CONTENTSIZE_ERROR)
44*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
45*33b1fccfSAndroid Build Coastguard Worker #else
46*33b1fccfSAndroid Build Coastguard Worker total = ZSTD_getDecompressedSize(src + inputmargin,
47*33b1fccfSAndroid Build Coastguard Worker rq->inputsize - inputmargin);
48*33b1fccfSAndroid Build Coastguard Worker #endif
49*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip || total != rq->decodedlength) {
50*33b1fccfSAndroid Build Coastguard Worker buff = malloc(total);
51*33b1fccfSAndroid Build Coastguard Worker if (!buff)
52*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
53*33b1fccfSAndroid Build Coastguard Worker dest = buff;
54*33b1fccfSAndroid Build Coastguard Worker }
55*33b1fccfSAndroid Build Coastguard Worker
56*33b1fccfSAndroid Build Coastguard Worker ret = ZSTD_decompress(dest, total,
57*33b1fccfSAndroid Build Coastguard Worker src + inputmargin, rq->inputsize - inputmargin);
58*33b1fccfSAndroid Build Coastguard Worker if (ZSTD_isError(ret)) {
59*33b1fccfSAndroid Build Coastguard Worker erofs_err("ZSTD decompress failed %d: %s", ZSTD_getErrorCode(ret),
60*33b1fccfSAndroid Build Coastguard Worker ZSTD_getErrorName(ret));
61*33b1fccfSAndroid Build Coastguard Worker ret = -EIO;
62*33b1fccfSAndroid Build Coastguard Worker goto out;
63*33b1fccfSAndroid Build Coastguard Worker }
64*33b1fccfSAndroid Build Coastguard Worker
65*33b1fccfSAndroid Build Coastguard Worker if (ret != (int)total) {
66*33b1fccfSAndroid Build Coastguard Worker erofs_err("ZSTD decompress length mismatch %d, expected %d",
67*33b1fccfSAndroid Build Coastguard Worker ret, total);
68*33b1fccfSAndroid Build Coastguard Worker goto out;
69*33b1fccfSAndroid Build Coastguard Worker }
70*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip || total != rq->decodedlength)
71*33b1fccfSAndroid Build Coastguard Worker memcpy(rq->out, dest + rq->decodedskip,
72*33b1fccfSAndroid Build Coastguard Worker rq->decodedlength - rq->decodedskip);
73*33b1fccfSAndroid Build Coastguard Worker out:
74*33b1fccfSAndroid Build Coastguard Worker if (buff)
75*33b1fccfSAndroid Build Coastguard Worker free(buff);
76*33b1fccfSAndroid Build Coastguard Worker return ret;
77*33b1fccfSAndroid Build Coastguard Worker }
78*33b1fccfSAndroid Build Coastguard Worker #endif
79*33b1fccfSAndroid Build Coastguard Worker
80*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_QPL
81*33b1fccfSAndroid Build Coastguard Worker #include <qpl/qpl.h>
82*33b1fccfSAndroid Build Coastguard Worker
83*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_qpl_job {
84*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_qpl_job *next;
85*33b1fccfSAndroid Build Coastguard Worker u8 job[];
86*33b1fccfSAndroid Build Coastguard Worker };
87*33b1fccfSAndroid Build Coastguard Worker static struct z_erofs_qpl_job *z_erofs_qpl_jobs;
88*33b1fccfSAndroid Build Coastguard Worker static unsigned int z_erofs_qpl_reclaim_quot;
89*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD_H
90*33b1fccfSAndroid Build Coastguard Worker static pthread_mutex_t z_erofs_qpl_mutex;
91*33b1fccfSAndroid Build Coastguard Worker #endif
92*33b1fccfSAndroid Build Coastguard Worker
z_erofs_load_deflate_config(struct erofs_sb_info * sbi,struct erofs_super_block * dsb,void * data,int size)93*33b1fccfSAndroid Build Coastguard Worker int z_erofs_load_deflate_config(struct erofs_sb_info *sbi,
94*33b1fccfSAndroid Build Coastguard Worker struct erofs_super_block *dsb, void *data, int size)
95*33b1fccfSAndroid Build Coastguard Worker {
96*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_deflate_cfgs *dfl = data;
97*33b1fccfSAndroid Build Coastguard Worker static erofs_atomic_bool_t inited;
98*33b1fccfSAndroid Build Coastguard Worker
99*33b1fccfSAndroid Build Coastguard Worker if (!dfl || size < sizeof(struct z_erofs_deflate_cfgs)) {
100*33b1fccfSAndroid Build Coastguard Worker erofs_err("invalid deflate cfgs, size=%u", size);
101*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
102*33b1fccfSAndroid Build Coastguard Worker }
103*33b1fccfSAndroid Build Coastguard Worker
104*33b1fccfSAndroid Build Coastguard Worker /*
105*33b1fccfSAndroid Build Coastguard Worker * In Intel QPL, decompression is supported for DEFLATE streams where
106*33b1fccfSAndroid Build Coastguard Worker * the size of the history buffer is no more than 4 KiB, otherwise
107*33b1fccfSAndroid Build Coastguard Worker * QPL_STS_BAD_DIST_ERR code is returned.
108*33b1fccfSAndroid Build Coastguard Worker */
109*33b1fccfSAndroid Build Coastguard Worker sbi->useqpl = (dfl->windowbits <= 12);
110*33b1fccfSAndroid Build Coastguard Worker if (sbi->useqpl) {
111*33b1fccfSAndroid Build Coastguard Worker if (!erofs_atomic_test_and_set(&inited))
112*33b1fccfSAndroid Build Coastguard Worker z_erofs_qpl_reclaim_quot = erofs_get_available_processors();
113*33b1fccfSAndroid Build Coastguard Worker erofs_info("Intel QPL will be used for DEFLATE decompression");
114*33b1fccfSAndroid Build Coastguard Worker }
115*33b1fccfSAndroid Build Coastguard Worker return 0;
116*33b1fccfSAndroid Build Coastguard Worker }
117*33b1fccfSAndroid Build Coastguard Worker
z_erofs_qpl_get_job(void)118*33b1fccfSAndroid Build Coastguard Worker static qpl_job *z_erofs_qpl_get_job(void)
119*33b1fccfSAndroid Build Coastguard Worker {
120*33b1fccfSAndroid Build Coastguard Worker qpl_path_t execution_path = qpl_path_auto;
121*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_qpl_job *job;
122*33b1fccfSAndroid Build Coastguard Worker int32_t jobsize = 0;
123*33b1fccfSAndroid Build Coastguard Worker qpl_status status;
124*33b1fccfSAndroid Build Coastguard Worker
125*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD_H
126*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_lock(&z_erofs_qpl_mutex);
127*33b1fccfSAndroid Build Coastguard Worker #endif
128*33b1fccfSAndroid Build Coastguard Worker job = z_erofs_qpl_jobs;
129*33b1fccfSAndroid Build Coastguard Worker if (job)
130*33b1fccfSAndroid Build Coastguard Worker z_erofs_qpl_jobs = job->next;
131*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD_H
132*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_unlock(&z_erofs_qpl_mutex);
133*33b1fccfSAndroid Build Coastguard Worker #endif
134*33b1fccfSAndroid Build Coastguard Worker
135*33b1fccfSAndroid Build Coastguard Worker if (!job) {
136*33b1fccfSAndroid Build Coastguard Worker status = qpl_get_job_size(execution_path, &jobsize);
137*33b1fccfSAndroid Build Coastguard Worker if (status != QPL_STS_OK) {
138*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to get job size: %d", status);
139*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(-EOPNOTSUPP);
140*33b1fccfSAndroid Build Coastguard Worker }
141*33b1fccfSAndroid Build Coastguard Worker
142*33b1fccfSAndroid Build Coastguard Worker job = malloc(jobsize + sizeof(struct z_erofs_qpl_job));
143*33b1fccfSAndroid Build Coastguard Worker if (!job)
144*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(-ENOMEM);
145*33b1fccfSAndroid Build Coastguard Worker
146*33b1fccfSAndroid Build Coastguard Worker status = qpl_init_job(execution_path, (qpl_job *)job->job);
147*33b1fccfSAndroid Build Coastguard Worker if (status != QPL_STS_OK) {
148*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to initialize job: %d", status);
149*33b1fccfSAndroid Build Coastguard Worker return ERR_PTR(-EOPNOTSUPP);
150*33b1fccfSAndroid Build Coastguard Worker }
151*33b1fccfSAndroid Build Coastguard Worker erofs_atomic_dec_return(&z_erofs_qpl_reclaim_quot);
152*33b1fccfSAndroid Build Coastguard Worker }
153*33b1fccfSAndroid Build Coastguard Worker return (qpl_job *)job->job;
154*33b1fccfSAndroid Build Coastguard Worker }
155*33b1fccfSAndroid Build Coastguard Worker
z_erofs_qpl_put_job(qpl_job * qjob)156*33b1fccfSAndroid Build Coastguard Worker static bool z_erofs_qpl_put_job(qpl_job *qjob)
157*33b1fccfSAndroid Build Coastguard Worker {
158*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_qpl_job *job =
159*33b1fccfSAndroid Build Coastguard Worker container_of((void *)qjob, struct z_erofs_qpl_job, job);
160*33b1fccfSAndroid Build Coastguard Worker
161*33b1fccfSAndroid Build Coastguard Worker if (erofs_atomic_inc_return(&z_erofs_qpl_reclaim_quot) <= 0) {
162*33b1fccfSAndroid Build Coastguard Worker qpl_status status = qpl_fini_job(qjob);
163*33b1fccfSAndroid Build Coastguard Worker
164*33b1fccfSAndroid Build Coastguard Worker free(job);
165*33b1fccfSAndroid Build Coastguard Worker if (status != QPL_STS_OK)
166*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to finalize job: %d", status);
167*33b1fccfSAndroid Build Coastguard Worker return status == QPL_STS_OK;
168*33b1fccfSAndroid Build Coastguard Worker }
169*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD_H
170*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_lock(&z_erofs_qpl_mutex);
171*33b1fccfSAndroid Build Coastguard Worker #endif
172*33b1fccfSAndroid Build Coastguard Worker job->next = z_erofs_qpl_jobs;
173*33b1fccfSAndroid Build Coastguard Worker z_erofs_qpl_jobs = job;
174*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_PTHREAD_H
175*33b1fccfSAndroid Build Coastguard Worker pthread_mutex_unlock(&z_erofs_qpl_mutex);
176*33b1fccfSAndroid Build Coastguard Worker #endif
177*33b1fccfSAndroid Build Coastguard Worker return true;
178*33b1fccfSAndroid Build Coastguard Worker }
179*33b1fccfSAndroid Build Coastguard Worker
z_erofs_decompress_qpl(struct z_erofs_decompress_req * rq)180*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_decompress_qpl(struct z_erofs_decompress_req *rq)
181*33b1fccfSAndroid Build Coastguard Worker {
182*33b1fccfSAndroid Build Coastguard Worker u8 *dest = (u8 *)rq->out;
183*33b1fccfSAndroid Build Coastguard Worker u8 *src = (u8 *)rq->in;
184*33b1fccfSAndroid Build Coastguard Worker u8 *buff = NULL;
185*33b1fccfSAndroid Build Coastguard Worker unsigned int inputmargin;
186*33b1fccfSAndroid Build Coastguard Worker qpl_status status;
187*33b1fccfSAndroid Build Coastguard Worker qpl_job *job;
188*33b1fccfSAndroid Build Coastguard Worker int ret;
189*33b1fccfSAndroid Build Coastguard Worker
190*33b1fccfSAndroid Build Coastguard Worker job = z_erofs_qpl_get_job();
191*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(job))
192*33b1fccfSAndroid Build Coastguard Worker return PTR_ERR(job);
193*33b1fccfSAndroid Build Coastguard Worker
194*33b1fccfSAndroid Build Coastguard Worker inputmargin = z_erofs_fixup_insize(src, rq->inputsize);
195*33b1fccfSAndroid Build Coastguard Worker if (inputmargin >= rq->inputsize)
196*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
197*33b1fccfSAndroid Build Coastguard Worker
198*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip) {
199*33b1fccfSAndroid Build Coastguard Worker buff = malloc(rq->decodedlength);
200*33b1fccfSAndroid Build Coastguard Worker if (!buff)
201*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
202*33b1fccfSAndroid Build Coastguard Worker dest = buff;
203*33b1fccfSAndroid Build Coastguard Worker }
204*33b1fccfSAndroid Build Coastguard Worker
205*33b1fccfSAndroid Build Coastguard Worker job->op = qpl_op_decompress;
206*33b1fccfSAndroid Build Coastguard Worker job->next_in_ptr = src + inputmargin;
207*33b1fccfSAndroid Build Coastguard Worker job->next_out_ptr = dest;
208*33b1fccfSAndroid Build Coastguard Worker job->available_in = rq->inputsize - inputmargin;
209*33b1fccfSAndroid Build Coastguard Worker job->available_out = rq->decodedlength;
210*33b1fccfSAndroid Build Coastguard Worker job->flags = QPL_FLAG_FIRST | QPL_FLAG_LAST;
211*33b1fccfSAndroid Build Coastguard Worker status = qpl_execute_job(job);
212*33b1fccfSAndroid Build Coastguard Worker if (status != QPL_STS_OK) {
213*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to decompress: %d", status);
214*33b1fccfSAndroid Build Coastguard Worker ret = -EIO;
215*33b1fccfSAndroid Build Coastguard Worker goto out_inflate_end;
216*33b1fccfSAndroid Build Coastguard Worker }
217*33b1fccfSAndroid Build Coastguard Worker
218*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip)
219*33b1fccfSAndroid Build Coastguard Worker memcpy(rq->out, dest + rq->decodedskip,
220*33b1fccfSAndroid Build Coastguard Worker rq->decodedlength - rq->decodedskip);
221*33b1fccfSAndroid Build Coastguard Worker ret = 0;
222*33b1fccfSAndroid Build Coastguard Worker out_inflate_end:
223*33b1fccfSAndroid Build Coastguard Worker if (!z_erofs_qpl_put_job(job))
224*33b1fccfSAndroid Build Coastguard Worker ret = -EFAULT;
225*33b1fccfSAndroid Build Coastguard Worker if (buff)
226*33b1fccfSAndroid Build Coastguard Worker free(buff);
227*33b1fccfSAndroid Build Coastguard Worker return ret;
228*33b1fccfSAndroid Build Coastguard Worker }
229*33b1fccfSAndroid Build Coastguard Worker #else
z_erofs_load_deflate_config(struct erofs_sb_info * sbi,struct erofs_super_block * dsb,void * data,int size)230*33b1fccfSAndroid Build Coastguard Worker int z_erofs_load_deflate_config(struct erofs_sb_info *sbi,
231*33b1fccfSAndroid Build Coastguard Worker struct erofs_super_block *dsb, void *data, int size)
232*33b1fccfSAndroid Build Coastguard Worker {
233*33b1fccfSAndroid Build Coastguard Worker return 0;
234*33b1fccfSAndroid Build Coastguard Worker }
235*33b1fccfSAndroid Build Coastguard Worker #endif
236*33b1fccfSAndroid Build Coastguard Worker
237*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBDEFLATE
238*33b1fccfSAndroid Build Coastguard Worker /* if libdeflate is available, use libdeflate instead. */
239*33b1fccfSAndroid Build Coastguard Worker #include <libdeflate.h>
240*33b1fccfSAndroid Build Coastguard Worker
z_erofs_decompress_deflate(struct z_erofs_decompress_req * rq)241*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq)
242*33b1fccfSAndroid Build Coastguard Worker {
243*33b1fccfSAndroid Build Coastguard Worker u8 *dest = (u8 *)rq->out;
244*33b1fccfSAndroid Build Coastguard Worker u8 *src = (u8 *)rq->in;
245*33b1fccfSAndroid Build Coastguard Worker u8 *buff = NULL;
246*33b1fccfSAndroid Build Coastguard Worker size_t actual_out;
247*33b1fccfSAndroid Build Coastguard Worker unsigned int inputmargin;
248*33b1fccfSAndroid Build Coastguard Worker struct libdeflate_decompressor *inf;
249*33b1fccfSAndroid Build Coastguard Worker enum libdeflate_result ret;
250*33b1fccfSAndroid Build Coastguard Worker unsigned int decodedcapacity;
251*33b1fccfSAndroid Build Coastguard Worker
252*33b1fccfSAndroid Build Coastguard Worker inputmargin = z_erofs_fixup_insize(src, rq->inputsize);
253*33b1fccfSAndroid Build Coastguard Worker if (inputmargin >= rq->inputsize)
254*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
255*33b1fccfSAndroid Build Coastguard Worker
256*33b1fccfSAndroid Build Coastguard Worker decodedcapacity = rq->decodedlength << (4 * rq->partial_decoding);
257*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip || rq->partial_decoding) {
258*33b1fccfSAndroid Build Coastguard Worker buff = malloc(decodedcapacity);
259*33b1fccfSAndroid Build Coastguard Worker if (!buff)
260*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
261*33b1fccfSAndroid Build Coastguard Worker dest = buff;
262*33b1fccfSAndroid Build Coastguard Worker }
263*33b1fccfSAndroid Build Coastguard Worker
264*33b1fccfSAndroid Build Coastguard Worker inf = libdeflate_alloc_decompressor();
265*33b1fccfSAndroid Build Coastguard Worker if (!inf) {
266*33b1fccfSAndroid Build Coastguard Worker ret = -ENOMEM;
267*33b1fccfSAndroid Build Coastguard Worker goto out_free_mem;
268*33b1fccfSAndroid Build Coastguard Worker }
269*33b1fccfSAndroid Build Coastguard Worker
270*33b1fccfSAndroid Build Coastguard Worker if (rq->partial_decoding) {
271*33b1fccfSAndroid Build Coastguard Worker while (1) {
272*33b1fccfSAndroid Build Coastguard Worker ret = libdeflate_deflate_decompress(inf, src + inputmargin,
273*33b1fccfSAndroid Build Coastguard Worker rq->inputsize - inputmargin, dest,
274*33b1fccfSAndroid Build Coastguard Worker decodedcapacity, &actual_out);
275*33b1fccfSAndroid Build Coastguard Worker if (ret == LIBDEFLATE_SUCCESS)
276*33b1fccfSAndroid Build Coastguard Worker break;
277*33b1fccfSAndroid Build Coastguard Worker if (ret != LIBDEFLATE_INSUFFICIENT_SPACE) {
278*33b1fccfSAndroid Build Coastguard Worker ret = -EIO;
279*33b1fccfSAndroid Build Coastguard Worker goto out_inflate_end;
280*33b1fccfSAndroid Build Coastguard Worker }
281*33b1fccfSAndroid Build Coastguard Worker decodedcapacity = decodedcapacity << 1;
282*33b1fccfSAndroid Build Coastguard Worker dest = realloc(buff, decodedcapacity);
283*33b1fccfSAndroid Build Coastguard Worker if (!dest) {
284*33b1fccfSAndroid Build Coastguard Worker ret = -ENOMEM;
285*33b1fccfSAndroid Build Coastguard Worker goto out_inflate_end;
286*33b1fccfSAndroid Build Coastguard Worker }
287*33b1fccfSAndroid Build Coastguard Worker buff = dest;
288*33b1fccfSAndroid Build Coastguard Worker }
289*33b1fccfSAndroid Build Coastguard Worker
290*33b1fccfSAndroid Build Coastguard Worker if (actual_out < rq->decodedlength) {
291*33b1fccfSAndroid Build Coastguard Worker ret = -EIO;
292*33b1fccfSAndroid Build Coastguard Worker goto out_inflate_end;
293*33b1fccfSAndroid Build Coastguard Worker }
294*33b1fccfSAndroid Build Coastguard Worker } else {
295*33b1fccfSAndroid Build Coastguard Worker ret = libdeflate_deflate_decompress(inf, src + inputmargin,
296*33b1fccfSAndroid Build Coastguard Worker rq->inputsize - inputmargin, dest,
297*33b1fccfSAndroid Build Coastguard Worker rq->decodedlength, NULL);
298*33b1fccfSAndroid Build Coastguard Worker if (ret != LIBDEFLATE_SUCCESS) {
299*33b1fccfSAndroid Build Coastguard Worker ret = -EIO;
300*33b1fccfSAndroid Build Coastguard Worker goto out_inflate_end;
301*33b1fccfSAndroid Build Coastguard Worker }
302*33b1fccfSAndroid Build Coastguard Worker }
303*33b1fccfSAndroid Build Coastguard Worker
304*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip || rq->partial_decoding)
305*33b1fccfSAndroid Build Coastguard Worker memcpy(rq->out, dest + rq->decodedskip,
306*33b1fccfSAndroid Build Coastguard Worker rq->decodedlength - rq->decodedskip);
307*33b1fccfSAndroid Build Coastguard Worker
308*33b1fccfSAndroid Build Coastguard Worker out_inflate_end:
309*33b1fccfSAndroid Build Coastguard Worker libdeflate_free_decompressor(inf);
310*33b1fccfSAndroid Build Coastguard Worker out_free_mem:
311*33b1fccfSAndroid Build Coastguard Worker if (buff)
312*33b1fccfSAndroid Build Coastguard Worker free(buff);
313*33b1fccfSAndroid Build Coastguard Worker return ret;
314*33b1fccfSAndroid Build Coastguard Worker }
315*33b1fccfSAndroid Build Coastguard Worker #elif defined(HAVE_ZLIB)
316*33b1fccfSAndroid Build Coastguard Worker #include <zlib.h>
317*33b1fccfSAndroid Build Coastguard Worker
318*33b1fccfSAndroid Build Coastguard Worker /* report a zlib or i/o error */
zerr(int ret)319*33b1fccfSAndroid Build Coastguard Worker static int zerr(int ret)
320*33b1fccfSAndroid Build Coastguard Worker {
321*33b1fccfSAndroid Build Coastguard Worker switch (ret) {
322*33b1fccfSAndroid Build Coastguard Worker case Z_STREAM_ERROR:
323*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
324*33b1fccfSAndroid Build Coastguard Worker case Z_DATA_ERROR:
325*33b1fccfSAndroid Build Coastguard Worker return -EIO;
326*33b1fccfSAndroid Build Coastguard Worker case Z_MEM_ERROR:
327*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
328*33b1fccfSAndroid Build Coastguard Worker case Z_ERRNO:
329*33b1fccfSAndroid Build Coastguard Worker case Z_VERSION_ERROR:
330*33b1fccfSAndroid Build Coastguard Worker default:
331*33b1fccfSAndroid Build Coastguard Worker return -EFAULT;
332*33b1fccfSAndroid Build Coastguard Worker }
333*33b1fccfSAndroid Build Coastguard Worker }
334*33b1fccfSAndroid Build Coastguard Worker
z_erofs_decompress_deflate(struct z_erofs_decompress_req * rq)335*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_decompress_deflate(struct z_erofs_decompress_req *rq)
336*33b1fccfSAndroid Build Coastguard Worker {
337*33b1fccfSAndroid Build Coastguard Worker u8 *dest = (u8 *)rq->out;
338*33b1fccfSAndroid Build Coastguard Worker u8 *src = (u8 *)rq->in;
339*33b1fccfSAndroid Build Coastguard Worker u8 *buff = NULL;
340*33b1fccfSAndroid Build Coastguard Worker unsigned int inputmargin;
341*33b1fccfSAndroid Build Coastguard Worker z_stream strm;
342*33b1fccfSAndroid Build Coastguard Worker int ret;
343*33b1fccfSAndroid Build Coastguard Worker
344*33b1fccfSAndroid Build Coastguard Worker inputmargin = z_erofs_fixup_insize(src, rq->inputsize);
345*33b1fccfSAndroid Build Coastguard Worker if (inputmargin >= rq->inputsize)
346*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
347*33b1fccfSAndroid Build Coastguard Worker
348*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip) {
349*33b1fccfSAndroid Build Coastguard Worker buff = malloc(rq->decodedlength);
350*33b1fccfSAndroid Build Coastguard Worker if (!buff)
351*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
352*33b1fccfSAndroid Build Coastguard Worker dest = buff;
353*33b1fccfSAndroid Build Coastguard Worker }
354*33b1fccfSAndroid Build Coastguard Worker
355*33b1fccfSAndroid Build Coastguard Worker /* allocate inflate state */
356*33b1fccfSAndroid Build Coastguard Worker strm.zalloc = Z_NULL;
357*33b1fccfSAndroid Build Coastguard Worker strm.zfree = Z_NULL;
358*33b1fccfSAndroid Build Coastguard Worker strm.opaque = Z_NULL;
359*33b1fccfSAndroid Build Coastguard Worker strm.avail_in = 0;
360*33b1fccfSAndroid Build Coastguard Worker strm.next_in = Z_NULL;
361*33b1fccfSAndroid Build Coastguard Worker ret = inflateInit2(&strm, -15);
362*33b1fccfSAndroid Build Coastguard Worker if (ret != Z_OK) {
363*33b1fccfSAndroid Build Coastguard Worker free(buff);
364*33b1fccfSAndroid Build Coastguard Worker return zerr(ret);
365*33b1fccfSAndroid Build Coastguard Worker }
366*33b1fccfSAndroid Build Coastguard Worker
367*33b1fccfSAndroid Build Coastguard Worker strm.next_in = src + inputmargin;
368*33b1fccfSAndroid Build Coastguard Worker strm.avail_in = rq->inputsize - inputmargin;
369*33b1fccfSAndroid Build Coastguard Worker strm.next_out = dest;
370*33b1fccfSAndroid Build Coastguard Worker strm.avail_out = rq->decodedlength;
371*33b1fccfSAndroid Build Coastguard Worker
372*33b1fccfSAndroid Build Coastguard Worker ret = inflate(&strm, rq->partial_decoding ? Z_SYNC_FLUSH : Z_FINISH);
373*33b1fccfSAndroid Build Coastguard Worker if (ret != Z_STREAM_END || strm.total_out != rq->decodedlength) {
374*33b1fccfSAndroid Build Coastguard Worker if (ret != Z_OK || !rq->partial_decoding) {
375*33b1fccfSAndroid Build Coastguard Worker ret = zerr(ret);
376*33b1fccfSAndroid Build Coastguard Worker goto out_inflate_end;
377*33b1fccfSAndroid Build Coastguard Worker }
378*33b1fccfSAndroid Build Coastguard Worker }
379*33b1fccfSAndroid Build Coastguard Worker
380*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip)
381*33b1fccfSAndroid Build Coastguard Worker memcpy(rq->out, dest + rq->decodedskip,
382*33b1fccfSAndroid Build Coastguard Worker rq->decodedlength - rq->decodedskip);
383*33b1fccfSAndroid Build Coastguard Worker
384*33b1fccfSAndroid Build Coastguard Worker out_inflate_end:
385*33b1fccfSAndroid Build Coastguard Worker inflateEnd(&strm);
386*33b1fccfSAndroid Build Coastguard Worker if (buff)
387*33b1fccfSAndroid Build Coastguard Worker free(buff);
388*33b1fccfSAndroid Build Coastguard Worker return ret;
389*33b1fccfSAndroid Build Coastguard Worker }
390*33b1fccfSAndroid Build Coastguard Worker #endif
391*33b1fccfSAndroid Build Coastguard Worker
392*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
393*33b1fccfSAndroid Build Coastguard Worker #include <lzma.h>
394*33b1fccfSAndroid Build Coastguard Worker
z_erofs_decompress_lzma(struct z_erofs_decompress_req * rq)395*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_decompress_lzma(struct z_erofs_decompress_req *rq)
396*33b1fccfSAndroid Build Coastguard Worker {
397*33b1fccfSAndroid Build Coastguard Worker int ret = 0;
398*33b1fccfSAndroid Build Coastguard Worker u8 *dest = (u8 *)rq->out;
399*33b1fccfSAndroid Build Coastguard Worker u8 *src = (u8 *)rq->in;
400*33b1fccfSAndroid Build Coastguard Worker u8 *buff = NULL;
401*33b1fccfSAndroid Build Coastguard Worker unsigned int inputmargin;
402*33b1fccfSAndroid Build Coastguard Worker lzma_stream strm;
403*33b1fccfSAndroid Build Coastguard Worker lzma_ret ret2;
404*33b1fccfSAndroid Build Coastguard Worker
405*33b1fccfSAndroid Build Coastguard Worker inputmargin = z_erofs_fixup_insize(src, rq->inputsize);
406*33b1fccfSAndroid Build Coastguard Worker if (inputmargin >= rq->inputsize)
407*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
408*33b1fccfSAndroid Build Coastguard Worker
409*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip) {
410*33b1fccfSAndroid Build Coastguard Worker buff = malloc(rq->decodedlength);
411*33b1fccfSAndroid Build Coastguard Worker if (!buff)
412*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
413*33b1fccfSAndroid Build Coastguard Worker dest = buff;
414*33b1fccfSAndroid Build Coastguard Worker }
415*33b1fccfSAndroid Build Coastguard Worker
416*33b1fccfSAndroid Build Coastguard Worker strm = (lzma_stream)LZMA_STREAM_INIT;
417*33b1fccfSAndroid Build Coastguard Worker strm.next_in = src + inputmargin;
418*33b1fccfSAndroid Build Coastguard Worker strm.avail_in = rq->inputsize - inputmargin;
419*33b1fccfSAndroid Build Coastguard Worker strm.next_out = dest;
420*33b1fccfSAndroid Build Coastguard Worker strm.avail_out = rq->decodedlength;
421*33b1fccfSAndroid Build Coastguard Worker
422*33b1fccfSAndroid Build Coastguard Worker ret2 = lzma_microlzma_decoder(&strm, strm.avail_in, rq->decodedlength,
423*33b1fccfSAndroid Build Coastguard Worker !rq->partial_decoding,
424*33b1fccfSAndroid Build Coastguard Worker Z_EROFS_LZMA_MAX_DICT_SIZE);
425*33b1fccfSAndroid Build Coastguard Worker if (ret2 != LZMA_OK) {
426*33b1fccfSAndroid Build Coastguard Worker erofs_err("fail to initialize lzma decoder %u", ret2 | 0U);
427*33b1fccfSAndroid Build Coastguard Worker ret = -EFAULT;
428*33b1fccfSAndroid Build Coastguard Worker goto out;
429*33b1fccfSAndroid Build Coastguard Worker }
430*33b1fccfSAndroid Build Coastguard Worker
431*33b1fccfSAndroid Build Coastguard Worker ret2 = lzma_code(&strm, LZMA_FINISH);
432*33b1fccfSAndroid Build Coastguard Worker if (ret2 != LZMA_STREAM_END) {
433*33b1fccfSAndroid Build Coastguard Worker ret = -EFSCORRUPTED;
434*33b1fccfSAndroid Build Coastguard Worker goto out_lzma_end;
435*33b1fccfSAndroid Build Coastguard Worker }
436*33b1fccfSAndroid Build Coastguard Worker
437*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip)
438*33b1fccfSAndroid Build Coastguard Worker memcpy(rq->out, dest + rq->decodedskip,
439*33b1fccfSAndroid Build Coastguard Worker rq->decodedlength - rq->decodedskip);
440*33b1fccfSAndroid Build Coastguard Worker
441*33b1fccfSAndroid Build Coastguard Worker out_lzma_end:
442*33b1fccfSAndroid Build Coastguard Worker lzma_end(&strm);
443*33b1fccfSAndroid Build Coastguard Worker out:
444*33b1fccfSAndroid Build Coastguard Worker if (buff)
445*33b1fccfSAndroid Build Coastguard Worker free(buff);
446*33b1fccfSAndroid Build Coastguard Worker return ret;
447*33b1fccfSAndroid Build Coastguard Worker }
448*33b1fccfSAndroid Build Coastguard Worker #endif
449*33b1fccfSAndroid Build Coastguard Worker
450*33b1fccfSAndroid Build Coastguard Worker #ifdef LZ4_ENABLED
451*33b1fccfSAndroid Build Coastguard Worker #include <lz4.h>
452*33b1fccfSAndroid Build Coastguard Worker
z_erofs_decompress_lz4(struct z_erofs_decompress_req * rq)453*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_decompress_lz4(struct z_erofs_decompress_req *rq)
454*33b1fccfSAndroid Build Coastguard Worker {
455*33b1fccfSAndroid Build Coastguard Worker int ret = 0;
456*33b1fccfSAndroid Build Coastguard Worker char *dest = rq->out;
457*33b1fccfSAndroid Build Coastguard Worker char *src = rq->in;
458*33b1fccfSAndroid Build Coastguard Worker char *buff = NULL;
459*33b1fccfSAndroid Build Coastguard Worker bool support_0padding = false;
460*33b1fccfSAndroid Build Coastguard Worker unsigned int inputmargin = 0;
461*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = rq->sbi;
462*33b1fccfSAndroid Build Coastguard Worker
463*33b1fccfSAndroid Build Coastguard Worker if (erofs_sb_has_lz4_0padding(sbi)) {
464*33b1fccfSAndroid Build Coastguard Worker support_0padding = true;
465*33b1fccfSAndroid Build Coastguard Worker
466*33b1fccfSAndroid Build Coastguard Worker inputmargin = z_erofs_fixup_insize((u8 *)src, rq->inputsize);
467*33b1fccfSAndroid Build Coastguard Worker if (inputmargin >= rq->inputsize)
468*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
469*33b1fccfSAndroid Build Coastguard Worker }
470*33b1fccfSAndroid Build Coastguard Worker
471*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip) {
472*33b1fccfSAndroid Build Coastguard Worker buff = malloc(rq->decodedlength);
473*33b1fccfSAndroid Build Coastguard Worker if (!buff)
474*33b1fccfSAndroid Build Coastguard Worker return -ENOMEM;
475*33b1fccfSAndroid Build Coastguard Worker dest = buff;
476*33b1fccfSAndroid Build Coastguard Worker }
477*33b1fccfSAndroid Build Coastguard Worker
478*33b1fccfSAndroid Build Coastguard Worker if (rq->partial_decoding || !support_0padding)
479*33b1fccfSAndroid Build Coastguard Worker ret = LZ4_decompress_safe_partial(src + inputmargin, dest,
480*33b1fccfSAndroid Build Coastguard Worker rq->inputsize - inputmargin,
481*33b1fccfSAndroid Build Coastguard Worker rq->decodedlength, rq->decodedlength);
482*33b1fccfSAndroid Build Coastguard Worker else
483*33b1fccfSAndroid Build Coastguard Worker ret = LZ4_decompress_safe(src + inputmargin, dest,
484*33b1fccfSAndroid Build Coastguard Worker rq->inputsize - inputmargin,
485*33b1fccfSAndroid Build Coastguard Worker rq->decodedlength);
486*33b1fccfSAndroid Build Coastguard Worker
487*33b1fccfSAndroid Build Coastguard Worker if (ret != (int)rq->decodedlength) {
488*33b1fccfSAndroid Build Coastguard Worker erofs_err("failed to %s decompress %d in[%u, %u] out[%u]",
489*33b1fccfSAndroid Build Coastguard Worker rq->partial_decoding ? "partial" : "full",
490*33b1fccfSAndroid Build Coastguard Worker ret, rq->inputsize, inputmargin, rq->decodedlength);
491*33b1fccfSAndroid Build Coastguard Worker ret = -EIO;
492*33b1fccfSAndroid Build Coastguard Worker goto out;
493*33b1fccfSAndroid Build Coastguard Worker }
494*33b1fccfSAndroid Build Coastguard Worker
495*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedskip)
496*33b1fccfSAndroid Build Coastguard Worker memcpy(rq->out, dest + rq->decodedskip,
497*33b1fccfSAndroid Build Coastguard Worker rq->decodedlength - rq->decodedskip);
498*33b1fccfSAndroid Build Coastguard Worker
499*33b1fccfSAndroid Build Coastguard Worker out:
500*33b1fccfSAndroid Build Coastguard Worker if (buff)
501*33b1fccfSAndroid Build Coastguard Worker free(buff);
502*33b1fccfSAndroid Build Coastguard Worker
503*33b1fccfSAndroid Build Coastguard Worker return ret;
504*33b1fccfSAndroid Build Coastguard Worker }
505*33b1fccfSAndroid Build Coastguard Worker #endif
506*33b1fccfSAndroid Build Coastguard Worker
z_erofs_decompress(struct z_erofs_decompress_req * rq)507*33b1fccfSAndroid Build Coastguard Worker int z_erofs_decompress(struct z_erofs_decompress_req *rq)
508*33b1fccfSAndroid Build Coastguard Worker {
509*33b1fccfSAndroid Build Coastguard Worker struct erofs_sb_info *sbi = rq->sbi;
510*33b1fccfSAndroid Build Coastguard Worker
511*33b1fccfSAndroid Build Coastguard Worker if (rq->alg == Z_EROFS_COMPRESSION_INTERLACED) {
512*33b1fccfSAndroid Build Coastguard Worker unsigned int count, rightpart, skip;
513*33b1fccfSAndroid Build Coastguard Worker
514*33b1fccfSAndroid Build Coastguard Worker /* XXX: should support inputsize >= erofs_blksiz(sbi) later */
515*33b1fccfSAndroid Build Coastguard Worker if (rq->inputsize > erofs_blksiz(sbi))
516*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
517*33b1fccfSAndroid Build Coastguard Worker
518*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedlength > erofs_blksiz(sbi))
519*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
520*33b1fccfSAndroid Build Coastguard Worker
521*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedlength < rq->decodedskip)
522*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
523*33b1fccfSAndroid Build Coastguard Worker
524*33b1fccfSAndroid Build Coastguard Worker count = rq->decodedlength - rq->decodedskip;
525*33b1fccfSAndroid Build Coastguard Worker skip = erofs_blkoff(sbi, rq->interlaced_offset + rq->decodedskip);
526*33b1fccfSAndroid Build Coastguard Worker rightpart = min(erofs_blksiz(sbi) - skip, count);
527*33b1fccfSAndroid Build Coastguard Worker memcpy(rq->out, rq->in + skip, rightpart);
528*33b1fccfSAndroid Build Coastguard Worker memcpy(rq->out + rightpart, rq->in, count - rightpart);
529*33b1fccfSAndroid Build Coastguard Worker return 0;
530*33b1fccfSAndroid Build Coastguard Worker } else if (rq->alg == Z_EROFS_COMPRESSION_SHIFTED) {
531*33b1fccfSAndroid Build Coastguard Worker if (rq->decodedlength > rq->inputsize)
532*33b1fccfSAndroid Build Coastguard Worker return -EFSCORRUPTED;
533*33b1fccfSAndroid Build Coastguard Worker
534*33b1fccfSAndroid Build Coastguard Worker DBG_BUGON(rq->decodedlength < rq->decodedskip);
535*33b1fccfSAndroid Build Coastguard Worker memcpy(rq->out, rq->in + rq->decodedskip,
536*33b1fccfSAndroid Build Coastguard Worker rq->decodedlength - rq->decodedskip);
537*33b1fccfSAndroid Build Coastguard Worker return 0;
538*33b1fccfSAndroid Build Coastguard Worker }
539*33b1fccfSAndroid Build Coastguard Worker
540*33b1fccfSAndroid Build Coastguard Worker #ifdef LZ4_ENABLED
541*33b1fccfSAndroid Build Coastguard Worker if (rq->alg == Z_EROFS_COMPRESSION_LZ4)
542*33b1fccfSAndroid Build Coastguard Worker return z_erofs_decompress_lz4(rq);
543*33b1fccfSAndroid Build Coastguard Worker #endif
544*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBLZMA
545*33b1fccfSAndroid Build Coastguard Worker if (rq->alg == Z_EROFS_COMPRESSION_LZMA)
546*33b1fccfSAndroid Build Coastguard Worker return z_erofs_decompress_lzma(rq);
547*33b1fccfSAndroid Build Coastguard Worker #endif
548*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_QPL
549*33b1fccfSAndroid Build Coastguard Worker if (rq->alg == Z_EROFS_COMPRESSION_DEFLATE && rq->sbi->useqpl)
550*33b1fccfSAndroid Build Coastguard Worker if (!z_erofs_decompress_qpl(rq))
551*33b1fccfSAndroid Build Coastguard Worker return 0;
552*33b1fccfSAndroid Build Coastguard Worker #endif
553*33b1fccfSAndroid Build Coastguard Worker #if defined(HAVE_ZLIB) || defined(HAVE_LIBDEFLATE)
554*33b1fccfSAndroid Build Coastguard Worker if (rq->alg == Z_EROFS_COMPRESSION_DEFLATE)
555*33b1fccfSAndroid Build Coastguard Worker return z_erofs_decompress_deflate(rq);
556*33b1fccfSAndroid Build Coastguard Worker #endif
557*33b1fccfSAndroid Build Coastguard Worker #ifdef HAVE_LIBZSTD
558*33b1fccfSAndroid Build Coastguard Worker if (rq->alg == Z_EROFS_COMPRESSION_ZSTD)
559*33b1fccfSAndroid Build Coastguard Worker return z_erofs_decompress_zstd(rq);
560*33b1fccfSAndroid Build Coastguard Worker #endif
561*33b1fccfSAndroid Build Coastguard Worker return -EOPNOTSUPP;
562*33b1fccfSAndroid Build Coastguard Worker }
563*33b1fccfSAndroid Build Coastguard Worker
z_erofs_load_lz4_config(struct erofs_sb_info * sbi,struct erofs_super_block * dsb,void * data,int size)564*33b1fccfSAndroid Build Coastguard Worker static int z_erofs_load_lz4_config(struct erofs_sb_info *sbi,
565*33b1fccfSAndroid Build Coastguard Worker struct erofs_super_block *dsb, void *data, int size)
566*33b1fccfSAndroid Build Coastguard Worker {
567*33b1fccfSAndroid Build Coastguard Worker struct z_erofs_lz4_cfgs *lz4 = data;
568*33b1fccfSAndroid Build Coastguard Worker u16 distance;
569*33b1fccfSAndroid Build Coastguard Worker
570*33b1fccfSAndroid Build Coastguard Worker if (lz4) {
571*33b1fccfSAndroid Build Coastguard Worker if (size < sizeof(struct z_erofs_lz4_cfgs)) {
572*33b1fccfSAndroid Build Coastguard Worker erofs_err("invalid lz4 cfgs, size=%u", size);
573*33b1fccfSAndroid Build Coastguard Worker return -EINVAL;
574*33b1fccfSAndroid Build Coastguard Worker }
575*33b1fccfSAndroid Build Coastguard Worker distance = le16_to_cpu(lz4->max_distance);
576*33b1fccfSAndroid Build Coastguard Worker
577*33b1fccfSAndroid Build Coastguard Worker sbi->lz4.max_pclusterblks = le16_to_cpu(lz4->max_pclusterblks);
578*33b1fccfSAndroid Build Coastguard Worker if (!sbi->lz4.max_pclusterblks)
579*33b1fccfSAndroid Build Coastguard Worker sbi->lz4.max_pclusterblks = 1; /* reserved case */
580*33b1fccfSAndroid Build Coastguard Worker } else {
581*33b1fccfSAndroid Build Coastguard Worker distance = le16_to_cpu(dsb->u1.lz4_max_distance);
582*33b1fccfSAndroid Build Coastguard Worker sbi->lz4.max_pclusterblks = 1;
583*33b1fccfSAndroid Build Coastguard Worker }
584*33b1fccfSAndroid Build Coastguard Worker sbi->lz4.max_distance = distance;
585*33b1fccfSAndroid Build Coastguard Worker return 0;
586*33b1fccfSAndroid Build Coastguard Worker }
587*33b1fccfSAndroid Build Coastguard Worker
z_erofs_parse_cfgs(struct erofs_sb_info * sbi,struct erofs_super_block * dsb)588*33b1fccfSAndroid Build Coastguard Worker int z_erofs_parse_cfgs(struct erofs_sb_info *sbi, struct erofs_super_block *dsb)
589*33b1fccfSAndroid Build Coastguard Worker {
590*33b1fccfSAndroid Build Coastguard Worker unsigned int algs, alg;
591*33b1fccfSAndroid Build Coastguard Worker erofs_off_t offset;
592*33b1fccfSAndroid Build Coastguard Worker int size, ret = 0;
593*33b1fccfSAndroid Build Coastguard Worker
594*33b1fccfSAndroid Build Coastguard Worker if (!erofs_sb_has_compr_cfgs(sbi)) {
595*33b1fccfSAndroid Build Coastguard Worker sbi->available_compr_algs = 1 << Z_EROFS_COMPRESSION_LZ4;
596*33b1fccfSAndroid Build Coastguard Worker return z_erofs_load_lz4_config(sbi, dsb, NULL, 0);
597*33b1fccfSAndroid Build Coastguard Worker }
598*33b1fccfSAndroid Build Coastguard Worker
599*33b1fccfSAndroid Build Coastguard Worker sbi->available_compr_algs = le16_to_cpu(dsb->u1.available_compr_algs);
600*33b1fccfSAndroid Build Coastguard Worker if (sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS) {
601*33b1fccfSAndroid Build Coastguard Worker erofs_err("unidentified algorithms %x, please upgrade erofs-utils",
602*33b1fccfSAndroid Build Coastguard Worker sbi->available_compr_algs & ~Z_EROFS_ALL_COMPR_ALGS);
603*33b1fccfSAndroid Build Coastguard Worker return -EOPNOTSUPP;
604*33b1fccfSAndroid Build Coastguard Worker }
605*33b1fccfSAndroid Build Coastguard Worker
606*33b1fccfSAndroid Build Coastguard Worker offset = EROFS_SUPER_OFFSET + sbi->sb_size;
607*33b1fccfSAndroid Build Coastguard Worker alg = 0;
608*33b1fccfSAndroid Build Coastguard Worker for (algs = sbi->available_compr_algs; algs; algs >>= 1, ++alg) {
609*33b1fccfSAndroid Build Coastguard Worker void *data;
610*33b1fccfSAndroid Build Coastguard Worker
611*33b1fccfSAndroid Build Coastguard Worker if (!(algs & 1))
612*33b1fccfSAndroid Build Coastguard Worker continue;
613*33b1fccfSAndroid Build Coastguard Worker
614*33b1fccfSAndroid Build Coastguard Worker data = erofs_read_metadata(sbi, 0, &offset, &size);
615*33b1fccfSAndroid Build Coastguard Worker if (IS_ERR(data)) {
616*33b1fccfSAndroid Build Coastguard Worker ret = PTR_ERR(data);
617*33b1fccfSAndroid Build Coastguard Worker break;
618*33b1fccfSAndroid Build Coastguard Worker }
619*33b1fccfSAndroid Build Coastguard Worker
620*33b1fccfSAndroid Build Coastguard Worker ret = 0;
621*33b1fccfSAndroid Build Coastguard Worker if (alg == Z_EROFS_COMPRESSION_LZ4)
622*33b1fccfSAndroid Build Coastguard Worker ret = z_erofs_load_lz4_config(sbi, dsb, data, size);
623*33b1fccfSAndroid Build Coastguard Worker else if (alg == Z_EROFS_COMPRESSION_DEFLATE)
624*33b1fccfSAndroid Build Coastguard Worker ret = z_erofs_load_deflate_config(sbi, dsb, data, size);
625*33b1fccfSAndroid Build Coastguard Worker free(data);
626*33b1fccfSAndroid Build Coastguard Worker if (ret)
627*33b1fccfSAndroid Build Coastguard Worker break;
628*33b1fccfSAndroid Build Coastguard Worker }
629*33b1fccfSAndroid Build Coastguard Worker return ret;
630*33b1fccfSAndroid Build Coastguard Worker }
631