1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 #define pr_fmt(fmt) "deflate: " fmt
4
5 #include <linux/kernel.h>
6 #include <linux/slab.h>
7 #include <linux/vmalloc.h>
8 #include <linux/zlib.h>
9
10 #include "backend_deflate.h"
11
12 /* Use the same value as crypto API */
13 #define DEFLATE_DEF_WINBITS (-11)
14 #define DEFLATE_DEF_MEMLEVEL MAX_MEM_LEVEL
15
16 struct deflate_ctx {
17 struct z_stream_s cctx;
18 struct z_stream_s dctx;
19 };
20
deflate_release_params(struct zcomp_params * params)21 static void deflate_release_params(struct zcomp_params *params)
22 {
23 }
24
deflate_setup_params(struct zcomp_params * params)25 static int deflate_setup_params(struct zcomp_params *params)
26 {
27 if (params->dict_sz) {
28 pr_err("dictionary is not supported\n");
29 return -EOPNOTSUPP;
30 }
31
32 if (params->level == ZCOMP_PARAM_NOT_SET) {
33 params->level = Z_DEFAULT_COMPRESSION;
34 } else if (params->level < Z_DEFAULT_COMPRESSION ||
35 params->level > Z_BEST_COMPRESSION) {
36 pr_err("invalid compression level %d\n", params->level);
37 return -EINVAL;
38 }
39
40 if (params->deflate.winbits == ZCOMP_PARAM_NOT_SET) {
41 params->deflate.winbits = DEFLATE_DEF_WINBITS;
42 } else {
43 s32 wb = params->deflate.winbits;
44
45 if ((wb < -15 || wb > -9) && (wb < 9 || wb > 15)) {
46 pr_err("invalid winbits %d\n", wb);
47 return -EINVAL;
48 }
49 }
50
51 return 0;
52 }
53
deflate_destroy(struct zcomp_ctx * ctx)54 static void deflate_destroy(struct zcomp_ctx *ctx)
55 {
56 struct deflate_ctx *zctx = ctx->context;
57
58 if (!zctx)
59 return;
60
61 if (zctx->cctx.workspace) {
62 zlib_deflateEnd(&zctx->cctx);
63 vfree(zctx->cctx.workspace);
64 }
65 if (zctx->dctx.workspace) {
66 zlib_inflateEnd(&zctx->dctx);
67 vfree(zctx->dctx.workspace);
68 }
69 kfree(zctx);
70 }
71
deflate_create(struct zcomp_params * params,struct zcomp_ctx * ctx)72 static int deflate_create(struct zcomp_params *params, struct zcomp_ctx *ctx)
73 {
74 struct deflate_ctx *zctx;
75 size_t sz;
76 int ret;
77
78 zctx = kzalloc_obj(*zctx);
79 if (!zctx)
80 return -ENOMEM;
81
82 ctx->context = zctx;
83 sz = zlib_deflate_workspacesize(params->deflate.winbits, MAX_MEM_LEVEL);
84 zctx->cctx.workspace = vzalloc(sz);
85 if (!zctx->cctx.workspace)
86 goto error;
87
88 ret = zlib_deflateInit2(&zctx->cctx, params->level, Z_DEFLATED,
89 params->deflate.winbits, DEFLATE_DEF_MEMLEVEL,
90 Z_DEFAULT_STRATEGY);
91 if (ret != Z_OK)
92 goto error;
93
94 sz = zlib_inflate_workspacesize();
95 zctx->dctx.workspace = vzalloc(sz);
96 if (!zctx->dctx.workspace)
97 goto error;
98
99 ret = zlib_inflateInit2(&zctx->dctx, params->deflate.winbits);
100 if (ret != Z_OK)
101 goto error;
102
103 return 0;
104
105 error:
106 deflate_destroy(ctx);
107 return -EINVAL;
108 }
109
deflate_compress(struct zcomp_params * params,struct zcomp_ctx * ctx,struct zcomp_req * req)110 static int deflate_compress(struct zcomp_params *params, struct zcomp_ctx *ctx,
111 struct zcomp_req *req)
112 {
113 struct deflate_ctx *zctx = ctx->context;
114 struct z_stream_s *deflate;
115 int ret;
116
117 deflate = &zctx->cctx;
118 ret = zlib_deflateReset(deflate);
119 if (ret != Z_OK)
120 return -EINVAL;
121
122 deflate->next_in = (u8 *)req->src;
123 deflate->avail_in = req->src_len;
124 deflate->next_out = (u8 *)req->dst;
125 deflate->avail_out = req->dst_len;
126
127 ret = zlib_deflate(deflate, Z_FINISH);
128 if (ret != Z_STREAM_END)
129 return -EINVAL;
130
131 req->dst_len = deflate->total_out;
132 return 0;
133 }
134
deflate_decompress(struct zcomp_params * params,struct zcomp_ctx * ctx,struct zcomp_req * req)135 static int deflate_decompress(struct zcomp_params *params,
136 struct zcomp_ctx *ctx,
137 struct zcomp_req *req)
138 {
139 struct deflate_ctx *zctx = ctx->context;
140 struct z_stream_s *inflate;
141 int ret;
142
143 inflate = &zctx->dctx;
144
145 ret = zlib_inflateReset(inflate);
146 if (ret != Z_OK)
147 return -EINVAL;
148
149 inflate->next_in = (u8 *)req->src;
150 inflate->avail_in = req->src_len;
151 inflate->next_out = (u8 *)req->dst;
152 inflate->avail_out = req->dst_len;
153
154 ret = zlib_inflate(inflate, Z_SYNC_FLUSH);
155 if (ret != Z_STREAM_END)
156 return -EINVAL;
157
158 return 0;
159 }
160
161 const struct zcomp_ops backend_deflate = {
162 .compress = deflate_compress,
163 .decompress = deflate_decompress,
164 .create_ctx = deflate_create,
165 .destroy_ctx = deflate_destroy,
166 .setup_params = deflate_setup_params,
167 .release_params = deflate_release_params,
168 .name = "deflate",
169 };
170