xref: /linux/drivers/block/zram/backend_deflate.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
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 
21 static void deflate_release_params(struct zcomp_params *params)
22 {
23 }
24 
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 
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 
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 
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 
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