decompressor_lzma.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. #include <linux/xz.h>
  3. #include "compress.h"
  4. struct z_erofs_lzma {
  5. struct z_erofs_lzma *next;
  6. struct xz_dec_microlzma *state;
  7. u8 bounce[PAGE_SIZE];
  8. };
  9. /* considering the LZMA performance, no need to use a lockless list for now */
  10. static DEFINE_SPINLOCK(z_erofs_lzma_lock);
  11. static unsigned int z_erofs_lzma_max_dictsize;
  12. static unsigned int z_erofs_lzma_nstrms, z_erofs_lzma_avail_strms;
  13. static struct z_erofs_lzma *z_erofs_lzma_head;
  14. static DECLARE_WAIT_QUEUE_HEAD(z_erofs_lzma_wq);
  15. module_param_named(lzma_streams, z_erofs_lzma_nstrms, uint, 0444);
  16. static void z_erofs_lzma_exit(void)
  17. {
  18. /* there should be no running fs instance */
  19. while (z_erofs_lzma_avail_strms) {
  20. struct z_erofs_lzma *strm;
  21. spin_lock(&z_erofs_lzma_lock);
  22. strm = z_erofs_lzma_head;
  23. if (!strm) {
  24. spin_unlock(&z_erofs_lzma_lock);
  25. DBG_BUGON(1);
  26. return;
  27. }
  28. z_erofs_lzma_head = NULL;
  29. spin_unlock(&z_erofs_lzma_lock);
  30. while (strm) {
  31. struct z_erofs_lzma *n = strm->next;
  32. if (strm->state)
  33. xz_dec_microlzma_end(strm->state);
  34. kfree(strm);
  35. --z_erofs_lzma_avail_strms;
  36. strm = n;
  37. }
  38. }
  39. }
  40. static int __init z_erofs_lzma_init(void)
  41. {
  42. unsigned int i;
  43. /* by default, use # of possible CPUs instead */
  44. if (!z_erofs_lzma_nstrms)
  45. z_erofs_lzma_nstrms = num_possible_cpus();
  46. for (i = 0; i < z_erofs_lzma_nstrms; ++i) {
  47. struct z_erofs_lzma *strm = kzalloc_obj(*strm);
  48. if (!strm) {
  49. z_erofs_lzma_exit();
  50. return -ENOMEM;
  51. }
  52. spin_lock(&z_erofs_lzma_lock);
  53. strm->next = z_erofs_lzma_head;
  54. z_erofs_lzma_head = strm;
  55. spin_unlock(&z_erofs_lzma_lock);
  56. ++z_erofs_lzma_avail_strms;
  57. }
  58. return 0;
  59. }
  60. static int z_erofs_load_lzma_config(struct super_block *sb,
  61. struct erofs_super_block *dsb, void *data, int size)
  62. {
  63. static DEFINE_MUTEX(lzma_resize_mutex);
  64. struct z_erofs_lzma_cfgs *lzma = data;
  65. unsigned int dict_size, i;
  66. struct z_erofs_lzma *strm, *head = NULL;
  67. int err;
  68. if (!lzma || size < sizeof(struct z_erofs_lzma_cfgs)) {
  69. erofs_err(sb, "invalid lzma cfgs, size=%u", size);
  70. return -EINVAL;
  71. }
  72. if (lzma->format) {
  73. erofs_err(sb, "unidentified lzma format %x, please check kernel version",
  74. le16_to_cpu(lzma->format));
  75. return -EINVAL;
  76. }
  77. dict_size = le32_to_cpu(lzma->dict_size);
  78. if (dict_size > Z_EROFS_LZMA_MAX_DICT_SIZE || dict_size < 4096) {
  79. erofs_err(sb, "unsupported lzma dictionary size %u",
  80. dict_size);
  81. return -EINVAL;
  82. }
  83. /* in case 2 z_erofs_load_lzma_config() race to avoid deadlock */
  84. mutex_lock(&lzma_resize_mutex);
  85. if (z_erofs_lzma_max_dictsize >= dict_size) {
  86. mutex_unlock(&lzma_resize_mutex);
  87. return 0;
  88. }
  89. /* 1. collect/isolate all streams for the following check */
  90. for (i = 0; i < z_erofs_lzma_avail_strms; ++i) {
  91. struct z_erofs_lzma *last;
  92. again:
  93. spin_lock(&z_erofs_lzma_lock);
  94. strm = z_erofs_lzma_head;
  95. if (!strm) {
  96. spin_unlock(&z_erofs_lzma_lock);
  97. wait_event(z_erofs_lzma_wq,
  98. READ_ONCE(z_erofs_lzma_head));
  99. goto again;
  100. }
  101. z_erofs_lzma_head = NULL;
  102. spin_unlock(&z_erofs_lzma_lock);
  103. for (last = strm; last->next; last = last->next)
  104. ++i;
  105. last->next = head;
  106. head = strm;
  107. }
  108. err = 0;
  109. /* 2. walk each isolated stream and grow max dict_size if needed */
  110. for (strm = head; strm; strm = strm->next) {
  111. if (strm->state)
  112. xz_dec_microlzma_end(strm->state);
  113. strm->state = xz_dec_microlzma_alloc(XZ_PREALLOC, dict_size);
  114. if (!strm->state)
  115. err = -ENOMEM;
  116. }
  117. /* 3. push back all to the global list and update max dict_size */
  118. spin_lock(&z_erofs_lzma_lock);
  119. DBG_BUGON(z_erofs_lzma_head);
  120. z_erofs_lzma_head = head;
  121. spin_unlock(&z_erofs_lzma_lock);
  122. wake_up_all(&z_erofs_lzma_wq);
  123. z_erofs_lzma_max_dictsize = dict_size;
  124. mutex_unlock(&lzma_resize_mutex);
  125. return err;
  126. }
  127. static const char *z_erofs_lzma_decompress(struct z_erofs_decompress_req *rq,
  128. struct page **pgpl)
  129. {
  130. struct super_block *sb = rq->sb;
  131. struct z_erofs_stream_dctx dctx = { .rq = rq, .no = -1, .ni = 0 };
  132. struct xz_buf buf = {};
  133. struct z_erofs_lzma *strm;
  134. enum xz_ret xz_err;
  135. const char *reason;
  136. /* 1. get the exact LZMA compressed size */
  137. dctx.kin = kmap_local_page(*rq->in);
  138. reason = z_erofs_fixup_insize(rq, dctx.kin + rq->pageofs_in,
  139. min(rq->inputsize, sb->s_blocksize - rq->pageofs_in));
  140. if (reason) {
  141. kunmap_local(dctx.kin);
  142. return reason;
  143. }
  144. /* 2. get an available lzma context */
  145. again:
  146. spin_lock(&z_erofs_lzma_lock);
  147. strm = z_erofs_lzma_head;
  148. if (!strm) {
  149. spin_unlock(&z_erofs_lzma_lock);
  150. wait_event(z_erofs_lzma_wq, READ_ONCE(z_erofs_lzma_head));
  151. goto again;
  152. }
  153. z_erofs_lzma_head = strm->next;
  154. spin_unlock(&z_erofs_lzma_lock);
  155. /* 3. multi-call decompress */
  156. xz_dec_microlzma_reset(strm->state, rq->inputsize, rq->outputsize,
  157. !rq->partial_decoding);
  158. buf.in_size = min(rq->inputsize, PAGE_SIZE - rq->pageofs_in);
  159. rq->inputsize -= buf.in_size;
  160. buf.in = dctx.kin + rq->pageofs_in;
  161. dctx.bounce = strm->bounce;
  162. do {
  163. dctx.avail_out = buf.out_size - buf.out_pos;
  164. dctx.inbuf_sz = buf.in_size;
  165. dctx.inbuf_pos = buf.in_pos;
  166. reason = z_erofs_stream_switch_bufs(&dctx, (void **)&buf.out,
  167. (void **)&buf.in, pgpl);
  168. if (reason)
  169. break;
  170. if (buf.out_size == buf.out_pos) {
  171. buf.out_size = dctx.avail_out;
  172. buf.out_pos = 0;
  173. }
  174. buf.in_size = dctx.inbuf_sz;
  175. buf.in_pos = dctx.inbuf_pos;
  176. xz_err = xz_dec_microlzma_run(strm->state, &buf);
  177. DBG_BUGON(buf.out_pos > buf.out_size);
  178. DBG_BUGON(buf.in_pos > buf.in_size);
  179. if (xz_err != XZ_OK) {
  180. if (xz_err == XZ_STREAM_END && !rq->outputsize)
  181. break;
  182. reason = (xz_err == XZ_DATA_ERROR ?
  183. "corrupted compressed data" :
  184. "unexpected end of stream");
  185. break;
  186. }
  187. } while (1);
  188. if (dctx.kout)
  189. kunmap_local(dctx.kout);
  190. kunmap_local(dctx.kin);
  191. /* 4. push back LZMA stream context to the global list */
  192. spin_lock(&z_erofs_lzma_lock);
  193. strm->next = z_erofs_lzma_head;
  194. z_erofs_lzma_head = strm;
  195. spin_unlock(&z_erofs_lzma_lock);
  196. wake_up(&z_erofs_lzma_wq);
  197. return reason;
  198. }
  199. const struct z_erofs_decompressor z_erofs_lzma_decomp = {
  200. .config = z_erofs_load_lzma_config,
  201. .decompress = z_erofs_lzma_decompress,
  202. .init = z_erofs_lzma_init,
  203. .exit = z_erofs_lzma_exit,
  204. .name = "lzma"
  205. };