diff --git a/ChangeLog b/ChangeLog index f46277405..676c374aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2011-04-18 Vladimir Serbinenko + + * grub-core/fs/btrfs.c (grub_btrfs_read_logical): Support huge + chunks. + * include/grub/err.h (grub_err_t): New enum value GRUB_ERR_BUG. + 2011-04-18 Vladimir Serbinenko Complete 64-bit division support. diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c index bbb326b98..42aa257d9 100644 --- a/grub-core/fs/btrfs.c +++ b/grub-core/fs/btrfs.c @@ -588,7 +588,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, grub_uint8_t *ptr; struct grub_btrfs_key *key; struct grub_btrfs_chunk_item *chunk; - grub_ssize_t csize; + grub_uint64_t csize; grub_err_t err; struct grub_btrfs_key key_out; int challoc = 0; @@ -648,11 +648,18 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, chunk_found: { grub_uint32_t stripen; - grub_uint32_t stripe_offset; + grub_uint64_t stripe_offset; grub_uint64_t off = addr - grub_le_to_cpu64 (key->offset); unsigned redundancy = 1; unsigned i, j; + if (grub_le_to_cpu64 (chunk->size) <= off) + { + grub_dprintf ("btrfs", "no chunk\n"); + return grub_error (GRUB_ERR_BAD_FS, + "couldn't find the chunk descriptor"); + } + grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T "+0x%" PRIxGRUB_UINT64_T " (%d stripes (%d substripes) of %" @@ -668,17 +675,19 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, { case GRUB_BTRFS_CHUNK_TYPE_SINGLE: { - grub_uint32_t stripe_length; - stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), - grub_le_to_cpu16 (chunk->nstripes), - NULL); - stripen = grub_divmod64 (off, stripe_length, &stripe_offset); + grub_uint64_t stripe_length; + grub_dprintf ("btrfs", "single\n"); + stripe_length = grub_divmod64_full (grub_le_to_cpu64 (chunk->size), + grub_le_to_cpu16 (chunk->nstripes), + NULL); + stripen = grub_divmod64_full (off, stripe_length, &stripe_offset); csize = (stripen + 1) * stripe_length - off; break; } case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED: case GRUB_BTRFS_CHUNK_TYPE_RAID1: { + grub_dprintf ("btrfs", "RAID1\n"); stripen = 0; stripe_offset = off; csize = grub_le_to_cpu64 (chunk->size) - off; @@ -689,6 +698,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, { grub_uint64_t middle, high; grub_uint32_t low; + grub_dprintf ("btrfs", "RAID0\n"); middle = grub_divmod64 (off, grub_le_to_cpu64 (chunk->stripe_length), &low); @@ -721,12 +731,13 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, break; } default: + grub_dprintf ("btrfs", "unsupported RAID\n"); return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "unsupported RAID flags %" PRIxGRUB_UINT64_T, grub_le_to_cpu64 (chunk->type)); } - if (csize <= 0) - return grub_error (GRUB_ERR_BAD_FS, + if (csize == 0) + return grub_error (GRUB_ERR_BUG, "couldn't find the chunk descriptor"); if ((grub_size_t) csize > size) csize = size; diff --git a/include/grub/err.h b/include/grub/err.h index 22334038d..69bc6ec79 100644 --- a/include/grub/err.h +++ b/include/grub/err.h @@ -55,7 +55,8 @@ typedef enum GRUB_ERR_TIMEOUT, GRUB_ERR_IO, GRUB_ERR_ACCESS_DENIED, - GRUB_ERR_EXTRACTOR + GRUB_ERR_EXTRACTOR, + GRUB_ERR_BUG } grub_err_t;