xref: /linux/drivers/block/zram/backend_lz4hc.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
1c60a4ef5SSergey Senozhatsky #include <linux/kernel.h>
2c60a4ef5SSergey Senozhatsky #include <linux/lz4.h>
3c60a4ef5SSergey Senozhatsky #include <linux/slab.h>
4c60a4ef5SSergey Senozhatsky #include <linux/vmalloc.h>
5c60a4ef5SSergey Senozhatsky 
6c60a4ef5SSergey Senozhatsky #include "backend_lz4hc.h"
7c60a4ef5SSergey Senozhatsky 
8*1e673c8cSSergey Senozhatsky struct lz4hc_ctx {
9*1e673c8cSSergey Senozhatsky 	void *mem;
10*1e673c8cSSergey Senozhatsky 
11*1e673c8cSSergey Senozhatsky 	LZ4_streamDecode_t *dstrm;
12*1e673c8cSSergey Senozhatsky 	LZ4_streamHC_t *cstrm;
13*1e673c8cSSergey Senozhatsky };
14*1e673c8cSSergey Senozhatsky 
lz4hc_release_params(struct zcomp_params * params)15b8f03cb7SSergey Senozhatsky static void lz4hc_release_params(struct zcomp_params *params)
16b8f03cb7SSergey Senozhatsky {
17b8f03cb7SSergey Senozhatsky }
18b8f03cb7SSergey Senozhatsky 
lz4hc_setup_params(struct zcomp_params * params)19b8f03cb7SSergey Senozhatsky static int lz4hc_setup_params(struct zcomp_params *params)
20b8f03cb7SSergey Senozhatsky {
21b8f03cb7SSergey Senozhatsky 	if (params->level == ZCOMP_PARAM_NO_LEVEL)
22b8f03cb7SSergey Senozhatsky 		params->level = LZ4HC_DEFAULT_CLEVEL;
23b8f03cb7SSergey Senozhatsky 
24b8f03cb7SSergey Senozhatsky 	return 0;
25b8f03cb7SSergey Senozhatsky }
26c60a4ef5SSergey Senozhatsky 
lz4hc_destroy(struct zcomp_ctx * ctx)276a81bdfeSSergey Senozhatsky static void lz4hc_destroy(struct zcomp_ctx *ctx)
28c60a4ef5SSergey Senozhatsky {
29*1e673c8cSSergey Senozhatsky 	struct lz4hc_ctx *zctx = ctx->context;
30*1e673c8cSSergey Senozhatsky 
31*1e673c8cSSergey Senozhatsky 	if (!zctx)
32*1e673c8cSSergey Senozhatsky 		return;
33*1e673c8cSSergey Senozhatsky 
34*1e673c8cSSergey Senozhatsky 	kfree(zctx->dstrm);
35*1e673c8cSSergey Senozhatsky 	kfree(zctx->cstrm);
36*1e673c8cSSergey Senozhatsky 	vfree(zctx->mem);
37*1e673c8cSSergey Senozhatsky 	kfree(zctx);
38c60a4ef5SSergey Senozhatsky }
39c60a4ef5SSergey Senozhatsky 
lz4hc_create(struct zcomp_params * params,struct zcomp_ctx * ctx)406a81bdfeSSergey Senozhatsky static int lz4hc_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
41c60a4ef5SSergey Senozhatsky {
42*1e673c8cSSergey Senozhatsky 	struct lz4hc_ctx *zctx;
43*1e673c8cSSergey Senozhatsky 
44*1e673c8cSSergey Senozhatsky 	zctx = kzalloc(sizeof(*zctx), GFP_KERNEL);
45*1e673c8cSSergey Senozhatsky 	if (!zctx)
466a81bdfeSSergey Senozhatsky 		return -ENOMEM;
47c60a4ef5SSergey Senozhatsky 
48*1e673c8cSSergey Senozhatsky 	ctx->context = zctx;
49*1e673c8cSSergey Senozhatsky 	if (params->dict_sz == 0) {
50*1e673c8cSSergey Senozhatsky 		zctx->mem = vmalloc(LZ4HC_MEM_COMPRESS);
51*1e673c8cSSergey Senozhatsky 		if (!zctx->mem)
52*1e673c8cSSergey Senozhatsky 			goto error;
53*1e673c8cSSergey Senozhatsky 	} else {
54*1e673c8cSSergey Senozhatsky 		zctx->dstrm = kzalloc(sizeof(*zctx->dstrm), GFP_KERNEL);
55*1e673c8cSSergey Senozhatsky 		if (!zctx->dstrm)
56*1e673c8cSSergey Senozhatsky 			goto error;
57*1e673c8cSSergey Senozhatsky 
58*1e673c8cSSergey Senozhatsky 		zctx->cstrm = kzalloc(sizeof(*zctx->cstrm), GFP_KERNEL);
59*1e673c8cSSergey Senozhatsky 		if (!zctx->cstrm)
60*1e673c8cSSergey Senozhatsky 			goto error;
61*1e673c8cSSergey Senozhatsky 	}
62*1e673c8cSSergey Senozhatsky 
636a81bdfeSSergey Senozhatsky 	return 0;
64*1e673c8cSSergey Senozhatsky 
65*1e673c8cSSergey Senozhatsky error:
66*1e673c8cSSergey Senozhatsky 	lz4hc_destroy(ctx);
67*1e673c8cSSergey Senozhatsky 	return -EINVAL;
68c60a4ef5SSergey Senozhatsky }
69c60a4ef5SSergey Senozhatsky 
lz4hc_compress(struct zcomp_params * params,struct zcomp_ctx * ctx,struct zcomp_req * req)70b8f03cb7SSergey Senozhatsky static int lz4hc_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
71b8f03cb7SSergey Senozhatsky 			  struct zcomp_req *req)
72c60a4ef5SSergey Senozhatsky {
73*1e673c8cSSergey Senozhatsky 	struct lz4hc_ctx *zctx = ctx->context;
74c60a4ef5SSergey Senozhatsky 	int ret;
75c60a4ef5SSergey Senozhatsky 
76*1e673c8cSSergey Senozhatsky 	if (!zctx->cstrm) {
77*1e673c8cSSergey Senozhatsky 		ret = LZ4_compress_HC(req->src, req->dst, req->src_len,
78*1e673c8cSSergey Senozhatsky 				      req->dst_len, params->level,
79*1e673c8cSSergey Senozhatsky 				      zctx->mem);
80*1e673c8cSSergey Senozhatsky 	} else {
81*1e673c8cSSergey Senozhatsky 		/* Cstrm needs to be reset */
82*1e673c8cSSergey Senozhatsky 		LZ4_resetStreamHC(zctx->cstrm, params->level);
83*1e673c8cSSergey Senozhatsky 		ret = LZ4_loadDictHC(zctx->cstrm, params->dict,
84*1e673c8cSSergey Senozhatsky 				     params->dict_sz);
85*1e673c8cSSergey Senozhatsky 		if (ret != params->dict_sz)
86*1e673c8cSSergey Senozhatsky 			return -EINVAL;
87*1e673c8cSSergey Senozhatsky 		ret = LZ4_compress_HC_continue(zctx->cstrm, req->src, req->dst,
88*1e673c8cSSergey Senozhatsky 					       req->src_len, req->dst_len);
89*1e673c8cSSergey Senozhatsky 	}
90c60a4ef5SSergey Senozhatsky 	if (!ret)
91c60a4ef5SSergey Senozhatsky 		return -EINVAL;
9252c7b4e2SSergey Senozhatsky 	req->dst_len = ret;
93c60a4ef5SSergey Senozhatsky 	return 0;
94c60a4ef5SSergey Senozhatsky }
95c60a4ef5SSergey Senozhatsky 
lz4hc_decompress(struct zcomp_params * params,struct zcomp_ctx * ctx,struct zcomp_req * req)96b8f03cb7SSergey Senozhatsky static int lz4hc_decompress(struct zcomp_params *params, struct zcomp_ctx *ctx,
97b8f03cb7SSergey Senozhatsky 			    struct zcomp_req *req)
98c60a4ef5SSergey Senozhatsky {
99*1e673c8cSSergey Senozhatsky 	struct lz4hc_ctx *zctx = ctx->context;
100c60a4ef5SSergey Senozhatsky 	int ret;
101c60a4ef5SSergey Senozhatsky 
102*1e673c8cSSergey Senozhatsky 	if (!zctx->dstrm) {
10352c7b4e2SSergey Senozhatsky 		ret = LZ4_decompress_safe(req->src, req->dst, req->src_len,
10452c7b4e2SSergey Senozhatsky 					  req->dst_len);
105*1e673c8cSSergey Senozhatsky 	} else {
106*1e673c8cSSergey Senozhatsky 		/* Dstrm needs to be reset */
107*1e673c8cSSergey Senozhatsky 		ret = LZ4_setStreamDecode(zctx->dstrm, params->dict,
108*1e673c8cSSergey Senozhatsky 					  params->dict_sz);
109*1e673c8cSSergey Senozhatsky 		if (!ret)
110*1e673c8cSSergey Senozhatsky 			return -EINVAL;
111*1e673c8cSSergey Senozhatsky 		ret = LZ4_decompress_safe_continue(zctx->dstrm, req->src,
112*1e673c8cSSergey Senozhatsky 						   req->dst, req->src_len,
113*1e673c8cSSergey Senozhatsky 						   req->dst_len);
114*1e673c8cSSergey Senozhatsky 	}
115c60a4ef5SSergey Senozhatsky 	if (ret < 0)
116c60a4ef5SSergey Senozhatsky 		return -EINVAL;
117c60a4ef5SSergey Senozhatsky 	return 0;
118c60a4ef5SSergey Senozhatsky }
119c60a4ef5SSergey Senozhatsky 
120c60a4ef5SSergey Senozhatsky const struct zcomp_ops backend_lz4hc = {
121c60a4ef5SSergey Senozhatsky 	.compress	= lz4hc_compress,
122c60a4ef5SSergey Senozhatsky 	.decompress	= lz4hc_decompress,
123c60a4ef5SSergey Senozhatsky 	.create_ctx	= lz4hc_create,
124c60a4ef5SSergey Senozhatsky 	.destroy_ctx	= lz4hc_destroy,
125b8f03cb7SSergey Senozhatsky 	.setup_params	= lz4hc_setup_params,
126b8f03cb7SSergey Senozhatsky 	.release_params	= lz4hc_release_params,
127c60a4ef5SSergey Senozhatsky 	.name		= "lz4hc",
128c60a4ef5SSergey Senozhatsky };
129