xref: /linux/drivers/block/zram/backend_lz4.c (revision c8d430db8eec7d4fd13a6bea27b7086a54eda6da)
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 }
18 
19 static int lz4_setup_params(struct zcomp_params *params)
20 {
21 	if (params->level == ZCOMP_PARAM_NO_LEVEL)
22 		params->level = LZ4_ACCELERATION_DEFAULT;
23 
24 	return 0;
25 }
26 
27 static void lz4_destroy(struct zcomp_ctx *ctx)
28 {
29 	struct lz4_ctx *zctx = ctx->context;
30 
31 	if (!zctx)
32 		return;
33 
34 	vfree(zctx->mem);
35 	kfree(zctx->dstrm);
36 	kfree(zctx->cstrm);
37 	kfree(zctx);
38 }
39 
40 static int lz4_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
41 {
42 	struct lz4_ctx *zctx;
43 
44 	zctx = kzalloc(sizeof(*zctx), GFP_KERNEL);
45 	if (!zctx)
46 		return -ENOMEM;
47 
48 	ctx->context = zctx;
49 	if (params->dict_sz == 0) {
50 		zctx->mem = vmalloc(LZ4_MEM_COMPRESS);
51 		if (!zctx->mem)
52 			goto error;
53 	} else {
54 		zctx->dstrm = kzalloc(sizeof(*zctx->dstrm), GFP_KERNEL);
55 		if (!zctx->dstrm)
56 			goto error;
57 
58 		zctx->cstrm = kzalloc(sizeof(*zctx->cstrm), GFP_KERNEL);
59 		if (!zctx->cstrm)
60 			goto error;
61 	}
62 
63 	return 0;
64 
65 error:
66 	lz4_destroy(ctx);
67 	return -ENOMEM;
68 }
69 
70 static int lz4_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
71 			struct zcomp_req *req)
72 {
73 	struct lz4_ctx *zctx = ctx->context;
74 	int ret;
75 
76 	if (!zctx->cstrm) {
77 		ret = LZ4_compress_fast(req->src, req->dst, req->src_len,
78 					req->dst_len, params->level,
79 					zctx->mem);
80 	} else {
81 		/* Cstrm needs to be reset */
82 		ret = LZ4_loadDict(zctx->cstrm, params->dict, params->dict_sz);
83 		if (ret != params->dict_sz)
84 			return -EINVAL;
85 		ret = LZ4_compress_fast_continue(zctx->cstrm, req->src,
86 						 req->dst, req->src_len,
87 						 req->dst_len, params->level);
88 	}
89 	if (!ret)
90 		return -EINVAL;
91 	req->dst_len = ret;
92 	return 0;
93 }
94 
95 static int lz4_decompress(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->dstrm) {
102 		ret = LZ4_decompress_safe(req->src, req->dst, req->src_len,
103 					  req->dst_len);
104 	} else {
105 		/* Dstrm needs to be reset */
106 		ret = LZ4_setStreamDecode(zctx->dstrm, params->dict,
107 					  params->dict_sz);
108 		if (!ret)
109 			return -EINVAL;
110 		ret = LZ4_decompress_safe_continue(zctx->dstrm, req->src,
111 						   req->dst, req->src_len,
112 						   req->dst_len);
113 	}
114 	if (ret < 0)
115 		return -EINVAL;
116 	return 0;
117 }
118 
119 const struct zcomp_ops backend_lz4 = {
120 	.compress	= lz4_compress,
121 	.decompress	= lz4_decompress,
122 	.create_ctx	= lz4_create,
123 	.destroy_ctx	= lz4_destroy,
124 	.setup_params	= lz4_setup_params,
125 	.release_params	= lz4_release_params,
126 	.name		= "lz4",
127 };
128