compress.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2024, SUSE LLC
  4. *
  5. * Authors: Enzo Matsumiya <ematsumiya@suse.de>
  6. *
  7. * This file implements I/O compression support for SMB2 messages (SMB 3.1.1 only).
  8. * See compress/ for implementation details of each algorithm.
  9. *
  10. * References:
  11. * MS-SMB2 "3.1.4.4 Compressing the Message"
  12. * MS-SMB2 "3.1.5.3 Decompressing the Chained Message"
  13. * MS-XCA - for details of the supported algorithms
  14. */
  15. #include <linux/slab.h>
  16. #include <linux/kernel.h>
  17. #include <linux/uio.h>
  18. #include <linux/sort.h>
  19. #include "cifsglob.h"
  20. #include "../common/smb2pdu.h"
  21. #include "cifsproto.h"
  22. #include "smb2proto.h"
  23. #include "compress/lz77.h"
  24. #include "compress.h"
  25. /*
  26. * The heuristic_*() functions below try to determine data compressibility.
  27. *
  28. * Derived from fs/btrfs/compression.c, changing coding style, some parameters, and removing
  29. * unused parts.
  30. *
  31. * Read that file for better and more detailed explanation of the calculations.
  32. *
  33. * The algorithms are ran in a collected sample of the input (uncompressed) data.
  34. * The sample is formed of 2K reads in PAGE_SIZE intervals, with a maximum size of 4M.
  35. *
  36. * Parsing the sample goes from "low-hanging fruits" (fastest algorithms, likely compressible)
  37. * to "need more analysis" (likely uncompressible).
  38. */
  39. struct bucket {
  40. unsigned int count;
  41. };
  42. /**
  43. * has_low_entropy() - Compute Shannon entropy of the sampled data.
  44. * @bkt: Bytes counts of the sample.
  45. * @slen: Size of the sample.
  46. *
  47. * Return: true if the level (percentage of number of bits that would be required to
  48. * compress the data) is below the minimum threshold.
  49. *
  50. * Note:
  51. * There _is_ an entropy level here that's > 65 (minimum threshold) that would indicate a
  52. * possibility of compression, but compressing, or even further analysing, it would waste so much
  53. * resources that it's simply not worth it.
  54. *
  55. * Also Shannon entropy is the last computed heuristic; if we got this far and ended up
  56. * with uncertainty, just stay on the safe side and call it uncompressible.
  57. */
  58. static bool has_low_entropy(struct bucket *bkt, size_t slen)
  59. {
  60. const size_t threshold = 65, max_entropy = 8 * ilog2(16);
  61. size_t i, p, p2, len, sum = 0;
  62. #define pow4(n) (n * n * n * n)
  63. len = ilog2(pow4(slen));
  64. for (i = 0; i < 256 && bkt[i].count > 0; i++) {
  65. p = bkt[i].count;
  66. p2 = ilog2(pow4(p));
  67. sum += p * (len - p2);
  68. }
  69. sum /= slen;
  70. return ((sum * 100 / max_entropy) <= threshold);
  71. }
  72. #define BYTE_DIST_BAD 0
  73. #define BYTE_DIST_GOOD 1
  74. #define BYTE_DIST_MAYBE 2
  75. /**
  76. * calc_byte_distribution() - Compute byte distribution on the sampled data.
  77. * @bkt: Byte counts of the sample.
  78. * @slen: Size of the sample.
  79. *
  80. * Return:
  81. * BYTE_DIST_BAD: A "hard no" for compression -- a computed uniform distribution of
  82. * the bytes (e.g. random or encrypted data).
  83. * BYTE_DIST_GOOD: High probability (normal (Gaussian) distribution) of the data being
  84. * compressible.
  85. * BYTE_DIST_MAYBE: When computed byte distribution resulted in "low > n < high"
  86. * grounds. has_low_entropy() should be used for a final decision.
  87. */
  88. static int calc_byte_distribution(struct bucket *bkt, size_t slen)
  89. {
  90. const size_t low = 64, high = 200, threshold = slen * 90 / 100;
  91. size_t sum = 0;
  92. int i;
  93. for (i = 0; i < low; i++)
  94. sum += bkt[i].count;
  95. if (sum > threshold)
  96. return BYTE_DIST_BAD;
  97. for (; i < high && bkt[i].count > 0; i++) {
  98. sum += bkt[i].count;
  99. if (sum > threshold)
  100. break;
  101. }
  102. if (i <= low)
  103. return BYTE_DIST_GOOD;
  104. if (i >= high)
  105. return BYTE_DIST_BAD;
  106. return BYTE_DIST_MAYBE;
  107. }
  108. static bool is_mostly_ascii(const struct bucket *bkt)
  109. {
  110. size_t count = 0;
  111. int i;
  112. for (i = 0; i < 256; i++)
  113. if (bkt[i].count > 0)
  114. /* Too many non-ASCII (0-63) bytes. */
  115. if (++count > 64)
  116. return false;
  117. return true;
  118. }
  119. static bool has_repeated_data(const u8 *sample, size_t len)
  120. {
  121. size_t s = len / 2;
  122. return (!memcmp(&sample[0], &sample[s], s));
  123. }
  124. static int cmp_bkt(const void *_a, const void *_b)
  125. {
  126. const struct bucket *a = _a, *b = _b;
  127. /* Reverse sort. */
  128. if (a->count > b->count)
  129. return -1;
  130. return 1;
  131. }
  132. /*
  133. * Collect some 2K samples with 2K gaps between.
  134. */
  135. static int collect_sample(const struct iov_iter *source, ssize_t max, u8 *sample)
  136. {
  137. struct iov_iter iter = *source;
  138. size_t s = 0;
  139. while (iov_iter_count(&iter) >= SZ_2K) {
  140. size_t part = umin(umin(iov_iter_count(&iter), SZ_2K), max);
  141. size_t n;
  142. n = copy_from_iter(sample + s, part, &iter);
  143. if (n != part)
  144. return -EFAULT;
  145. s += n;
  146. max -= n;
  147. if (iov_iter_count(&iter) < PAGE_SIZE - SZ_2K)
  148. break;
  149. iov_iter_advance(&iter, SZ_2K);
  150. }
  151. return s;
  152. }
  153. /**
  154. * is_compressible() - Determines if a chunk of data is compressible.
  155. * @data: Iterator containing uncompressed data.
  156. *
  157. * Return: true if @data is compressible, false otherwise.
  158. *
  159. * Tests shows that this function is quite reliable in predicting data compressibility,
  160. * matching close to 1:1 with the behaviour of LZ77 compression success and failures.
  161. */
  162. static bool is_compressible(const struct iov_iter *data)
  163. {
  164. const size_t read_size = SZ_2K, bkt_size = 256, max = SZ_4M;
  165. struct bucket *bkt = NULL;
  166. size_t len;
  167. u8 *sample;
  168. bool ret = false;
  169. int i;
  170. /* Preventive double check -- already checked in should_compress(). */
  171. len = iov_iter_count(data);
  172. if (unlikely(len < read_size))
  173. return ret;
  174. if (len - read_size > max)
  175. len = max;
  176. sample = kvzalloc(len, GFP_KERNEL);
  177. if (!sample) {
  178. WARN_ON_ONCE(1);
  179. return ret;
  180. }
  181. /* Sample 2K bytes per page of the uncompressed data. */
  182. i = collect_sample(data, len, sample);
  183. if (i <= 0) {
  184. WARN_ON_ONCE(1);
  185. goto out;
  186. }
  187. len = i;
  188. ret = true;
  189. if (has_repeated_data(sample, len))
  190. goto out;
  191. bkt = kcalloc(bkt_size, sizeof(*bkt), GFP_KERNEL);
  192. if (!bkt) {
  193. WARN_ON_ONCE(1);
  194. ret = false;
  195. goto out;
  196. }
  197. for (i = 0; i < len; i++)
  198. bkt[sample[i]].count++;
  199. if (is_mostly_ascii(bkt))
  200. goto out;
  201. /* Sort in descending order */
  202. sort(bkt, bkt_size, sizeof(*bkt), cmp_bkt, NULL);
  203. i = calc_byte_distribution(bkt, len);
  204. if (i != BYTE_DIST_MAYBE) {
  205. ret = !!i;
  206. goto out;
  207. }
  208. ret = has_low_entropy(bkt, len);
  209. out:
  210. kvfree(sample);
  211. kfree(bkt);
  212. return ret;
  213. }
  214. bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *rq)
  215. {
  216. const struct smb2_hdr *shdr = rq->rq_iov->iov_base;
  217. if (unlikely(!tcon || !tcon->ses || !tcon->ses->server))
  218. return false;
  219. if (!tcon->ses->server->compression.enabled)
  220. return false;
  221. if (!(tcon->share_flags & SMB2_SHAREFLAG_COMPRESS_DATA))
  222. return false;
  223. if (shdr->Command == SMB2_WRITE) {
  224. const struct smb2_write_req *wreq = rq->rq_iov->iov_base;
  225. if (le32_to_cpu(wreq->Length) < SMB_COMPRESS_MIN_LEN)
  226. return false;
  227. return is_compressible(&rq->rq_iter);
  228. }
  229. return (shdr->Command == SMB2_READ);
  230. }
  231. int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, compress_send_fn send_fn)
  232. {
  233. struct iov_iter iter;
  234. u32 slen, dlen;
  235. void *src, *dst = NULL;
  236. int ret;
  237. if (!server || !rq || !rq->rq_iov || !rq->rq_iov->iov_base)
  238. return -EINVAL;
  239. if (rq->rq_iov->iov_len != sizeof(struct smb2_write_req))
  240. return -EINVAL;
  241. slen = iov_iter_count(&rq->rq_iter);
  242. src = kvzalloc(slen, GFP_KERNEL);
  243. if (!src) {
  244. ret = -ENOMEM;
  245. goto err_free;
  246. }
  247. /* Keep the original iter intact. */
  248. iter = rq->rq_iter;
  249. if (!copy_from_iter_full(src, slen, &iter)) {
  250. ret = -EIO;
  251. goto err_free;
  252. }
  253. /*
  254. * This is just overprovisioning, as the algorithm will error out if @dst reaches 7/8
  255. * of @slen.
  256. */
  257. dlen = slen;
  258. dst = kvzalloc(dlen, GFP_KERNEL);
  259. if (!dst) {
  260. ret = -ENOMEM;
  261. goto err_free;
  262. }
  263. ret = lz77_compress(src, slen, dst, &dlen);
  264. if (!ret) {
  265. struct smb2_compression_hdr hdr = { 0 };
  266. struct smb_rqst comp_rq = { .rq_nvec = 3, };
  267. struct kvec iov[3];
  268. hdr.ProtocolId = SMB2_COMPRESSION_TRANSFORM_ID;
  269. hdr.OriginalCompressedSegmentSize = cpu_to_le32(slen);
  270. hdr.CompressionAlgorithm = SMB3_COMPRESS_LZ77;
  271. hdr.Flags = SMB2_COMPRESSION_FLAG_NONE;
  272. hdr.Offset = cpu_to_le32(rq->rq_iov[0].iov_len);
  273. iov[0].iov_base = &hdr;
  274. iov[0].iov_len = sizeof(hdr);
  275. iov[1] = rq->rq_iov[0];
  276. iov[2].iov_base = dst;
  277. iov[2].iov_len = dlen;
  278. comp_rq.rq_iov = iov;
  279. ret = send_fn(server, 1, &comp_rq);
  280. } else if (ret == -EMSGSIZE || dlen >= slen) {
  281. ret = send_fn(server, 1, rq);
  282. }
  283. err_free:
  284. kvfree(dst);
  285. kvfree(src);
  286. return ret;
  287. }