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