zcomp.c 8.6 KB

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