Add support for LZO compression in btrfs.

* Makefile.util.def (libgrubmods.a): Add minilzo.c and add required flags
to cflags in cppflags.
* Makefile.core.def (btrfs): Likewise.
* grub-core/fs/btrfs.c: Include minilzo.h.
(grub_btrfs_superblock): Add sectorsize, nodesize, leafsize, stripsize and
dummy5 field.
(GRUB_BTRFS_COMPRESSION_LZO): New define.
(grub_btrfs_extent_read): Add support for LZO compression type.
This commit is contained in:
Szymon Janc 2011-08-14 11:46:05 +02:00
parent b6085f3236
commit 095f077e6d
4 changed files with 143 additions and 12 deletions

View file

@ -1,3 +1,16 @@
2011-08-14 Szymon Janc <szymon@janc.net.pl>
Add support for LZO compression in btrfs.
* Makefile.util.def (libgrubmods.a): Add minilzo.c and add required flags
to cflags in cppflags.
* Makefile.core.def (btrfs): Likewise.
* grub-core/fs/btrfs.c: Include minilzo.h.
(grub_btrfs_superblock): Add sectorsize, nodesize, leafsize, stripsize and
dummy5 field.
(GRUB_BTRFS_COMPRESSION_LZO): New define.
(grub_btrfs_extent_read): Add support for LZO compression type.
2011-08-14 Szymon Janc <szymon@janc.net.pl> 2011-08-14 Szymon Janc <szymon@janc.net.pl>
* grub-core/fs/btrfs.c: Some code style fixes. * grub-core/fs/btrfs.c: Some code style fixes.

View file

