1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * This file is part of UBIFS.
4  *
5  * Copyright (C) 2006-2008 Nokia Corporation.
6  * Copyright (C) 2006, 2007 University of Szeged, Hungary
7  *
8  * Authors: Adrian Hunter
9  *          Artem Bityutskiy (Битюцкий Артём)
10  *          Zoltan Sogor
11  */
12 
13 /*
14  * This file provides a single place to access to compression and
15  * decompression.
16  */
17 
18 #include <crypto/acompress.h>
19 #include <linux/highmem.h>
20 #include "ubifs.h"
21 
22 /* Fake description object for the "none" compressor */
23 static struct ubifs_compressor none_compr = {
24 	.compr_type = UBIFS_COMPR_NONE,
25 	.name = "none",
26 	.capi_name = "",
27 };
28 
29 #ifdef CONFIG_UBIFS_FS_LZO
30 static struct ubifs_compressor lzo_compr = {
31 	.compr_type = UBIFS_COMPR_LZO,
32 	.name = "lzo",
33 	.capi_name = "lzo",
34 };
35 #else
36 static struct ubifs_compressor lzo_compr = {
37 	.compr_type = UBIFS_COMPR_LZO,
38 	.name = "lzo",
39 };
40 #endif
41 
42 #ifdef CONFIG_UBIFS_FS_ZLIB
43 static struct ubifs_compressor zlib_compr = {
44 	.compr_type = UBIFS_COMPR_ZLIB,
45 	.name = "zlib",
46 	.capi_name = "deflate",
47 };
48 #else
49 static struct ubifs_compressor zlib_compr = {
50 	.compr_type = UBIFS_COMPR_ZLIB,
51 	.name = "zlib",
52 };
53 #endif
54 
55 #ifdef CONFIG_UBIFS_FS_ZSTD
56 static struct ubifs_compressor zstd_compr = {
57 	.compr_type = UBIFS_COMPR_ZSTD,
58 	.name = "zstd",
59 	.capi_name = "zstd",
60 };
61 #else
62 static struct ubifs_compressor zstd_compr = {
63 	.compr_type = UBIFS_COMPR_ZSTD,
64 	.name = "zstd",
65 };
66 #endif
67 
68 /* All UBIFS compressors */
69 struct ubifs_compressor *ubifs_compressors[UBIFS_COMPR_TYPES_CNT];
70 
ubifs_compress_req(const struct ubifs_info * c,struct acomp_req * req,void * out_buf,int * out_len,const char * compr_name)71 static int ubifs_compress_req(const struct ubifs_info *c,
72 			      struct acomp_req *req,
73 			      void *out_buf, int *out_len,
74 			      const char *compr_name)
75 {
76 	struct crypto_wait wait;
77 	int in_len = req->slen;
78 	int dlen = *out_len;
79 	int err;
80 
81 	dlen = min(dlen, in_len - UBIFS_MIN_COMPRESS_DIFF);
82 
83 	crypto_init_wait(&wait);
84 	acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
85 				   crypto_req_done, &wait);
86 	acomp_request_set_dst_dma(req, out_buf, dlen);
87 	err = crypto_acomp_compress(req);
88 	err = crypto_wait_req(err, &wait);
89 	*out_len = req->dlen;
90 	acomp_request_free(req);
91 
92 	return err;
93 }
94 
95 /**
96  * ubifs_compress - compress data.
97  * @c: UBIFS file-system description object
98  * @in_buf: data to compress
99  * @in_len: length of the data to compress
100  * @out_buf: output buffer where compressed data should be stored
101  * @out_len: output buffer length is returned here
102  * @compr_type: type of compression to use on enter, actually used compression
103  *              type on exit
104  *
105  * This function compresses input buffer @in_buf of length @in_len and stores
106  * the result in the output buffer @out_buf and the resulting length in
107  * @out_len. If the input buffer does not compress, it is just copied to the
108  * @out_buf. The same happens if @compr_type is %UBIFS_COMPR_NONE or if
109  * compression error occurred.
110  *
111  * Note, if the input buffer was not compressed, it is copied to the output
112  * buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
113  */
ubifs_compress(const struct ubifs_info * c,const void * in_buf,int in_len,void * out_buf,int * out_len,int * compr_type)114 void ubifs_compress(const struct ubifs_info *c, const void *in_buf,
115 		    int in_len, void *out_buf, int *out_len, int *compr_type)
116 {
117 	int err;
118 	struct ubifs_compressor *compr = ubifs_compressors[*compr_type];
119 
120 	if (*compr_type == UBIFS_COMPR_NONE)
121 		goto no_compr;
122 
123 	/* If the input data is small, do not even try to compress it */
124 	if (in_len < UBIFS_MIN_COMPR_LEN)
125 		goto no_compr;
126 
127 	{
128 		ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
129 
130 		acomp_request_set_src_dma(req, in_buf, in_len);
131 		err = ubifs_compress_req(c, req, out_buf, out_len, compr->name);
132 	}
133 
134 	if (err)
135 		goto no_compr;
136 
137 	return;
138 
139 no_compr:
140 	memcpy(out_buf, in_buf, in_len);
141 	*out_len = in_len;
142 	*compr_type = UBIFS_COMPR_NONE;
143 }
144 
145 /**
146  * ubifs_compress_folio - compress folio.
147  * @c: UBIFS file-system description object
148  * @in_folio: data to compress
149  * @in_offset: offset into @in_folio
150  * @in_len: length of the data to compress
151  * @out_buf: output buffer where compressed data should be stored
152  * @out_len: output buffer length is returned here
153  * @compr_type: type of compression to use on enter, actually used compression
154  *              type on exit
155  *
156  * This function compresses input folio @in_folio of length @in_len and
157  * stores the result in the output buffer @out_buf and the resulting length
158  * in @out_len. If the input buffer does not compress, it is just copied
159  * to the @out_buf. The same happens if @compr_type is %UBIFS_COMPR_NONE
160  * or if compression error occurred.
161  *
162  * Note, if the input buffer was not compressed, it is copied to the output
163  * buffer and %UBIFS_COMPR_NONE is returned in @compr_type.
164  */
ubifs_compress_folio(const struct ubifs_info * c,struct folio * in_folio,size_t in_offset,int in_len,void * out_buf,int * out_len,int * compr_type)165 void ubifs_compress_folio(const struct ubifs_info *c, struct folio *in_folio,
166 			  size_t in_offset, int in_len, void *out_buf,
167 			  int *out_len, int *compr_type)
168 {
169 	int err;
170 	struct ubifs_compressor *compr = ubifs_compressors[*compr_type];
171 
172 	if (*compr_type == UBIFS_COMPR_NONE)
173 		goto no_compr;
174 
175 	/* If the input data is small, do not even try to compress it */
176 	if (in_len < UBIFS_MIN_COMPR_LEN)
177 		goto no_compr;
178 
179 	{
180 		ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
181 
182 		acomp_request_set_src_folio(req, in_folio, in_offset, in_len);
183 		err = ubifs_compress_req(c, req, out_buf, out_len, compr->name);
184 	}
185 
186 	if (err)
187 		goto no_compr;
188 
189 	return;
190 
191 no_compr:
192 	memcpy_from_folio(out_buf, in_folio, in_offset, in_len);
193 	*out_len = in_len;
194 	*compr_type = UBIFS_COMPR_NONE;
195 }
196 
ubifs_decompress_req(const struct ubifs_info * c,struct acomp_req * req,const void * in_buf,int in_len,int * out_len,const char * compr_name)197 static int ubifs_decompress_req(const struct ubifs_info *c,
198 				struct acomp_req *req,
199 				const void *in_buf, int in_len, int *out_len,
200 				const char *compr_name)
201 {
202 	struct crypto_wait wait;
203 	int err;
204 
205 	crypto_init_wait(&wait);
206 	acomp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
207 				   crypto_req_done, &wait);
208 	acomp_request_set_src_dma(req, in_buf, in_len);
209 	err = crypto_acomp_decompress(req);
210 	err = crypto_wait_req(err, &wait);
211 	*out_len = req->dlen;
212 
213 	if (err)
214 		ubifs_err(c, "cannot decompress %d bytes, compressor %s, error %d",
215 			  in_len, compr_name, err);
216 
217 	acomp_request_free(req);
218 
219 	return err;
220 }
221 
222 /**
223  * ubifs_decompress - decompress data.
224  * @c: UBIFS file-system description object
225  * @in_buf: data to decompress
226  * @in_len: length of the data to decompress
227  * @out_buf: output buffer where decompressed data should
228  * @out_len: output length is returned here
229  * @compr_type: type of compression
230  *
231  * This function decompresses data from buffer @in_buf into buffer @out_buf.
232  * The length of the uncompressed data is returned in @out_len. This functions
233  * returns %0 on success or a negative error code on failure.
234  */
ubifs_decompress(const struct ubifs_info * c,const void * in_buf,int in_len,void * out_buf,int * out_len,int compr_type)235 int ubifs_decompress(const struct ubifs_info *c, const void *in_buf,
236 		     int in_len, void *out_buf, int *out_len, int compr_type)
237 {
238 	struct ubifs_compressor *compr;
239 
240 	if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
241 		ubifs_err(c, "invalid compression type %d", compr_type);
242 		return -EINVAL;
243 	}
244 
245 	compr = ubifs_compressors[compr_type];
246 
247 	if (unlikely(!compr->capi_name)) {
248 		ubifs_err(c, "%s compression is not compiled in", compr->name);
249 		return -EINVAL;
250 	}
251 
252 	if (compr_type == UBIFS_COMPR_NONE) {
253 		memcpy(out_buf, in_buf, in_len);
254 		*out_len = in_len;
255 		return 0;
256 	}
257 
258 	{
259 		ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
260 
261 		acomp_request_set_dst_dma(req, out_buf, *out_len);
262 		return ubifs_decompress_req(c, req, in_buf, in_len, out_len,
263 					    compr->name);
264 	}
265 }
266 
267 /**
268  * ubifs_decompress_folio - decompress folio.
269  * @c: UBIFS file-system description object
270  * @in_buf: data to decompress
271  * @in_len: length of the data to decompress
272  * @out_folio: output folio where decompressed data should
273  * @out_offset: offset into @out_folio
274  * @out_len: output length is returned here
275  * @compr_type: type of compression
276  *
277  * This function decompresses data from buffer @in_buf into folio
278  * @out_folio.  The length of the uncompressed data is returned in
279  * @out_len.  This functions returns %0 on success or a negative error
280  * code on failure.
281  */
ubifs_decompress_folio(const struct ubifs_info * c,const void * in_buf,int in_len,struct folio * out_folio,size_t out_offset,int * out_len,int compr_type)282 int ubifs_decompress_folio(const struct ubifs_info *c, const void *in_buf,
283 			   int in_len, struct folio *out_folio,
284 			   size_t out_offset, int *out_len, int compr_type)
285 {
286 	struct ubifs_compressor *compr;
287 
288 	if (unlikely(compr_type < 0 || compr_type >= UBIFS_COMPR_TYPES_CNT)) {
289 		ubifs_err(c, "invalid compression type %d", compr_type);
290 		return -EINVAL;
291 	}
292 
293 	compr = ubifs_compressors[compr_type];
294 
295 	if (unlikely(!compr->capi_name)) {
296 		ubifs_err(c, "%s compression is not compiled in", compr->name);
297 		return -EINVAL;
298 	}
299 
300 	if (compr_type == UBIFS_COMPR_NONE) {
301 		memcpy_to_folio(out_folio, out_offset, in_buf, in_len);
302 		*out_len = in_len;
303 		return 0;
304 	}
305 
306 	{
307 		ACOMP_REQUEST_ALLOC(req, compr->cc, GFP_NOFS | __GFP_NOWARN);
308 
309 		acomp_request_set_dst_folio(req, out_folio, out_offset,
310 					    *out_len);
311 		return ubifs_decompress_req(c, req, in_buf, in_len, out_len,
312 					    compr->name);
313 	}
314 }
315 
316 /**
317  * compr_init - initialize a compressor.
318  * @compr: compressor description object
319  *
320  * This function initializes the requested compressor and returns zero in case
321  * of success or a negative error code in case of failure.
322  */
compr_init(struct ubifs_compressor * compr)323 static int __init compr_init(struct ubifs_compressor *compr)
324 {
325 	if (compr->capi_name) {
326 		compr->cc = crypto_alloc_acomp(compr->capi_name, 0, 0);
327 		if (IS_ERR(compr->cc)) {
328 			pr_err("UBIFS error (pid %d): cannot initialize compressor %s, error %ld",
329 			       current->pid, compr->name, PTR_ERR(compr->cc));
330 			return PTR_ERR(compr->cc);
331 		}
332 	}
333 
334 	ubifs_compressors[compr->compr_type] = compr;
335 	return 0;
336 }
337 
338 /**
339  * compr_exit - de-initialize a compressor.
340  * @compr: compressor description object
341  */
compr_exit(struct ubifs_compressor * compr)342 static void compr_exit(struct ubifs_compressor *compr)
343 {
344 	if (compr->capi_name)
345 		crypto_free_acomp(compr->cc);
346 }
347 
348 /**
349  * ubifs_compressors_init - initialize UBIFS compressors.
350  *
351  * This function initializes the compressor which were compiled in. Returns
352  * zero in case of success and a negative error code in case of failure.
353  */
ubifs_compressors_init(void)354 int __init ubifs_compressors_init(void)
355 {
356 	int err;
357 
358 	err = compr_init(&lzo_compr);
359 	if (err)
360 		return err;
361 
362 	err = compr_init(&zstd_compr);
363 	if (err)
364 		goto out_lzo;
365 
366 	err = compr_init(&zlib_compr);
367 	if (err)
368 		goto out_zstd;
369 
370 	ubifs_compressors[UBIFS_COMPR_NONE] = &none_compr;
371 	return 0;
372 
373 out_zstd:
374 	compr_exit(&zstd_compr);
375 out_lzo:
376 	compr_exit(&lzo_compr);
377 	return err;
378 }
379 
380 /**
381  * ubifs_compressors_exit - de-initialize UBIFS compressors.
382  */
ubifs_compressors_exit(void)383 void ubifs_compressors_exit(void)
384 {
385 	compr_exit(&lzo_compr);
386 	compr_exit(&zlib_compr);
387 	compr_exit(&zstd_compr);
388 }
389