Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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 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
26static 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
52static 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
65static 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
90error:
91 lz4_destroy(ctx);
92 return -ENOMEM;
93}
94
95static 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
118static 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
142const 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};