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.
This commit is contained in:
Jérôme Duval
2011-11-19 23:34:45 +01:00
parent 940c916013
commit b1f9573f59
3 changed files with 109 additions and 4 deletions
@@ -1,6 +1,7 @@
/* /*
* Copyright 2011, Jérôme Duval, [email protected]. * Copyright 2011, Jérôme Duval, [email protected].
* Copyright 2008, Axel Dörfler, [email protected]. * Copyright 2008, Axel Dörfler, [email protected].
* Copyright 2005-2007, Ingo Weinhold, [email protected].
* This file may be used under the terms of the MIT License. * This file may be used under the terms of the MIT License.
*/ */
@@ -9,6 +10,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <zlib.h>
#include "BPlusTree.h" #include "BPlusTree.h"
#include "CachedBlock.h" #include "CachedBlock.h"
@@ -197,20 +199,27 @@ Inode::ReadAt(off_t pos, uint8* buffer, size_t* _length)
search_key.SetObjectID(fID); search_key.SetObjectID(fID);
search_key.SetOffset(pos + 1); search_key.SetOffset(pos + 1);
size_t item_size;
btrfs_extent_data *extent_data; btrfs_extent_data *extent_data;
status_t status = fVolume->FSTree()->FindPrevious(search_key, status_t status = fVolume->FSTree()->FindPrevious(search_key,
(void**)&extent_data); (void**)&extent_data, &item_size);
if (status != B_OK) { if (status != B_OK) {
ERROR("Inode::FindBlock(): Couldn't find extent_data 0x%lx\n", status); ERROR("Inode::FindBlock(): Couldn't find extent_data 0x%lx\n", status);
return status; return status;
} }
uint8 compression = extent_data->Compression();
if (FileCache() != NULL if (FileCache() != NULL
&& extent_data->Type() == BTRFS_EXTENT_DATA_REGULAR) { && extent_data->Type() == BTRFS_EXTENT_DATA_REGULAR) {
TRACE("inode %" B_PRIdINO ": ReadAt cache (pos %lld, length %lu)\n", TRACE("inode %" B_PRIdINO ": ReadAt cache (pos %lld, length %lu)\n",
ID(), pos, length); ID(), pos, length);
free(extent_data); 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(), 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) if (extent_data->Type() != BTRFS_EXTENT_DATA_INLINE)
panic("unknown extent type; %d\n", extent_data->Type()); panic("unknown extent type; %d\n", extent_data->Type());
*_length = min_c(extent_data->MemoryBytes() - diff, *_length); *_length = min_c(extent_data->Size() - diff, *_length);
memcpy(buffer, extent_data->inline_data, *_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); free(extent_data);
return B_OK; return B_OK;
@@ -1,8 +1,13 @@
SubDir HAIKU_TOP src add-ons kernel file_systems btrfs ; SubDir HAIKU_TOP src add-ons kernel file_systems btrfs ;
UseHeaders [ FDirName $(HAIKU_TOP) headers libs zlib ] ;
UsePrivateHeaders [ FDirName kernel util ] ; UsePrivateHeaders [ FDirName kernel util ] ;
UsePrivateHeaders shared storage ; UsePrivateHeaders shared storage ;
UsePrivateKernelHeaders ; UsePrivateKernelHeaders ;
SubDirSysHdrs $(HAIKU_TOP) headers libs zlib ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src libs zlib ] ;
KernelAddon btrfs : KernelAddon btrfs :
kernel_interface.cpp kernel_interface.cpp
@@ -14,4 +19,11 @@ KernelAddon btrfs :
DirectoryIterator.cpp DirectoryIterator.cpp
Inode.cpp Inode.cpp
Volume.cpp Volume.cpp
inflate.c
inffast.c
inftrees.c
adler32.c
crc32.c
zutil.c
; ;
@@ -279,6 +279,7 @@ struct btrfs_extent_data {
return B_LENDIAN_TO_HOST_INT64(generation); } return B_LENDIAN_TO_HOST_INT64(generation); }
uint64 MemoryBytes() const { uint64 MemoryBytes() const {
return B_LENDIAN_TO_HOST_INT64(memory_size); } return B_LENDIAN_TO_HOST_INT64(memory_size); }
uint8 Compression() const { return compression; }
uint8 Type() const { return type; } uint8 Type() const { return type; }
uint64 DiskOffset() const { uint64 DiskOffset() const {
return B_LENDIAN_TO_HOST_INT64(disk_offset); } 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_ROOT_ITEM 132
#define BTRFS_KEY_TYPE_XATTR_ITEM 24 #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_INLINE 0
#define BTRFS_EXTENT_DATA_REGULAR 1 #define BTRFS_EXTENT_DATA_REGULAR 1
#define BTRFS_EXTENT_DATA_PRE 2 #define BTRFS_EXTENT_DATA_PRE 2