xref: /linux/drivers/block/zram/backend_lz4.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
122d651c3SSergey Senozhatsky #include <linux/kernel.h>
222d651c3SSergey Senozhatsky #include <linux/lz4.h>
322d651c3SSergey Senozhatsky #include <linux/slab.h>
422d651c3SSergey Senozhatsky #include <linux/vmalloc.h>
522d651c3SSergey Senozhatsky 
622d651c3SSergey Senozhatsky #include "backend_lz4.h"
722d651c3SSergey Senozhatsky 
8*fb4f644eSSergey Senozhatsky struct lz4_ctx {
9*fb4f644eSSergey Senozhatsky 	void *mem;
10*fb4f644eSSergey Senozhatsky 
11*fb4f644eSSergey Senozhatsky 	LZ4_streamDecode_t *dstrm;
12*fb4f644eSSergey Senozhatsky 	LZ4_stream_t *cstrm;
13*fb4f644eSSergey Senozhatsky };
14*fb4f644eSSergey Senozhatsky 
lz4_release_params(struct zcomp_params * params)15b8f03cb7SSergey Senozhatsky static void lz4_release_params(struct zcomp_params *params)
16b8f03cb7SSergey Senozhatsky {
17b8f03cb7SSergey Senozhatsky }
18b8f03cb7SSergey Senozhatsky 
lz4_setup_params(struct zcomp_params * params)19b8f03cb7SSergey Senozhatsky static int lz4_setup_params(struct zcomp_params *params)
20b8f03cb7SSergey Senozhatsky {
21b8f03cb7SSergey Senozhatsky 	if (params->level == ZCOMP_PARAM_NO_LEVEL)
22b8f03cb7SSergey Senozhatsky 		params->level = LZ4_ACCELERATION_DEFAULT;
23b8f03cb7SSergey Senozhatsky 
24b8f03cb7SSergey Senozhatsky 	return 0;
25b8f03cb7SSergey Senozhatsky }
2622d651c3SSergey Senozhatsky 
lz4_destroy(struct zcomp_ctx * ctx)276a81bdfeSSergey Senozhatsky static void lz4_destroy(struct zcomp_ctx *ctx)
2822d651c3SSergey Senozhatsky {
29*fb4f644eSSergey Senozhatsky 	struct lz4_ctx *zctx = ctx->context;
30*fb4f644eSSergey Senozhatsky 
31*fb4f644eSSergey Senozhatsky 	if (!zctx)
32*fb4f644eSSergey Senozhatsky 		return;
33*fb4f644eSSergey Senozhatsky 
34*fb4f644eSSergey Senozhatsky 	vfree(zctx->mem);
35*fb4f644eSSergey Senozhatsky 	kfree(zctx->dstrm);
36*fb4f644eSSergey Senozhatsky 	kfree(zctx->cstrm);
37*fb4f644eSSergey Senozhatsky 	kfree(zctx);
3822d651c3SSergey Senozhatsky }
3922d651c3SSergey Senozhatsky 
lz4_create(struct zcomp_params * params,struct zcomp_ctx * ctx)406a81bdfeSSergey Senozhatsky static int lz4_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
4122d651c3SSergey Senozhatsky {
42*fb4f644eSSergey Senozhatsky 	struct lz4_ctx *zctx;
43*fb4f644eSSergey Senozhatsky 
44*fb4f644eSSergey Senozhatsky 	zctx = kzalloc(sizeof(*zctx), GFP_KERNEL);
45*fb4f644eSSergey Senozhatsky 	if (!zctx)
466a81bdfeSSergey Senozhatsky 		return -ENOMEM;
4722d651c3SSergey Senozhatsky 
48*fb4f644eSSergey Senozhatsky 	ctx->context = zctx;
49*fb4f644eSSergey Senozhatsky 	if (params->dict_sz == 0) {
50*fb4f644eSSergey Senozhatsky 		zctx->mem = vmalloc(LZ4_MEM_COMPRESS);
51*fb4f644eSSergey Senozhatsky 		if (!zctx->mem)
52*fb4f644eSSergey Senozhatsky 			goto error;
53*fb4f644eSSergey Senozhatsky 	} else {
54*fb4f644eSSergey Senozhatsky 		zctx->dstrm = kzalloc(sizeof(*zctx->dstrm), GFP_KERNEL);
55*fb4f644eSSergey Senozhatsky 		if (!zctx->dstrm)
56*fb4f644eSSergey Senozhatsky 			goto error;
57*fb4f644eSSergey Senozhatsky 
58*fb4f644eSSergey Senozhatsky 		zctx->cstrm = kzalloc(sizeof(*zctx->cstrm), GFP_KERNEL);
59*fb4f644eSSergey Senozhatsky 		if (!zctx->cstrm)
60*fb4f644eSSergey Senozhatsky 			goto error;
61*fb4f644eSSergey Senozhatsky 	}
62*fb4f644eSSergey Senozhatsky 
636a81bdfeSSergey Senozhatsky 	return 0;
64*fb4f644eSSergey Senozhatsky 
65*fb4f644eSSergey Senozhatsky error:
66*fb4f644eSSergey Senozhatsky 	lz4_destroy(ctx);
67*fb4f644eSSergey Senozhatsky 	return -ENOMEM;
6822d651c3SSergey Senozhatsky }
6922d651c3SSergey Senozhatsky 
lz4_compress(struct zcomp_params * params,struct zcomp_ctx * ctx,struct zcomp_req * req)70b8f03cb7SSergey Senozhatsky static int lz4_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
71b8f03cb7SSergey Senozhatsky 			struct zcomp_req *req)
7222d651c3SSergey Senozhatsky {
73*fb4f644eSSergey Senozhatsky 	struct lz4_ctx *zctx = ctx->context;
7422d651c3SSergey Senozhatsky 	int ret;
7522d651c3SSergey Senozhatsky 
76*fb4f644eSSergey Senozhatsky 	if (!zctx->cstrm) {
7752c7b4e2SSergey Senozhatsky 		ret = LZ4_compress_fast(req->src, req->dst, req->src_len,
78*fb4f644eSSergey Senozhatsky 					req->dst_len, params->level,
79*fb4f644eSSergey Senozhatsky 					zctx->mem);
80*fb4f644eSSergey Senozhatsky 	} else {
81*fb4f644eSSergey Senozhatsky 		/* Cstrm needs to be reset */
82*fb4f644eSSergey Senozhatsky 		ret = LZ4_loadDict(zctx->cstrm, params->dict, params->dict_sz);
83*fb4f644eSSergey Senozhatsky 		if (ret != params->dict_sz)
84*fb4f644eSSergey Senozhatsky 			return -EINVAL;
85*fb4f644eSSergey Senozhatsky 		ret = LZ4_compress_fast_continue(zctx->cstrm, req->src,
86*fb4f644eSSergey Senozhatsky 						 req->dst, req->src_len,
87*fb4f644eSSergey Senozhatsky 						 req->dst_len, params->level);
88*fb4f644eSSergey Senozhatsky 	}
8922d651c3SSergey Senozhatsky 	if (!ret)
9022d651c3SSergey Senozhatsky 		return -EINVAL;
9152c7b4e2SSergey Senozhatsky 	req->dst_len = ret;
9222d651c3SSergey Senozhatsky 	return 0;
9322d651c3SSergey Senozhatsky }
9422d651c3SSergey Senozhatsky 
lz4_decompress(struct zcomp_params * params,struct zcomp_ctx * ctx,struct zcomp_req * req)95b8f03cb7SSergey Senozhatsky static int lz4_decompress(struct zcomp_params *params, struct zcomp_ctx *ctx,
96b8f03cb7SSergey Senozhatsky 			  struct zcomp_req *req)
9722d651c3SSergey Senozhatsky {
98*fb4f644eSSergey Senozhatsky 	struct lz4_ctx *zctx = ctx->context;
9922d651c3SSergey Senozhatsky 	int ret;
10022d651c3SSergey Senozhatsky 
101*fb4f644eSSergey Senozhatsky 	if (!zctx->dstrm) {
10252c7b4e2SSergey Senozhatsky 		ret = LZ4_decompress_safe(req->src, req->dst, req->src_len,
10352c7b4e2SSergey Senozhatsky 					  req->dst_len);
104*fb4f644eSSergey Senozhatsky 	} else {
105*fb4f644eSSergey Senozhatsky 		/* Dstrm needs to be reset */
106*fb4f644eSSergey Senozhatsky 		ret = LZ4_setStreamDecode(zctx->dstrm, params->dict,
107*fb4f644eSSergey Senozhatsky 					  params->dict_sz);
108*fb4f644eSSergey Senozhatsky 		if (!ret)
109*fb4f644eSSergey Senozhatsky 			return -EINVAL;
110*fb4f644eSSergey Senozhatsky 		ret = LZ4_decompress_safe_continue(zctx->dstrm, req->src,
111*fb4f644eSSergey Senozhatsky 						   req->dst, req->src_len,
112*fb4f644eSSergey Senozhatsky 						   req->dst_len);
113*fb4f644eSSergey Senozhatsky 	}
11422d651c3SSergey Senozhatsky 	if (ret < 0)
11522d651c3SSergey Senozhatsky 		return -EINVAL;
11622d651c3SSergey Senozhatsky 	return 0;
11722d651c3SSergey Senozhatsky }
11822d651c3SSergey Senozhatsky 
11922d651c3SSergey Senozhatsky const struct zcomp_ops backend_lz4 = {
12022d651c3SSergey Senozhatsky 	.compress	= lz4_compress,
12122d651c3SSergey Senozhatsky 	.decompress	= lz4_decompress,
12222d651c3SSergey Senozhatsky 	.create_ctx	= lz4_create,
12322d651c3SSergey Senozhatsky 	.destroy_ctx	= lz4_destroy,
124b8f03cb7SSergey Senozhatsky 	.setup_params	= lz4_setup_params,
125b8f03cb7SSergey Senozhatsky 	.release_params	= lz4_release_params,
12622d651c3SSergey Senozhatsky 	.name		= "lz4",
12722d651c3SSergey Senozhatsky };
128