lz4_wrapper.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (c) 2013, 2014
  4. * Phillip Lougher <[email protected]>
  5. */
  6. #include <linux/bio.h>
  7. #include <linux/mutex.h>
  8. #include <linux/slab.h>
  9. #include <linux/vmalloc.h>
  10. #include <linux/lz4.h>
  11. #include "squashfs_fs.h"
  12. #include "squashfs_fs_sb.h"
  13. #include "squashfs.h"
  14. #include "decompressor.h"
  15. #include "page_actor.h"
  16. #define LZ4_LEGACY 1
  17. struct lz4_comp_opts {
  18. __le32 version;
  19. __le32 flags;
  20. };
  21. struct squashfs_lz4 {
  22. void *input;
  23. void *output;
  24. };
  25. static void *lz4_comp_opts(struct squashfs_sb_info *msblk,
  26. void *buff, int len)
  27. {
  28. struct lz4_comp_opts *comp_opts = buff;
  29. /* LZ4 compressed filesystems always have compression options */
  30. if (comp_opts == NULL || len < sizeof(*comp_opts))
  31. return ERR_PTR(-EIO);
  32. if (le32_to_cpu(comp_opts->version) != LZ4_LEGACY) {
  33. /* LZ4 format currently used by the kernel is the 'legacy'
  34. * format */
  35. ERROR("Unknown LZ4 version\n");
  36. return ERR_PTR(-EINVAL);
  37. }
  38. return NULL;
  39. }
  40. static void *lz4_init(struct squashfs_sb_info *msblk, void *buff)
  41. {
  42. int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE);
  43. struct squashfs_lz4 *stream;
  44. stream = kzalloc(sizeof(*stream), GFP_KERNEL);
  45. if (stream == NULL)
  46. goto failed;
  47. stream->input = vmalloc(block_size);
  48. if (stream->input == NULL)
  49. goto failed2;
  50. stream->output = vmalloc(block_size);
  51. if (stream->output == NULL)
  52. goto failed3;
  53. return stream;
  54. failed3:
  55. vfree(stream->input);
  56. failed2:
  57. kfree(stream);
  58. failed:
  59. ERROR("Failed to initialise LZ4 decompressor\n");
  60. return ERR_PTR(-ENOMEM);
  61. }
  62. static void lz4_free(void *strm)
  63. {
  64. struct squashfs_lz4 *stream = strm;
  65. if (stream) {
  66. vfree(stream->input);
  67. vfree(stream->output);
  68. }
  69. kfree(stream);
  70. }
  71. static int lz4_uncompress(struct squashfs_sb_info *msblk, void *strm,
  72. struct bio *bio, int offset, int length,
  73. struct squashfs_page_actor *output)
  74. {
  75. struct bvec_iter_all iter_all = {};
  76. struct bio_vec *bvec = bvec_init_iter_all(&iter_all);
  77. struct squashfs_lz4 *stream = strm;
  78. void *buff = stream->input, *data;
  79. int bytes = length, res;
  80. while (bio_next_segment(bio, &iter_all)) {
  81. int avail = min(bytes, ((int)bvec->bv_len) - offset);
  82. data = bvec_virt(bvec);
  83. memcpy(buff, data + offset, avail);
  84. buff += avail;
  85. bytes -= avail;
  86. offset = 0;
  87. }
  88. res = LZ4_decompress_safe(stream->input, stream->output,
  89. length, output->length);
  90. if (res < 0)
  91. return -EIO;
  92. bytes = res;
  93. data = squashfs_first_page(output);
  94. buff = stream->output;
  95. while (data) {
  96. if (bytes <= PAGE_SIZE) {
  97. if (!IS_ERR(data))
  98. memcpy(data, buff, bytes);
  99. break;
  100. }
  101. if (!IS_ERR(data))
  102. memcpy(data, buff, PAGE_SIZE);
  103. buff += PAGE_SIZE;
  104. bytes -= PAGE_SIZE;
  105. data = squashfs_next_page(output);
  106. }
  107. squashfs_finish_page(output);
  108. return res;
  109. }
  110. const struct squashfs_decompressor squashfs_lz4_comp_ops = {
  111. .init = lz4_init,
  112. .comp_opts = lz4_comp_opts,
  113. .free = lz4_free,
  114. .decompress = lz4_uncompress,
  115. .id = LZ4_COMPRESSION,
  116. .name = "lz4",
  117. .alloc_buffer = 0,
  118. .supported = 1
  119. };