9ab45d41624b0a9b4556dc457202e33fa17745f5
[cascardo/linux.git] / drivers / block / zram / zcomp.c
1 /*
2  * Copyright (C) 2014 Sergey Senozhatsky.
3  *
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.
8  */
9
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>
16 #include <linux/cpu.h>
17 #include <linux/crypto.h>
18
19 #include "zcomp.h"
20
21 static const char * const backends[] = {
22         "lzo",
23 #if IS_ENABLED(CONFIG_CRYPTO_LZ4)
24         "lz4",
25 #endif
26         NULL
27 };
28
29 static void zcomp_strm_free(struct zcomp_strm *zstrm)
30 {
31         if (!IS_ERR_OR_NULL(zstrm->tfm))
32                 crypto_free_comp(zstrm->tfm);
33         free_pages((unsigned long)zstrm->buffer, 1);
34         kfree(zstrm);
35 }
36
37 /*
38  * allocate new zcomp_strm structure with ->tfm initialized by
39  * backend, return NULL on error
40  */
41 static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp, gfp_t flags)
42 {
43         struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), flags);
44         if (!zstrm)
45                 return NULL;
46
47         zstrm->tfm = crypto_alloc_comp(comp->name, 0, 0);
48         /*
49          * allocate 2 pages. 1 for compressed data, plus 1 extra for the
50          * case when compressed size is larger than the original one
51          */
52         zstrm->buffer = (void *)__get_free_pages(flags | __GFP_ZERO, 1);
53         if (IS_ERR_OR_NULL(zstrm->tfm) || !zstrm->buffer) {
54                 zcomp_strm_free(zstrm);
55                 zstrm = NULL;
56         }
57         return zstrm;
58 }
59
60 bool zcomp_available_algorithm(const char *comp)
61 {
62         int i = 0;
63
64         while (backends[i]) {
65                 if (sysfs_streq(comp, backends[i]))
66                         return true;
67                 i++;
68         }
69
70         /*
71          * Crypto does not ignore a trailing new line symbol,
72          * so make sure you don't supply a string containing
73          * one.
74          * This also means that we permit zcomp initialisation
75          * with any compressing algorithm known to crypto api.
76          */
77         return crypto_has_comp(comp, 0, 0) == 1;
78 }
79
80 /* show available compressors */
81 ssize_t zcomp_available_show(const char *comp, char *buf)
82 {
83         bool known_algorithm = false;
84         ssize_t sz = 0;
85         int i = 0;
86
87         for (; backends[i]; i++) {
88                 if (!strcmp(comp, backends[i])) {
89                         known_algorithm = true;
90                         sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
91                                         "[%s] ", backends[i]);
92                 } else {
93                         sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
94                                         "%s ", backends[i]);
95                 }
96         }
97
98         /*
99          * Out-of-tree module known to crypto api or a missing
100          * entry in `backends'.
101          */
102         if (!known_algorithm && crypto_has_comp(comp, 0, 0) == 1)
103                 sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
104                                 "[%s] ", comp);
105
106         sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
107         return sz;
108 }
109
110 struct zcomp_strm *zcomp_stream_get(struct zcomp *comp)
111 {
112         return *get_cpu_ptr(comp->stream);
113 }
114
115 void zcomp_stream_put(struct zcomp *comp)
116 {
117         put_cpu_ptr(comp->stream);
118 }
119
120 int zcomp_compress(struct zcomp_strm *zstrm,
121                 const void *src, unsigned int *dst_len)
122 {
123         /*
124          * Our dst memory (zstrm->buffer) is always `2 * PAGE_SIZE' sized
125          * because sometimes we can endup having a bigger compressed data
126          * due to various reasons: for example compression algorithms tend
127          * to add some padding to the compressed buffer. Speaking of padding,
128          * comp algorithm `842' pads the compressed length to multiple of 8
129          * and returns -ENOSP when the dst memory is not big enough, which
130          * is not something that ZRAM wants to see. We can handle the
131          * `compressed_size > PAGE_SIZE' case easily in ZRAM, but when we
132          * receive -ERRNO from the compressing backend we can't help it
133          * anymore. To make `842' happy we need to tell the exact size of
134          * the dst buffer, zram_drv will take care of the fact that
135          * compressed buffer is too big.
136          */
137         *dst_len = PAGE_SIZE * 2;
138
139         return crypto_comp_compress(zstrm->tfm,
140                         src, PAGE_SIZE,
141                         zstrm->buffer, dst_len);
142 }
143
144 int zcomp_decompress(struct zcomp_strm *zstrm,
145                 const void *src, unsigned int src_len, void *dst)
146 {
147         unsigned int dst_len = PAGE_SIZE;
148
149         return crypto_comp_decompress(zstrm->tfm,
150                         src, src_len,
151                         dst, &dst_len);
152 }
153
154 static int __zcomp_cpu_notifier(struct zcomp *comp,
155                 unsigned long action, unsigned long cpu)
156 {
157         struct zcomp_strm *zstrm;
158
159         switch (action) {
160         case CPU_UP_PREPARE:
161                 if (WARN_ON(*per_cpu_ptr(comp->stream, cpu)))
162                         break;
163                 zstrm = zcomp_strm_alloc(comp, GFP_KERNEL);
164                 if (IS_ERR_OR_NULL(zstrm)) {
165                         pr_err("Can't allocate a compression stream\n");
166                         return NOTIFY_BAD;
167                 }
168                 *per_cpu_ptr(comp->stream, cpu) = zstrm;
169                 break;
170         case CPU_DEAD:
171         case CPU_UP_CANCELED:
172                 zstrm = *per_cpu_ptr(comp->stream, cpu);
173                 if (!IS_ERR_OR_NULL(zstrm))
174                         zcomp_strm_free(zstrm);
175                 *per_cpu_ptr(comp->stream, cpu) = NULL;
176                 break;
177         default:
178                 break;
179         }
180         return NOTIFY_OK;
181 }
182
183 static int zcomp_cpu_notifier(struct notifier_block *nb,
184                 unsigned long action, void *pcpu)
185 {
186         unsigned long cpu = (unsigned long)pcpu;
187         struct zcomp *comp = container_of(nb, typeof(*comp), notifier);
188
189         return __zcomp_cpu_notifier(comp, action, cpu);
190 }
191
192 static int zcomp_init(struct zcomp *comp)
193 {
194         unsigned long cpu;
195         int ret;
196
197         comp->notifier.notifier_call = zcomp_cpu_notifier;
198
199         comp->stream = alloc_percpu(struct zcomp_strm *);
200         if (!comp->stream)
201                 return -ENOMEM;
202
203         cpu_notifier_register_begin();
204         for_each_online_cpu(cpu) {
205                 ret = __zcomp_cpu_notifier(comp, CPU_UP_PREPARE, cpu);
206                 if (ret == NOTIFY_BAD)
207                         goto cleanup;
208         }
209         __register_cpu_notifier(&comp->notifier);
210         cpu_notifier_register_done();
211         return 0;
212
213 cleanup:
214         for_each_online_cpu(cpu)
215                 __zcomp_cpu_notifier(comp, CPU_UP_CANCELED, cpu);
216         cpu_notifier_register_done();
217         return -ENOMEM;
218 }
219
220 void zcomp_destroy(struct zcomp *comp)
221 {
222         unsigned long cpu;
223
224         cpu_notifier_register_begin();
225         for_each_online_cpu(cpu)
226                 __zcomp_cpu_notifier(comp, CPU_UP_CANCELED, cpu);
227         __unregister_cpu_notifier(&comp->notifier);
228         cpu_notifier_register_done();
229
230         free_percpu(comp->stream);
231         kfree(comp);
232 }
233
234 /*
235  * search available compressors for requested algorithm.
236  * allocate new zcomp and initialize it. return compressing
237  * backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL)
238  * if requested algorithm is not supported, ERR_PTR(-ENOMEM) in
239  * case of allocation error, or any other error potentially
240  * returned by zcomp_init().
241  */
242 struct zcomp *zcomp_create(const char *compress)
243 {
244         struct zcomp *comp;
245         int error;
246
247         if (!zcomp_available_algorithm(compress))
248                 return ERR_PTR(-EINVAL);
249
250         comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
251         if (!comp)
252                 return ERR_PTR(-ENOMEM);
253
254         comp->name = compress;
255         error = zcomp_init(comp);
256         if (error) {
257                 kfree(comp);
258                 return ERR_PTR(error);
259         }
260         return comp;
261 }