zcomp.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  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. #include <linux/kernel.h>
  10. #include <linux/string.h>
  11. #include <linux/err.h>
  12. #include <linux/slab.h>
  13. #include <linux/wait.h>
  14. #include <linux/sched.h>
  15. #include "zcomp.h"
  16. #include "zcomp_lzo.h"
  17. #ifdef CONFIG_ZRAM_LZ4_COMPRESS
  18. #include "zcomp_lz4.h"
  19. #endif
  20. /*
  21. * single zcomp_strm backend
  22. */
  23. struct zcomp_strm_single {
  24. struct mutex strm_lock;
  25. struct zcomp_strm *zstrm;
  26. };
  27. /*
  28. * multi zcomp_strm backend
  29. */
  30. struct zcomp_strm_multi {
  31. /* protect strm list */
  32. spinlock_t strm_lock;
  33. /* max possible number of zstrm streams */
  34. int max_strm;
  35. /* number of available zstrm streams */
  36. int avail_strm;
  37. /* list of available strms */
  38. struct list_head idle_strm;
  39. wait_queue_head_t strm_wait;
  40. };
  41. static struct zcomp_backend *backends[] = {
  42. &zcomp_lzo,
  43. #ifdef CONFIG_ZRAM_LZ4_COMPRESS
  44. &zcomp_lz4,
  45. #endif
  46. NULL
  47. };
  48. static struct zcomp_backend *find_backend(const char *compress)
  49. {
  50. int i = 0;
  51. while (backends[i]) {
  52. if (sysfs_streq(compress, backends[i]->name))
  53. break;
  54. i++;
  55. }
  56. return backends[i];
  57. }
  58. static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
  59. {
  60. if (zstrm->private)
  61. comp->backend->destroy(zstrm->private);
  62. free_pages((unsigned long)zstrm->buffer, 1);
  63. kfree(zstrm);
  64. }
  65. /*
  66. * allocate new zcomp_strm structure with ->private initialized by
  67. * backend, return NULL on error
  68. */
  69. static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp, gfp_t flags)
  70. {
  71. struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), flags);
  72. if (!zstrm)
  73. return NULL;
  74. zstrm->private = comp->backend->create(flags);
  75. /*
  76. * allocate 2 pages. 1 for compressed data, plus 1 extra for the
  77. * case when compressed size is larger than the original one
  78. */
  79. zstrm->buffer = (void *)__get_free_pages(flags | __GFP_ZERO, 1);
  80. if (!zstrm->private || !zstrm->buffer) {
  81. zcomp_strm_free(comp, zstrm);
  82. zstrm = NULL;
  83. }
  84. return zstrm;
  85. }
  86. /*
  87. * get idle zcomp_strm or wait until other process release
  88. * (zcomp_strm_release()) one for us
  89. */
  90. static struct zcomp_strm *zcomp_strm_multi_find(struct zcomp *comp)
  91. {
  92. struct zcomp_strm_multi *zs = comp->stream;
  93. struct zcomp_strm *zstrm;
  94. while (1) {
  95. spin_lock(&zs->strm_lock);
  96. if (!list_empty(&zs->idle_strm)) {
  97. zstrm = list_entry(zs->idle_strm.next,
  98. struct zcomp_strm, list);
  99. list_del(&zstrm->list);
  100. spin_unlock(&zs->strm_lock);
  101. return zstrm;
  102. }
  103. /* zstrm streams limit reached, wait for idle stream */
  104. if (zs->avail_strm >= zs->max_strm) {
  105. spin_unlock(&zs->strm_lock);
  106. wait_event(zs->strm_wait, !list_empty(&zs->idle_strm));
  107. continue;
  108. }
  109. /* allocate new zstrm stream */
  110. zs->avail_strm++;
  111. spin_unlock(&zs->strm_lock);
  112. /*
  113. * This function can be called in swapout/fs write path
  114. * so we can't use GFP_FS|IO. And it assumes we already
  115. * have at least one stream in zram initialization so we
  116. * don't do best effort to allocate more stream in here.
  117. * A default stream will work well without further multiple
  118. * streams. That's why we use NORETRY | NOWARN.
  119. */
  120. zstrm = zcomp_strm_alloc(comp, GFP_NOIO | __GFP_NORETRY |
  121. __GFP_NOWARN);
  122. if (!zstrm) {
  123. spin_lock(&zs->strm_lock);
  124. zs->avail_strm--;
  125. spin_unlock(&zs->strm_lock);
  126. wait_event(zs->strm_wait, !list_empty(&zs->idle_strm));
  127. continue;
  128. }
  129. break;
  130. }
  131. return zstrm;
  132. }
  133. /* add stream back to idle list and wake up waiter or free the stream */
  134. static void zcomp_strm_multi_release(struct zcomp *comp, struct zcomp_strm *zstrm)
  135. {
  136. struct zcomp_strm_multi *zs = comp->stream;
  137. spin_lock(&zs->strm_lock);
  138. if (zs->avail_strm <= zs->max_strm) {
  139. list_add(&zstrm->list, &zs->idle_strm);
  140. spin_unlock(&zs->strm_lock);
  141. wake_up(&zs->strm_wait);
  142. return;
  143. }
  144. zs->avail_strm--;
  145. spin_unlock(&zs->strm_lock);
  146. zcomp_strm_free(comp, zstrm);
  147. }
  148. /* change max_strm limit */
  149. static bool zcomp_strm_multi_set_max_streams(struct zcomp *comp, int num_strm)
  150. {
  151. struct zcomp_strm_multi *zs = comp->stream;
  152. struct zcomp_strm *zstrm;
  153. spin_lock(&zs->strm_lock);
  154. zs->max_strm = num_strm;
  155. /*
  156. * if user has lowered the limit and there are idle streams,
  157. * immediately free as much streams (and memory) as we can.
  158. */
  159. while (zs->avail_strm > num_strm && !list_empty(&zs->idle_strm)) {
  160. zstrm = list_entry(zs->idle_strm.next,
  161. struct zcomp_strm, list);
  162. list_del(&zstrm->list);
  163. zcomp_strm_free(comp, zstrm);
  164. zs->avail_strm--;
  165. }
  166. spin_unlock(&zs->strm_lock);
  167. return true;
  168. }
  169. static void zcomp_strm_multi_destroy(struct zcomp *comp)
  170. {
  171. struct zcomp_strm_multi *zs = comp->stream;
  172. struct zcomp_strm *zstrm;
  173. while (!list_empty(&zs->idle_strm)) {
  174. zstrm = list_entry(zs->idle_strm.next,
  175. struct zcomp_strm, list);
  176. list_del(&zstrm->list);
  177. zcomp_strm_free(comp, zstrm);
  178. }
  179. kfree(zs);
  180. }
  181. static int zcomp_strm_multi_create(struct zcomp *comp, int max_strm)
  182. {
  183. struct zcomp_strm *zstrm;
  184. struct zcomp_strm_multi *zs;
  185. comp->destroy = zcomp_strm_multi_destroy;
  186. comp->strm_find = zcomp_strm_multi_find;
  187. comp->strm_release = zcomp_strm_multi_release;
  188. comp->set_max_streams = zcomp_strm_multi_set_max_streams;
  189. zs = kmalloc(sizeof(struct zcomp_strm_multi), GFP_KERNEL);
  190. if (!zs)
  191. return -ENOMEM;
  192. comp->stream = zs;
  193. spin_lock_init(&zs->strm_lock);
  194. INIT_LIST_HEAD(&zs->idle_strm);
  195. init_waitqueue_head(&zs->strm_wait);
  196. zs->max_strm = max_strm;
  197. zs->avail_strm = 1;
  198. zstrm = zcomp_strm_alloc(comp, GFP_KERNEL);
  199. if (!zstrm) {
  200. kfree(zs);
  201. return -ENOMEM;
  202. }
  203. list_add(&zstrm->list, &zs->idle_strm);
  204. return 0;
  205. }
  206. static struct zcomp_strm *zcomp_strm_single_find(struct zcomp *comp)
  207. {
  208. struct zcomp_strm_single *zs = comp->stream;
  209. mutex_lock(&zs->strm_lock);
  210. return zs->zstrm;
  211. }
  212. static void zcomp_strm_single_release(struct zcomp *comp,
  213. struct zcomp_strm *zstrm)
  214. {
  215. struct zcomp_strm_single *zs = comp->stream;
  216. mutex_unlock(&zs->strm_lock);
  217. }
  218. static bool zcomp_strm_single_set_max_streams(struct zcomp *comp, int num_strm)
  219. {
  220. /* zcomp_strm_single support only max_comp_streams == 1 */
  221. return false;
  222. }
  223. static void zcomp_strm_single_destroy(struct zcomp *comp)
  224. {
  225. struct zcomp_strm_single *zs = comp->stream;
  226. zcomp_strm_free(comp, zs->zstrm);
  227. kfree(zs);
  228. }
  229. static int zcomp_strm_single_create(struct zcomp *comp)
  230. {
  231. struct zcomp_strm_single *zs;
  232. comp->destroy = zcomp_strm_single_destroy;
  233. comp->strm_find = zcomp_strm_single_find;
  234. comp->strm_release = zcomp_strm_single_release;
  235. comp->set_max_streams = zcomp_strm_single_set_max_streams;
  236. zs = kmalloc(sizeof(struct zcomp_strm_single), GFP_KERNEL);
  237. if (!zs)
  238. return -ENOMEM;
  239. comp->stream = zs;
  240. mutex_init(&zs->strm_lock);
  241. zs->zstrm = zcomp_strm_alloc(comp, GFP_KERNEL);
  242. if (!zs->zstrm) {
  243. kfree(zs);
  244. return -ENOMEM;
  245. }
  246. return 0;
  247. }
  248. /* show available compressors */
  249. ssize_t zcomp_available_show(const char *comp, char *buf)
  250. {
  251. ssize_t sz = 0;
  252. int i = 0;
  253. while (backends[i]) {
  254. if (sysfs_streq(comp, backends[i]->name))
  255. sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
  256. "[%s] ", backends[i]->name);
  257. else
  258. sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
  259. "%s ", backends[i]->name);
  260. i++;
  261. }
  262. sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
  263. return sz;
  264. }
  265. bool zcomp_set_max_streams(struct zcomp *comp, int num_strm)
  266. {
  267. return comp->set_max_streams(comp, num_strm);
  268. }
  269. struct zcomp_strm *zcomp_strm_find(struct zcomp *comp)
  270. {
  271. return comp->strm_find(comp);
  272. }
  273. void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm)
  274. {
  275. comp->strm_release(comp, zstrm);
  276. }
  277. int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
  278. const unsigned char *src, size_t *dst_len)
  279. {
  280. return comp->backend->compress(src, zstrm->buffer, dst_len,
  281. zstrm->private);
  282. }
  283. int zcomp_decompress(struct zcomp *comp, const unsigned char *src,
  284. size_t src_len, unsigned char *dst)
  285. {
  286. return comp->backend->decompress(src, src_len, dst);
  287. }
  288. void zcomp_destroy(struct zcomp *comp)
  289. {
  290. comp->destroy(comp);
  291. kfree(comp);
  292. }
  293. /*
  294. * search available compressors for requested algorithm.
  295. * allocate new zcomp and initialize it. return compressing
  296. * backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL)
  297. * if requested algorithm is not supported, ERR_PTR(-ENOMEM) in
  298. * case of allocation error, or any other error potentially
  299. * returned by functions zcomp_strm_{multi,single}_create.
  300. */
  301. struct zcomp *zcomp_create(const char *compress, int max_strm)
  302. {
  303. struct zcomp *comp;
  304. struct zcomp_backend *backend;
  305. int error;
  306. backend = find_backend(compress);
  307. if (!backend)
  308. return ERR_PTR(-EINVAL);
  309. comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
  310. if (!comp)
  311. return ERR_PTR(-ENOMEM);
  312. comp->backend = backend;
  313. if (max_strm > 1)
  314. error = zcomp_strm_multi_create(comp, max_strm);
  315. else
  316. error = zcomp_strm_single_create(comp);
  317. if (error) {
  318. kfree(comp);
  319. return ERR_PTR(error);
  320. }
  321. return comp;
  322. }