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