1 /* btrfs.c - B-tree file system. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2010,2011,2012,2013 Free Software Foundation, Inc.
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
21 * Tell zstd to expose functions that aren't part of the stable API, which
22 * aren't safe to use when linking against a dynamic library. We vendor in a
23 * specific zstd version, so we know what we're getting. We need these unstable
24 * functions to provide our own allocator, which uses grub_malloc(), to zstd.
26 #define ZSTD_STATIC_LINKING_ONLY
29 #include <grub/file.h>
31 #include <grub/misc.h>
32 #include <grub/disk.h>
34 #include <grub/types.h>
35 #include <grub/lib/crc.h>
36 #include <grub/deflate.h>
39 #include <grub/i18n.h>
40 #include <grub/btrfs.h>
41 #include <grub/crypto.h>
42 #include <grub/diskfilter.h>
43 #include <grub/safemath.h>
45 GRUB_MOD_LICENSE ("GPLv3+");
47 #define GRUB_BTRFS_SIGNATURE "_BHRfS_M"
49 /* From http://www.oberhumer.com/opensource/lzo/lzofaq.php
50 * LZO will expand incompressible data by a little amount. I still haven't
51 * computed the exact values, but I suggest using these formulas for
52 * a worst-case expansion calculation:
54 * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3
56 #define GRUB_BTRFS_LZO_BLOCK_SIZE 4096
57 #define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \
58 (GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3)
60 #define ZSTD_BTRFS_MAX_WINDOWLOG 17
61 #define ZSTD_BTRFS_MAX_INPUT (1 << ZSTD_BTRFS_MAX_WINDOWLOG)
63 typedef grub_uint8_t grub_btrfs_checksum_t
[0x20];
64 typedef grub_uint16_t grub_btrfs_uuid_t
[8];
66 struct grub_btrfs_device
68 grub_uint64_t device_id
;
70 grub_uint8_t dummy
[0x62 - 0x10];
73 struct grub_btrfs_superblock
75 grub_btrfs_checksum_t checksum
;
76 grub_btrfs_uuid_t uuid
;
77 grub_uint8_t dummy
[0x10];
78 grub_uint8_t signature
[sizeof (GRUB_BTRFS_SIGNATURE
) - 1];
79 grub_uint64_t generation
;
80 grub_uint64_t root_tree
;
81 grub_uint64_t chunk_tree
;
82 grub_uint8_t dummy2
[0x20];
83 grub_uint64_t root_dir_objectid
;
84 grub_uint8_t dummy3
[0x41];
85 struct grub_btrfs_device this_device
;
87 grub_uint8_t dummy4
[0x100];
88 grub_uint8_t bootstrap_mapping
[0x800];
93 grub_btrfs_checksum_t checksum
;
94 grub_btrfs_uuid_t uuid
;
96 grub_uint8_t dummy
[0x28];
101 struct grub_btrfs_device_desc
107 struct grub_btrfs_data
109 struct grub_btrfs_superblock sblock
;
113 struct grub_btrfs_device_desc
*devices_attached
;
114 unsigned n_devices_attached
;
115 unsigned n_devices_allocated
;
117 /* Cached extent data. */
118 grub_uint64_t extstart
;
119 grub_uint64_t extend
;
120 grub_uint64_t extino
;
121 grub_uint64_t exttree
;
123 struct grub_btrfs_extent_data
*extent
;
126 struct grub_btrfs_chunk_item
130 grub_uint64_t stripe_length
;
132 #define GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE 0x07
133 #define GRUB_BTRFS_CHUNK_TYPE_SINGLE 0x00
134 #define GRUB_BTRFS_CHUNK_TYPE_RAID0 0x08
135 #define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10
136 #define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED 0x20
137 #define GRUB_BTRFS_CHUNK_TYPE_RAID10 0x40
138 #define GRUB_BTRFS_CHUNK_TYPE_RAID5 0x80
139 #define GRUB_BTRFS_CHUNK_TYPE_RAID6 0x100
140 #define GRUB_BTRFS_CHUNK_TYPE_RAID1C3 0x200
141 #define GRUB_BTRFS_CHUNK_TYPE_RAID1C4 0x400
142 grub_uint8_t dummy2
[0xc];
143 grub_uint16_t nstripes
;
144 grub_uint16_t nsubstripes
;
147 struct grub_btrfs_chunk_stripe
149 grub_uint64_t device_id
;
150 grub_uint64_t offset
;
151 grub_btrfs_uuid_t device_uuid
;
154 struct grub_btrfs_leaf_node
156 struct grub_btrfs_key key
;
157 grub_uint32_t offset
;
161 struct grub_btrfs_internal_node
163 struct grub_btrfs_key key
;
168 struct grub_btrfs_dir_item
170 struct grub_btrfs_key key
;
171 grub_uint8_t dummy
[8];
174 #define GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR 1
175 #define GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY 2
176 #define GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK 7
181 struct grub_btrfs_leaf_descriptor
187 grub_disk_addr_t addr
;
194 struct grub_btrfs_time
197 grub_uint32_t nanosec
;
200 struct grub_btrfs_inode
202 grub_uint8_t dummy1
[0x10];
204 grub_uint8_t dummy2
[0x70];
205 struct grub_btrfs_time mtime
;
208 struct grub_btrfs_extent_data
212 grub_uint8_t compression
;
213 grub_uint8_t encryption
;
214 grub_uint16_t encoding
;
222 grub_uint64_t compressed_size
;
223 grub_uint64_t offset
;
224 grub_uint64_t filled
;
229 #define GRUB_BTRFS_EXTENT_INLINE 0
230 #define GRUB_BTRFS_EXTENT_REGULAR 1
232 #define GRUB_BTRFS_COMPRESSION_NONE 0
233 #define GRUB_BTRFS_COMPRESSION_ZLIB 1
234 #define GRUB_BTRFS_COMPRESSION_LZO 2
235 #define GRUB_BTRFS_COMPRESSION_ZSTD 3
237 #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
239 static grub_disk_addr_t superblock_sectors
[] = { 64 * 2, 64 * 1024 * 2,
240 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2
244 grub_btrfs_read_logical (struct grub_btrfs_data
*data
,
245 grub_disk_addr_t addr
, void *buf
, grub_size_t size
,
246 int recursion_depth
);
249 read_sblock (grub_disk_t disk
, struct grub_btrfs_superblock
*sb
)
251 struct grub_btrfs_superblock sblock
;
253 grub_err_t err
= GRUB_ERR_NONE
;
254 for (i
= 0; i
< ARRAY_SIZE (superblock_sectors
); i
++)
256 /* Don't try additional superblocks beyond device size. */
257 if (i
&& (grub_le_to_cpu64 (sblock
.this_device
.size
)
258 >> GRUB_DISK_SECTOR_BITS
) <= superblock_sectors
[i
])
260 err
= grub_disk_read (disk
, superblock_sectors
[i
], 0,
261 sizeof (sblock
), &sblock
);
262 if (err
== GRUB_ERR_OUT_OF_RANGE
)
265 if (grub_memcmp ((char *) sblock
.signature
, GRUB_BTRFS_SIGNATURE
,
266 sizeof (GRUB_BTRFS_SIGNATURE
) - 1) != 0)
268 if (i
== 0 || grub_le_to_cpu64 (sblock
.generation
)
269 > grub_le_to_cpu64 (sb
->generation
))
270 grub_memcpy (sb
, &sblock
, sizeof (sblock
));
273 if ((err
== GRUB_ERR_OUT_OF_RANGE
|| !err
) && i
== 0)
274 return grub_error (GRUB_ERR_BAD_FS
, "not a Btrfs filesystem");
276 if (err
== GRUB_ERR_OUT_OF_RANGE
)
277 grub_errno
= err
= GRUB_ERR_NONE
;
283 key_cmp (const struct grub_btrfs_key
*a
, const struct grub_btrfs_key
*b
)
285 if (grub_le_to_cpu64 (a
->object_id
) < grub_le_to_cpu64 (b
->object_id
))
287 if (grub_le_to_cpu64 (a
->object_id
) > grub_le_to_cpu64 (b
->object_id
))
290 if (a
->type
< b
->type
)
292 if (a
->type
> b
->type
)
295 if (grub_le_to_cpu64 (a
->offset
) < grub_le_to_cpu64 (b
->offset
))
297 if (grub_le_to_cpu64 (a
->offset
) > grub_le_to_cpu64 (b
->offset
))
303 free_iterator (struct grub_btrfs_leaf_descriptor
*desc
)
305 grub_free (desc
->data
);
309 check_btrfs_header (struct grub_btrfs_data
*data
, struct btrfs_header
*header
,
310 grub_disk_addr_t addr
)
312 if (grub_le_to_cpu64 (header
->bytenr
) != addr
)
314 grub_dprintf ("btrfs", "btrfs_header.bytenr is not equal node addr\n");
315 return grub_error (GRUB_ERR_BAD_FS
,
316 "header bytenr is not equal node addr");
318 if (grub_memcmp (data
->sblock
.uuid
, header
->uuid
, sizeof(grub_btrfs_uuid_t
)))
320 grub_dprintf ("btrfs", "btrfs_header.uuid doesn't match sblock uuid\n");
321 return grub_error (GRUB_ERR_BAD_FS
,
322 "header uuid doesn't match sblock uuid");
324 return GRUB_ERR_NONE
;
328 save_ref (struct grub_btrfs_leaf_descriptor
*desc
,
329 grub_disk_addr_t addr
, unsigned i
, unsigned m
, int l
)
332 if (desc
->allocated
< desc
->depth
)
337 if (grub_mul (desc
->allocated
, 2, &desc
->allocated
) ||
338 grub_mul (desc
->allocated
, sizeof (desc
->data
[0]), &sz
))
339 return GRUB_ERR_OUT_OF_RANGE
;
341 newdata
= grub_realloc (desc
->data
, sz
);
344 desc
->data
= newdata
;
346 desc
->data
[desc
->depth
- 1].addr
= addr
;
347 desc
->data
[desc
->depth
- 1].iter
= i
;
348 desc
->data
[desc
->depth
- 1].maxiter
= m
;
349 desc
->data
[desc
->depth
- 1].leaf
= l
;
350 return GRUB_ERR_NONE
;
354 next (struct grub_btrfs_data
*data
,
355 struct grub_btrfs_leaf_descriptor
*desc
,
356 grub_disk_addr_t
* outaddr
, grub_size_t
* outsize
,
357 struct grub_btrfs_key
*key_out
)
360 struct grub_btrfs_leaf_node leaf
;
362 for (; desc
->depth
> 0; desc
->depth
--)
364 desc
->data
[desc
->depth
- 1].iter
++;
365 if (desc
->data
[desc
->depth
- 1].iter
366 < desc
->data
[desc
->depth
- 1].maxiter
)
369 if (desc
->depth
== 0)
371 while (!desc
->data
[desc
->depth
- 1].leaf
)
373 struct grub_btrfs_internal_node node
;
374 struct btrfs_header head
;
376 err
= grub_btrfs_read_logical (data
, desc
->data
[desc
->depth
- 1].iter
378 + sizeof (struct btrfs_header
)
379 + desc
->data
[desc
->depth
- 1].addr
,
380 &node
, sizeof (node
), 0);
384 err
= grub_btrfs_read_logical (data
, grub_le_to_cpu64 (node
.addr
),
385 &head
, sizeof (head
), 0);
388 check_btrfs_header (data
, &head
, grub_le_to_cpu64 (node
.addr
));
390 save_ref (desc
, grub_le_to_cpu64 (node
.addr
), 0,
391 grub_le_to_cpu32 (head
.nitems
), !head
.level
);
393 err
= grub_btrfs_read_logical (data
, desc
->data
[desc
->depth
- 1].iter
395 + sizeof (struct btrfs_header
)
396 + desc
->data
[desc
->depth
- 1].addr
, &leaf
,
400 *outsize
= grub_le_to_cpu32 (leaf
.size
);
401 *outaddr
= desc
->data
[desc
->depth
- 1].addr
+ sizeof (struct btrfs_header
)
402 + grub_le_to_cpu32 (leaf
.offset
);
408 lower_bound (struct grub_btrfs_data
*data
,
409 const struct grub_btrfs_key
*key_in
,
410 struct grub_btrfs_key
*key_out
,
412 grub_disk_addr_t
*outaddr
, grub_size_t
*outsize
,
413 struct grub_btrfs_leaf_descriptor
*desc
,
416 grub_disk_addr_t addr
= grub_le_to_cpu64 (root
);
421 desc
->allocated
= 16;
423 desc
->data
= grub_calloc (desc
->allocated
, sizeof (desc
->data
[0]));
428 /* > 2 would work as well but be robust and allow a bit more just in case.
430 if (recursion_depth
> 10)
431 return grub_error (GRUB_ERR_BAD_FS
, "too deep btrfs virtual nesting");
433 grub_dprintf ("btrfs",
434 "retrieving %" PRIxGRUB_UINT64_T
435 " %x %" PRIxGRUB_UINT64_T
"\n",
436 key_in
->object_id
, key_in
->type
, key_in
->offset
);
441 struct btrfs_header head
;
445 /* FIXME: preread few nodes into buffer. */
446 err
= grub_btrfs_read_logical (data
, addr
, &head
, sizeof (head
),
447 recursion_depth
+ 1);
450 check_btrfs_header (data
, &head
, addr
);
451 addr
+= sizeof (head
);
455 struct grub_btrfs_internal_node node
, node_last
;
457 grub_memset (&node_last
, 0, sizeof (node_last
));
458 for (i
= 0; i
< grub_le_to_cpu32 (head
.nitems
); i
++)
460 err
= grub_btrfs_read_logical (data
, addr
+ i
* sizeof (node
),
461 &node
, sizeof (node
),
462 recursion_depth
+ 1);
466 grub_dprintf ("btrfs",
467 "internal node (depth %d) %" PRIxGRUB_UINT64_T
468 " %x %" PRIxGRUB_UINT64_T
"\n", depth
,
469 node
.key
.object_id
, node
.key
.type
,
472 if (key_cmp (&node
.key
, key_in
) == 0)
476 err
= save_ref (desc
, addr
- sizeof (head
), i
,
477 grub_le_to_cpu32 (head
.nitems
), 0);
480 addr
= grub_le_to_cpu64 (node
.addr
);
483 if (key_cmp (&node
.key
, key_in
) > 0)
492 err
= save_ref (desc
, addr
- sizeof (head
), i
- 1,
493 grub_le_to_cpu32 (head
.nitems
), 0);
496 addr
= grub_le_to_cpu64 (node_last
.addr
);
501 grub_memset (key_out
, 0, sizeof (*key_out
));
503 return save_ref (desc
, addr
- sizeof (head
), -1,
504 grub_le_to_cpu32 (head
.nitems
), 0);
505 return GRUB_ERR_NONE
;
509 struct grub_btrfs_leaf_node leaf
, leaf_last
;
511 for (i
= 0; i
< grub_le_to_cpu32 (head
.nitems
); i
++)
513 err
= grub_btrfs_read_logical (data
, addr
+ i
* sizeof (leaf
),
514 &leaf
, sizeof (leaf
),
515 recursion_depth
+ 1);
519 grub_dprintf ("btrfs",
520 "leaf (depth %d) %" PRIxGRUB_UINT64_T
521 " %x %" PRIxGRUB_UINT64_T
"\n", depth
,
522 leaf
.key
.object_id
, leaf
.key
.type
, leaf
.key
.offset
);
524 if (key_cmp (&leaf
.key
, key_in
) == 0)
526 grub_memcpy (key_out
, &leaf
.key
, sizeof (*key_out
));
527 *outsize
= grub_le_to_cpu32 (leaf
.size
);
528 *outaddr
= addr
+ grub_le_to_cpu32 (leaf
.offset
);
530 return save_ref (desc
, addr
- sizeof (head
), i
,
531 grub_le_to_cpu32 (head
.nitems
), 1);
532 return GRUB_ERR_NONE
;
535 if (key_cmp (&leaf
.key
, key_in
) > 0)
544 grub_memcpy (key_out
, &leaf_last
.key
, sizeof (*key_out
));
545 *outsize
= grub_le_to_cpu32 (leaf_last
.size
);
546 *outaddr
= addr
+ grub_le_to_cpu32 (leaf_last
.offset
);
548 return save_ref (desc
, addr
- sizeof (head
), i
- 1,
549 grub_le_to_cpu32 (head
.nitems
), 1);
550 return GRUB_ERR_NONE
;
554 grub_memset (key_out
, 0, sizeof (*key_out
));
556 return save_ref (desc
, addr
- sizeof (head
), -1,
557 grub_le_to_cpu32 (head
.nitems
), 1);
558 return GRUB_ERR_NONE
;
563 /* Context for find_device. */
564 struct find_device_ctx
566 struct grub_btrfs_data
*data
;
568 grub_device_t dev_found
;
571 /* Helper for find_device. */
573 find_device_iter (const char *name
, void *data
)
575 struct find_device_ctx
*ctx
= data
;
578 struct grub_btrfs_superblock sb
;
580 dev
= grub_device_open (name
);
585 grub_device_close (dev
);
588 err
= read_sblock (dev
->disk
, &sb
);
589 if (err
== GRUB_ERR_BAD_FS
)
591 grub_device_close (dev
);
592 grub_errno
= GRUB_ERR_NONE
;
597 grub_device_close (dev
);
601 if (grub_memcmp (ctx
->data
->sblock
.uuid
, sb
.uuid
, sizeof (sb
.uuid
)) != 0
602 || sb
.this_device
.device_id
!= ctx
->id
)
604 grub_device_close (dev
);
608 ctx
->dev_found
= dev
;
613 find_device (struct grub_btrfs_data
*data
, grub_uint64_t id
)
615 struct find_device_ctx ctx
= {
622 for (i
= 0; i
< data
->n_devices_attached
; i
++)
623 if (id
== data
->devices_attached
[i
].id
)
624 return data
->devices_attached
[i
].dev
;
626 grub_device_iterate (find_device_iter
, &ctx
);
628 data
->n_devices_attached
++;
629 if (data
->n_devices_attached
> data
->n_devices_allocated
)
634 if (grub_mul (data
->n_devices_attached
, 2, &data
->n_devices_allocated
) ||
635 grub_add (data
->n_devices_allocated
, 1, &data
->n_devices_allocated
) ||
636 grub_mul (data
->n_devices_allocated
, sizeof (data
->devices_attached
[0]), &sz
))
639 data
->devices_attached
= grub_realloc (tmp
= data
->devices_attached
, sz
);
640 if (!data
->devices_attached
)
642 data
->devices_attached
= tmp
;
646 grub_device_close (ctx
.dev_found
);
650 data
->devices_attached
[data
->n_devices_attached
- 1].id
= id
;
651 data
->devices_attached
[data
->n_devices_attached
- 1].dev
= ctx
.dev_found
;
652 return ctx
.dev_found
;
656 btrfs_read_from_chunk (struct grub_btrfs_data
*data
,
657 struct grub_btrfs_chunk_item
*chunk
,
658 grub_uint64_t stripen
, grub_uint64_t stripe_offset
,
659 int redundancy
, grub_uint64_t csize
,
662 struct grub_btrfs_chunk_stripe
*stripe
;
663 grub_disk_addr_t paddr
;
667 stripe
= (struct grub_btrfs_chunk_stripe
*) (chunk
+ 1);
668 /* Right now the redundancy handling is easy.
669 With RAID5-like it will be more difficult. */
670 stripe
+= stripen
+ redundancy
;
672 paddr
= grub_le_to_cpu64 (stripe
->offset
) + stripe_offset
;
674 grub_dprintf ("btrfs", "stripe %" PRIxGRUB_UINT64_T
675 " maps to 0x%" PRIxGRUB_UINT64_T
"\n"
676 "reading paddr 0x%" PRIxGRUB_UINT64_T
"\n",
677 stripen
, stripe
->offset
, paddr
);
679 dev
= find_device (data
, stripe
->device_id
);
682 grub_dprintf ("btrfs",
683 "couldn't find a necessary member device "
684 "of multi-device filesystem\n");
685 grub_errno
= GRUB_ERR_NONE
;
686 return GRUB_ERR_READ_ERROR
;
689 err
= grub_disk_read (dev
->disk
, paddr
>> GRUB_DISK_SECTOR_BITS
,
690 paddr
& (GRUB_DISK_SECTOR_SIZE
- 1),
695 struct raid56_buffer
{
701 rebuild_raid5 (char *dest
, struct raid56_buffer
*buffers
,
702 grub_uint64_t nstripes
, grub_uint64_t csize
)
707 for(i
= 0; buffers
[i
].data_is_valid
&& i
< nstripes
; i
++);
711 grub_dprintf ("btrfs", "called rebuild_raid5(), but all disks are OK\n");
715 grub_dprintf ("btrfs", "rebuilding RAID 5 stripe #%" PRIuGRUB_UINT64_T
"\n", i
);
717 for (i
= 0, first
= 1; i
< nstripes
; i
++)
719 if (!buffers
[i
].data_is_valid
)
723 grub_memcpy(dest
, buffers
[i
].buf
, csize
);
726 grub_crypto_xor (dest
, dest
, buffers
[i
].buf
, csize
);
731 raid6_recover_read_buffer (void *data
, int disk_nr
,
732 grub_uint64_t addr
__attribute__ ((unused
)),
733 void *dest
, grub_size_t size
)
735 struct raid56_buffer
*buffers
= data
;
737 if (!buffers
[disk_nr
].data_is_valid
)
738 return grub_errno
= GRUB_ERR_READ_ERROR
;
740 grub_memcpy(dest
, buffers
[disk_nr
].buf
, size
);
742 return grub_errno
= GRUB_ERR_NONE
;
746 rebuild_raid6 (struct raid56_buffer
*buffers
, grub_uint64_t nstripes
,
747 grub_uint64_t csize
, grub_uint64_t parities_pos
, void *dest
,
748 grub_uint64_t stripen
)
751 grub_raid6_recover_gen (buffers
, nstripes
, stripen
, parities_pos
,
752 dest
, 0, csize
, 0, raid6_recover_read_buffer
);
756 raid56_read_retry (struct grub_btrfs_data
*data
,
757 struct grub_btrfs_chunk_item
*chunk
,
758 grub_uint64_t stripe_offset
, grub_uint64_t stripen
,
759 grub_uint64_t csize
, void *buf
, grub_uint64_t parities_pos
)
761 struct raid56_buffer
*buffers
;
762 grub_uint64_t nstripes
= grub_le_to_cpu16 (chunk
->nstripes
);
763 grub_uint64_t chunk_type
= grub_le_to_cpu64 (chunk
->type
);
764 grub_err_t ret
= GRUB_ERR_OUT_OF_MEMORY
;
765 grub_uint64_t i
, failed_devices
;
767 buffers
= grub_calloc (nstripes
, sizeof (*buffers
));
771 for (i
= 0; i
< nstripes
; i
++)
773 buffers
[i
].buf
= grub_zalloc (csize
);
778 for (failed_devices
= 0, i
= 0; i
< nstripes
; i
++)
780 struct grub_btrfs_chunk_stripe
*stripe
;
781 grub_disk_addr_t paddr
;
786 * The struct grub_btrfs_chunk_stripe array lives
787 * behind struct grub_btrfs_chunk_item.
789 stripe
= (struct grub_btrfs_chunk_stripe
*) (chunk
+ 1) + i
;
791 paddr
= grub_le_to_cpu64 (stripe
->offset
) + stripe_offset
;
792 grub_dprintf ("btrfs", "reading paddr %" PRIxGRUB_UINT64_T
793 " from stripe ID %" PRIxGRUB_UINT64_T
"\n",
794 paddr
, stripe
->device_id
);
796 dev
= find_device (data
, stripe
->device_id
);
799 grub_dprintf ("btrfs", "stripe %" PRIuGRUB_UINT64_T
" FAILED (dev ID %"
800 PRIxGRUB_UINT64_T
")\n", i
, stripe
->device_id
);
805 err
= grub_disk_read (dev
->disk
, paddr
>> GRUB_DISK_SECTOR_BITS
,
806 paddr
& (GRUB_DISK_SECTOR_SIZE
- 1),
807 csize
, buffers
[i
].buf
);
808 if (err
== GRUB_ERR_NONE
)
810 buffers
[i
].data_is_valid
= 1;
811 grub_dprintf ("btrfs", "stripe %" PRIuGRUB_UINT64_T
" OK (dev ID %"
812 PRIxGRUB_UINT64_T
")\n", i
, stripe
->device_id
);
816 grub_dprintf ("btrfs", "stripe %" PRIuGRUB_UINT64_T
817 " READ FAILED (dev ID %" PRIxGRUB_UINT64_T
")\n",
818 i
, stripe
->device_id
);
823 if (failed_devices
> 1 && (chunk_type
& GRUB_BTRFS_CHUNK_TYPE_RAID5
))
825 grub_dprintf ("btrfs", "not enough disks for RAID 5: total %" PRIuGRUB_UINT64_T
826 ", missing %" PRIuGRUB_UINT64_T
"\n",
827 nstripes
, failed_devices
);
828 ret
= GRUB_ERR_READ_ERROR
;
831 else if (failed_devices
> 2 && (chunk_type
& GRUB_BTRFS_CHUNK_TYPE_RAID6
))
833 grub_dprintf ("btrfs", "not enough disks for RAID 6: total %" PRIuGRUB_UINT64_T
834 ", missing %" PRIuGRUB_UINT64_T
"\n",
835 nstripes
, failed_devices
);
836 ret
= GRUB_ERR_READ_ERROR
;
840 grub_dprintf ("btrfs", "enough disks for RAID 5: total %"
841 PRIuGRUB_UINT64_T
", missing %" PRIuGRUB_UINT64_T
"\n",
842 nstripes
, failed_devices
);
844 /* We have enough disks. So, rebuild the data. */
845 if (chunk_type
& GRUB_BTRFS_CHUNK_TYPE_RAID5
)
846 rebuild_raid5 (buf
, buffers
, nstripes
, csize
);
848 rebuild_raid6 (buffers
, nstripes
, csize
, parities_pos
, buf
, stripen
);
853 for (i
= 0; i
< nstripes
; i
++)
854 grub_free (buffers
[i
].buf
);
861 grub_btrfs_read_logical (struct grub_btrfs_data
*data
, grub_disk_addr_t addr
,
862 void *buf
, grub_size_t size
, int recursion_depth
)
867 struct grub_btrfs_key
*key
;
868 struct grub_btrfs_chunk_item
*chunk
;
871 struct grub_btrfs_key key_out
;
873 struct grub_btrfs_key key_in
;
875 grub_disk_addr_t chaddr
;
877 grub_dprintf ("btrfs", "searching for laddr %" PRIxGRUB_UINT64_T
"\n",
879 for (ptr
= data
->sblock
.bootstrap_mapping
;
880 ptr
< data
->sblock
.bootstrap_mapping
881 + sizeof (data
->sblock
.bootstrap_mapping
)
882 - sizeof (struct grub_btrfs_key
);)
884 key
= (struct grub_btrfs_key
*) ptr
;
885 if (key
->type
!= GRUB_BTRFS_ITEM_TYPE_CHUNK
)
887 chunk
= (struct grub_btrfs_chunk_item
*) (key
+ 1);
888 grub_dprintf ("btrfs",
889 "%" PRIxGRUB_UINT64_T
" %" PRIxGRUB_UINT64_T
" \n",
890 grub_le_to_cpu64 (key
->offset
),
891 grub_le_to_cpu64 (chunk
->size
));
892 if (grub_le_to_cpu64 (key
->offset
) <= addr
893 && addr
< grub_le_to_cpu64 (key
->offset
)
894 + grub_le_to_cpu64 (chunk
->size
))
896 ptr
+= sizeof (*key
) + sizeof (*chunk
)
897 + sizeof (struct grub_btrfs_chunk_stripe
)
898 * grub_le_to_cpu16 (chunk
->nstripes
);
901 key_in
.object_id
= grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK
);
902 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_CHUNK
;
903 key_in
.offset
= grub_cpu_to_le64 (addr
);
904 err
= lower_bound (data
, &key_in
, &key_out
,
905 data
->sblock
.chunk_tree
,
906 &chaddr
, &chsize
, NULL
, recursion_depth
);
910 if (key
->type
!= GRUB_BTRFS_ITEM_TYPE_CHUNK
911 || !(grub_le_to_cpu64 (key
->offset
) <= addr
))
912 return grub_error (GRUB_ERR_BAD_FS
,
913 "couldn't find the chunk descriptor");
915 chunk
= grub_malloc (chsize
);
920 err
= grub_btrfs_read_logical (data
, chaddr
, chunk
, chsize
,
930 grub_uint64_t stripen
;
931 grub_uint64_t stripe_offset
;
932 grub_uint64_t off
= addr
- grub_le_to_cpu64 (key
->offset
);
933 grub_uint64_t chunk_stripe_length
;
934 grub_uint16_t nstripes
;
935 unsigned redundancy
= 1;
938 grub_uint64_t parities_pos
= 0;
940 is_raid56
= !!(grub_le_to_cpu64 (chunk
->type
) &
941 (GRUB_BTRFS_CHUNK_TYPE_RAID5
|
942 GRUB_BTRFS_CHUNK_TYPE_RAID6
));
944 if (grub_le_to_cpu64 (chunk
->size
) <= off
)
946 grub_dprintf ("btrfs", "no chunk\n");
947 return grub_error (GRUB_ERR_BAD_FS
,
948 "couldn't find the chunk descriptor");
951 nstripes
= grub_le_to_cpu16 (chunk
->nstripes
) ? : 1;
952 chunk_stripe_length
= grub_le_to_cpu64 (chunk
->stripe_length
) ? : 512;
953 grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
954 "+0x%" PRIxGRUB_UINT64_T
955 " (%d stripes (%d substripes) of %"
956 PRIxGRUB_UINT64_T
")\n",
957 grub_le_to_cpu64 (key
->offset
),
958 grub_le_to_cpu64 (chunk
->size
),
960 grub_le_to_cpu16 (chunk
->nsubstripes
),
961 chunk_stripe_length
);
963 switch (grub_le_to_cpu64 (chunk
->type
)
964 & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE
)
966 case GRUB_BTRFS_CHUNK_TYPE_SINGLE
:
968 grub_uint64_t stripe_length
;
969 grub_dprintf ("btrfs", "single\n");
970 stripe_length
= grub_divmod64 (grub_le_to_cpu64 (chunk
->size
),
973 if (stripe_length
== 0)
975 stripen
= grub_divmod64 (off
, stripe_length
, &stripe_offset
);
976 csize
= (stripen
+ 1) * stripe_length
- off
;
979 case GRUB_BTRFS_CHUNK_TYPE_RAID1C4
:
982 case GRUB_BTRFS_CHUNK_TYPE_RAID1C3
:
985 case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED
:
986 case GRUB_BTRFS_CHUNK_TYPE_RAID1
:
988 grub_dprintf ("btrfs", "RAID1 (copies: %d)\n", ++redundancy
);
991 csize
= grub_le_to_cpu64 (chunk
->size
) - off
;
994 case GRUB_BTRFS_CHUNK_TYPE_RAID0
:
996 grub_uint64_t middle
, high
;
998 grub_dprintf ("btrfs", "RAID0\n");
999 middle
= grub_divmod64 (off
,
1000 chunk_stripe_length
,
1003 high
= grub_divmod64 (middle
, nstripes
,
1006 low
+ chunk_stripe_length
* high
;
1007 csize
= chunk_stripe_length
- low
;
1010 case GRUB_BTRFS_CHUNK_TYPE_RAID10
:
1012 grub_uint64_t middle
, high
;
1014 grub_uint16_t nsubstripes
;
1015 nsubstripes
= grub_le_to_cpu16 (chunk
->nsubstripes
) ? : 1;
1016 middle
= grub_divmod64 (off
,
1017 chunk_stripe_length
,
1020 high
= grub_divmod64 (middle
,
1021 nstripes
/ nsubstripes
? : 1,
1023 stripen
*= nsubstripes
;
1024 redundancy
= nsubstripes
;
1025 stripe_offset
= low
+ chunk_stripe_length
1027 csize
= chunk_stripe_length
- low
;
1030 case GRUB_BTRFS_CHUNK_TYPE_RAID5
:
1031 case GRUB_BTRFS_CHUNK_TYPE_RAID6
:
1033 grub_uint64_t nparities
, stripe_nr
, high
, low
;
1035 redundancy
= 1; /* no redundancy for now */
1037 if (grub_le_to_cpu64 (chunk
->type
) & GRUB_BTRFS_CHUNK_TYPE_RAID5
)
1039 grub_dprintf ("btrfs", "RAID5\n");
1044 grub_dprintf ("btrfs", "RAID6\n");
1049 * RAID 6 layout consists of several stripes spread over
1052 * Disk_0 Disk_1 Disk_2 Disk_3
1057 * Note: placement of the parities depend on row number.
1059 * Pay attention that the btrfs terminology may differ from
1060 * terminology used in other RAID implementations, e.g. LVM,
1061 * dm or md. The main difference is that btrfs calls contiguous
1062 * block of data on a given disk, e.g. A0, stripe instead of chunk.
1064 * The variables listed below have following meaning:
1065 * - stripe_nr is the stripe number excluding the parities
1066 * (A0 = 0, B0 = 1, A1 = 2, B1 = 3, etc.),
1067 * - high is the row number (0 for A0...Q0, 1 for Q1...P1, etc.),
1068 * - stripen is the disk number in a row (0 for A0, Q1, P2,
1069 * 1 for B0, A1, Q2, etc.),
1070 * - off is the logical address to read,
1071 * - chunk_stripe_length is the size of a stripe (typically 64 KiB),
1072 * - nstripes is the number of disks in a row,
1073 * - low is the offset of the data inside a stripe,
1074 * - stripe_offset is the data offset in an array,
1075 * - csize is the "potential" data to read; it will be reduced
1076 * to size if the latter is smaller,
1077 * - nparities is the number of parities (1 for RAID 5, 2 for
1078 * RAID 6); used only in RAID 5/6 code.
1080 stripe_nr
= grub_divmod64 (off
, chunk_stripe_length
, &low
);
1083 * stripen is computed without the parities
1084 * (0 for A0, A1, A2, 1 for B0, B1, B2, etc.).
1086 if (nparities
>= nstripes
)
1087 return grub_error (GRUB_ERR_BAD_FS
,
1088 "invalid RAID5/6: nparities >= nstripes");
1089 high
= grub_divmod64 (stripe_nr
, nstripes
- nparities
, &stripen
);
1092 * The stripes are spread over the disks. Every each row their
1093 * positions are shifted by 1 place. So, the real disks number
1094 * change. Hence, we have to take into account current row number
1095 * modulo nstripes (0 for A0, 1 for A1, 2 for A2, etc.).
1097 grub_divmod64 (high
+ stripen
, nstripes
, &stripen
);
1100 * parities_pos is equal to ((high - nparities) % nstripes)
1101 * (see the diagram above). However, (high - nparities) can
1102 * be negative, e.g. when high == 0, leading to an incorrect
1103 * results. (high + nstripes - nparities) is always positive and
1104 * modulo nstripes is equal to ((high - nparities) % nstripes).
1106 grub_divmod64 (high
+ nstripes
- nparities
, nstripes
, &parities_pos
);
1108 stripe_offset
= chunk_stripe_length
* high
+ low
;
1109 csize
= chunk_stripe_length
- low
;
1114 grub_dprintf ("btrfs", "unsupported RAID\n");
1115 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1116 "unsupported RAID flags %" PRIxGRUB_UINT64_T
,
1117 grub_le_to_cpu64 (chunk
->type
));
1120 return grub_error (GRUB_ERR_BUG
,
1121 "couldn't find the chunk descriptor");
1122 if (csize
> (grub_uint64_t
) size
)
1125 for (j
= 0; j
< 2; j
++)
1127 grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
1128 "+0x%" PRIxGRUB_UINT64_T
1129 " (%d stripes (%d substripes) of %"
1130 PRIxGRUB_UINT64_T
")\n",
1131 grub_le_to_cpu64 (key
->offset
),
1132 grub_le_to_cpu64 (chunk
->size
),
1133 grub_le_to_cpu16 (chunk
->nstripes
),
1134 grub_le_to_cpu16 (chunk
->nsubstripes
),
1135 grub_le_to_cpu64 (chunk
->stripe_length
));
1136 grub_dprintf ("btrfs", "reading laddr 0x%" PRIxGRUB_UINT64_T
"\n",
1141 err
= btrfs_read_from_chunk (data
, chunk
, stripen
,
1145 grub_errno
= GRUB_ERR_NONE
;
1147 err
= raid56_read_retry (data
, chunk
, stripe_offset
,
1148 stripen
, csize
, buf
, parities_pos
);
1151 for (i
= 0; i
< redundancy
; i
++)
1153 err
= btrfs_read_from_chunk (data
, chunk
, stripen
,
1159 grub_errno
= GRUB_ERR_NONE
;
1165 return grub_errno
= err
;
1168 buf
= (grub_uint8_t
*) buf
+ csize
;
1173 return GRUB_ERR_NONE
;
1176 static struct grub_btrfs_data
*
1177 grub_btrfs_mount (grub_device_t dev
)
1179 struct grub_btrfs_data
*data
;
1184 grub_error (GRUB_ERR_BAD_FS
, "not BtrFS");
1188 data
= grub_zalloc (sizeof (*data
));
1192 err
= read_sblock (dev
->disk
, &data
->sblock
);
1199 data
->n_devices_allocated
= 16;
1200 data
->devices_attached
= grub_malloc (sizeof (data
->devices_attached
[0])
1201 * data
->n_devices_allocated
);
1202 if (!data
->devices_attached
)
1207 data
->n_devices_attached
= 1;
1208 data
->devices_attached
[0].dev
= dev
;
1209 data
->devices_attached
[0].id
= data
->sblock
.this_device
.device_id
;
1215 grub_btrfs_unmount (struct grub_btrfs_data
*data
)
1218 /* The device 0 is closed one layer upper. */
1219 for (i
= 1; i
< data
->n_devices_attached
; i
++)
1220 if (data
->devices_attached
[i
].dev
)
1221 grub_device_close (data
->devices_attached
[i
].dev
);
1222 grub_free (data
->devices_attached
);
1223 grub_free (data
->extent
);
1228 grub_btrfs_read_inode (struct grub_btrfs_data
*data
,
1229 struct grub_btrfs_inode
*inode
, grub_uint64_t num
,
1232 struct grub_btrfs_key key_in
, key_out
;
1233 grub_disk_addr_t elemaddr
;
1234 grub_size_t elemsize
;
1237 key_in
.object_id
= num
;
1238 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
;
1241 err
= lower_bound (data
, &key_in
, &key_out
, tree
, &elemaddr
, &elemsize
, NULL
,
1245 if (num
!= key_out
.object_id
1246 || key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
)
1247 return grub_error (GRUB_ERR_BAD_FS
, "inode not found");
1249 return grub_btrfs_read_logical (data
, elemaddr
, inode
, sizeof (*inode
), 0);
1252 static void *grub_zstd_malloc (void *state
__attribute__((unused
)), size_t size
)
1254 return grub_malloc (size
);
1257 static void grub_zstd_free (void *state
__attribute__((unused
)), void *address
)
1259 return grub_free (address
);
1262 static ZSTD_customMem
grub_zstd_allocator (void)
1264 ZSTD_customMem allocator
;
1266 allocator
.customAlloc
= &grub_zstd_malloc
;
1267 allocator
.customFree
= &grub_zstd_free
;
1268 allocator
.opaque
= NULL
;
1274 grub_btrfs_zstd_decompress (char *ibuf
, grub_size_t isize
, grub_off_t off
,
1275 char *obuf
, grub_size_t osize
)
1277 void *allocated
= NULL
;
1278 char *otmpbuf
= obuf
;
1279 grub_size_t otmpsize
= osize
;
1280 ZSTD_DCtx
*dctx
= NULL
;
1281 grub_size_t zstd_ret
;
1282 grub_ssize_t ret
= -1;
1285 * Zstd will fail if it can't fit the entire output in the destination
1286 * buffer, so if osize isn't large enough, allocate a temporary buffer.
1288 if (otmpsize
< ZSTD_BTRFS_MAX_INPUT
)
1290 allocated
= grub_malloc (ZSTD_BTRFS_MAX_INPUT
);
1293 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "failed allocate a zstd buffer");
1296 otmpbuf
= (char *) allocated
;
1297 otmpsize
= ZSTD_BTRFS_MAX_INPUT
;
1300 /* Create the ZSTD_DCtx. */
1301 dctx
= ZSTD_createDCtx_advanced (grub_zstd_allocator ());
1304 /* ZSTD_createDCtx_advanced() only fails if it is out of memory. */
1305 grub_error (GRUB_ERR_OUT_OF_MEMORY
, "failed to create a zstd context");
1310 * Get the real input size, there may be junk at the
1313 isize
= ZSTD_findFrameCompressedSize (ibuf
, isize
);
1314 if (ZSTD_isError (isize
))
1316 grub_error (GRUB_ERR_BAD_COMPRESSED_DATA
, "zstd data corrupted");
1320 /* Decompress and check for errors. */
1321 zstd_ret
= ZSTD_decompressDCtx (dctx
, otmpbuf
, otmpsize
, ibuf
, isize
);
1322 if (ZSTD_isError (zstd_ret
))
1324 grub_error (GRUB_ERR_BAD_COMPRESSED_DATA
, "zstd data corrupted");
1329 * Move the requested data into the obuf. obuf may be equal
1330 * to otmpbuf, which is why grub_memmove() is required.
1332 grub_memmove (obuf
, otmpbuf
+ off
, osize
);
1336 grub_free (allocated
);
1337 ZSTD_freeDCtx (dctx
);
1343 grub_btrfs_lzo_decompress(char *ibuf
, grub_size_t isize
, grub_off_t off
,
1344 char *obuf
, grub_size_t osize
)
1346 grub_uint32_t total_size
, cblock_size
;
1347 grub_size_t ret
= 0;
1350 total_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
1351 ibuf
+= sizeof (total_size
);
1353 if (isize
< total_size
)
1356 /* Jump forward to first block with requested data. */
1357 while (off
>= GRUB_BTRFS_LZO_BLOCK_SIZE
)
1359 /* Don't let following uint32_t cross the page boundary. */
1360 if (((ibuf
- ibuf0
) & 0xffc) == 0xffc)
1361 ibuf
= ((ibuf
- ibuf0
+ 3) & ~3) + ibuf0
;
1363 cblock_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
1364 ibuf
+= sizeof (cblock_size
);
1366 if (cblock_size
> GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE
)
1369 off
-= GRUB_BTRFS_LZO_BLOCK_SIZE
;
1370 ibuf
+= cblock_size
;
1375 lzo_uint usize
= GRUB_BTRFS_LZO_BLOCK_SIZE
;
1377 /* Don't let following uint32_t cross the page boundary. */
1378 if (((ibuf
- ibuf0
) & 0xffc) == 0xffc)
1379 ibuf
= ((ibuf
- ibuf0
+ 3) & ~3) + ibuf0
;
1381 cblock_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
1382 ibuf
+= sizeof (cblock_size
);
1384 if (cblock_size
> GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE
)
1387 /* Block partially filled with requested data. */
1388 if (off
> 0 || osize
< GRUB_BTRFS_LZO_BLOCK_SIZE
)
1390 grub_size_t to_copy
= GRUB_BTRFS_LZO_BLOCK_SIZE
- off
;
1393 if (to_copy
> osize
)
1396 buf
= grub_malloc (GRUB_BTRFS_LZO_BLOCK_SIZE
);
1400 if (lzo1x_decompress_safe ((lzo_bytep
)ibuf
, cblock_size
, buf
, &usize
,
1407 if (to_copy
> usize
)
1409 grub_memcpy(obuf
, buf
+ off
, to_copy
);
1414 ibuf
+= cblock_size
;
1421 /* Decompress whole block directly to output buffer. */
1422 if (lzo1x_decompress_safe ((lzo_bytep
)ibuf
, cblock_size
, (lzo_bytep
)obuf
,
1423 &usize
, NULL
) != LZO_E_OK
)
1429 ibuf
+= cblock_size
;
1436 grub_btrfs_extent_read (struct grub_btrfs_data
*data
,
1437 grub_uint64_t ino
, grub_uint64_t tree
,
1438 grub_off_t pos0
, char *buf
, grub_size_t len
)
1440 grub_off_t pos
= pos0
;
1446 if (!data
->extent
|| data
->extstart
> pos
|| data
->extino
!= ino
1447 || data
->exttree
!= tree
|| data
->extend
<= pos
)
1449 struct grub_btrfs_key key_in
, key_out
;
1450 grub_disk_addr_t elemaddr
;
1451 grub_size_t elemsize
;
1453 grub_free (data
->extent
);
1454 key_in
.object_id
= ino
;
1455 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM
;
1456 key_in
.offset
= grub_cpu_to_le64 (pos
);
1457 err
= lower_bound (data
, &key_in
, &key_out
, tree
,
1458 &elemaddr
, &elemsize
, NULL
, 0);
1461 if (key_out
.object_id
!= ino
1462 || key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM
)
1464 grub_error (GRUB_ERR_BAD_FS
, "extent not found");
1467 if ((grub_ssize_t
) elemsize
< ((char *) &data
->extent
->inl
1468 - (char *) data
->extent
))
1470 grub_error (GRUB_ERR_BAD_FS
, "extent descriptor is too short");
1473 data
->extstart
= grub_le_to_cpu64 (key_out
.offset
);
1474 data
->extsize
= elemsize
;
1475 data
->extent
= grub_malloc (elemsize
);
1477 data
->exttree
= tree
;
1481 err
= grub_btrfs_read_logical (data
, elemaddr
, data
->extent
,
1486 data
->extend
= data
->extstart
+ grub_le_to_cpu64 (data
->extent
->size
);
1487 if (data
->extent
->type
== GRUB_BTRFS_EXTENT_REGULAR
1488 && (char *) data
->extent
+ elemsize
1489 >= (char *) &data
->extent
->filled
+ sizeof (data
->extent
->filled
))
1491 data
->extstart
+ grub_le_to_cpu64 (data
->extent
->filled
);
1493 grub_dprintf ("btrfs", "regular extent 0x%" PRIxGRUB_UINT64_T
"+0x%"
1494 PRIxGRUB_UINT64_T
"\n",
1495 grub_le_to_cpu64 (key_out
.offset
),
1496 grub_le_to_cpu64 (data
->extent
->size
));
1497 if (data
->extend
<= pos
)
1499 grub_error (GRUB_ERR_BAD_FS
, "extent not found");
1503 csize
= data
->extend
- pos
;
1504 extoff
= pos
- data
->extstart
;
1508 if (data
->extent
->encryption
)
1510 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1511 "encryption not supported");
1515 if (data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_NONE
1516 && data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_ZLIB
1517 && data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_LZO
1518 && data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_ZSTD
)
1520 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1521 "compression type 0x%x not supported",
1522 data
->extent
->compression
);
1526 if (data
->extent
->encoding
)
1528 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "encoding not supported");
1532 switch (data
->extent
->type
)
1534 case GRUB_BTRFS_EXTENT_INLINE
:
1535 if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_ZLIB
)
1537 if (grub_zlib_decompress (data
->extent
->inl
, data
->extsize
-
1538 ((grub_uint8_t
*) data
->extent
->inl
1539 - (grub_uint8_t
*) data
->extent
),
1541 != (grub_ssize_t
) csize
)
1544 grub_error (GRUB_ERR_BAD_COMPRESSED_DATA
,
1545 "premature end of compressed");
1549 else if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_LZO
)
1551 if (grub_btrfs_lzo_decompress(data
->extent
->inl
, data
->extsize
-
1552 ((grub_uint8_t
*) data
->extent
->inl
1553 - (grub_uint8_t
*) data
->extent
),
1555 != (grub_ssize_t
) csize
)
1558 else if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_ZSTD
)
1560 if (grub_btrfs_zstd_decompress (data
->extent
->inl
, data
->extsize
-
1561 ((grub_uint8_t
*) data
->extent
->inl
1562 - (grub_uint8_t
*) data
->extent
),
1564 != (grub_ssize_t
) csize
)
1568 grub_memcpy (buf
, data
->extent
->inl
+ extoff
, csize
);
1570 case GRUB_BTRFS_EXTENT_REGULAR
:
1571 if (!data
->extent
->laddr
)
1573 grub_memset (buf
, 0, csize
);
1577 if (data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_NONE
)
1580 grub_uint64_t zsize
;
1583 zsize
= grub_le_to_cpu64 (data
->extent
->compressed_size
);
1584 tmp
= grub_malloc (zsize
);
1587 err
= grub_btrfs_read_logical (data
,
1588 grub_le_to_cpu64 (data
->extent
->laddr
),
1596 if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_ZLIB
)
1597 ret
= grub_zlib_decompress (tmp
, zsize
, extoff
1598 + grub_le_to_cpu64 (data
->extent
->offset
),
1600 else if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_LZO
)
1601 ret
= grub_btrfs_lzo_decompress (tmp
, zsize
, extoff
1602 + grub_le_to_cpu64 (data
->extent
->offset
),
1604 else if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_ZSTD
)
1605 ret
= grub_btrfs_zstd_decompress (tmp
, zsize
, extoff
1606 + grub_le_to_cpu64 (data
->extent
->offset
),
1613 if (ret
!= (grub_ssize_t
) csize
)
1616 grub_error (GRUB_ERR_BAD_COMPRESSED_DATA
,
1617 "premature end of compressed");
1623 err
= grub_btrfs_read_logical (data
,
1624 grub_le_to_cpu64 (data
->extent
->laddr
)
1625 + grub_le_to_cpu64 (data
->extent
->offset
)
1626 + extoff
, buf
, csize
, 0);
1631 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1632 "unsupported extent type 0x%x", data
->extent
->type
);
1643 get_root (struct grub_btrfs_data
*data
, struct grub_btrfs_key
*key
,
1644 grub_uint64_t
*tree
, grub_uint8_t
*type
)
1647 grub_disk_addr_t elemaddr
;
1648 grub_size_t elemsize
;
1649 struct grub_btrfs_key key_out
, key_in
;
1650 struct grub_btrfs_root_item ri
;
1652 key_in
.object_id
= grub_cpu_to_le64_compile_time (GRUB_BTRFS_ROOT_VOL_OBJECTID
);
1654 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM
;
1655 err
= lower_bound (data
, &key_in
, &key_out
,
1656 data
->sblock
.root_tree
,
1657 &elemaddr
, &elemsize
, NULL
, 0);
1660 if (key_in
.object_id
!= key_out
.object_id
1661 || key_in
.type
!= key_out
.type
1662 || key_in
.offset
!= key_out
.offset
)
1663 return grub_error (GRUB_ERR_BAD_FS
, "no root");
1664 err
= grub_btrfs_read_logical (data
, elemaddr
, &ri
,
1668 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1670 key
->object_id
= grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK
);
1672 *type
= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
;
1673 return GRUB_ERR_NONE
;
1677 find_path (struct grub_btrfs_data
*data
,
1678 const char *path
, struct grub_btrfs_key
*key
,
1679 grub_uint64_t
*tree
, grub_uint8_t
*type
)
1681 const char *slash
= path
;
1683 grub_disk_addr_t elemaddr
;
1684 grub_size_t elemsize
;
1685 grub_size_t allocated
= 0;
1686 struct grub_btrfs_dir_item
*direl
= NULL
;
1687 struct grub_btrfs_key key_out
;
1689 grub_size_t ctokenlen
;
1690 char *path_alloc
= NULL
;
1691 char *origpath
= NULL
;
1692 unsigned symlinks_max
= 32;
1694 err
= get_root (data
, key
, tree
, type
);
1698 origpath
= grub_strdup (path
);
1704 while (path
[0] == '/')
1708 slash
= grub_strchr (path
, '/');
1710 slash
= path
+ grub_strlen (path
);
1712 ctokenlen
= slash
- path
;
1714 if (*type
!= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1716 grub_free (path_alloc
);
1717 grub_free (origpath
);
1718 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a directory"));
1721 if (ctokenlen
== 1 && ctoken
[0] == '.')
1726 if (ctokenlen
== 2 && ctoken
[0] == '.' && ctoken
[1] == '.')
1728 key
->type
= GRUB_BTRFS_ITEM_TYPE_INODE_REF
;
1731 err
= lower_bound (data
, key
, &key_out
, *tree
, &elemaddr
, &elemsize
,
1736 grub_free (path_alloc
);
1737 grub_free (origpath
);
1741 if (key_out
.type
!= key
->type
1742 || key
->object_id
!= key_out
.object_id
)
1745 grub_free (path_alloc
);
1746 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1747 grub_free (origpath
);
1751 *type
= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
;
1752 key
->object_id
= key_out
.offset
;
1759 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1760 key
->offset
= grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken
, ctokenlen
));
1762 err
= lower_bound (data
, key
, &key_out
, *tree
, &elemaddr
, &elemsize
,
1767 grub_free (path_alloc
);
1768 grub_free (origpath
);
1771 if (key_cmp (key
, &key_out
) != 0)
1774 grub_free (path_alloc
);
1775 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1776 grub_free (origpath
);
1780 struct grub_btrfs_dir_item
*cdirel
;
1781 if (elemsize
> allocated
)
1783 allocated
= 2 * elemsize
;
1785 direl
= grub_malloc (allocated
+ 1);
1788 grub_free (path_alloc
);
1789 grub_free (origpath
);
1794 err
= grub_btrfs_read_logical (data
, elemaddr
, direl
, elemsize
, 0);
1798 grub_free (path_alloc
);
1799 grub_free (origpath
);
1803 for (cdirel
= direl
;
1804 (grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1805 < (grub_ssize_t
) elemsize
;
1806 cdirel
= (void *) ((grub_uint8_t
*) (direl
+ 1)
1807 + grub_le_to_cpu16 (cdirel
->n
)
1808 + grub_le_to_cpu16 (cdirel
->m
)))
1810 if (ctokenlen
== grub_le_to_cpu16 (cdirel
->n
)
1811 && grub_memcmp (cdirel
->name
, ctoken
, ctokenlen
) == 0)
1814 if ((grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1815 >= (grub_ssize_t
) elemsize
)
1818 grub_free (path_alloc
);
1819 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1820 grub_free (origpath
);
1825 if (cdirel
->type
== GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK
)
1827 struct grub_btrfs_inode inode
;
1829 if (--symlinks_max
== 0)
1832 grub_free (path_alloc
);
1833 grub_free (origpath
);
1834 return grub_error (GRUB_ERR_SYMLINK_LOOP
,
1835 N_("too deep nesting of symlinks"));
1838 err
= grub_btrfs_read_inode (data
, &inode
,
1839 cdirel
->key
.object_id
, *tree
);
1843 grub_free (path_alloc
);
1844 grub_free (origpath
);
1847 tmp
= grub_malloc (grub_le_to_cpu64 (inode
.size
)
1848 + grub_strlen (path
) + 1);
1852 grub_free (path_alloc
);
1853 grub_free (origpath
);
1857 if (grub_btrfs_extent_read (data
, cdirel
->key
.object_id
,
1859 grub_le_to_cpu64 (inode
.size
))
1860 != (grub_ssize_t
) grub_le_to_cpu64 (inode
.size
))
1863 grub_free (path_alloc
);
1864 grub_free (origpath
);
1868 grub_memcpy (tmp
+ grub_le_to_cpu64 (inode
.size
), path
,
1869 grub_strlen (path
) + 1);
1870 grub_free (path_alloc
);
1871 path
= path_alloc
= tmp
;
1874 err
= get_root (data
, key
, tree
, type
);
1880 *type
= cdirel
->type
;
1882 switch (cdirel
->key
.type
)
1884 case GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM
:
1886 struct grub_btrfs_root_item ri
;
1887 err
= lower_bound (data
, &cdirel
->key
, &key_out
,
1888 data
->sblock
.root_tree
,
1889 &elemaddr
, &elemsize
, NULL
, 0);
1893 grub_free (path_alloc
);
1894 grub_free (origpath
);
1897 if (cdirel
->key
.object_id
!= key_out
.object_id
1898 || cdirel
->key
.type
!= key_out
.type
)
1901 grub_free (path_alloc
);
1902 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1903 grub_free (origpath
);
1906 err
= grub_btrfs_read_logical (data
, elemaddr
, &ri
,
1911 grub_free (path_alloc
);
1912 grub_free (origpath
);
1915 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1917 key
->object_id
= grub_cpu_to_le64_compile_time (GRUB_BTRFS_OBJECT_ID_CHUNK
);
1921 case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
:
1922 if (*slash
&& *type
== GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR
)
1925 grub_free (path_alloc
);
1926 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, N_("file `%s' not found"), origpath
);
1927 grub_free (origpath
);
1931 if (*type
== GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1932 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1935 grub_free (path_alloc
);
1936 grub_free (origpath
);
1938 return grub_error (GRUB_ERR_BAD_FS
, "unrecognised object type 0x%x",
1944 grub_free (origpath
);
1945 grub_free (path_alloc
);
1946 return GRUB_ERR_NONE
;
1950 grub_btrfs_dir (grub_device_t device
, const char *path
,
1951 grub_fs_dir_hook_t hook
, void *hook_data
)
1953 struct grub_btrfs_data
*data
= grub_btrfs_mount (device
);
1954 struct grub_btrfs_key key_in
, key_out
;
1956 grub_disk_addr_t elemaddr
;
1957 grub_size_t elemsize
;
1958 grub_size_t allocated
= 0;
1959 struct grub_btrfs_dir_item
*direl
= NULL
;
1960 struct grub_btrfs_leaf_descriptor desc
;
1968 err
= find_path (data
, path
, &key_in
, &tree
, &type
);
1971 grub_btrfs_unmount (data
);
1974 if (type
!= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1976 grub_btrfs_unmount (data
);
1977 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a directory"));
1980 err
= lower_bound (data
, &key_in
, &key_out
, tree
,
1981 &elemaddr
, &elemsize
, &desc
, 0);
1984 grub_btrfs_unmount (data
);
1987 if (key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
1988 || key_out
.object_id
!= key_in
.object_id
)
1990 r
= next (data
, &desc
, &elemaddr
, &elemsize
, &key_out
);
1996 struct grub_btrfs_dir_item
*cdirel
;
1997 if (key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
1998 || key_out
.object_id
!= key_in
.object_id
)
2003 if (elemsize
> allocated
)
2005 allocated
= 2 * elemsize
;
2007 direl
= grub_malloc (allocated
+ 1);
2015 err
= grub_btrfs_read_logical (data
, elemaddr
, direl
, elemsize
, 0);
2022 for (cdirel
= direl
;
2023 (grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
2024 < (grub_ssize_t
) elemsize
;
2025 cdirel
= (void *) ((grub_uint8_t
*) (direl
+ 1)
2026 + grub_le_to_cpu16 (cdirel
->n
)
2027 + grub_le_to_cpu16 (cdirel
->m
)))
2030 struct grub_btrfs_inode inode
;
2031 struct grub_dirhook_info info
;
2032 err
= grub_btrfs_read_inode (data
, &inode
, cdirel
->key
.object_id
,
2034 grub_memset (&info
, 0, sizeof (info
));
2036 grub_errno
= GRUB_ERR_NONE
;
2039 info
.mtime
= grub_le_to_cpu64 (inode
.mtime
.sec
);
2042 c
= cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)];
2043 cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)] = 0;
2044 info
.dir
= (cdirel
->type
== GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
);
2045 if (hook (cdirel
->name
, &info
, hook_data
))
2047 cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)] = c
;
2049 r
= next (data
, &desc
, &elemaddr
, &elemsize
, &key_out
);
2056 free_iterator (&desc
);
2057 grub_btrfs_unmount (data
);
2063 grub_btrfs_open (struct grub_file
*file
, const char *name
)
2065 struct grub_btrfs_data
*data
= grub_btrfs_mount (file
->device
);
2067 struct grub_btrfs_inode inode
;
2069 struct grub_btrfs_key key_in
;
2074 err
= find_path (data
, name
, &key_in
, &data
->tree
, &type
);
2077 grub_btrfs_unmount (data
);
2080 if (type
!= GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR
)
2082 grub_btrfs_unmount (data
);
2083 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, N_("not a regular file"));
2086 data
->inode
= key_in
.object_id
;
2087 err
= grub_btrfs_read_inode (data
, &inode
, data
->inode
, data
->tree
);
2090 grub_btrfs_unmount (data
);
2095 file
->size
= grub_le_to_cpu64 (inode
.size
);
2101 grub_btrfs_close (grub_file_t file
)
2103 grub_btrfs_unmount (file
->data
);
2105 return GRUB_ERR_NONE
;
2109 grub_btrfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
2111 struct grub_btrfs_data
*data
= file
->data
;
2113 return grub_btrfs_extent_read (data
, data
->inode
,
2114 data
->tree
, file
->offset
, buf
, len
);
2118 grub_btrfs_uuid (grub_device_t device
, char **uuid
)
2120 struct grub_btrfs_data
*data
;
2124 data
= grub_btrfs_mount (device
);
2128 *uuid
= grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
2129 grub_be_to_cpu16 (data
->sblock
.uuid
[0]),
2130 grub_be_to_cpu16 (data
->sblock
.uuid
[1]),
2131 grub_be_to_cpu16 (data
->sblock
.uuid
[2]),
2132 grub_be_to_cpu16 (data
->sblock
.uuid
[3]),
2133 grub_be_to_cpu16 (data
->sblock
.uuid
[4]),
2134 grub_be_to_cpu16 (data
->sblock
.uuid
[5]),
2135 grub_be_to_cpu16 (data
->sblock
.uuid
[6]),
2136 grub_be_to_cpu16 (data
->sblock
.uuid
[7]));
2138 grub_btrfs_unmount (data
);
2144 grub_btrfs_label (grub_device_t device
, char **label
)
2146 struct grub_btrfs_data
*data
;
2150 data
= grub_btrfs_mount (device
);
2154 *label
= grub_strndup (data
->sblock
.label
, sizeof (data
->sblock
.label
));
2156 grub_btrfs_unmount (data
);
2163 grub_btrfs_embed (grub_device_t device
__attribute__ ((unused
)),
2164 unsigned int *nsectors
,
2165 unsigned int max_nsectors
,
2166 grub_embed_type_t embed_type
,
2167 grub_disk_addr_t
**sectors
)
2171 if (embed_type
!= GRUB_EMBED_PCBIOS
)
2172 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
2173 "BtrFS currently supports only PC-BIOS embedding");
2175 if (64 * 2 - 1 < *nsectors
)
2176 return grub_error (GRUB_ERR_OUT_OF_RANGE
,
2177 N_("your core.img is unusually large. "
2178 "It won't fit in the embedding area"));
2180 *nsectors
= 64 * 2 - 1;
2181 if (*nsectors
> max_nsectors
)
2182 *nsectors
= max_nsectors
;
2183 *sectors
= grub_calloc (*nsectors
, sizeof (**sectors
));
2186 for (i
= 0; i
< *nsectors
; i
++)
2187 (*sectors
)[i
] = i
+ 1;
2189 return GRUB_ERR_NONE
;
2193 static struct grub_fs grub_btrfs_fs
= {
2195 .fs_dir
= grub_btrfs_dir
,
2196 .fs_open
= grub_btrfs_open
,
2197 .fs_read
= grub_btrfs_read
,
2198 .fs_close
= grub_btrfs_close
,
2199 .fs_uuid
= grub_btrfs_uuid
,
2200 .fs_label
= grub_btrfs_label
,
2202 .fs_embed
= grub_btrfs_embed
,
2203 .reserved_first_sector
= 1,
2204 .blocklist_install
= 0,
2208 GRUB_MOD_INIT (btrfs
)
2210 grub_fs_register (&grub_btrfs_fs
);
2213 GRUB_MOD_FINI (btrfs
)
2215 grub_fs_unregister (&grub_btrfs_fs
);