1 /* btrfs.c - B-tree file system. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2010 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 #include <grub/file.h>
23 #include <grub/misc.h>
24 #include <grub/disk.h>
26 #include <grub/types.h>
27 #include <grub/lib/crc.h>
28 #include <grub/deflate.h>
31 GRUB_MOD_LICENSE ("GPLv3+");
33 #define GRUB_BTRFS_SIGNATURE "_BHRfS_M"
35 /* From http://www.oberhumer.com/opensource/lzo/lzofaq.php
36 * LZO will expand incompressible data by a little amount. I still haven't
37 * computed the exact values, but I suggest using these formulas for
38 * a worst-case expansion calculation:
40 * output_block_size = input_block_size + (input_block_size / 16) + 64 + 3
42 #define GRUB_BTRFS_LZO_BLOCK_SIZE 4096
43 #define GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE (GRUB_BTRFS_LZO_BLOCK_SIZE + \
44 (GRUB_BTRFS_LZO_BLOCK_SIZE / 16) + 64 + 3)
46 typedef grub_uint8_t grub_btrfs_checksum_t
[0x20];
47 typedef grub_uint16_t grub_btrfs_uuid_t
[8];
49 struct grub_btrfs_device
51 grub_uint64_t device_id
;
52 grub_uint8_t dummy
[0x62 - 8];
53 } __attribute__ ((packed
));
55 struct grub_btrfs_superblock
57 grub_btrfs_checksum_t checksum
;
58 grub_btrfs_uuid_t uuid
;
59 grub_uint8_t dummy
[0x10];
60 grub_uint8_t signature
[sizeof (GRUB_BTRFS_SIGNATURE
) - 1];
61 grub_uint64_t generation
;
62 grub_uint64_t root_tree
;
63 grub_uint64_t chunk_tree
;
64 grub_uint8_t dummy2
[0x20];
65 grub_uint64_t root_dir_objectid
;
66 grub_uint8_t dummy3
[0x41];
67 struct grub_btrfs_device this_device
;
69 grub_uint8_t dummy4
[0x100];
70 grub_uint8_t bootstrap_mapping
[0x800];
71 } __attribute__ ((packed
));
75 grub_btrfs_checksum_t checksum
;
76 grub_btrfs_uuid_t uuid
;
77 grub_uint8_t dummy
[0x30];
80 } __attribute__ ((packed
));
82 struct grub_btrfs_device_desc
88 struct grub_btrfs_data
90 struct grub_btrfs_superblock sblock
;
94 struct grub_btrfs_device_desc
*devices_attached
;
95 unsigned n_devices_attached
;
96 unsigned n_devices_allocated
;
98 /* Cached extent data. */
99 grub_uint64_t extstart
;
100 grub_uint64_t extend
;
101 grub_uint64_t extino
;
102 grub_uint64_t exttree
;
104 struct grub_btrfs_extent_data
*extent
;
107 struct grub_btrfs_key
109 grub_uint64_t object_id
;
110 #define GRUB_BTRFS_ITEM_TYPE_INODE_ITEM 0x01
111 #define GRUB_BTRFS_ITEM_TYPE_DIR_ITEM 0x54
112 #define GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM 0x6c
113 #define GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM 0x84
114 #define GRUB_BTRFS_ITEM_TYPE_DEVICE 0xd8
115 #define GRUB_BTRFS_ITEM_TYPE_CHUNK 0xe4
117 grub_uint64_t offset
;
118 } __attribute__ ((packed
));
120 struct grub_btrfs_chunk_item
124 grub_uint64_t stripe_length
;
126 #define GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE 0x07
127 #define GRUB_BTRFS_CHUNK_TYPE_SINGLE 0x00
128 #define GRUB_BTRFS_CHUNK_TYPE_RAID0 0x08
129 #define GRUB_BTRFS_CHUNK_TYPE_RAID1 0x10
130 #define GRUB_BTRFS_CHUNK_TYPE_DUPLICATED 0x20
131 #define GRUB_BTRFS_CHUNK_TYPE_RAID10 0x40
132 grub_uint8_t dummy2
[0xc];
133 grub_uint16_t nstripes
;
134 grub_uint16_t nsubstripes
;
135 } __attribute__ ((packed
));
137 struct grub_btrfs_chunk_stripe
139 grub_uint64_t device_id
;
140 grub_uint64_t offset
;
141 grub_btrfs_uuid_t device_uuid
;
142 } __attribute__ ((packed
));
144 struct grub_btrfs_leaf_node
146 struct grub_btrfs_key key
;
147 grub_uint32_t offset
;
149 } __attribute__ ((packed
));
151 struct grub_btrfs_internal_node
153 struct grub_btrfs_key key
;
156 } __attribute__ ((packed
));
158 struct grub_btrfs_dir_item
160 struct grub_btrfs_key key
;
161 grub_uint8_t dummy
[8];
164 #define GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR 1
165 #define GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY 2
166 #define GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK 7
169 } __attribute__ ((packed
));
171 struct grub_btrfs_leaf_descriptor
177 grub_disk_addr_t addr
;
184 struct grub_btrfs_root_item
186 grub_uint8_t dummy
[0xb0];
191 struct grub_btrfs_time
194 grub_uint32_t nanosec
;
195 } __attribute__ ((aligned (4)));
197 struct grub_btrfs_inode
199 grub_uint8_t dummy1
[0x10];
201 grub_uint8_t dummy2
[0x70];
202 struct grub_btrfs_time mtime
;
203 } __attribute__ ((packed
));
205 struct grub_btrfs_extent_data
209 grub_uint8_t compression
;
210 grub_uint8_t encryption
;
211 grub_uint16_t encoding
;
219 grub_uint64_t compressed_size
;
220 grub_uint64_t offset
;
221 grub_uint64_t filled
;
224 } __attribute__ ((packed
));
226 #define GRUB_BTRFS_EXTENT_INLINE 0
227 #define GRUB_BTRFS_EXTENT_REGULAR 1
229 #define GRUB_BTRFS_COMPRESSION_NONE 0
230 #define GRUB_BTRFS_COMPRESSION_ZLIB 1
231 #define GRUB_BTRFS_COMPRESSION_LZO 2
233 #define GRUB_BTRFS_OBJECT_ID_CHUNK 0x100
235 static grub_disk_addr_t superblock_sectors
[] = { 64 * 2, 64 * 1024 * 2,
236 256 * 1048576 * 2, 1048576ULL * 1048576ULL * 2
240 grub_btrfs_read_logical (struct grub_btrfs_data
*data
,
241 grub_disk_addr_t addr
, void *buf
, grub_size_t size
);
244 read_sblock (grub_disk_t disk
, struct grub_btrfs_superblock
*sb
)
247 grub_err_t err
= GRUB_ERR_NONE
;
248 for (i
= 0; i
< ARRAY_SIZE (superblock_sectors
); i
++)
250 struct grub_btrfs_superblock sblock
;
251 err
= grub_disk_read (disk
, superblock_sectors
[i
], 0,
252 sizeof (sblock
), &sblock
);
253 if (err
== GRUB_ERR_OUT_OF_RANGE
)
256 if (grub_memcmp ((char *) sblock
.signature
, GRUB_BTRFS_SIGNATURE
,
257 sizeof (GRUB_BTRFS_SIGNATURE
) - 1) != 0)
259 if (i
== 0 || grub_le_to_cpu64 (sblock
.generation
)
260 > grub_le_to_cpu64 (sb
->generation
))
261 grub_memcpy (sb
, &sblock
, sizeof (sblock
));
264 if ((err
== GRUB_ERR_OUT_OF_RANGE
|| !err
) && i
== 0)
265 return grub_error (GRUB_ERR_BAD_FS
, "not a Btrfs filesystem");
267 if (err
== GRUB_ERR_OUT_OF_RANGE
)
268 grub_errno
= err
= GRUB_ERR_NONE
;
274 key_cmp (const struct grub_btrfs_key
*a
, const struct grub_btrfs_key
*b
)
276 if (grub_cpu_to_le64 (a
->object_id
) < grub_cpu_to_le64 (b
->object_id
))
278 if (grub_cpu_to_le64 (a
->object_id
) > grub_cpu_to_le64 (b
->object_id
))
281 if (a
->type
< b
->type
)
283 if (a
->type
> b
->type
)
286 if (grub_cpu_to_le64 (a
->offset
) < grub_cpu_to_le64 (b
->offset
))
288 if (grub_cpu_to_le64 (a
->offset
) > grub_cpu_to_le64 (b
->offset
))
294 free_iterator (struct grub_btrfs_leaf_descriptor
*desc
)
296 grub_free (desc
->data
);
300 save_ref (struct grub_btrfs_leaf_descriptor
*desc
,
301 grub_disk_addr_t addr
, unsigned i
, unsigned m
, int l
)
304 if (desc
->allocated
< desc
->depth
)
307 desc
->allocated
*= 2;
308 newdata
= grub_realloc (desc
->data
, sizeof (desc
->data
[0])
312 desc
->data
= newdata
;
314 desc
->data
[desc
->depth
- 1].addr
= addr
;
315 desc
->data
[desc
->depth
- 1].iter
= i
;
316 desc
->data
[desc
->depth
- 1].maxiter
= m
;
317 desc
->data
[desc
->depth
- 1].leaf
= l
;
318 return GRUB_ERR_NONE
;
322 next (struct grub_btrfs_data
*data
,
323 struct grub_btrfs_leaf_descriptor
*desc
,
324 grub_disk_addr_t
* outaddr
, grub_size_t
* outsize
,
325 struct grub_btrfs_key
*key_out
)
328 struct grub_btrfs_leaf_node leaf
;
330 for (; desc
->depth
> 0; desc
->depth
--)
332 desc
->data
[desc
->depth
- 1].iter
++;
333 if (desc
->data
[desc
->depth
- 1].iter
334 < desc
->data
[desc
->depth
- 1].maxiter
)
337 if (desc
->depth
== 0)
339 while (!desc
->data
[desc
->depth
- 1].leaf
)
341 struct grub_btrfs_internal_node node
;
342 struct btrfs_header head
;
344 err
= grub_btrfs_read_logical (data
, desc
->data
[desc
->depth
- 1].iter
346 + sizeof (struct btrfs_header
)
347 + desc
->data
[desc
->depth
- 1].addr
,
348 &node
, sizeof (node
));
352 err
= grub_btrfs_read_logical (data
, grub_le_to_cpu64 (node
.addr
),
353 &head
, sizeof (head
));
357 save_ref (desc
, grub_le_to_cpu64 (node
.addr
), 0,
358 grub_le_to_cpu32 (head
.nitems
), !head
.level
);
360 err
= grub_btrfs_read_logical (data
, desc
->data
[desc
->depth
- 1].iter
362 + sizeof (struct btrfs_header
)
363 + desc
->data
[desc
->depth
- 1].addr
, &leaf
,
367 *outsize
= grub_le_to_cpu32 (leaf
.size
);
368 *outaddr
= desc
->data
[desc
->depth
- 1].addr
+ sizeof (struct btrfs_header
)
369 + grub_le_to_cpu32 (leaf
.offset
);
375 lower_bound (struct grub_btrfs_data
*data
,
376 const struct grub_btrfs_key
*key_in
,
377 struct grub_btrfs_key
*key_out
,
378 grub_disk_addr_t root
,
379 grub_disk_addr_t
*outaddr
, grub_size_t
*outsize
,
380 struct grub_btrfs_leaf_descriptor
*desc
)
382 grub_disk_addr_t addr
= root
;
387 desc
->allocated
= 16;
389 desc
->data
= grub_malloc (sizeof (desc
->data
[0]) * desc
->allocated
);
394 grub_dprintf ("btrfs",
395 "retrieving %" PRIxGRUB_UINT64_T
396 " %x %" PRIxGRUB_UINT64_T
"\n",
397 key_in
->object_id
, key_in
->type
, key_in
->offset
);
402 struct btrfs_header head
;
406 /* FIXME: preread few nodes into buffer. */
407 err
= grub_btrfs_read_logical (data
, addr
, &head
, sizeof (head
));
410 addr
+= sizeof (head
);
414 struct grub_btrfs_internal_node node
, node_last
;
416 grub_memset (&node_last
, 0, sizeof (node_last
));
417 for (i
= 0; i
< grub_le_to_cpu32 (head
.nitems
); i
++)
419 err
= grub_btrfs_read_logical (data
, addr
+ i
* sizeof (node
),
420 &node
, sizeof (node
));
424 grub_dprintf ("btrfs",
425 "internal node (depth %d) %" PRIxGRUB_UINT64_T
426 " %x %" PRIxGRUB_UINT64_T
"\n", depth
,
427 node
.key
.object_id
, node
.key
.type
,
430 if (key_cmp (&node
.key
, key_in
) == 0)
434 err
= save_ref (desc
, addr
- sizeof (head
), i
,
435 grub_le_to_cpu32 (head
.nitems
), 0);
438 addr
= grub_le_to_cpu64 (node
.addr
);
441 if (key_cmp (&node
.key
, key_in
) > 0)
450 err
= save_ref (desc
, addr
- sizeof (head
), i
- 1,
451 grub_le_to_cpu32 (head
.nitems
), 0);
454 addr
= grub_le_to_cpu64 (node_last
.addr
);
459 grub_memset (key_out
, 0, sizeof (*key_out
));
461 return save_ref (desc
, addr
- sizeof (head
), -1,
462 grub_le_to_cpu32 (head
.nitems
), 0);
463 return GRUB_ERR_NONE
;
467 struct grub_btrfs_leaf_node leaf
, leaf_last
;
469 for (i
= 0; i
< grub_le_to_cpu32 (head
.nitems
); i
++)
471 err
= grub_btrfs_read_logical (data
, addr
+ i
* sizeof (leaf
),
472 &leaf
, sizeof (leaf
));
476 grub_dprintf ("btrfs",
477 "leaf (depth %d) %" PRIxGRUB_UINT64_T
478 " %x %" PRIxGRUB_UINT64_T
"\n", depth
,
479 leaf
.key
.object_id
, leaf
.key
.type
, leaf
.key
.offset
);
481 if (key_cmp (&leaf
.key
, key_in
) == 0)
483 grub_memcpy (key_out
, &leaf
.key
, sizeof (*key_out
));
484 *outsize
= grub_le_to_cpu32 (leaf
.size
);
485 *outaddr
= addr
+ grub_le_to_cpu32 (leaf
.offset
);
487 return save_ref (desc
, addr
- sizeof (head
), i
,
488 grub_le_to_cpu32 (head
.nitems
), 1);
489 return GRUB_ERR_NONE
;
492 if (key_cmp (&leaf
.key
, key_in
) > 0)
501 grub_memcpy (key_out
, &leaf_last
.key
, sizeof (*key_out
));
502 *outsize
= grub_le_to_cpu32 (leaf_last
.size
);
503 *outaddr
= addr
+ grub_le_to_cpu32 (leaf_last
.offset
);
505 return save_ref (desc
, addr
- sizeof (head
), i
- 1,
506 grub_le_to_cpu32 (head
.nitems
), 1);
507 return GRUB_ERR_NONE
;
511 grub_memset (key_out
, 0, sizeof (*key_out
));
513 return save_ref (desc
, addr
- sizeof (head
), -1,
514 grub_le_to_cpu32 (head
.nitems
), 1);
515 return GRUB_ERR_NONE
;
521 find_device (struct grub_btrfs_data
*data
, grub_uint64_t id
, int do_rescan
)
523 grub_device_t dev_found
= NULL
;
524 auto int hook (const char *name
);
525 int hook (const char *name
)
529 struct grub_btrfs_superblock sb
;
530 dev
= grub_device_open (name
);
535 grub_device_close (dev
);
538 err
= read_sblock (dev
->disk
, &sb
);
539 if (err
== GRUB_ERR_BAD_FS
)
541 grub_device_close (dev
);
542 grub_errno
= GRUB_ERR_NONE
;
547 grub_device_close (dev
);
551 if (grub_memcmp (data
->sblock
.uuid
, sb
.uuid
, sizeof (sb
.uuid
)) != 0
552 || sb
.this_device
.device_id
!= id
)
554 grub_device_close (dev
);
564 for (i
= 0; i
< data
->n_devices_attached
; i
++)
565 if (id
== data
->devices_attached
[i
].id
)
566 return data
->devices_attached
[i
].dev
;
568 grub_device_iterate (hook
);
571 grub_error (GRUB_ERR_BAD_FS
, "couldn't find a member device");
574 data
->n_devices_attached
++;
575 if (data
->n_devices_attached
> data
->n_devices_allocated
)
578 data
->n_devices_allocated
= 2 * data
->n_devices_attached
+ 1;
579 data
->devices_attached
580 = grub_realloc (tmp
= data
->devices_attached
,
581 data
->n_devices_allocated
582 * sizeof (data
->devices_attached
[0]));
583 if (!data
->devices_attached
)
585 grub_device_close (dev_found
);
586 data
->devices_attached
= tmp
;
590 data
->devices_attached
[data
->n_devices_attached
- 1].id
= id
;
591 data
->devices_attached
[data
->n_devices_attached
- 1].dev
= dev_found
;
596 grub_btrfs_read_logical (struct grub_btrfs_data
*data
, grub_disk_addr_t addr
,
597 void *buf
, grub_size_t size
)
602 struct grub_btrfs_key
*key
;
603 struct grub_btrfs_chunk_item
*chunk
;
606 struct grub_btrfs_key key_out
;
609 struct grub_btrfs_key key_in
;
611 grub_disk_addr_t chaddr
;
613 grub_dprintf ("btrfs", "searching for laddr %" PRIxGRUB_UINT64_T
"\n",
615 for (ptr
= data
->sblock
.bootstrap_mapping
;
616 ptr
< data
->sblock
.bootstrap_mapping
617 + sizeof (data
->sblock
.bootstrap_mapping
)
618 - sizeof (struct grub_btrfs_key
);)
620 key
= (struct grub_btrfs_key
*) ptr
;
621 if (key
->type
!= GRUB_BTRFS_ITEM_TYPE_CHUNK
)
623 chunk
= (struct grub_btrfs_chunk_item
*) (key
+ 1);
624 grub_dprintf ("btrfs",
625 "%" PRIxGRUB_UINT64_T
" %" PRIxGRUB_UINT64_T
" \n",
626 grub_le_to_cpu64 (key
->offset
),
627 grub_le_to_cpu64 (chunk
->size
));
628 if (grub_le_to_cpu64 (key
->offset
) <= addr
629 && addr
< grub_le_to_cpu64 (key
->offset
)
630 + grub_le_to_cpu64 (chunk
->size
))
632 ptr
+= sizeof (*key
) + sizeof (*chunk
)
633 + sizeof (struct grub_btrfs_chunk_stripe
)
634 * grub_le_to_cpu16 (chunk
->nstripes
);
637 key_in
.object_id
= GRUB_BTRFS_OBJECT_ID_CHUNK
;
638 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_CHUNK
;
639 key_in
.offset
= addr
;
640 err
= lower_bound (data
, &key_in
, &key_out
,
641 grub_le_to_cpu64 (data
->sblock
.chunk_tree
),
642 &chaddr
, &chsize
, NULL
);
646 if (key
->type
!= GRUB_BTRFS_ITEM_TYPE_CHUNK
647 || !(grub_le_to_cpu64 (key
->offset
) <= addr
))
648 return grub_error (GRUB_ERR_BAD_FS
,
649 "couldn't find the chunk descriptor");
651 chunk
= grub_malloc (chsize
);
656 err
= grub_btrfs_read_logical (data
, chaddr
, chunk
, chsize
);
665 grub_uint64_t stripen
;
666 grub_uint64_t stripe_offset
;
667 grub_uint64_t off
= addr
- grub_le_to_cpu64 (key
->offset
);
668 unsigned redundancy
= 1;
671 if (grub_le_to_cpu64 (chunk
->size
) <= off
)
673 grub_dprintf ("btrfs", "no chunk\n");
674 return grub_error (GRUB_ERR_BAD_FS
,
675 "couldn't find the chunk descriptor");
678 grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
679 "+0x%" PRIxGRUB_UINT64_T
680 " (%d stripes (%d substripes) of %"
681 PRIxGRUB_UINT64_T
")\n",
682 grub_le_to_cpu64 (key
->offset
),
683 grub_le_to_cpu64 (chunk
->size
),
684 grub_le_to_cpu16 (chunk
->nstripes
),
685 grub_le_to_cpu16 (chunk
->nsubstripes
),
686 grub_le_to_cpu64 (chunk
->stripe_length
));
688 switch (grub_le_to_cpu64 (chunk
->type
)
689 & ~GRUB_BTRFS_CHUNK_TYPE_BITS_DONTCARE
)
691 case GRUB_BTRFS_CHUNK_TYPE_SINGLE
:
693 grub_uint64_t stripe_length
;
694 grub_dprintf ("btrfs", "single\n");
695 stripe_length
= grub_divmod64 (grub_le_to_cpu64 (chunk
->size
),
696 grub_le_to_cpu16 (chunk
->nstripes
),
698 stripen
= grub_divmod64 (off
, stripe_length
, &stripe_offset
);
699 csize
= (stripen
+ 1) * stripe_length
- off
;
702 case GRUB_BTRFS_CHUNK_TYPE_DUPLICATED
:
703 case GRUB_BTRFS_CHUNK_TYPE_RAID1
:
705 grub_dprintf ("btrfs", "RAID1\n");
708 csize
= grub_le_to_cpu64 (chunk
->size
) - off
;
712 case GRUB_BTRFS_CHUNK_TYPE_RAID0
:
714 grub_uint64_t middle
, high
;
716 grub_dprintf ("btrfs", "RAID0\n");
717 middle
= grub_divmod64 (off
,
718 grub_le_to_cpu64 (chunk
->stripe_length
),
721 high
= grub_divmod64 (middle
, grub_le_to_cpu16 (chunk
->nstripes
),
724 low
+ grub_le_to_cpu64 (chunk
->stripe_length
) * high
;
725 csize
= grub_le_to_cpu64 (chunk
->stripe_length
) - low
;
728 case GRUB_BTRFS_CHUNK_TYPE_RAID10
:
730 grub_uint64_t middle
, high
;
732 middle
= grub_divmod64 (off
,
733 grub_le_to_cpu64 (chunk
->stripe_length
),
736 high
= grub_divmod64 (middle
,
737 grub_le_to_cpu16 (chunk
->nstripes
)
738 / grub_le_to_cpu16 (chunk
->nsubstripes
),
740 stripen
*= grub_le_to_cpu16 (chunk
->nsubstripes
);
741 redundancy
= grub_le_to_cpu16 (chunk
->nsubstripes
);
742 stripe_offset
= low
+ grub_le_to_cpu64 (chunk
->stripe_length
)
744 csize
= grub_le_to_cpu64 (chunk
->stripe_length
) - low
;
748 grub_dprintf ("btrfs", "unsupported RAID\n");
749 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
750 "unsupported RAID flags %" PRIxGRUB_UINT64_T
,
751 grub_le_to_cpu64 (chunk
->type
));
754 return grub_error (GRUB_ERR_BUG
,
755 "couldn't find the chunk descriptor");
756 if ((grub_size_t
) csize
> size
)
759 for (j
= 0; j
< 2; j
++)
761 for (i
= 0; i
< redundancy
; i
++)
763 struct grub_btrfs_chunk_stripe
*stripe
;
764 grub_disk_addr_t paddr
;
766 stripe
= (struct grub_btrfs_chunk_stripe
*) (chunk
+ 1);
767 /* Right now the redundancy handling is easy.
768 With RAID5-like it will be more difficult. */
769 stripe
+= stripen
+ i
;
771 paddr
= stripe
->offset
+ stripe_offset
;
773 grub_dprintf ("btrfs", "chunk 0x%" PRIxGRUB_UINT64_T
774 "+0x%" PRIxGRUB_UINT64_T
775 " (%d stripes (%d substripes) of %"
776 PRIxGRUB_UINT64_T
") stripe %" PRIxGRUB_UINT64_T
777 " maps to 0x%" PRIxGRUB_UINT64_T
"\n",
778 grub_le_to_cpu64 (key
->offset
),
779 grub_le_to_cpu64 (chunk
->size
),
780 grub_le_to_cpu16 (chunk
->nstripes
),
781 grub_le_to_cpu16 (chunk
->nsubstripes
),
782 grub_le_to_cpu64 (chunk
->stripe_length
),
783 stripen
, stripe
->offset
);
784 grub_dprintf ("btrfs", "reading paddr 0x%" PRIxGRUB_UINT64_T
785 " for laddr 0x%" PRIxGRUB_UINT64_T
"\n", paddr
,
788 dev
= find_device (data
, stripe
->device_id
, j
);
792 grub_errno
= GRUB_ERR_NONE
;
796 err
= grub_disk_read (dev
->disk
, paddr
>> GRUB_DISK_SECTOR_BITS
,
797 paddr
& (GRUB_DISK_SECTOR_SIZE
- 1),
801 grub_errno
= GRUB_ERR_NONE
;
807 return grub_errno
= err
;
810 buf
= (grub_uint8_t
*) buf
+ csize
;
815 return GRUB_ERR_NONE
;
818 static struct grub_btrfs_data
*
819 grub_btrfs_mount (grub_device_t dev
)
821 struct grub_btrfs_data
*data
;
826 grub_error (GRUB_ERR_BAD_FS
, "not BtrFS");
830 data
= grub_zalloc (sizeof (*data
));
834 err
= read_sblock (dev
->disk
, &data
->sblock
);
841 data
->n_devices_allocated
= 16;
842 data
->devices_attached
= grub_malloc (sizeof (data
->devices_attached
[0])
843 * data
->n_devices_allocated
);
844 if (!data
->devices_attached
)
849 data
->n_devices_attached
= 1;
850 data
->devices_attached
[0].dev
= dev
;
851 data
->devices_attached
[0].id
= data
->sblock
.this_device
.device_id
;
857 grub_btrfs_unmount (struct grub_btrfs_data
*data
)
860 /* The device 0 is closed one layer upper. */
861 for (i
= 1; i
< data
->n_devices_attached
; i
++)
862 grub_device_close (data
->devices_attached
[i
].dev
);
863 grub_free (data
->devices_attached
);
864 grub_free (data
->extent
);
869 grub_btrfs_read_inode (struct grub_btrfs_data
*data
,
870 struct grub_btrfs_inode
*inode
, grub_uint64_t num
,
873 struct grub_btrfs_key key_in
, key_out
;
874 grub_disk_addr_t elemaddr
;
875 grub_size_t elemsize
;
878 key_in
.object_id
= num
;
879 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
;
882 err
= lower_bound (data
, &key_in
, &key_out
, tree
, &elemaddr
, &elemsize
, NULL
);
885 if (num
!= key_out
.object_id
886 || key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
)
887 return grub_error (GRUB_ERR_BAD_FS
, "inode not found");
889 return grub_btrfs_read_logical (data
, elemaddr
, inode
, sizeof (*inode
));
893 grub_btrfs_lzo_decompress(char *ibuf
, grub_size_t isize
, grub_off_t off
,
894 char *obuf
, grub_size_t osize
)
896 grub_uint32_t total_size
, cblock_size
, ret
= 0;
897 unsigned char buf
[GRUB_BTRFS_LZO_BLOCK_SIZE
];
899 total_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
900 ibuf
+= sizeof (total_size
);
902 if (isize
< total_size
)
905 /* Jump forward to first block with requested data. */
906 while (off
>= GRUB_BTRFS_LZO_BLOCK_SIZE
)
908 cblock_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
909 ibuf
+= sizeof (cblock_size
);
911 if (cblock_size
> GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE
)
914 off
-= GRUB_BTRFS_LZO_BLOCK_SIZE
;
920 lzo_uint usize
= GRUB_BTRFS_LZO_BLOCK_SIZE
;
922 cblock_size
= grub_le_to_cpu32 (grub_get_unaligned32 (ibuf
));
923 ibuf
+= sizeof (cblock_size
);
925 if (cblock_size
> GRUB_BTRFS_LZO_BLOCK_MAX_CSIZE
)
928 /* Block partially filled with requested data. */
929 if (off
> 0 || osize
< GRUB_BTRFS_LZO_BLOCK_SIZE
)
931 grub_size_t to_copy
= grub_min(osize
, GRUB_BTRFS_LZO_BLOCK_SIZE
- off
);
933 if (lzo1x_decompress_safe ((lzo_bytep
)ibuf
, cblock_size
, buf
, &usize
,
937 to_copy
= grub_min(to_copy
, usize
);
938 grub_memcpy(obuf
, buf
+ off
, to_copy
);
948 /* Decompress whole block directly to output buffer. */
949 if (lzo1x_decompress_safe ((lzo_bytep
)ibuf
, cblock_size
, (lzo_bytep
)obuf
,
950 &usize
, NULL
) != LZO_E_OK
)
963 grub_btrfs_extent_read (struct grub_btrfs_data
*data
,
964 grub_uint64_t ino
, grub_uint64_t tree
,
965 grub_off_t pos0
, char *buf
, grub_size_t len
)
967 grub_off_t pos
= pos0
;
973 if (!data
->extent
|| data
->extstart
> pos
|| data
->extino
!= ino
974 || data
->exttree
!= tree
|| data
->extend
<= pos
)
976 struct grub_btrfs_key key_in
, key_out
;
977 grub_disk_addr_t elemaddr
;
978 grub_size_t elemsize
;
980 grub_free (data
->extent
);
981 key_in
.object_id
= ino
;
982 key_in
.type
= GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM
;
983 key_in
.offset
= grub_cpu_to_le64 (pos
);
984 err
= lower_bound (data
, &key_in
, &key_out
, tree
,
985 &elemaddr
, &elemsize
, NULL
);
988 if (key_out
.object_id
!= ino
989 || key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_EXTENT_ITEM
)
991 grub_error (GRUB_ERR_BAD_FS
, "extent not found");
994 if ((grub_ssize_t
) elemsize
< ((char *) &data
->extent
->inl
995 - (char *) data
->extent
))
997 grub_error (GRUB_ERR_BAD_FS
, "extent descriptor is too short");
1000 data
->extstart
= grub_le_to_cpu64 (key_out
.offset
);
1001 data
->extsize
= elemsize
;
1002 data
->extent
= grub_malloc (elemsize
);
1004 data
->exttree
= tree
;
1008 err
= grub_btrfs_read_logical (data
, elemaddr
, data
->extent
,
1013 data
->extend
= data
->extstart
+ grub_le_to_cpu64 (data
->extent
->size
);
1014 if (data
->extent
->type
== GRUB_BTRFS_EXTENT_REGULAR
1015 && (char *) &data
->extent
+ elemsize
1016 >= (char *) &data
->extent
->filled
+ sizeof (data
->extent
->filled
))
1018 data
->extstart
+ grub_le_to_cpu64 (data
->extent
->filled
);
1020 grub_dprintf ("btrfs", "regular extent 0x%" PRIxGRUB_UINT64_T
"+0x%"
1021 PRIxGRUB_UINT64_T
"\n",
1022 grub_le_to_cpu64 (key_out
.offset
),
1023 grub_le_to_cpu64 (data
->extent
->size
));
1024 if (data
->extend
<= pos
)
1026 grub_error (GRUB_ERR_BAD_FS
, "extent not found");
1030 csize
= data
->extend
- pos
;
1031 extoff
= pos
- data
->extstart
;
1035 if (data
->extent
->encryption
)
1037 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1038 "encryption not supported");
1042 if (data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_NONE
1043 && data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_ZLIB
1044 && data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_LZO
)
1046 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1047 "compression type 0x%x not supported",
1048 data
->extent
->compression
);
1052 if (data
->extent
->encoding
)
1054 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
, "encoding not supported");
1058 switch (data
->extent
->type
)
1060 case GRUB_BTRFS_EXTENT_INLINE
:
1061 if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_ZLIB
)
1063 if (grub_zlib_decompress (data
->extent
->inl
, data
->extsize
-
1064 ((grub_uint8_t
*) data
->extent
->inl
1065 - (grub_uint8_t
*) data
->extent
),
1067 != (grub_ssize_t
) csize
)
1070 else if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_LZO
)
1072 if (grub_btrfs_lzo_decompress(data
->extent
->inl
, data
->extsize
-
1073 ((grub_uint8_t
*) data
->extent
->inl
1074 - (grub_uint8_t
*) data
->extent
),
1076 != (grub_ssize_t
) csize
)
1080 grub_memcpy (buf
, data
->extent
->inl
+ extoff
, csize
);
1082 case GRUB_BTRFS_EXTENT_REGULAR
:
1083 if (!data
->extent
->laddr
)
1085 grub_memset (buf
, 0, csize
);
1089 if (data
->extent
->compression
!= GRUB_BTRFS_COMPRESSION_NONE
)
1092 grub_uint64_t zsize
;
1095 zsize
= grub_le_to_cpu64 (data
->extent
->compressed_size
);
1096 tmp
= grub_malloc (zsize
);
1099 err
= grub_btrfs_read_logical (data
,
1100 grub_le_to_cpu64 (data
->extent
->laddr
),
1108 if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_ZLIB
)
1109 ret
= grub_zlib_decompress (tmp
, zsize
, extoff
1110 + grub_le_to_cpu64 (data
->extent
->offset
),
1112 else if (data
->extent
->compression
== GRUB_BTRFS_COMPRESSION_LZO
)
1113 ret
= grub_btrfs_lzo_decompress (tmp
, zsize
, extoff
1114 + grub_le_to_cpu64 (data
->extent
->offset
),
1121 if (ret
!= (grub_ssize_t
) csize
)
1126 err
= grub_btrfs_read_logical (data
,
1127 grub_le_to_cpu64 (data
->extent
->laddr
)
1128 + grub_le_to_cpu64 (data
->extent
->offset
)
1129 + extoff
, buf
, csize
);
1134 grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1135 "unsupported extent type 0x%x", data
->extent
->type
);
1146 find_path (struct grub_btrfs_data
*data
,
1147 const char *path
, struct grub_btrfs_key
*key
,
1148 grub_uint64_t
*tree
, grub_uint8_t
*type
)
1150 const char *slash
= path
;
1152 grub_disk_addr_t elemaddr
;
1153 grub_size_t elemsize
;
1154 grub_size_t allocated
= 0;
1155 struct grub_btrfs_dir_item
*direl
= NULL
;
1156 struct grub_btrfs_key key_out
;
1159 grub_size_t ctokenlen
;
1160 char *path_alloc
= NULL
;
1161 char *origpath
= NULL
;
1162 unsigned symlinks_max
= 32;
1164 *type
= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
;
1165 *tree
= data
->sblock
.root_tree
;
1166 key
->object_id
= data
->sblock
.root_dir_objectid
;
1167 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1170 origpath
= grub_strdup (path
);
1178 while (path
[0] == '/')
1182 slash
= grub_strchr (path
, '/');
1184 slash
= path
+ grub_strlen (path
);
1186 ctokenlen
= slash
- path
;
1191 ctokenlen
= sizeof ("default") - 1;
1194 if (*type
!= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1196 grub_free (path_alloc
);
1197 grub_free (origpath
);
1198 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
1201 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1202 key
->offset
= grub_cpu_to_le64 (~grub_getcrc32c (1, ctoken
, ctokenlen
));
1204 err
= lower_bound (data
, key
, &key_out
, *tree
, &elemaddr
, &elemsize
,
1209 grub_free (path_alloc
);
1210 grub_free (origpath
);
1213 if (key_cmp (key
, &key_out
) != 0)
1216 grub_free (path_alloc
);
1217 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file `%s' not found", origpath
);
1218 grub_free (origpath
);
1222 struct grub_btrfs_dir_item
*cdirel
;
1223 if (elemsize
> allocated
)
1225 allocated
= 2 * elemsize
;
1227 direl
= grub_malloc (allocated
+ 1);
1230 grub_free (path_alloc
);
1231 grub_free (origpath
);
1236 err
= grub_btrfs_read_logical (data
, elemaddr
, direl
, elemsize
);
1240 grub_free (path_alloc
);
1241 grub_free (origpath
);
1245 for (cdirel
= direl
;
1246 (grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1247 < (grub_ssize_t
) elemsize
;
1248 cdirel
= (void *) ((grub_uint8_t
*) (direl
+ 1)
1249 + grub_le_to_cpu16 (cdirel
->n
)
1250 + grub_le_to_cpu16 (cdirel
->m
)))
1252 if (ctokenlen
== grub_le_to_cpu16 (cdirel
->n
)
1253 && grub_memcmp (cdirel
->name
, ctoken
, ctokenlen
) == 0)
1256 if ((grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1257 >= (grub_ssize_t
) elemsize
)
1260 grub_free (path_alloc
);
1261 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file `%s' not found", origpath
);
1262 grub_free (origpath
);
1269 if (cdirel
->type
== GRUB_BTRFS_DIR_ITEM_TYPE_SYMLINK
)
1271 struct grub_btrfs_inode inode
;
1273 if (--symlinks_max
== 0)
1276 grub_free (path_alloc
);
1277 grub_free (origpath
);
1278 return grub_error (GRUB_ERR_SYMLINK_LOOP
,
1279 "too deep nesting of symlinks");
1282 err
= grub_btrfs_read_inode (data
, &inode
,
1283 cdirel
->key
.object_id
, *tree
);
1287 grub_free (path_alloc
);
1288 grub_free (origpath
);
1291 tmp
= grub_malloc (grub_le_to_cpu64 (inode
.size
)
1292 + grub_strlen (path
) + 1);
1296 grub_free (path_alloc
);
1297 grub_free (origpath
);
1301 if (grub_btrfs_extent_read (data
, cdirel
->key
.object_id
,
1303 grub_le_to_cpu64 (inode
.size
))
1304 != (grub_ssize_t
) grub_le_to_cpu64 (inode
.size
))
1307 grub_free (path_alloc
);
1308 grub_free (origpath
);
1312 grub_memcpy (tmp
+ grub_le_to_cpu64 (inode
.size
), path
,
1313 grub_strlen (path
) + 1);
1314 grub_free (path_alloc
);
1315 path
= path_alloc
= tmp
;
1318 *type
= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
;
1319 *tree
= data
->sblock
.root_tree
;
1320 key
->object_id
= data
->sblock
.root_dir_objectid
;
1321 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1327 *type
= cdirel
->type
;
1329 switch (cdirel
->key
.type
)
1331 case GRUB_BTRFS_ITEM_TYPE_ROOT_ITEM
:
1333 struct grub_btrfs_root_item ri
;
1334 err
= lower_bound (data
, &cdirel
->key
, &key_out
,
1335 data
->sblock
.root_tree
,
1336 &elemaddr
, &elemsize
, NULL
);
1340 grub_free (path_alloc
);
1341 grub_free (origpath
);
1344 if (cdirel
->key
.object_id
!= key_out
.object_id
1345 || cdirel
->key
.type
!= key_out
.type
)
1348 grub_free (path_alloc
);
1349 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file `%s' not found", origpath
);
1350 grub_free (origpath
);
1353 err
= grub_btrfs_read_logical (data
, elemaddr
, &ri
, sizeof (ri
));
1357 grub_free (path_alloc
);
1358 grub_free (origpath
);
1361 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1363 key
->object_id
= GRUB_BTRFS_OBJECT_ID_CHUNK
;
1364 *tree
= grub_le_to_cpu64 (ri
.tree
);
1367 case GRUB_BTRFS_ITEM_TYPE_INODE_ITEM
:
1368 if (*slash
&& *type
== GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR
)
1371 grub_free (path_alloc
);
1372 err
= grub_error (GRUB_ERR_FILE_NOT_FOUND
, "file `%s' not found", origpath
);
1373 grub_free (origpath
);
1377 if (*type
== GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1378 key
->type
= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
;
1381 grub_free (path_alloc
);
1382 grub_free (origpath
);
1384 return grub_error (GRUB_ERR_BAD_FS
, "unrecognised object type 0x%x",
1390 grub_free (origpath
);
1391 grub_free (path_alloc
);
1392 return GRUB_ERR_NONE
;
1396 grub_btrfs_dir (grub_device_t device
, const char *path
,
1397 int (*hook
) (const char *filename
,
1398 const struct grub_dirhook_info
*info
))
1400 struct grub_btrfs_data
*data
= grub_btrfs_mount (device
);
1401 struct grub_btrfs_key key_in
, key_out
;
1403 grub_disk_addr_t elemaddr
;
1404 grub_size_t elemsize
;
1405 grub_size_t allocated
= 0;
1406 struct grub_btrfs_dir_item
*direl
= NULL
;
1407 struct grub_btrfs_leaf_descriptor desc
;
1415 err
= find_path (data
, path
, &key_in
, &tree
, &type
);
1418 grub_btrfs_unmount (data
);
1421 if (type
!= GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
)
1423 grub_btrfs_unmount (data
);
1424 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a directory");
1427 err
= lower_bound (data
, &key_in
, &key_out
, tree
, &elemaddr
, &elemsize
, &desc
);
1430 grub_btrfs_unmount (data
);
1433 if (key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
1434 || key_out
.object_id
!= key_in
.object_id
)
1436 r
= next (data
, &desc
, &elemaddr
, &elemsize
, &key_out
);
1442 struct grub_btrfs_dir_item
*cdirel
;
1443 if (key_out
.type
!= GRUB_BTRFS_ITEM_TYPE_DIR_ITEM
1444 || key_out
.object_id
!= key_in
.object_id
)
1449 if (elemsize
> allocated
)
1451 allocated
= 2 * elemsize
;
1453 direl
= grub_malloc (allocated
+ 1);
1461 err
= grub_btrfs_read_logical (data
, elemaddr
, direl
, elemsize
);
1468 for (cdirel
= direl
;
1469 (grub_uint8_t
*) cdirel
- (grub_uint8_t
*) direl
1470 < (grub_ssize_t
) elemsize
;
1471 cdirel
= (void *) ((grub_uint8_t
*) (direl
+ 1)
1472 + grub_le_to_cpu16 (cdirel
->n
)
1473 + grub_le_to_cpu16 (cdirel
->m
)))
1476 struct grub_btrfs_inode inode
;
1477 struct grub_dirhook_info info
;
1478 err
= grub_btrfs_read_inode (data
, &inode
, cdirel
->key
.object_id
,
1480 grub_memset (&info
, 0, sizeof (info
));
1482 grub_errno
= GRUB_ERR_NONE
;
1485 info
.mtime
= inode
.mtime
.sec
;
1488 c
= cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)];
1489 cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)] = 0;
1490 info
.dir
= (cdirel
->type
== GRUB_BTRFS_DIR_ITEM_TYPE_DIRECTORY
);
1491 if (hook (cdirel
->name
, &info
))
1493 cdirel
->name
[grub_le_to_cpu16 (cdirel
->n
)] = c
;
1495 r
= next (data
, &desc
, &elemaddr
, &elemsize
, &key_out
);
1502 free_iterator (&desc
);
1503 grub_btrfs_unmount (data
);
1509 grub_btrfs_open (struct grub_file
*file
, const char *name
)
1511 struct grub_btrfs_data
*data
= grub_btrfs_mount (file
->device
);
1513 struct grub_btrfs_inode inode
;
1515 struct grub_btrfs_key key_in
;
1520 err
= find_path (data
, name
, &key_in
, &data
->tree
, &type
);
1523 grub_btrfs_unmount (data
);
1526 if (type
!= GRUB_BTRFS_DIR_ITEM_TYPE_REGULAR
)
1528 grub_btrfs_unmount (data
);
1529 return grub_error (GRUB_ERR_BAD_FILE_TYPE
, "not a regular file");
1532 data
->inode
= key_in
.object_id
;
1533 err
= grub_btrfs_read_inode (data
, &inode
, data
->inode
, data
->tree
);
1536 grub_btrfs_unmount (data
);
1541 file
->size
= grub_le_to_cpu64 (inode
.size
);
1547 grub_btrfs_close (grub_file_t file
)
1549 grub_btrfs_unmount (file
->data
);
1551 return GRUB_ERR_NONE
;
1555 grub_btrfs_read (grub_file_t file
, char *buf
, grub_size_t len
)
1557 struct grub_btrfs_data
*data
= file
->data
;
1559 return grub_btrfs_extent_read (data
, data
->inode
,
1560 data
->tree
, file
->offset
, buf
, len
);
1564 grub_btrfs_uuid (grub_device_t device
, char **uuid
)
1566 struct grub_btrfs_data
*data
;
1570 data
= grub_btrfs_mount (device
);
1574 *uuid
= grub_xasprintf ("%04x%04x-%04x-%04x-%04x-%04x%04x%04x",
1575 grub_be_to_cpu16 (data
->sblock
.uuid
[0]),
1576 grub_be_to_cpu16 (data
->sblock
.uuid
[1]),
1577 grub_be_to_cpu16 (data
->sblock
.uuid
[2]),
1578 grub_be_to_cpu16 (data
->sblock
.uuid
[3]),
1579 grub_be_to_cpu16 (data
->sblock
.uuid
[4]),
1580 grub_be_to_cpu16 (data
->sblock
.uuid
[5]),
1581 grub_be_to_cpu16 (data
->sblock
.uuid
[6]),
1582 grub_be_to_cpu16 (data
->sblock
.uuid
[7]));
1584 grub_btrfs_unmount (data
);
1590 grub_btrfs_label (grub_device_t device
, char **label
)
1592 struct grub_btrfs_data
*data
;
1596 data
= grub_btrfs_mount (device
);
1600 *label
= grub_strndup (data
->sblock
.label
, sizeof (data
->sblock
.label
));
1602 grub_btrfs_unmount (data
);
1609 grub_btrfs_embed (grub_device_t device
__attribute__ ((unused
)),
1610 unsigned int *nsectors
,
1611 grub_embed_type_t embed_type
,
1612 grub_disk_addr_t
**sectors
)
1616 if (embed_type
!= GRUB_EMBED_PCBIOS
)
1617 return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET
,
1618 "BtrFS currently supports only PC-BIOS embedding");
1620 if (64 * 2 - 1 < *nsectors
)
1621 return grub_error (GRUB_ERR_OUT_OF_RANGE
,
1622 "Your core.img is unusually large. "
1623 "It won't fit in the embedding area.");
1625 *nsectors
= 64 * 2 - 1;
1626 *sectors
= grub_malloc (*nsectors
* sizeof (**sectors
));
1629 for (i
= 0; i
< *nsectors
; i
++)
1630 (*sectors
)[i
] = i
+ 1;
1632 return GRUB_ERR_NONE
;
1636 static struct grub_fs grub_btrfs_fs
= {
1638 .dir
= grub_btrfs_dir
,
1639 .open
= grub_btrfs_open
,
1640 .read
= grub_btrfs_read
,
1641 .close
= grub_btrfs_close
,
1642 .uuid
= grub_btrfs_uuid
,
1643 .label
= grub_btrfs_label
,
1645 .embed
= grub_btrfs_embed
,
1646 .reserved_first_sector
= 1,
1650 GRUB_MOD_INIT (btrfs
)
1652 grub_fs_register (&grub_btrfs_fs
);
1655 GRUB_MOD_FINI (btrfs
)
1657 grub_fs_unregister (&grub_btrfs_fs
);