On Thu, Oct 21, 2021 at 04:55:19PM +0300, Nikolay Borisov wrote:
On 1.09.21 г. 20:01, Omar Sandoval wrote:
quoted
From: Boris Burkov <redacted>
+static int decompress_lzo(const char *encoded_data, u64 encoded_len,
+ char *unencoded_data, u64 unencoded_len,
+ unsigned int page_size)
+{
+ uint32_t total_len;
+ size_t in_pos, out_pos;
+
+ if (encoded_len < 4) {
+ error("lzo header is truncated");
+ return -EIO;
+ }
+ memcpy(&total_len, encoded_data, 4);
+ total_len = le32toh(total_len);
+ if (total_len > encoded_len) {
+ error("lzo header is invalid");
+ return -EIO;
+ }
+
+ in_pos = 4;
+ out_pos = 0;
+ while (in_pos < total_len && out_pos < unencoded_len) {
+ size_t page_remaining;
+ uint32_t src_len;
+ lzo_uint dst_len;
+ int ret;
+
+ page_remaining = -in_pos % page_size;
Why the -in_pos?
in_pos is our position in the encoded data. This calculates how many
bytes are remaining in the page that in_pos current points to.
quoted
+ if (page_remaining < 4) {
+ if (total_len - in_pos <= page_remaining)
+ break;
+ in_pos += page_remaining;
+ }
+
+ if (total_len - in_pos < 4) {
+ error("lzo segment header is truncated");
+ return -EIO;
+ }
+
+ memcpy(&src_len, encoded_data + in_pos, 4);
+ src_len = le32toh(src_len);
+ in_pos += 4;
+ if (src_len > total_len - in_pos) {
+ error("lzo segment header is invalid");
+ return -EIO;
+ }
+
+ dst_len = page_size;
+ ret = lzo1x_decompress_safe((void *)(encoded_data + in_pos),
+ src_len,
+ (void *)(unencoded_data + out_pos),
+ &dst_len, NULL);
+ if (ret != LZO_E_OK) {
+ error("lzo1x_decompress_safe failed: %d", ret);
+ return -EIO;
+ }
+
+ in_pos += src_len;
+ out_pos += dst_len;
+ }
+ return 0;
+}
+
+static int decompress_and_write(struct btrfs_receive *rctx,
+ const char *encoded_data, u64 offset,
+ u64 encoded_len, u64 unencoded_file_len,
+ u64 unencoded_len, u64 unencoded_offset,
+ u32 compression)
+{
+ int ret = 0;
+ size_t pos;
+ ssize_t w;
+ char *unencoded_data;
+ int page_shift;
+
+ unencoded_data = calloc(unencoded_len, 1);
+ if (!unencoded_data) {
+ error("allocating space for unencoded data failed: %m");
+ return -errno;
+ }
+
+ switch (compression) {
+ case BTRFS_ENCODED_IO_COMPRESSION_ZLIB:
+ ret = decompress_zlib(rctx, encoded_data, encoded_len,
+ unencoded_data, unencoded_len);
+ if (ret)
+ goto out;
+ break;
+ case BTRFS_ENCODED_IO_COMPRESSION_ZSTD:
+ ret = decompress_zstd(rctx, encoded_data, encoded_len,
+ unencoded_data, unencoded_len);
+ if (ret)
+ goto out;
+ break;
+ case BTRFS_ENCODED_IO_COMPRESSION_LZO_4K:
+ case BTRFS_ENCODED_IO_COMPRESSION_LZO_8K:
+ case BTRFS_ENCODED_IO_COMPRESSION_LZO_16K:
+ case BTRFS_ENCODED_IO_COMPRESSION_LZO_32K:
+ case BTRFS_ENCODED_IO_COMPRESSION_LZO_64K:
+ page_shift = compression - BTRFS_ENCODED_IO_COMPRESSION_LZO_4K + 12;
Doesn't this calculation assume page size is 4k, what about arches with
larger page size (ppc/aarch64), shouldn't that '12' be adjusted?
This is unrelated to the machine page size. It is translating the
BTRFS_ENCODED_IO_COMPRESSION_LZO_* value to the page size used for
compressing the data:
compression | - LZO_4K | + 12 | 1 <<
=====================================
LZO_4K = 3 | 0 | 12 | 4096
LZO_8K = 4 | 1 | 13 | 8192
LZO_16K = 5 | 2 | 14 | 16384
LZO_32K = 6 | 3 | 15 | 32768
LZO_64K = 7 | 4 | 16 | 65536
I'll fix the other comments, thanks.