@ -33,6 +33,8 @@ library = {
library = { library = {
name = libgrubmods.a; name = libgrubmods.a;
cflags = '$(CFLAGS_POSIX) -Wno-undef';
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(top_srcdir)/grub-core/lib/minilzo -DMINILZO_HAVE_CONFIG_H';
common_nodist = grub_script.tab.c; common_nodist = grub_script.tab.c;
common_nodist = grub_script.yy.c; common_nodist = grub_script.yy.c;
@ -107,6 +109,7 @@ library = {
common = grub-core/script/argv.c; common = grub-core/script/argv.c;
common = grub-core/io/gzio.c; common = grub-core/io/gzio.c;
common = grub-core/kern/ia64/dl_helper.c; common = grub-core/kern/ia64/dl_helper.c;
common = grub-core/lib/minilzo/minilzo.c;
}; };
program = { program = {

View file

@ -979,6 +979,9 @@ module = {
name = btrfs; name = btrfs;
common = fs/btrfs.c; common = fs/btrfs.c;
common = lib/crc.c; common = lib/crc.c;
common = lib/minilzo/minilzo.c;
cflags = '$(CFLAGS_POSIX) -Wno-undef';
cppflags = '-I$(srcdir)/lib/posix_wrap -I$(srcdir)/lib/minilzo -DMINILZO_HAVE_CONFIG_H';
}; };
module = { module = {

View file

@ -26,6 +26,7 @@
#include <grub/types.h> #include <grub/types.h>
#include <grub/lib/crc.h> #include <grub/lib/crc.h>
#include <grub/deflate.h> #include <grub/deflate.h>
#include "minilzo.h"
GRUB_MOD_LICENSE ("GPLv3+"); GRUB_MOD_LICENSE ("GPLv3+");
@ -51,10 +52,15 @@ struct grub_btrfs_superblock
grub_uint64_t chunk_tree; grub_uint64_t chunk_tree;
grub_uint8_t dummy2[0x20]; grub_uint8_t dummy2[0x20];
grub_uint64_t root_dir_objectid; grub_uint64_t root_dir_objectid;
grub_uint8_t dummy3[0x41]; grub_uint8_t dummy3[0x8];
grub_uint32_t sectorsize;
grub_uint32_t nodesize;
grub_uint32_t leafsize;
grub_uint32_t stripsize;
grub_uint8_t dummy4[0x29];
struct grub_btrfs_device this_device; struct grub_btrfs_device this_device;
char label[0x100]; char label[0x100];
grub_uint8_t dummy4[0x100]; grub_uint8_t dummy5[0x100];
grub_uint8_t bootstrap_mapping[0x800]; grub_uint8_t bootstrap_mapping[0x800];
} __attribute__ ((packed)); } __attribute__ ((packed));
@ -216,6 +222,7 @@ struct grub_btrfs_extent_data
#define GRUB_BTRFS_COMPRESSION_NONE 0 #define GRUB_BTRFS_COMPRESSION_NONE 0
#define GRUB_BTRFS_COMPRESSION_ZLIB 1 #define GRUB_BTRFS_COMPRESSION_ZLIB 1
#define GRUB_BTRFS_COMPRESSION_LZO 2
#define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100 #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
@ -954,7 +961,8 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
} }
if (data->extent->compression != GRUB_BTRFS_COMPRESSION_NONE if (data->extent->compression != GRUB_BTRFS_COMPRESSION_NONE
&& data->extent->compression != GRUB_BTRFS_COMPRESSION_ZLIB) && data->extent->compression != GRUB_BTRFS_COMPRESSION_ZLIB
&& data->extent->compression != GRUB_BTRFS_COMPRESSION_LZO)
{ {
grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET,
"compression type 0x%x not supported", "compression type 0x%x not supported",
@ -980,6 +988,42 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
!= (grub_ssize_t) csize) != (grub_ssize_t) csize)
return -1; return -1;
} }
else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
{
grub_uint32_t total_size, chunk_size;
unsigned char *obuf;
unsigned char *ibuf = (unsigned char *) data->extent->inl;
lzo_uint ocnt = extoff + csize;
int ret;
obuf = grub_malloc (extoff + csize);
if (!obuf)
return -1;
total_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf));
ibuf += sizeof (total_size);
chunk_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf));
ibuf += sizeof (chunk_size);
/* Can we have multiple chunks in inline extent? */
if (chunk_size + (sizeof (grub_uint32_t) * 2) != total_size)
{
grub_free (obuf);
return -1;
}
ret = lzo1x_decompress_safe (ibuf, chunk_size, obuf, &ocnt, NULL);
if (ret != LZO_E_OK)
{
grub_free (obuf);
return -1;
}
grub_memcpy (buf, obuf + extoff, ocnt - extoff);
grub_free (obuf);
}
else else
grub_memcpy (buf, data->extent->inl + extoff, csize); grub_memcpy (buf, data->extent->inl + extoff, csize);
break; break;
@ -989,9 +1033,10 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
grub_memset (buf, 0, csize); grub_memset (buf, 0, csize);
break; break;
} }
if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB)
if (data->extent->compression != GRUB_BTRFS_COMPRESSION_NONE)
{ {
char *tmp; void *tmp;
grub_uint64_t zsize; grub_uint64_t zsize;
zsize = grub_le_to_cpu64 (data->extent->compressed_size); zsize = grub_le_to_cpu64 (data->extent->compressed_size);
tmp = grub_malloc (zsize); tmp = grub_malloc (zsize);
@ -1005,16 +1050,83 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data,
grub_free (tmp); grub_free (tmp);
return -1; return -1;
} }
if (grub_zlib_decompress (tmp, zsize, extoff +
grub_le_to_cpu64 (data->extent->offset), if (data->extent->compression == GRUB_BTRFS_COMPRESSION_ZLIB)
buf, csize) != (grub_ssize_t) csize) {
grub_ssize_t ret;
ret = grub_zlib_decompress (tmp, zsize, extoff
+ grub_le_to_cpu64 (data->extent->offset),
buf, csize);
grub_free (tmp);
if (ret != (grub_ssize_t) csize)
return -1;
break;
}
else if (data->extent->compression == GRUB_BTRFS_COMPRESSION_LZO)
{
grub_uint32_t total_size, chunk_size, usize = 0;
grub_size_t off = extoff;
unsigned char *chunk, *ibuf = tmp;
char *obuf = buf;
/* XXX Is this correct size from sblock? */
grub_uint32_t udata_size = grub_le_to_cpu32 (data->sblock.sectorsize);
chunk = grub_malloc (udata_size);
if (!chunk)
{ {
grub_free (tmp); grub_free (tmp);
return -1; return -1;
} }
/* XXX Use this for some sanity checks while decompressing. */
total_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf));
ibuf += sizeof (total_size);
chunk_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf));
ibuf += sizeof (chunk_size);
/* Jump to first chunk with requested data. */
while (off >= udata_size)
{
chunk_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf));
ibuf += sizeof (chunk_size);
ibuf += chunk_size;
off -= udata_size;
}
while (usize < csize)
{
chunk_size = grub_le_to_cpu32 (grub_get_unaligned32 (ibuf));
lzo_uint csize2 = udata_size;
int diff;
ibuf += sizeof (chunk_size);
if (lzo1x_decompress_safe (ibuf, chunk_size, chunk, &csize2, NULL) != LZO_E_OK)
{
grub_free (tmp); grub_free (tmp);
grub_free (chunk);
return -1;
}
diff = grub_min (csize2 - off, csize - usize);
grub_memcpy (obuf, chunk + off, diff);
obuf += diff;
ibuf += chunk_size;
usize += diff;
off = 0;
}
grub_free (tmp);
grub_free (chunk);
break; break;
} }
}
err = grub_btrfs_read_logical (data, err = grub_btrfs_read_logical (data,
grub_le_to_cpu64 (data->extent->laddr) grub_le_to_cpu64 (data->extent->laddr)
+ grub_le_to_cpu64 (data->extent->offset) + grub_le_to_cpu64 (data->extent->offset)