xref: /linux/drivers/block/zram/backend_lz4.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
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