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
8struct lz4_ctx {
9 void *mem;
10
11 LZ4_streamDecode_t *dstrm;
12 LZ4_stream_t *cstrm;
13};
14
15static void lz4_release_params(struct zcomp_params *params)
16{
17}
18
19static int lz4_setup_params(struct zcomp_params *params)
20{
21 if (params->level == ZCOMP_PARAM_NOT_SET)
22 params->level = LZ4_ACCELERATION_DEFAULT;
23
24 return 0;
25}
26
27static void lz4_destroy(struct zcomp_ctx *ctx)
28{
29 struct lz4_ctx *zctx = ctx->context;
30
31 if (!zctx)
32 return;
33
34 vfree(addr: zctx->mem);
35 kfree(objp: zctx->dstrm);
36 kfree(objp: zctx->cstrm);
37 kfree(objp: zctx);
38}
39
40static 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
65error:
66 lz4_destroy(ctx);
67 return -ENOMEM;
68}
69
70static 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(source: req->src, dest: req->dst, inputSize: req->src_len,
78 maxOutputSize: req->dst_len, acceleration: params->level,
79 wrkmem: zctx->mem);
80 } else {
81 /* Cstrm needs to be reset */
82 ret = LZ4_loadDict(streamPtr: zctx->cstrm, dictionary: params->dict, dictSize: params->dict_sz);
83 if (ret != params->dict_sz)
84 return -EINVAL;
85 ret = LZ4_compress_fast_continue(streamPtr: zctx->cstrm, src: req->src,
86 dst: req->dst, srcSize: req->src_len,
87 maxDstSize: req->dst_len, acceleration: params->level);
88 }
89 if (!ret)
90 return -EINVAL;
91 req->dst_len = ret;
92 return 0;
93}
94
95static 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(source: req->src, dest: req->dst, compressedSize: req->src_len,
103 maxDecompressedSize: req->dst_len);
104 } else {
105 /* Dstrm needs to be reset */
106 ret = LZ4_setStreamDecode(LZ4_streamDecode: zctx->dstrm, dictionary: params->dict,
107 dictSize: params->dict_sz);
108 if (!ret)
109 return -EINVAL;
110 ret = LZ4_decompress_safe_continue(LZ4_streamDecode: zctx->dstrm, source: req->src,
111 dest: req->dst, compressedSize: req->src_len,
112 maxDecompressedSize: req->dst_len);
113 }
114 if (ret < 0)
115 return -EINVAL;
116 return 0;
117}
118
119const 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

source code of linux/drivers/block/zram/backend_lz4.c