diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c index ad7b10826..f8fbf95e9 100644 --- a/grub-core/fs/btrfs.c +++ b/grub-core/fs/btrfs.c @@ -49,7 +49,7 @@ struct grub_btrfs_superblock grub_uint8_t dummy2[0x20]; grub_uint64_t root_dir_objectid; grub_uint8_t dummy3[0x41]; - struct grub_btrfs_device this_device; + struct grub_btrfs_device this_device; char label[0x100]; grub_uint8_t dummy4[0x100]; grub_uint8_t bootstrap_mapping[0x800]; @@ -64,13 +64,22 @@ struct btrfs_header grub_uint8_t level; } __attribute__ ((packed)); +struct grub_btrfs_device_desc +{ + grub_device_t dev; + grub_uint64_t id; +}; + struct grub_btrfs_data { struct grub_btrfs_superblock sblock; - unsigned int sblock_number; grub_uint64_t tree; grub_uint64_t inode; + struct grub_btrfs_device_desc *devices_attached; + unsigned n_devices_attached; + unsigned n_devices_allocated; + /* Cached extent data. */ grub_uint64_t extstart; grub_uint64_t extino; @@ -96,9 +105,15 @@ struct grub_btrfs_chunk_item grub_uint64_t size; grub_uint64_t dummy; grub_uint64_t stripe_length; - grub_uint8_t dummy2[0x14]; + grub_uint64_t type; +#define GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE 0x07 +#define GRUB_BTRFS_CHUNK_TYPE_SINGLE 0x00 +#define GRUB_BTRFS_CHUNK_TYPE_RAID0 0x08 +#define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10 +#define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED 0x20 + grub_uint8_t dummy2[0xc]; grub_uint16_t nstripes; - grub_uint16_t dummy3; + grub_uint16_t nsubstripes; } __attribute__ ((packed)); struct grub_btrfs_chunk_stripe @@ -187,8 +202,37 @@ static grub_disk_addr_t superblock_sectors[] = { 64 * 2, 64 * 1024 * 2, static grub_err_t grub_btrfs_read_logical (struct grub_btrfs_data *data, - grub_disk_t disk, grub_disk_addr_t addr, - void *buf, grub_size_t size); + grub_disk_addr_t addr, void *buf, grub_size_t size); + +static grub_err_t +read_sblock (grub_disk_t disk, struct grub_btrfs_superblock *sb) +{ + unsigned i; + grub_err_t err = GRUB_ERR_NONE; + for (i = 0; i < ARRAY_SIZE (superblock_sectors); i++) + { + struct grub_btrfs_superblock sblock; + err = grub_disk_read (disk, superblock_sectors[i], 0, + sizeof (sblock), &sblock); + if (err == GRUB_ERR_OUT_OF_RANGE) + break; + + if (grub_memcmp ((char *) sblock.signature, GRUB_BTRFS_SIGNATURE, + sizeof (GRUB_BTRFS_SIGNATURE) - 1) != 0) + break; + if (i == 0 || grub_le_to_cpu64 (sblock.generation) + > grub_le_to_cpu64 (sb->generation)) + grub_memcpy (sb, &sblock, sizeof (sblock)); + } + + if ((err == GRUB_ERR_OUT_OF_RANGE || !err) && i == 0) + return grub_error (GRUB_ERR_BAD_FS, "not a Btrfs filesystem"); + + if (err == GRUB_ERR_OUT_OF_RANGE) + grub_errno = err = GRUB_ERR_NONE; + + return err; +} static int key_cmp (const struct grub_btrfs_key *a, const struct grub_btrfs_key *b) @@ -239,7 +283,7 @@ save_ref (struct grub_btrfs_leaf_descriptor *desc, } static int -next (struct grub_btrfs_data *data, grub_disk_t disk, +next (struct grub_btrfs_data *data, struct grub_btrfs_leaf_descriptor *desc, grub_disk_addr_t *outaddr, grub_size_t *outsize, struct grub_btrfs_key *key_out) @@ -261,8 +305,7 @@ next (struct grub_btrfs_data *data, grub_disk_t disk, struct grub_btrfs_internal_node node; struct btrfs_header head; - err = grub_btrfs_read_logical (data, disk, - desc->data[desc->depth - 1].iter + err = grub_btrfs_read_logical (data, desc->data[desc->depth - 1].iter * sizeof (node) + sizeof (struct btrfs_header) + desc->data[desc->depth - 1].addr, &node, @@ -270,8 +313,7 @@ next (struct grub_btrfs_data *data, grub_disk_t disk, if (err) return -err; - err = grub_btrfs_read_logical (data, disk, - grub_le_to_cpu64 (node.addr), &head, + err = grub_btrfs_read_logical (data, grub_le_to_cpu64 (node.addr), &head, sizeof (head)); if (err) return -err; @@ -279,8 +321,7 @@ next (struct grub_btrfs_data *data, grub_disk_t disk, save_ref (desc, grub_le_to_cpu64 (node.addr), 0, grub_le_to_cpu32 (head.nitems), !head.level); } - err = grub_btrfs_read_logical (data, disk, - desc->data[desc->depth - 1].iter + err = grub_btrfs_read_logical (data, desc->data[desc->depth - 1].iter * sizeof (leaf) + sizeof (struct btrfs_header) + desc->data[desc->depth - 1].addr, &leaf, @@ -295,7 +336,7 @@ next (struct grub_btrfs_data *data, grub_disk_t disk, } static grub_err_t -lower_bound (struct grub_btrfs_data *data, grub_disk_t disk, +lower_bound (struct grub_btrfs_data *data, const struct grub_btrfs_key *key_in, struct grub_btrfs_key *key_out, grub_disk_addr_t root, @@ -327,7 +368,7 @@ lower_bound (struct grub_btrfs_data *data, grub_disk_t disk, reiter: depth++; /* FIXME: preread few nodes into buffer. */ - err = grub_btrfs_read_logical (data, disk, addr, &head, sizeof (head)); + err = grub_btrfs_read_logical (data, addr, &head, sizeof (head)); if (err) return err; addr += sizeof (head); @@ -339,8 +380,7 @@ lower_bound (struct grub_btrfs_data *data, grub_disk_t disk, grub_memset (&node_last, 0, sizeof (node_last)); for (i = 0; i < grub_le_to_cpu32 (head.nitems); i++) { - err = grub_btrfs_read_logical (data, disk, addr - + i * sizeof (node), + err = grub_btrfs_read_logical (data, addr + i * sizeof (node), &node, sizeof (node)); if (err) return err; @@ -391,7 +431,7 @@ lower_bound (struct grub_btrfs_data *data, grub_disk_t disk, int have_last = 0; for (i = 0; i < grub_le_to_cpu32 (head.nitems); i++) { - err = grub_btrfs_read_logical (data, disk, addr + i * sizeof (leaf), + err = grub_btrfs_read_logical (data, addr + i * sizeof (leaf), &leaf, sizeof (leaf)); if (err) return err; @@ -440,9 +480,83 @@ lower_bound (struct grub_btrfs_data *data, grub_disk_t disk, } } +static grub_device_t +find_device (struct grub_btrfs_data *data, grub_uint64_t id) +{ + grub_device_t dev_found = NULL; + auto int hook (const char *name); + int hook (const char *name) + { + grub_device_t dev; + grub_err_t err; + struct grub_btrfs_superblock sb; + dev = grub_device_open (name); + if (!dev) + return 0; + if (!dev->disk) + { + grub_device_close (dev); + return 0; + } + err = read_sblock (dev->disk, &sb); + if (err == GRUB_ERR_BAD_FS) + { + grub_device_close (dev); + grub_errno = GRUB_ERR_NONE; + return 0; + } + if (err) + { + grub_device_close (dev); + grub_print_error (); + return 0; + } + if (grub_memcmp (data->sblock.uuid, sb.uuid, sizeof (sb.uuid)) != 0 + || sb.this_device.device_id != id) + { + grub_device_close (dev); + return 0; + } + + dev_found = dev; + return 1; + } + + unsigned i; + + for (i = 0; i < data->n_devices_attached; i++) + if (id == data->devices_attached[i].id) + return data->devices_attached[i].dev; + grub_device_iterate (hook); + if (!dev_found) + { + grub_error (GRUB_ERR_BAD_FS, "couldn't find a member device"); + return NULL; + } + data->n_devices_attached++; + if (data->n_devices_attached > data->n_devices_allocated) + { + void *tmp; + data->n_devices_allocated = 2 * data->n_devices_attached + 1; + data->devices_attached + = grub_realloc (tmp = data->devices_attached, + data->n_devices_allocated + * sizeof (data->devices_attached[0])); + if (!data->devices_attached) + { + grub_device_close (dev_found); + data->devices_attached = tmp; + return NULL; + } + } + data->devices_attached[data->n_devices_attached - 1].id = id; + data->devices_attached[data->n_devices_attached - 1].dev = dev_found; + return dev_found; +} + static grub_err_t grub_btrfs_read_logical (struct grub_btrfs_data *data, - grub_disk_t disk, grub_disk_addr_t addr, + grub_disk_addr_t addr, void *buf, grub_size_t size) { while (size > 0) @@ -451,14 +565,11 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, struct grub_btrfs_key *key; struct grub_btrfs_chunk_item *chunk; struct grub_btrfs_chunk_stripe *stripe; - grub_size_t csize; + grub_ssize_t csize; grub_err_t err; - grub_disk_addr_t paddr; - grub_uint64_t stripen; - grub_uint32_t stripe_length; - grub_uint32_t stripe_offset; struct grub_btrfs_key key_out; int challoc = 0; + grub_device_t dev; for (ptr = data->sblock.bootstrap_mapping; ptr < data->sblock.bootstrap_mapping + sizeof (data->sblock.bootstrap_mapping) @@ -485,8 +596,7 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, key_in.object_id = GRUB_BTRFS_OBJECT_ID_CHUNK; key_in.type = GRUB_BTRFS_ITEM_TYPE_CHUNK; key_in.offset = addr; - err = lower_bound (data, disk, - &key_in, &key_out, + err = lower_bound (data, &key_in, &key_out, grub_le_to_cpu64 (data->sblock.chunk_tree), &chaddr, &chsize, NULL); if (err) @@ -502,55 +612,99 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, return grub_errno; challoc = 1; - err = grub_btrfs_read_logical (data, disk, chaddr, - chunk, chsize); + err = grub_btrfs_read_logical (data, chaddr, chunk, chsize); if (err) { grub_free (chunk); return err; } - - if (!(addr < grub_le_to_cpu64 (key->offset) - + grub_le_to_cpu64 (chunk->size))) - return grub_error (GRUB_ERR_BAD_FS, - "couldn't find the chunk descriptor"); chunk_found: - stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), - grub_le_to_cpu16 (chunk->nstripes), - NULL); - stripen = grub_divmod64 (addr - grub_le_to_cpu64 (key->offset), - stripe_length, &stripe_offset); - stripe = (struct grub_btrfs_chunk_stripe *) (chunk + 1); - stripe += stripen; - csize = grub_le_to_cpu64 (key->offset) + grub_le_to_cpu64 (chunk->size) - - addr; - if (csize > size) - csize = size; - if (grub_le_to_cpu64 (stripe->device_id) != grub_le_to_cpu64 (data->sblock.this_device.device_id)) - { - if (challoc) - grub_free (chunk); - return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, - "multidevice isn't implemented yet"); - } - grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T - "+0x%" PRIxGRUB_UINT64_T " (%d stripes of %" - PRIxGRUB_UINT64_T ") stripe %" PRIxGRUB_UINT64_T - " maps to 0x%" PRIxGRUB_UINT64_T "\n", - grub_le_to_cpu64 (key->offset), - grub_le_to_cpu64 (chunk->size), - grub_le_to_cpu16 (chunk->nstripes), - grub_le_to_cpu64 (chunk->stripe_length), - stripen, - stripe->offset); - paddr = stripe->offset + stripe_offset; + { + grub_uint32_t stripen; + grub_uint32_t stripe_offset; + grub_uint64_t off = addr - grub_le_to_cpu64 (key->offset); + grub_disk_addr_t paddr; - grub_dprintf ("btrfs", "reading paddr 0x%" PRIxGRUB_UINT64_T - " for laddr 0x%" PRIxGRUB_UINT64_T"\n", paddr, - addr); - err = grub_disk_read (disk, paddr >> GRUB_DISK_SECTOR_BITS, - paddr & (GRUB_DISK_SECTOR_SIZE - 1), csize, buf); + stripe = (struct grub_btrfs_chunk_stripe *) (chunk + 1); + switch (grub_le_to_cpu64 (chunk->type) + & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE) + { + 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); + csize = (stripen + 1) * stripe_length - off; + break; + } + case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED: + case GRUB_BTRFS_CHUNK_TYPE_RAID1: + /* FIXME: Use redundancy. */ + { + grub_uint32_t stripe_length; + stripe_length = grub_divmod64 (grub_le_to_cpu64 (chunk->size), + grub_le_to_cpu16 (chunk->nstripes), + NULL); + stripen = 0; + stripe_offset = off; + csize = stripe_length - off; + break; + } + case GRUB_BTRFS_CHUNK_TYPE_RAID0: + { + grub_uint64_t middle, high; + grub_uint32_t low; + middle = grub_divmod64 (off, + grub_le_to_cpu64 (chunk->stripe_length), + &low); + + high = grub_divmod64 (middle, grub_le_to_cpu16 (chunk->nstripes), + &stripen); + stripe_offset = low + grub_le_to_cpu64 (chunk->stripe_length) + * high; + csize = grub_le_to_cpu64 (chunk->stripe_length) - low; + break; + } + default: + grub_printf ("unsupported RAID flags %" PRIxGRUB_UINT64_T "\n", + grub_le_to_cpu64 (chunk->type)); + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + "unsupported RAID flags %" PRIxGRUB_UINT64_T, + grub_le_to_cpu64 (chunk->type)); + } + stripe += stripen; + if (csize <= 0) + return grub_error (GRUB_ERR_BAD_FS, + "couldn't find the chunk descriptor"); + if ((grub_size_t) csize > size) + csize = size; + dev = find_device (data, stripe->device_id); + if (!dev) + return grub_errno; + grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T + "+0x%" PRIxGRUB_UINT64_T " (%d stripes (%d substripes) of %" + PRIxGRUB_UINT64_T ") stripe %" PRIxGRUB_UINT32_T + " maps to 0x%" PRIxGRUB_UINT64_T "\n", + grub_le_to_cpu64 (key->offset), + grub_le_to_cpu64 (chunk->size), + grub_le_to_cpu16 (chunk->nstripes), + grub_le_to_cpu16 (chunk->nsubstripes), + grub_le_to_cpu64 (chunk->stripe_length), + stripen, + stripe->offset); + paddr = stripe->offset + stripe_offset; + + grub_dprintf ("btrfs", "reading paddr 0x%" PRIxGRUB_UINT64_T + " for laddr 0x%" PRIxGRUB_UINT64_T"\n", paddr, + addr); + err = grub_disk_read (dev->disk, paddr >> GRUB_DISK_SECTOR_BITS, + paddr & (GRUB_DISK_SECTOR_SIZE - 1), csize, buf); + if (err) + return err; + } size -= csize; buf = (grub_uint8_t *) buf + csize; addr += csize; @@ -561,54 +715,57 @@ grub_btrfs_read_logical (struct grub_btrfs_data *data, } static struct grub_btrfs_data * -grub_btrfs_mount (grub_disk_t disk) +grub_btrfs_mount (grub_device_t dev) { - struct grub_btrfs_data *data = grub_zalloc (sizeof (*data)); - unsigned i; - grub_err_t err = GRUB_ERR_NONE; + struct grub_btrfs_data *data; + grub_err_t err; + if (!dev->disk) + { + grub_error (GRUB_ERR_BAD_FS, "not BtrFS"); + return NULL; + } + + data = grub_zalloc (sizeof (*data)); if (! data) return NULL; - for (i = 0; i < ARRAY_SIZE (superblock_sectors); i++) + err = read_sblock (dev->disk, &data->sblock); + if (err) { - struct grub_btrfs_superblock sblock; - err = grub_disk_read (disk, superblock_sectors[i], 0, - sizeof (sblock), &sblock); - if (err == GRUB_ERR_OUT_OF_RANGE) - break; - - if (grub_memcmp ((char *) sblock.signature, GRUB_BTRFS_SIGNATURE, - sizeof (GRUB_BTRFS_SIGNATURE) - 1)) - break; - if (i == 0 || grub_le_to_cpu64 (sblock.generation) - > grub_le_to_cpu64 (data->sblock.generation)) - { - grub_memcpy (&data->sblock, &sblock, sizeof (sblock)); - data->sblock_number = i; - } + grub_free (data); + return NULL; } - if ((err == GRUB_ERR_OUT_OF_RANGE || !err) && i == 0) + data->n_devices_allocated = 16; + data->devices_attached = grub_malloc (sizeof (data->devices_attached[0]) + * data->n_devices_allocated); + if (!data->devices_attached) { - grub_error (GRUB_ERR_BAD_FS, "not a Btrfs filesystem"); - goto fail; + grub_free (data); + return NULL; } - - if (err == GRUB_ERR_OUT_OF_RANGE) - grub_errno = err = GRUB_ERR_NONE; - - grub_dprintf ("btrfs", "using superblock %d\n", data->sblock_number); + data->n_devices_attached = 1; + data->devices_attached[0].dev = dev; + data->devices_attached[0].id = data->sblock.this_device.device_id; return data; +} - fail: +static void +grub_btrfs_unmount (struct grub_btrfs_data *data) +{ + unsigned i; + /* The device 0 is closed one layer upper. */ + for (i = 1; i < data->n_devices_attached; i++) + grub_device_close (data->devices_attached[i].dev); + grub_free (data->devices_attached); + grub_free (data->extent); grub_free (data); - return NULL; } static grub_err_t -grub_btrfs_read_inode (struct grub_btrfs_data *data, grub_disk_t disk, +grub_btrfs_read_inode (struct grub_btrfs_data *data, struct grub_btrfs_inode *inode, grub_uint64_t num, grub_uint64_t tree) { @@ -621,7 +778,7 @@ grub_btrfs_read_inode (struct grub_btrfs_data *data, grub_disk_t disk, key_in.type = GRUB_BTRFS_ITEM_TYPE_INODE_ITEM; key_in.offset = 0; - err = lower_bound (data,disk, &key_in, &key_out, tree, + err = lower_bound (data, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL); if (err) return err; @@ -629,11 +786,11 @@ grub_btrfs_read_inode (struct grub_btrfs_data *data, grub_disk_t disk, || key_out.type != GRUB_BTRFS_ITEM_TYPE_INODE_ITEM) return grub_error (GRUB_ERR_BAD_FS, "inode not found"); - return grub_btrfs_read_logical (data, disk, elemaddr, inode, sizeof (*inode)); + return grub_btrfs_read_logical (data, elemaddr, inode, sizeof (*inode)); } static grub_ssize_t -grub_btrfs_extent_read (struct grub_btrfs_data *data, grub_disk_t disk, +grub_btrfs_extent_read (struct grub_btrfs_data *data, grub_uint64_t ino, grub_uint64_t tree, grub_off_t pos0, char *buf, grub_size_t len) { @@ -654,7 +811,7 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, grub_disk_t disk, key_in.object_id = ino; key_in.type = GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM; key_in.offset = grub_cpu_to_le64 (pos); - err = lower_bound (data, disk, &key_in, &key_out, tree, + err = lower_bound (data, &key_in, &key_out, tree, &elemaddr, &elemsize, NULL); if (err) return -1; @@ -671,7 +828,7 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, grub_disk_t disk, if (!data->extent) return grub_errno; - err = grub_btrfs_read_logical (data, disk, elemaddr, + err = grub_btrfs_read_logical (data, elemaddr, data->extent, elemsize); if (err) return err; @@ -721,7 +878,7 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, grub_disk_t disk, grub_memset (buf, 0, csize); break; } - err = grub_btrfs_read_logical (data, disk, + err = grub_btrfs_read_logical (data, grub_le_to_cpu64 (data->extent->laddr) + extoff, buf, csize); @@ -742,7 +899,6 @@ grub_btrfs_extent_read (struct grub_btrfs_data *data, grub_disk_t disk, static grub_err_t find_path (struct grub_btrfs_data *data, - grub_disk_t disk, const char *path, struct grub_btrfs_key *key, grub_uint64_t *tree, grub_uint8_t *type) { @@ -757,6 +913,7 @@ find_path (struct grub_btrfs_data *data, const char *ctoken; grub_size_t ctokenlen; char *path_alloc = NULL; + unsigned symlinks_max = 32; *type = GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY; *tree = data->sblock.root_tree; @@ -794,7 +951,7 @@ find_path (struct grub_btrfs_data *data, key->type = GRUB_BTRFS_ITEM_TYPE_DIR_ITEM; key->offset = grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken, ctokenlen)); - err = lower_bound (data, disk, key, &key_out, *tree, + err = lower_bound (data, key, &key_out, *tree, &elemaddr, &elemsize, NULL); if (err) { @@ -822,8 +979,7 @@ find_path (struct grub_btrfs_data *data, } } - err = grub_btrfs_read_logical (data, disk, elemaddr, - direl, elemsize); + err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize); if (err) { grub_free (direl); @@ -860,7 +1016,15 @@ find_path (struct grub_btrfs_data *data, { struct grub_btrfs_inode inode; char *tmp; - err = grub_btrfs_read_inode (data, disk, &inode, + if (--symlinks_max == 0) + { + grub_free (direl); + grub_free (path_alloc); + return grub_error (GRUB_ERR_SYMLINK_LOOP, + "too deep nesting of symlinks"); + } + + err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id, *tree); if (err) { @@ -877,7 +1041,7 @@ find_path (struct grub_btrfs_data *data, return grub_errno; } - if (grub_btrfs_extent_read (data, disk, cdirel->key.object_id, + if (grub_btrfs_extent_read (data, cdirel->key.object_id, *tree, 0, tmp, grub_le_to_cpu64 (inode.size)) != (grub_ssize_t) grub_le_to_cpu64 (inode.size)) @@ -909,7 +1073,7 @@ find_path (struct grub_btrfs_data *data, case GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM: { struct grub_btrfs_root_item ri; - err = lower_bound (data, disk, &cdirel->key, &key_out, + err = lower_bound (data, &cdirel->key, &key_out, data->sblock.root_tree, &elemaddr, &elemsize, NULL); if (err) @@ -925,7 +1089,7 @@ find_path (struct grub_btrfs_data *data, grub_free (path_alloc); return grub_error (GRUB_ERR_FILE_NOT_FOUND, "file not found"); } - err = grub_btrfs_read_logical (data, disk, elemaddr, + err = grub_btrfs_read_logical (data, elemaddr, &ri, sizeof (ri)); if (err) { @@ -967,7 +1131,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, int (*hook) (const char *filename, const struct grub_dirhook_info *info)) { - struct grub_btrfs_data *data = grub_btrfs_mount (device->disk); + struct grub_btrfs_data *data = grub_btrfs_mount (device); struct grub_btrfs_key key_in, key_out; grub_err_t err; grub_disk_addr_t elemaddr; @@ -982,21 +1146,20 @@ grub_btrfs_dir (grub_device_t device, const char *path, if (!data) return grub_errno; - err = find_path (data, device->disk, path, &key_in, &tree, &type); + err = find_path (data, path, &key_in, &tree, &type); if (err) return err; if (type != GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY) return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a directory"); - err = lower_bound (data, device->disk, &key_in, &key_out, - tree, + err = lower_bound (data, &key_in, &key_out, tree, &elemaddr, &elemsize, &desc); if (err) return err; if (key_out.type != GRUB_BTRFS_ITEM_TYPE_DIR_ITEM || key_out.object_id != key_in.object_id) { - r = next (data, device->disk, &desc, &elemaddr, &elemsize, &key_out); + r = next (data, &desc, &elemaddr, &elemsize, &key_out); if (r <= 0) { free_iterator (&desc); @@ -1025,8 +1188,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, } } - err = grub_btrfs_read_logical (data, device->disk, elemaddr, - direl, elemsize); + err = grub_btrfs_read_logical (data, elemaddr, direl, elemsize); if (err) return err; @@ -1046,7 +1208,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, goto out; cdirel->name[grub_le_to_cpu16 (cdirel->n)] = c; } - r = next (data, device->disk, &desc, &elemaddr, &elemsize, &key_out); + r = next (data, &desc, &elemaddr, &elemsize, &key_out); } while (r > 0); @@ -1054,7 +1216,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, grub_free (direl); free_iterator (&desc); - grub_free (data); + grub_btrfs_unmount (data); return -r; } @@ -1062,7 +1224,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, static grub_err_t grub_btrfs_open (struct grub_file *file, const char *name) { - struct grub_btrfs_data *data = grub_btrfs_mount (file->device->disk); + struct grub_btrfs_data *data = grub_btrfs_mount (file->device); grub_err_t err; struct grub_btrfs_inode inode; grub_uint8_t type; @@ -1071,24 +1233,23 @@ grub_btrfs_open (struct grub_file *file, const char *name) if (!data) return grub_errno; - err = find_path (data, file->device->disk, name, &key_in, &data->tree, &type); + err = find_path (data, name, &key_in, &data->tree, &type); if (err) { - grub_free (data); + grub_btrfs_unmount (data); return err; } if (type != GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR) { - grub_free (data); + grub_btrfs_unmount (data); return grub_error (GRUB_ERR_BAD_FILE_TYPE, "not a regular file"); } data->inode = key_in.object_id; - err = grub_btrfs_read_inode (data, file->device->disk, &inode, data->inode, - data->tree); + err = grub_btrfs_read_inode (data, &inode, data->inode, data->tree); if (err) { - grub_free (data); + grub_btrfs_unmount (data); return err; } @@ -1101,10 +1262,7 @@ grub_btrfs_open (struct grub_file *file, const char *name) static grub_err_t grub_btrfs_close (grub_file_t file) { - struct grub_btrfs_data *data = file->data; - - grub_free (data->extent); - grub_free (data); + grub_btrfs_unmount (file->data); return GRUB_ERR_NONE; } @@ -1114,7 +1272,7 @@ grub_btrfs_read (grub_file_t file, char *buf, grub_size_t len) { struct grub_btrfs_data *data = file->data; - return grub_btrfs_extent_read (data, file->device->disk, data->inode, + return grub_btrfs_extent_read (data, data->inode, data->tree, file->offset, buf, len); } @@ -1125,7 +1283,7 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) *uuid = NULL; - data = grub_btrfs_mount (device->disk); + data = grub_btrfs_mount (device); if (! data) return grub_errno; @@ -1139,7 +1297,7 @@ grub_btrfs_uuid (grub_device_t device, char **uuid) grub_be_to_cpu16 (data->sblock.uuid[6]), grub_be_to_cpu16 (data->sblock.uuid[7])); - grub_free (data); + grub_btrfs_unmount (data); return grub_errno; } @@ -1151,13 +1309,13 @@ grub_btrfs_label (grub_device_t device, char **label) *label = NULL; - data = grub_btrfs_mount (device->disk); + data = grub_btrfs_mount (device); if (! data) return grub_errno; *label = grub_strndup (data->sblock.label, sizeof (data->sblock.label)); - grub_free (data); + grub_btrfs_unmount (data); return grub_errno; }