fs: btrfs: Use LZO_LEN to replace immediate number
[platform/kernel/u-boot.git] / fs / btrfs / compression.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * BTRFS filesystem implementation for U-Boot
4  *
5  * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
6  */
7
8 #include "btrfs.h"
9 #include <malloc.h>
10 #include <linux/lzo.h>
11 #include <linux/zstd.h>
12 #include <u-boot/zlib.h>
13 #include <asm/unaligned.h>
14
15 /* Header for each segment, LE32, recording the compressed size */
16 #define LZO_LEN         4
17 static u32 decompress_lzo(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
18 {
19         u32 tot_len, in_len, res;
20         size_t out_len;
21         int ret;
22
23         if (clen < LZO_LEN)
24                 return -1;
25
26         tot_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
27         cbuf += LZO_LEN;
28         clen -= LZO_LEN;
29         tot_len -= LZO_LEN;
30
31         if (tot_len == 0 && dlen)
32                 return -1;
33         if (tot_len < LZO_LEN)
34                 return -1;
35
36         res = 0;
37
38         while (tot_len > LZO_LEN) {
39                 in_len = le32_to_cpu(get_unaligned((u32 *)cbuf));
40                 cbuf += LZO_LEN;
41                 clen -= LZO_LEN;
42
43                 if (in_len > clen || tot_len < LZO_LEN + in_len)
44                         return -1;
45
46                 tot_len -= (LZO_LEN + in_len);
47
48                 out_len = dlen;
49                 ret = lzo1x_decompress_safe(cbuf, in_len, dbuf, &out_len);
50                 if (ret != LZO_E_OK)
51                         return -1;
52
53                 cbuf += in_len;
54                 clen -= in_len;
55                 dbuf += out_len;
56                 dlen -= out_len;
57
58                 res += out_len;
59         }
60
61         return res;
62 }
63
64 /* from zutil.h */
65 #define PRESET_DICT 0x20
66
67 static u32 decompress_zlib(const u8 *_cbuf, u32 clen, u8 *dbuf, u32 dlen)
68 {
69         int wbits = MAX_WBITS, ret = -1;
70         z_stream stream;
71         u8 *cbuf;
72         u32 res;
73
74         memset(&stream, 0, sizeof(stream));
75
76         cbuf = (u8 *) _cbuf;
77
78         stream.total_in = 0;
79
80         stream.next_out = dbuf;
81         stream.avail_out = dlen;
82         stream.total_out = 0;
83
84         /* skip adler32 check if deflate and no dictionary */
85         if (clen > 2 && !(cbuf[1] & PRESET_DICT) &&
86             ((cbuf[0] & 0x0f) == Z_DEFLATED) &&
87             !(((cbuf[0] << 8) + cbuf[1]) % 31)) {
88                 wbits = -((cbuf[0] >> 4) + 8);
89                 cbuf += 2;
90                 clen -= 2;
91         }
92
93         if (Z_OK != inflateInit2(&stream, wbits))
94                 return -1;
95
96         while (stream.total_in < clen) {
97                 stream.next_in = cbuf + stream.total_in;
98                 stream.avail_in = min((u32) (clen - stream.total_in),
99                                       (u32) btrfs_info.sb.sectorsize);
100
101                 ret = inflate(&stream, Z_NO_FLUSH);
102                 if (ret != Z_OK)
103                         break;
104         }
105
106         res = stream.total_out;
107         inflateEnd(&stream);
108
109         if (ret != Z_STREAM_END)
110                 return -1;
111
112         return res;
113 }
114
115 #define ZSTD_BTRFS_MAX_WINDOWLOG 17
116 #define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
117
118 static u32 decompress_zstd(const u8 *cbuf, u32 clen, u8 *dbuf, u32 dlen)
119 {
120         ZSTD_DStream *dstream;
121         ZSTD_inBuffer in_buf;
122         ZSTD_outBuffer out_buf;
123         void *workspace;
124         size_t wsize;
125         u32 res = -1;
126
127         wsize = ZSTD_DStreamWorkspaceBound(ZSTD_BTRFS_MAX_INPUT);
128         workspace = malloc(wsize);
129         if (!workspace) {
130                 debug("%s: cannot allocate workspace of size %zu\n", __func__,
131                       wsize);
132                 return -1;
133         }
134
135         dstream = ZSTD_initDStream(ZSTD_BTRFS_MAX_INPUT, workspace, wsize);
136         if (!dstream) {
137                 printf("%s: ZSTD_initDStream failed\n", __func__);
138                 goto err_free;
139         }
140
141         in_buf.src = cbuf;
142         in_buf.pos = 0;
143         in_buf.size = clen;
144
145         out_buf.dst = dbuf;
146         out_buf.pos = 0;
147         out_buf.size = dlen;
148
149         while (1) {
150                 size_t ret;
151
152                 ret = ZSTD_decompressStream(dstream, &out_buf, &in_buf);
153                 if (ZSTD_isError(ret)) {
154                         printf("%s: ZSTD_decompressStream error %d\n", __func__,
155                                ZSTD_getErrorCode(ret));
156                         goto err_free;
157                 }
158
159                 if (in_buf.pos >= clen || !ret)
160                         break;
161         }
162
163         res = out_buf.pos;
164
165 err_free:
166         free(workspace);
167         return res;
168 }
169
170 u32 btrfs_decompress(u8 type, const char *c, u32 clen, char *d, u32 dlen)
171 {
172         u32 res;
173         const u8 *cbuf;
174         u8 *dbuf;
175
176         cbuf = (const u8 *) c;
177         dbuf = (u8 *) d;
178
179         switch (type) {
180         case BTRFS_COMPRESS_NONE:
181                 res = dlen < clen ? dlen : clen;
182                 memcpy(dbuf, cbuf, res);
183                 return res;
184         case BTRFS_COMPRESS_ZLIB:
185                 return decompress_zlib(cbuf, clen, dbuf, dlen);
186         case BTRFS_COMPRESS_LZO:
187                 return decompress_lzo(cbuf, clen, dbuf, dlen);
188         case BTRFS_COMPRESS_ZSTD:
189                 return decompress_zstd(cbuf, clen, dbuf, dlen);
190         default:
191                 printf("%s: Unsupported compression in extent: %i\n", __func__,
192                        type);
193                 return -1;
194         }
195 }