2 * BTRFS filesystem implementation for U-Boot
4 * 2017 Marek Behun, CZ.NIC, marek.behun@nic.cz
6 * SPDX-License-Identifier: GPL-2.0+
11 #define BTRFS_SUPER_FLAG_SUPP (BTRFS_HEADER_FLAG_WRITTEN \
12 | BTRFS_HEADER_FLAG_RELOC \
13 | BTRFS_SUPER_FLAG_ERROR \
14 | BTRFS_SUPER_FLAG_SEEDING \
15 | BTRFS_SUPER_FLAG_METADUMP)
17 #define BTRFS_SUPER_INFO_SIZE 4096
19 static int btrfs_newest_root_backup(struct btrfs_super_block
*sb
)
21 struct btrfs_root_backup
*root_backup
;
24 for (i
= 0; i
< BTRFS_NUM_BACKUP_ROOTS
; ++i
) {
25 root_backup
= sb
->super_roots
+ i
;
26 if (root_backup
->tree_root_gen
== sb
->generation
)
33 static inline int is_power_of_2(u64 x
)
35 return !(x
& (x
- 1));
38 static int btrfs_check_super_csum(char *raw_disk_sb
)
40 struct btrfs_super_block
*disk_sb
=
41 (struct btrfs_super_block
*) raw_disk_sb
;
42 u16 csum_type
= le16_to_cpu(disk_sb
->csum_type
);
44 if (csum_type
== BTRFS_CSUM_TYPE_CRC32
) {
46 const int csum_size
= sizeof(crc
);
47 char result
[csum_size
];
49 crc
= btrfs_csum_data(raw_disk_sb
+ BTRFS_CSUM_SIZE
, crc
,
50 BTRFS_SUPER_INFO_SIZE
- BTRFS_CSUM_SIZE
);
51 btrfs_csum_final(crc
, result
);
53 if (memcmp(raw_disk_sb
, result
, csum_size
))
62 static int btrfs_check_super(struct btrfs_super_block
*sb
)
66 if (sb
->flags
& ~BTRFS_SUPER_FLAG_SUPP
) {
67 printf("%s: Unsupported flags: %llu\n", __func__
,
68 sb
->flags
& ~BTRFS_SUPER_FLAG_SUPP
);
71 if (sb
->root_level
> BTRFS_MAX_LEVEL
) {
72 printf("%s: tree_root level too big: %d >= %d\n", __func__
,
73 sb
->root_level
, BTRFS_MAX_LEVEL
);
77 if (sb
->chunk_root_level
> BTRFS_MAX_LEVEL
) {
78 printf("%s: chunk_root level too big: %d >= %d\n", __func__
,
79 sb
->chunk_root_level
, BTRFS_MAX_LEVEL
);
83 if (sb
->log_root_level
> BTRFS_MAX_LEVEL
) {
84 printf("%s: log_root level too big: %d >= %d\n", __func__
,
85 sb
->log_root_level
, BTRFS_MAX_LEVEL
);
89 if (!is_power_of_2(sb
->sectorsize
) || sb
->sectorsize
< 4096 ||
90 sb
->sectorsize
> BTRFS_MAX_METADATA_BLOCKSIZE
) {
91 printf("%s: invalid sectorsize %u\n", __func__
,
96 if (!is_power_of_2(sb
->nodesize
) || sb
->nodesize
< sb
->sectorsize
||
97 sb
->nodesize
> BTRFS_MAX_METADATA_BLOCKSIZE
) {
98 printf("%s: invalid nodesize %u\n", __func__
, sb
->nodesize
);
102 if (sb
->nodesize
!= sb
->__unused_leafsize
) {
103 printf("%s: invalid leafsize %u, should be %u\n", __func__
,
104 sb
->__unused_leafsize
, sb
->nodesize
);
108 if (!IS_ALIGNED(sb
->root
, sb
->sectorsize
)) {
109 printf("%s: tree_root block unaligned: %llu\n", __func__
,
114 if (!IS_ALIGNED(sb
->chunk_root
, sb
->sectorsize
)) {
115 printf("%s: chunk_root block unaligned: %llu\n", __func__
,
120 if (!IS_ALIGNED(sb
->log_root
, sb
->sectorsize
)) {
121 printf("%s: log_root block unaligned: %llu\n", __func__
,
126 if (memcmp(sb
->fsid
, sb
->dev_item
.fsid
, BTRFS_UUID_SIZE
) != 0) {
127 printf("%s: dev_item UUID does not match fsid\n", __func__
);
131 if (sb
->bytes_used
< 6*sb
->nodesize
) {
132 printf("%s: bytes_used is too small %llu\n", __func__
,
137 if (!is_power_of_2(sb
->stripesize
)) {
138 printf("%s: invalid stripesize %u\n", __func__
, sb
->stripesize
);
142 if (sb
->sys_chunk_array_size
> BTRFS_SYSTEM_CHUNK_ARRAY_SIZE
) {
143 printf("%s: system chunk array too big %u > %u\n", __func__
,
144 sb
->sys_chunk_array_size
, BTRFS_SYSTEM_CHUNK_ARRAY_SIZE
);
148 if (sb
->sys_chunk_array_size
< sizeof(struct btrfs_key
) +
149 sizeof(struct btrfs_chunk
)) {
150 printf("%s: system chunk array too small %u < %lu\n", __func__
,
151 sb
->sys_chunk_array_size
, (u32
) sizeof(struct btrfs_key
)
152 + sizeof(struct btrfs_chunk
));
159 int btrfs_read_superblock(void)
161 const u64 superblock_offsets
[4] = {
167 char raw_sb
[BTRFS_SUPER_INFO_SIZE
];
168 struct btrfs_super_block
*sb
= (struct btrfs_super_block
*) raw_sb
;
170 int i
, root_backup_idx
;
172 dev_total_bytes
= (u64
) btrfs_part_info
->size
* btrfs_part_info
->blksz
;
174 btrfs_info
.sb
.generation
= 0;
176 for (i
= 0; i
< 4; ++i
) {
177 if (superblock_offsets
[i
] + sizeof(sb
) > dev_total_bytes
)
180 if (!btrfs_devread(superblock_offsets
[i
], BTRFS_SUPER_INFO_SIZE
,
184 if (btrfs_check_super_csum(raw_sb
)) {
185 printf("%s: invalid checksum at superblock mirror %i\n",
190 btrfs_super_block_to_cpu(sb
);
192 if (sb
->magic
!= BTRFS_MAGIC
) {
193 printf("%s: invalid BTRFS magic 0x%016llX at "
194 "superblock mirror %i\n", __func__
, sb
->magic
,
196 } else if (sb
->bytenr
!= superblock_offsets
[i
]) {
197 printf("%s: invalid bytenr 0x%016llX (expected "
198 "0x%016llX) at superblock mirror %i\n",
199 __func__
, sb
->bytenr
, superblock_offsets
[i
], i
);
200 } else if (btrfs_check_super(sb
)) {
201 printf("%s: Checking superblock mirror %i failed\n",
203 } else if (sb
->generation
> btrfs_info
.sb
.generation
) {
204 memcpy(&btrfs_info
.sb
, sb
, sizeof(*sb
));
210 if (!btrfs_info
.sb
.generation
) {
211 printf("%s: No valid BTRFS superblock found!\n", __func__
);
215 root_backup_idx
= btrfs_newest_root_backup(&btrfs_info
.sb
);
216 if (root_backup_idx
< 0) {
217 printf("%s: No valid root_backup found!\n", __func__
);
220 btrfs_info
.root_backup
= btrfs_info
.sb
.super_roots
+ root_backup_idx
;
222 if (btrfs_info
.root_backup
->num_devices
!= 1) {
223 printf("%s: Unsupported number of devices (%lli). This driver "
224 "only supports filesystem on one device.\n", __func__
,
225 btrfs_info
.root_backup
->num_devices
);
229 debug("Chosen superblock with generation = %llu\n",
230 btrfs_info
.sb
.generation
);