2 * Copyright (C) 2014 Sergey Senozhatsky.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
10 #include <linux/kernel.h>
11 #include <linux/string.h>
12 #include <linux/err.h>
13 #include <linux/slab.h>
14 #include <linux/wait.h>
15 #include <linux/sched.h>
18 #include "zcomp_lzo.h"
19 #ifdef CONFIG_ZRAM_LZ4_COMPRESS
20 #include "zcomp_lz4.h"
24 * single zcomp_strm backend
26 struct zcomp_strm_single
{
27 struct mutex strm_lock
;
28 struct zcomp_strm
*zstrm
;
32 * multi zcomp_strm backend
34 struct zcomp_strm_multi
{
35 /* protect strm list */
37 /* max possible number of zstrm streams */
39 /* number of available zstrm streams */
41 /* list of available strms */
42 struct list_head idle_strm
;
43 wait_queue_head_t strm_wait
;
46 static struct zcomp_backend
*backends
[] = {
48 #ifdef CONFIG_ZRAM_LZ4_COMPRESS
54 static struct zcomp_backend
*find_backend(const char *compress
)
58 if (sysfs_streq(compress
, backends
[i
]->name
))
65 static void zcomp_strm_free(struct zcomp
*comp
, struct zcomp_strm
*zstrm
)
68 comp
->backend
->destroy(zstrm
->private);
69 free_pages((unsigned long)zstrm
->buffer
, 1);
74 * allocate new zcomp_strm structure with ->private initialized by
75 * backend, return NULL on error
77 static struct zcomp_strm
*zcomp_strm_alloc(struct zcomp
*comp
, gfp_t flags
)
79 struct zcomp_strm
*zstrm
= kmalloc(sizeof(*zstrm
), flags
);
83 zstrm
->private = comp
->backend
->create(flags
);
85 * allocate 2 pages. 1 for compressed data, plus 1 extra for the
86 * case when compressed size is larger than the original one
88 zstrm
->buffer
= (void *)__get_free_pages(flags
| __GFP_ZERO
, 1);
89 if (!zstrm
->private || !zstrm
->buffer
) {
90 zcomp_strm_free(comp
, zstrm
);
97 * get idle zcomp_strm or wait until other process release
98 * (zcomp_strm_release()) one for us
100 static struct zcomp_strm
*zcomp_strm_multi_find(struct zcomp
*comp
)
102 struct zcomp_strm_multi
*zs
= comp
->stream
;
103 struct zcomp_strm
*zstrm
;
106 spin_lock(&zs
->strm_lock
);
107 if (!list_empty(&zs
->idle_strm
)) {
108 zstrm
= list_entry(zs
->idle_strm
.next
,
109 struct zcomp_strm
, list
);
110 list_del(&zstrm
->list
);
111 spin_unlock(&zs
->strm_lock
);
114 /* zstrm streams limit reached, wait for idle stream */
115 if (zs
->avail_strm
>= zs
->max_strm
) {
116 spin_unlock(&zs
->strm_lock
);
117 wait_event(zs
->strm_wait
, !list_empty(&zs
->idle_strm
));
120 /* allocate new zstrm stream */
122 spin_unlock(&zs
->strm_lock
);
124 * This function can be called in swapout/fs write path
125 * so we can't use GFP_FS|IO. And it assumes we already
126 * have at least one stream in zram initialization so we
127 * don't do best effort to allocate more stream in here.
128 * A default stream will work well without further multiple
129 * streams. That's why we use NORETRY | NOWARN.
131 zstrm
= zcomp_strm_alloc(comp
, GFP_NOIO
| __GFP_NORETRY
|
134 spin_lock(&zs
->strm_lock
);
136 spin_unlock(&zs
->strm_lock
);
137 wait_event(zs
->strm_wait
, !list_empty(&zs
->idle_strm
));
145 /* add stream back to idle list and wake up waiter or free the stream */
146 static void zcomp_strm_multi_release(struct zcomp
*comp
, struct zcomp_strm
*zstrm
)
148 struct zcomp_strm_multi
*zs
= comp
->stream
;
150 spin_lock(&zs
->strm_lock
);
151 if (zs
->avail_strm
<= zs
->max_strm
) {
152 list_add(&zstrm
->list
, &zs
->idle_strm
);
153 spin_unlock(&zs
->strm_lock
);
154 wake_up(&zs
->strm_wait
);
159 spin_unlock(&zs
->strm_lock
);
160 zcomp_strm_free(comp
, zstrm
);
163 /* change max_strm limit */
164 static bool zcomp_strm_multi_set_max_streams(struct zcomp
*comp
, int num_strm
)
166 struct zcomp_strm_multi
*zs
= comp
->stream
;
167 struct zcomp_strm
*zstrm
;
169 spin_lock(&zs
->strm_lock
);
170 zs
->max_strm
= num_strm
;
172 * if user has lowered the limit and there are idle streams,
173 * immediately free as much streams (and memory) as we can.
175 while (zs
->avail_strm
> num_strm
&& !list_empty(&zs
->idle_strm
)) {
176 zstrm
= list_entry(zs
->idle_strm
.next
,
177 struct zcomp_strm
, list
);
178 list_del(&zstrm
->list
);
179 zcomp_strm_free(comp
, zstrm
);
182 spin_unlock(&zs
->strm_lock
);
186 static void zcomp_strm_multi_destroy(struct zcomp
*comp
)
188 struct zcomp_strm_multi
*zs
= comp
->stream
;
189 struct zcomp_strm
*zstrm
;
191 while (!list_empty(&zs
->idle_strm
)) {
192 zstrm
= list_entry(zs
->idle_strm
.next
,
193 struct zcomp_strm
, list
);
194 list_del(&zstrm
->list
);
195 zcomp_strm_free(comp
, zstrm
);
200 static int zcomp_strm_multi_create(struct zcomp
*comp
, int max_strm
)
202 struct zcomp_strm
*zstrm
;
203 struct zcomp_strm_multi
*zs
;
205 comp
->destroy
= zcomp_strm_multi_destroy
;
206 comp
->strm_find
= zcomp_strm_multi_find
;
207 comp
->strm_release
= zcomp_strm_multi_release
;
208 comp
->set_max_streams
= zcomp_strm_multi_set_max_streams
;
209 zs
= kmalloc(sizeof(struct zcomp_strm_multi
), GFP_KERNEL
);
214 spin_lock_init(&zs
->strm_lock
);
215 INIT_LIST_HEAD(&zs
->idle_strm
);
216 init_waitqueue_head(&zs
->strm_wait
);
217 zs
->max_strm
= max_strm
;
220 zstrm
= zcomp_strm_alloc(comp
, GFP_KERNEL
);
225 list_add(&zstrm
->list
, &zs
->idle_strm
);
229 static struct zcomp_strm
*zcomp_strm_single_find(struct zcomp
*comp
)
231 struct zcomp_strm_single
*zs
= comp
->stream
;
232 mutex_lock(&zs
->strm_lock
);
236 static void zcomp_strm_single_release(struct zcomp
*comp
,
237 struct zcomp_strm
*zstrm
)
239 struct zcomp_strm_single
*zs
= comp
->stream
;
240 mutex_unlock(&zs
->strm_lock
);
243 static bool zcomp_strm_single_set_max_streams(struct zcomp
*comp
, int num_strm
)
245 /* zcomp_strm_single support only max_comp_streams == 1 */
249 static void zcomp_strm_single_destroy(struct zcomp
*comp
)
251 struct zcomp_strm_single
*zs
= comp
->stream
;
252 zcomp_strm_free(comp
, zs
->zstrm
);
256 static int zcomp_strm_single_create(struct zcomp
*comp
)
258 struct zcomp_strm_single
*zs
;
260 comp
->destroy
= zcomp_strm_single_destroy
;
261 comp
->strm_find
= zcomp_strm_single_find
;
262 comp
->strm_release
= zcomp_strm_single_release
;
263 comp
->set_max_streams
= zcomp_strm_single_set_max_streams
;
264 zs
= kmalloc(sizeof(struct zcomp_strm_single
), GFP_KERNEL
);
269 mutex_init(&zs
->strm_lock
);
270 zs
->zstrm
= zcomp_strm_alloc(comp
, GFP_KERNEL
);
278 /* show available compressors */
279 ssize_t
zcomp_available_show(const char *comp
, char *buf
)
284 while (backends
[i
]) {
285 if (!strcmp(comp
, backends
[i
]->name
))
286 sz
+= scnprintf(buf
+ sz
, PAGE_SIZE
- sz
- 2,
287 "[%s] ", backends
[i
]->name
);
289 sz
+= scnprintf(buf
+ sz
, PAGE_SIZE
- sz
- 2,
290 "%s ", backends
[i
]->name
);
293 sz
+= scnprintf(buf
+ sz
, PAGE_SIZE
- sz
, "\n");
297 bool zcomp_available_algorithm(const char *comp
)
299 return find_backend(comp
) != NULL
;
302 bool zcomp_set_max_streams(struct zcomp
*comp
, int num_strm
)
304 return comp
->set_max_streams(comp
, num_strm
);
307 struct zcomp_strm
*zcomp_strm_find(struct zcomp
*comp
)
309 return comp
->strm_find(comp
);
312 void zcomp_strm_release(struct zcomp
*comp
, struct zcomp_strm
*zstrm
)
314 comp
->strm_release(comp
, zstrm
);
317 int zcomp_compress(struct zcomp
*comp
, struct zcomp_strm
*zstrm
,
318 const unsigned char *src
, size_t *dst_len
)
320 return comp
->backend
->compress(src
, zstrm
->buffer
, dst_len
,
324 int zcomp_decompress(struct zcomp
*comp
, const unsigned char *src
,
325 size_t src_len
, unsigned char *dst
)
327 return comp
->backend
->decompress(src
, src_len
, dst
);
330 void zcomp_destroy(struct zcomp
*comp
)
337 * search available compressors for requested algorithm.
338 * allocate new zcomp and initialize it. return compressing
339 * backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL)
340 * if requested algorithm is not supported, ERR_PTR(-ENOMEM) in
341 * case of allocation error, or any other error potentially
342 * returned by functions zcomp_strm_{multi,single}_create.
344 struct zcomp
*zcomp_create(const char *compress
, int max_strm
)
347 struct zcomp_backend
*backend
;
350 backend
= find_backend(compress
);
352 return ERR_PTR(-EINVAL
);
354 comp
= kzalloc(sizeof(struct zcomp
), GFP_KERNEL
);
356 return ERR_PTR(-ENOMEM
);
358 comp
->backend
= backend
;
360 error
= zcomp_strm_multi_create(comp
, max_strm
);
362 error
= zcomp_strm_single_create(comp
);
365 return ERR_PTR(error
);