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/slab.h>
13 #include <linux/wait.h>
14 #include <linux/sched.h>
17 #include "zcomp_lzo.h"
18 #ifdef CONFIG_ZRAM_LZ4_COMPRESS
19 #include "zcomp_lz4.h"
23 * single zcomp_strm backend
25 struct zcomp_strm_single
{
26 struct mutex strm_lock
;
27 struct zcomp_strm
*zstrm
;
31 * multi zcomp_strm backend
33 struct zcomp_strm_multi
{
34 /* protect strm list */
36 /* max possible number of zstrm streams */
38 /* number of available zstrm streams */
40 /* list of available strms */
41 struct list_head idle_strm
;
42 wait_queue_head_t strm_wait
;
45 static struct zcomp_backend
*backends
[] = {
47 #ifdef CONFIG_ZRAM_LZ4_COMPRESS
53 static struct zcomp_backend
*find_backend(const char *compress
)
57 if (sysfs_streq(compress
, backends
[i
]->name
))
64 static void zcomp_strm_free(struct zcomp
*comp
, struct zcomp_strm
*zstrm
)
67 comp
->backend
->destroy(zstrm
->private);
68 free_pages((unsigned long)zstrm
->buffer
, 1);
73 * allocate new zcomp_strm structure with ->private initialized by
74 * backend, return NULL on error
76 static struct zcomp_strm
*zcomp_strm_alloc(struct zcomp
*comp
)
78 struct zcomp_strm
*zstrm
= kmalloc(sizeof(*zstrm
), GFP_KERNEL
);
82 zstrm
->private = comp
->backend
->create();
84 * allocate 2 pages. 1 for compressed data, plus 1 extra for the
85 * case when compressed size is larger than the original one
87 zstrm
->buffer
= (void *)__get_free_pages(GFP_KERNEL
| __GFP_ZERO
, 1);
88 if (!zstrm
->private || !zstrm
->buffer
) {
89 zcomp_strm_free(comp
, zstrm
);
96 * get idle zcomp_strm or wait until other process release
97 * (zcomp_strm_release()) one for us
99 static struct zcomp_strm
*zcomp_strm_multi_find(struct zcomp
*comp
)
101 struct zcomp_strm_multi
*zs
= comp
->stream
;
102 struct zcomp_strm
*zstrm
;
105 spin_lock(&zs
->strm_lock
);
106 if (!list_empty(&zs
->idle_strm
)) {
107 zstrm
= list_entry(zs
->idle_strm
.next
,
108 struct zcomp_strm
, list
);
109 list_del(&zstrm
->list
);
110 spin_unlock(&zs
->strm_lock
);
113 /* zstrm streams limit reached, wait for idle stream */
114 if (zs
->avail_strm
>= zs
->max_strm
) {
115 spin_unlock(&zs
->strm_lock
);
116 wait_event(zs
->strm_wait
, !list_empty(&zs
->idle_strm
));
119 /* allocate new zstrm stream */
121 spin_unlock(&zs
->strm_lock
);
123 zstrm
= zcomp_strm_alloc(comp
);
125 spin_lock(&zs
->strm_lock
);
127 spin_unlock(&zs
->strm_lock
);
128 wait_event(zs
->strm_wait
, !list_empty(&zs
->idle_strm
));
136 /* add stream back to idle list and wake up waiter or free the stream */
137 static void zcomp_strm_multi_release(struct zcomp
*comp
, struct zcomp_strm
*zstrm
)
139 struct zcomp_strm_multi
*zs
= comp
->stream
;
141 spin_lock(&zs
->strm_lock
);
142 if (zs
->avail_strm
<= zs
->max_strm
) {
143 list_add(&zstrm
->list
, &zs
->idle_strm
);
144 spin_unlock(&zs
->strm_lock
);
145 wake_up(&zs
->strm_wait
);
150 spin_unlock(&zs
->strm_lock
);
151 zcomp_strm_free(comp
, zstrm
);
154 /* change max_strm limit */
155 static int zcomp_strm_multi_set_max_streams(struct zcomp
*comp
, int num_strm
)
157 struct zcomp_strm_multi
*zs
= comp
->stream
;
158 struct zcomp_strm
*zstrm
;
160 spin_lock(&zs
->strm_lock
);
161 zs
->max_strm
= num_strm
;
163 * if user has lowered the limit and there are idle streams,
164 * immediately free as much streams (and memory) as we can.
166 while (zs
->avail_strm
> num_strm
&& !list_empty(&zs
->idle_strm
)) {
167 zstrm
= list_entry(zs
->idle_strm
.next
,
168 struct zcomp_strm
, list
);
169 list_del(&zstrm
->list
);
170 zcomp_strm_free(comp
, zstrm
);
173 spin_unlock(&zs
->strm_lock
);
177 static void zcomp_strm_multi_destroy(struct zcomp
*comp
)
179 struct zcomp_strm_multi
*zs
= comp
->stream
;
180 struct zcomp_strm
*zstrm
;
182 while (!list_empty(&zs
->idle_strm
)) {
183 zstrm
= list_entry(zs
->idle_strm
.next
,
184 struct zcomp_strm
, list
);
185 list_del(&zstrm
->list
);
186 zcomp_strm_free(comp
, zstrm
);
191 static int zcomp_strm_multi_create(struct zcomp
*comp
, int max_strm
)
193 struct zcomp_strm
*zstrm
;
194 struct zcomp_strm_multi
*zs
;
196 comp
->destroy
= zcomp_strm_multi_destroy
;
197 comp
->strm_find
= zcomp_strm_multi_find
;
198 comp
->strm_release
= zcomp_strm_multi_release
;
199 comp
->set_max_streams
= zcomp_strm_multi_set_max_streams
;
200 zs
= kmalloc(sizeof(struct zcomp_strm_multi
), GFP_KERNEL
);
205 spin_lock_init(&zs
->strm_lock
);
206 INIT_LIST_HEAD(&zs
->idle_strm
);
207 init_waitqueue_head(&zs
->strm_wait
);
208 zs
->max_strm
= max_strm
;
211 zstrm
= zcomp_strm_alloc(comp
);
216 list_add(&zstrm
->list
, &zs
->idle_strm
);
220 static struct zcomp_strm
*zcomp_strm_single_find(struct zcomp
*comp
)
222 struct zcomp_strm_single
*zs
= comp
->stream
;
223 mutex_lock(&zs
->strm_lock
);
227 static void zcomp_strm_single_release(struct zcomp
*comp
,
228 struct zcomp_strm
*zstrm
)
230 struct zcomp_strm_single
*zs
= comp
->stream
;
231 mutex_unlock(&zs
->strm_lock
);
234 static int zcomp_strm_single_set_max_streams(struct zcomp
*comp
, int num_strm
)
236 /* zcomp_strm_single support only max_comp_streams == 1 */
240 static void zcomp_strm_single_destroy(struct zcomp
*comp
)
242 struct zcomp_strm_single
*zs
= comp
->stream
;
243 zcomp_strm_free(comp
, zs
->zstrm
);
247 static int zcomp_strm_single_create(struct zcomp
*comp
)
249 struct zcomp_strm_single
*zs
;
251 comp
->destroy
= zcomp_strm_single_destroy
;
252 comp
->strm_find
= zcomp_strm_single_find
;
253 comp
->strm_release
= zcomp_strm_single_release
;
254 comp
->set_max_streams
= zcomp_strm_single_set_max_streams
;
255 zs
= kmalloc(sizeof(struct zcomp_strm_single
), GFP_KERNEL
);
260 mutex_init(&zs
->strm_lock
);
261 zs
->zstrm
= zcomp_strm_alloc(comp
);
269 /* show available compressors */
270 ssize_t
zcomp_available_show(const char *comp
, char *buf
)
275 while (backends
[i
]) {
276 if (sysfs_streq(comp
, backends
[i
]->name
))
277 sz
+= sprintf(buf
+ sz
, "[%s] ", backends
[i
]->name
);
279 sz
+= sprintf(buf
+ sz
, "%s ", backends
[i
]->name
);
282 sz
+= sprintf(buf
+ sz
, "\n");
286 int zcomp_set_max_streams(struct zcomp
*comp
, int num_strm
)
288 return comp
->set_max_streams(comp
, num_strm
);
291 struct zcomp_strm
*zcomp_strm_find(struct zcomp
*comp
)
293 return comp
->strm_find(comp
);
296 void zcomp_strm_release(struct zcomp
*comp
, struct zcomp_strm
*zstrm
)
298 comp
->strm_release(comp
, zstrm
);
301 int zcomp_compress(struct zcomp
*comp
, struct zcomp_strm
*zstrm
,
302 const unsigned char *src
, size_t *dst_len
)
304 return comp
->backend
->compress(src
, zstrm
->buffer
, dst_len
,
308 int zcomp_decompress(struct zcomp
*comp
, const unsigned char *src
,
309 size_t src_len
, unsigned char *dst
)
311 return comp
->backend
->decompress(src
, src_len
, dst
);
314 void zcomp_destroy(struct zcomp
*comp
)
321 * search available compressors for requested algorithm.
322 * allocate new zcomp and initialize it. return NULL
323 * if requested algorithm is not supported or in case
326 struct zcomp
*zcomp_create(const char *compress
, int max_strm
)
329 struct zcomp_backend
*backend
;
331 backend
= find_backend(compress
);
335 comp
= kzalloc(sizeof(struct zcomp
), GFP_KERNEL
);
339 comp
->backend
= backend
;
341 zcomp_strm_multi_create(comp
, max_strm
);
343 zcomp_strm_single_create(comp
);