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