From b1f9573f594557d669c8bb2cf4af0940c44a3b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 19 Nov 2011 22:58:34 +0100 Subject: [PATCH] btrfs: added support for zlib decompression of inline extents. Reuse code from tarfs to decompress zlib compressed inline extents. No idea yet on how to decompress regular extents which are currently served by the file cache. --- .../kernel/file_systems/btrfs/Inode.cpp | 96 ++++++++++++++++++- src/add-ons/kernel/file_systems/btrfs/Jamfile | 12 +++ src/add-ons/kernel/file_systems/btrfs/btrfs.h | 5 + 3 files changed, 109 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/btrfs/Inode.cpp b/src/add-ons/kernel/file_systems/btrfs/Inode.cpp index 3d394e10f5..6c231f0160 100644 --- a/src/add-ons/kernel/file_systems/btrfs/Inode.cpp +++ b/src/add-ons/kernel/file_systems/btrfs/Inode.cpp @@ -1,6 +1,7 @@ /* * Copyright 2011, Jérôme Duval, korli@users.berlios.de. * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2005-2007, Ingo Weinhold, bonefish@cs.tu-berlin.de. * This file may be used under the terms of the MIT License. */ @@ -9,6 +10,7 @@ #include #include +#include #include "BPlusTree.h" #include "CachedBlock.h" @@ -197,20 +199,27 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length) search_key.SetObjectID(fID); search_key.SetOffset(pos + 1); + size_t item_size; btrfs_extent_data *extent_data; status_t status = fVolume->FSTree()->FindPrevious(search_key, - (void**)&extent_data); + (void**)&extent_data, &item_size); if (status != B_OK) { ERROR("Inode::FindBlock(): Couldn't find extent_data 0x%lx\n", status); return status; } + uint8 compression = extent_data->Compression(); if (FileCache() != NULL && extent_data->Type() == BTRFS_EXTENT_DATA_REGULAR) { TRACE("inode %" B_PRIdINO ": ReadAt cache (pos %lld, length %lu)\n", ID(), pos, length); free(extent_data); - return file_cache_read(FileCache(), NULL, pos, buffer, _length); + if (compression == BTRFS_EXTENT_COMPRESS_NONE) + return file_cache_read(FileCache(), NULL, pos, buffer, _length); + else if (compression == BTRFS_EXTENT_COMPRESS_ZLIB) + panic("zlib isn't unsupported for regular extent\n"); + else + panic("unknown extent compression; %d\n", compression); } TRACE("Inode::ReadAt(%" B_PRIdINO ") key.Offset() %lld\n", ID(), @@ -220,8 +229,87 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length) if (extent_data->Type() != BTRFS_EXTENT_DATA_INLINE) panic("unknown extent type; %d\n", extent_data->Type()); - *_length = min_c(extent_data->MemoryBytes() - diff, *_length); - memcpy(buffer, extent_data->inline_data, *_length); + *_length = min_c(extent_data->Size() - diff, *_length); + if (compression == BTRFS_EXTENT_COMPRESS_NONE) + memcpy(buffer, extent_data->inline_data, *_length); + else if (compression == BTRFS_EXTENT_COMPRESS_ZLIB) { + char in[2048]; + z_stream zStream = { + (Bytef*)in, // next in + sizeof(in), // avail in + 0, // total in + NULL, // next out + 0, // avail out + 0, // total out + 0, // msg + 0, // state + Z_NULL, // zalloc + Z_NULL, // zfree + Z_NULL, // opaque + 0, // data type + 0, // adler + 0, // reserved + }; + + int status; + ssize_t offset = 0; + size_t inline_size = item_size - 13; + bool headerRead = false; + + TRACE("Inode::ReadAt(%" B_PRIdINO ") diff %lld size %ld\n", ID(), + diff, item_size); + + do { + ssize_t bytesRead = min_c(sizeof(in), inline_size - offset); + memcpy(in, extent_data->inline_data + offset, bytesRead); + if (bytesRead != (ssize_t)sizeof(in)) { + if (bytesRead <= 0) { + status = Z_STREAM_ERROR; + break; + } + } + + zStream.avail_in = bytesRead; + zStream.next_in = (Bytef*)in; + + if (!headerRead) { + headerRead = true; + + zStream.avail_out = length; + zStream.next_out = (Bytef*)buffer; + + status = inflateInit2(&zStream, 15); + if (status != Z_OK) { + free(extent_data); + return B_ERROR; + } + } + + status = inflate(&zStream, Z_SYNC_FLUSH); + offset += bytesRead; + if (diff > 0) { + zStream.next_out -= max_c(bytesRead, diff); + diff -= max_c(bytesRead, diff); + } + + if (zStream.avail_in != 0 && status != Z_STREAM_END) { + TRACE("Inode::ReadAt() didn't read whole block: %s\n", + zStream.msg); + } + } while (status == Z_OK); + + inflateEnd(&zStream); + + if (status != Z_STREAM_END) { + TRACE("Inode::ReadAt() inflating failed: %d!\n", status); + free(extent_data); + return B_BAD_DATA; + } + + *_length = zStream.total_out; + + } else + panic("unknown extent compression; %d\n", compression); free(extent_data); return B_OK; diff --git a/src/add-ons/kernel/file_systems/btrfs/Jamfile b/src/add-ons/kernel/file_systems/btrfs/Jamfile index 47dbcaf000..d3ed5d178f 100644 --- a/src/add-ons/kernel/file_systems/btrfs/Jamfile +++ b/src/add-ons/kernel/file_systems/btrfs/Jamfile @@ -1,8 +1,13 @@ SubDir HAIKU_TOP src add-ons kernel file_systems btrfs ; +UseHeaders [ FDirName $(HAIKU_TOP) headers libs zlib ] ; + UsePrivateHeaders [ FDirName kernel util ] ; UsePrivateHeaders shared storage ; UsePrivateKernelHeaders ; +SubDirSysHdrs $(HAIKU_TOP) headers libs zlib ; + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src libs zlib ] ; KernelAddon btrfs : kernel_interface.cpp @@ -14,4 +19,11 @@ KernelAddon btrfs : DirectoryIterator.cpp Inode.cpp Volume.cpp + + inflate.c + inffast.c + inftrees.c + adler32.c + crc32.c + zutil.c ; diff --git a/src/add-ons/kernel/file_systems/btrfs/btrfs.h b/src/add-ons/kernel/file_systems/btrfs/btrfs.h index 3b950d5b82..fb95df6d40 100644 --- a/src/add-ons/kernel/file_systems/btrfs/btrfs.h +++ b/src/add-ons/kernel/file_systems/btrfs/btrfs.h @@ -279,6 +279,7 @@ struct btrfs_extent_data { return B_LENDIAN_TO_HOST_INT64(generation); } uint64 MemoryBytes() const { return B_LENDIAN_TO_HOST_INT64(memory_size); } + uint8 Compression() const { return compression; } uint8 Type() const { return type; } uint64 DiskOffset() const { return B_LENDIAN_TO_HOST_INT64(disk_offset); } @@ -310,6 +311,10 @@ struct btrfs_extent_data { #define BTRFS_KEY_TYPE_ROOT_ITEM 132 #define BTRFS_KEY_TYPE_XATTR_ITEM 24 +#define BTRFS_EXTENT_COMPRESS_NONE 0 +#define BTRFS_EXTENT_COMPRESS_ZLIB 1 +#define BTRFS_EXTENT_COMPRESS_LZO 2 + #define BTRFS_EXTENT_DATA_INLINE 0 #define BTRFS_EXTENT_DATA_REGULAR 1 #define BTRFS_EXTENT_DATA_PRE 2