1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #define pr_fmt(fmt) "lz4hc: " fmt 4 5 #include <linux/kernel.h> 6 #include <linux/lz4.h> 7 #include <linux/slab.h> 8 #include <linux/vmalloc.h> 9 10 #include "backend_lz4hc.h" 11 12 struct lz4hc_ctx { 13 void *mem; 14 15 LZ4_streamDecode_t *dstrm; 16 LZ4_streamHC_t *cstrm; 17 }; 18 19 static void lz4hc_release_params(struct zcomp_params *params) 20 { 21 } 22 23 static int lz4hc_setup_params(struct zcomp_params *params) 24 { 25 if (params->level == ZCOMP_PARAM_NOT_SET) { 26 params->level = LZ4HC_DEFAULT_CLEVEL; 27 } else if (params->level < 1 || params->level > LZ4HC_MAX_CLEVEL) { 28 /* 29 * Use < 1 rather than < LZ4HC_MIN_CLEVEL here because 30 * LZ4HC_compress_generic() only clamps levels below 1 31 * (levels 1 and 2 are valid). LZ4HC_MIN_CLEVEL (3) is 32 * advisory and not enforced by the library. 33 */ 34 pr_err("invalid compression level %d\n", params->level); 35 return -EINVAL; 36 } 37 38 return 0; 39 } 40 41 static void lz4hc_destroy(struct zcomp_ctx *ctx) 42 { 43 struct lz4hc_ctx *zctx = ctx->context; 44 45 if (!zctx) 46 return; 47 48 kfree(zctx->dstrm); 49 kfree(zctx->cstrm); 50 vfree(zctx->mem); 51 kfree(zctx); 52 } 53 54 static int lz4hc_create(struct zcomp_params *params, struct zcomp_ctx *ctx) 55 { 56 struct lz4hc_ctx *zctx; 57 58 zctx = kzalloc_obj(*zctx); 59 if (!zctx) 60 return -ENOMEM; 61 62 ctx->context = zctx; 63 if (params->dict_sz == 0) { 64 zctx->mem = vmalloc(LZ4HC_MEM_COMPRESS); 65 if (!zctx->mem) 66 goto error; 67 } else { 68 zctx->dstrm = kzalloc_obj(*zctx->dstrm); 69 if (!zctx->dstrm) 70 goto error; 71 72 zctx->cstrm = kzalloc_obj(*zctx->cstrm); 73 if (!zctx->cstrm) 74 goto error; 75 } 76 77 return 0; 78 79 error: 80 lz4hc_destroy(ctx); 81 return -EINVAL; 82 } 83 84 static int lz4hc_compress(struct zcomp_params *params, struct zcomp_ctx *ctx, 85 struct zcomp_req *req) 86 { 87 struct lz4hc_ctx *zctx = ctx->context; 88 int ret; 89 90 if (!zctx->cstrm) { 91 ret = LZ4_compress_HC(req->src, req->dst, req->src_len, 92 req->dst_len, params->level, 93 zctx->mem); 94 } else { 95 /* Cstrm needs to be reset */ 96 LZ4_resetStreamHC(zctx->cstrm, params->level); 97 ret = LZ4_loadDictHC(zctx->cstrm, params->dict, 98 params->dict_sz); 99 if (ret != params->dict_sz) 100 return -EINVAL; 101 ret = LZ4_compress_HC_continue(zctx->cstrm, req->src, req->dst, 102 req->src_len, req->dst_len); 103 } 104 if (!ret) 105 return -EINVAL; 106 req->dst_len = ret; 107 return 0; 108 } 109 110 static int lz4hc_decompress(struct zcomp_params *params, struct zcomp_ctx *ctx, 111 struct zcomp_req *req) 112 { 113 struct lz4hc_ctx *zctx = ctx->context; 114 int ret; 115 116 if (!zctx->dstrm) { 117 ret = LZ4_decompress_safe(req->src, req->dst, req->src_len, 118 req->dst_len); 119 } else { 120 /* Dstrm needs to be reset */ 121 ret = LZ4_setStreamDecode(zctx->dstrm, params->dict, 122 params->dict_sz); 123 if (!ret) 124 return -EINVAL; 125 ret = LZ4_decompress_safe_continue(zctx->dstrm, req->src, 126 req->dst, req->src_len, 127 req->dst_len); 128 } 129 if (ret < 0) 130 return -EINVAL; 131 return 0; 132 } 133 134 const struct zcomp_ops backend_lz4hc = { 135 .compress = lz4hc_compress, 136 .decompress = lz4hc_decompress, 137 .create_ctx = lz4hc_create, 138 .destroy_ctx = lz4hc_destroy, 139 .setup_params = lz4hc_setup_params, 140 .release_params = lz4hc_release_params, 141 .name = "lz4hc", 142 }; 143