1 // SPDX-License-Identifier: GPL-2.0-or-later
3 #include <linux/kernel.h>
4 #include <linux/string.h>
6 #include <linux/slab.h>
7 #include <linux/wait.h>
8 #include <linux/sched.h>
10 #include <linux/crypto.h>
11 #include <linux/vmalloc.h>
15 #include "backend_lzo.h"
16 #include "backend_lzorle.h"
17 #include "backend_lz4.h"
18 #include "backend_lz4hc.h"
19 #include "backend_zstd.h"
20 #include "backend_deflate.h"
21 #include "backend_842.h"
23 static const struct zcomp_ops
*backends
[] = {
24 #if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZO)
28 #if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZ4)
31 #if IS_ENABLED(CONFIG_ZRAM_BACKEND_LZ4HC)
34 #if IS_ENABLED(CONFIG_ZRAM_BACKEND_ZSTD)
37 #if IS_ENABLED(CONFIG_ZRAM_BACKEND_DEFLATE)
40 #if IS_ENABLED(CONFIG_ZRAM_BACKEND_842)
46 static void zcomp_strm_free(struct zcomp
*comp
, struct zcomp_strm
*zstrm
)
48 comp
->ops
->destroy_ctx(&zstrm
->ctx
);
53 static int zcomp_strm_init(struct zcomp
*comp
, struct zcomp_strm
*zstrm
)
57 ret
= comp
->ops
->create_ctx(comp
->params
, &zstrm
->ctx
);
62 * allocate 2 pages. 1 for compressed data, plus 1 extra for the
63 * case when compressed size is larger than the original one
65 zstrm
->buffer
= vzalloc(2 * PAGE_SIZE
);
67 zcomp_strm_free(comp
, zstrm
);
73 static const struct zcomp_ops
*lookup_backend_ops(const char *comp
)
78 if (sysfs_streq(comp
, backends
[i
]->name
))
85 bool zcomp_available_algorithm(const char *comp
)
87 return lookup_backend_ops(comp
) != NULL
;
90 /* show available compressors */
91 ssize_t
zcomp_available_show(const char *comp
, char *buf
)
96 for (i
= 0; i
< ARRAY_SIZE(backends
) - 1; i
++) {
97 if (!strcmp(comp
, backends
[i
]->name
)) {
98 sz
+= scnprintf(buf
+ sz
, PAGE_SIZE
- sz
- 2,
99 "[%s] ", backends
[i
]->name
);
101 sz
+= scnprintf(buf
+ sz
, PAGE_SIZE
- sz
- 2,
102 "%s ", backends
[i
]->name
);
106 sz
+= scnprintf(buf
+ sz
, PAGE_SIZE
- sz
, "\n");
110 struct zcomp_strm
*zcomp_stream_get(struct zcomp
*comp
)
112 local_lock(&comp
->stream
->lock
);
113 return this_cpu_ptr(comp
->stream
);
116 void zcomp_stream_put(struct zcomp
*comp
)
118 local_unlock(&comp
->stream
->lock
);
121 int zcomp_compress(struct zcomp
*comp
, struct zcomp_strm
*zstrm
,
122 const void *src
, unsigned int *dst_len
)
124 struct zcomp_req req
= {
126 .dst
= zstrm
->buffer
,
127 .src_len
= PAGE_SIZE
,
128 .dst_len
= 2 * PAGE_SIZE
,
132 ret
= comp
->ops
->compress(comp
->params
, &zstrm
->ctx
, &req
);
134 *dst_len
= req
.dst_len
;
138 int zcomp_decompress(struct zcomp
*comp
, struct zcomp_strm
*zstrm
,
139 const void *src
, unsigned int src_len
, void *dst
)
141 struct zcomp_req req
= {
145 .dst_len
= PAGE_SIZE
,
148 return comp
->ops
->decompress(comp
->params
, &zstrm
->ctx
, &req
);
151 int zcomp_cpu_up_prepare(unsigned int cpu
, struct hlist_node
*node
)
153 struct zcomp
*comp
= hlist_entry(node
, struct zcomp
, node
);
154 struct zcomp_strm
*zstrm
;
157 zstrm
= per_cpu_ptr(comp
->stream
, cpu
);
158 local_lock_init(&zstrm
->lock
);
160 ret
= zcomp_strm_init(comp
, zstrm
);
162 pr_err("Can't allocate a compression stream\n");
166 int zcomp_cpu_dead(unsigned int cpu
, struct hlist_node
*node
)
168 struct zcomp
*comp
= hlist_entry(node
, struct zcomp
, node
);
169 struct zcomp_strm
*zstrm
;
171 zstrm
= per_cpu_ptr(comp
->stream
, cpu
);
172 zcomp_strm_free(comp
, zstrm
);
176 static int zcomp_init(struct zcomp
*comp
, struct zcomp_params
*params
)
180 comp
->stream
= alloc_percpu(struct zcomp_strm
);
184 comp
->params
= params
;
185 ret
= comp
->ops
->setup_params(comp
->params
);
189 ret
= cpuhp_state_add_instance(CPUHP_ZCOMP_PREPARE
, &comp
->node
);
196 comp
->ops
->release_params(comp
->params
);
197 free_percpu(comp
->stream
);
201 void zcomp_destroy(struct zcomp
*comp
)
203 cpuhp_state_remove_instance(CPUHP_ZCOMP_PREPARE
, &comp
->node
);
204 comp
->ops
->release_params(comp
->params
);
205 free_percpu(comp
->stream
);
209 struct zcomp
*zcomp_create(const char *alg
, struct zcomp_params
*params
)
215 * The backends array has a sentinel NULL value, so the minimum
216 * size is 1. In order to be valid the array, apart from the
217 * sentinel NULL element, should have at least one compression
220 BUILD_BUG_ON(ARRAY_SIZE(backends
) <= 1);
222 comp
= kzalloc(sizeof(struct zcomp
), GFP_KERNEL
);
224 return ERR_PTR(-ENOMEM
);
226 comp
->ops
= lookup_backend_ops(alg
);
229 return ERR_PTR(-EINVAL
);
232 error
= zcomp_init(comp
, params
);
235 return ERR_PTR(error
);