1 // SPDX-License-Identifier: GPL-2.0-or-later 2 3 #define pr_fmt(fmt) "lz4: " 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_lz4.h" 11 12 struct lz4_ctx { 13 void *mem; 14 15 LZ4_streamDecode_t *dstrm; 16 LZ4_stream_t *cstrm; 17 }; 18 19 static void lz4_release_params(struct zcomp_params *params) 20 { 21 LZ4_stream_t *dict_stream = params->drv_data; 22 23 params->drv_data = NULL; 24 if (!dict_stream) 25 return; 26 27 kfree(dict_stream); 28 } 29 30 static int lz4_setup_params(struct zcomp_params *params) 31 { 32 LZ4_stream_t *dict_stream; 33 int ret; 34 35 if (params->level == ZCOMP_PARAM_NOT_SET) { 36 params->level = LZ4_ACCELERATION_DEFAULT; 37 } else if (params->level < LZ4_ACCELERATION_DEFAULT) { 38 pr_err("invalid compression level %d\n", params->level); 39 return -EINVAL; 40 } 41 42 if (!params->dict || !params->dict_sz) 43 return 0; 44 45 dict_stream = kzalloc_obj(*dict_stream); 46 if (!dict_stream) 47 return -ENOMEM; 48 49 ret = LZ4_loadDict(dict_stream, 50 params->dict, params->dict_sz); 51 if (ret != params->dict_sz) { 52 kfree(dict_stream); 53 return -EINVAL; 54 } 55 params->drv_data = dict_stream; 56 57 return 0; 58 } 59 60 static void lz4_destroy(struct zcomp_ctx *ctx) 61 { 62 struct lz4_ctx *zctx = ctx->context; 63 64 if (!zctx) 65 return; 66 67 vfree(zctx->mem); 68 kfree(zctx->dstrm); 69 kfree(zctx->cstrm); 70 kfree(zctx); 71 } 72 73 static int lz4_create(struct zcomp_params *params, struct zcomp_ctx *ctx) 74 { 75 struct lz4_ctx *zctx; 76 77 zctx = kzalloc_obj(*zctx); 78 if (!zctx) 79 return -ENOMEM; 80 81 ctx->context = zctx; 82 if (params->dict_sz == 0) { 83 zctx->mem = vmalloc(LZ4_MEM_COMPRESS); 84 if (!zctx->mem) 85 goto error; 86 } else { 87 zctx->dstrm = kzalloc_obj(*zctx->dstrm); 88 if (!zctx->dstrm) 89 goto error; 90 91 zctx->cstrm = kzalloc_obj(*zctx->cstrm); 92 if (!zctx->cstrm) 93 goto error; 94 } 95 96 return 0; 97 98 error: 99 lz4_destroy(ctx); 100 return -ENOMEM; 101 } 102 103 static int lz4_compress(struct zcomp_params *params, struct zcomp_ctx *ctx, 104 struct zcomp_req *req) 105 { 106 struct lz4_ctx *zctx = ctx->context; 107 int ret; 108 109 if (!zctx->cstrm) { 110 ret = LZ4_compress_fast(req->src, req->dst, req->src_len, 111 req->dst_len, params->level, 112 zctx->mem); 113 } else { 114 /* Cstrm needs to be reset */ 115 memcpy(zctx->cstrm, params->drv_data, sizeof(*zctx->cstrm)); 116 ret = LZ4_compress_fast_continue(zctx->cstrm, req->src, 117 req->dst, req->src_len, 118 req->dst_len, params->level); 119 } 120 if (!ret) 121 return -EINVAL; 122 req->dst_len = ret; 123 return 0; 124 } 125 126 static int lz4_decompress(struct zcomp_params *params, struct zcomp_ctx *ctx, 127 struct zcomp_req *req) 128 { 129 struct lz4_ctx *zctx = ctx->context; 130 int ret; 131 132 if (!zctx->dstrm) { 133 ret = LZ4_decompress_safe(req->src, req->dst, req->src_len, 134 req->dst_len); 135 } else { 136 /* Dstrm needs to be reset */ 137 ret = LZ4_setStreamDecode(zctx->dstrm, params->dict, 138 params->dict_sz); 139 if (!ret) 140 return -EINVAL; 141 ret = LZ4_decompress_safe_continue(zctx->dstrm, req->src, 142 req->dst, req->src_len, 143 req->dst_len); 144 } 145 if (ret < 0) 146 return -EINVAL; 147 return 0; 148 } 149 150 const struct zcomp_ops backend_lz4 = { 151 .compress = lz4_compress, 152 .decompress = lz4_decompress, 153 .create_ctx = lz4_create, 154 .destroy_ctx = lz4_destroy, 155 .setup_params = lz4_setup_params, 156 .release_params = lz4_release_params, 157 .name = "lz4", 158 }; 159