From: Nikita Ofitserov Date: Sun, 4 Jan 2026 21:44:46 +0000 (+0300) Subject: libblkid: (bcachefs) add members_v2 parsing support X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fae8ed6466cf879b25e53cf3f3ca043fd0e54560;p=thirdparty%2Futil-linux.git libblkid: (bcachefs) add members_v2 parsing support Since bcachefs 1.25, in many cases bcachefs does not write members_v1 field in the superblock, leading to UUID_SUB and FSSIZE tags missing in blkid output. Fix this by parsing the new extendable members_v2 superblock field too. Signed-off-by: Nikita Ofitserov --- diff --git a/libblkid/src/superblocks/bcache.c b/libblkid/src/superblocks/bcache.c index 8ad2dc0f8..10b1c8296 100644 --- a/libblkid/src/superblocks/bcache.c +++ b/libblkid/src/superblocks/bcache.c @@ -84,11 +84,18 @@ struct bcachefs_sb_member { uint64_t flags[2]; } __attribute__((packed)); -struct bcachefs_sb_field_members { +struct bcachefs_sb_field_members_v1 { struct bcachefs_sb_field field; struct bcachefs_sb_member members[]; } __attribute__((packed)); +struct bcachefs_sb_field_members_v2 { + struct bcachefs_sb_field field; + uint16_t member_bytes; + uint8_t pad[6]; + struct bcachefs_sb_member members[]; +} __attribute__((packed)); + struct bcachefs_sb_disk_group { uint8_t label[SB_LABEL_SIZE]; uint64_t flags[2]; @@ -166,8 +173,12 @@ struct bcachefs_super_block { #define BCACHEFS_SB_MAX_SIZE_SHIFT 0x10U /* fields offset within super block */ #define BCACHEFS_SB_FIELDS_OFF offsetof(struct bcachefs_super_block, _start) -/* tag value for members field */ -#define BCACHEFS_SB_FIELD_TYPE_MEMBERS 1 +/* tag value for v1 members field */ +#define BCACHEFS_SB_FIELD_TYPE_MEMBERS_V1 1 +/* v1 members field size in bytes */ +#define BCACHEFS_SB_FIELD_MEMBERS_V1_BYTES 56 +/* tag value for v2 members field */ +#define BCACHEFS_SB_FIELD_TYPE_MEMBERS_V2 11 /* tag value for disk_groups field */ #define BCACHEFS_SB_FIELD_TYPE_DISK_GROUPS 5 /* version splitting helpers */ @@ -226,23 +237,42 @@ static int probe_bcache (blkid_probe pr, const struct blkid_idmag *mag) return BLKID_PROBE_OK; } +#define FIELD_END(s, field) offsetof(s, field) + sizeof_member(s, field) + +/* Fields must be dynamically checked for existence before accessing (using FIELD_END) */ +static const struct bcachefs_sb_member *bcachefs_sb_member_get_unsafe( + const struct bcachefs_sb_member *members, + uint16_t member_bytes, size_t i) +{ + return (const void*)((const char *) members + i * member_bytes); +} + static void probe_bcachefs_sb_members(blkid_probe pr, const struct bcachefs_super_block *bcs, const struct bcachefs_sb_field *field, - uint8_t dev_idx) + const struct bcachefs_sb_member *members, + uint16_t member_bytes, size_t member_array_offset) { - struct bcachefs_sb_field_members *members = - (struct bcachefs_sb_field_members *) field; uint64_t sectors = 0; uint8_t i; + const struct bcachefs_sb_member *current; - if (BYTES(field) != offsetof(__typeof__(*members), members[bcs->nr_devices])) + if (BYTES(field) != member_array_offset + bcs->nr_devices * member_bytes) return; - blkid_probe_set_uuid_as(pr, members->members[dev_idx].uuid, "UUID_SUB"); + current = bcachefs_sb_member_get_unsafe(members, member_bytes, bcs->dev_idx); + + if (member_bytes < FIELD_END(struct bcachefs_sb_member, uuid)) + return; + + blkid_probe_set_uuid_as(pr, current->uuid, "UUID_SUB"); + + if (member_bytes < FIELD_END(struct bcachefs_sb_member, nbuckets) || + member_bytes < FIELD_END(struct bcachefs_sb_member, bucket_size)) + return; for (i = 0; i < bcs->nr_devices; i++) { - struct bcachefs_sb_member *member = &members->members[i]; + const struct bcachefs_sb_member *member = bcachefs_sb_member_get_unsafe(members, member_bytes, i); sectors += le64_to_cpu(member->nbuckets) * le16_to_cpu(member->bucket_size); } blkid_probe_set_fssize(pr, sectors * BCACHEFS_SECTOR_SIZE); @@ -300,8 +330,17 @@ static void probe_bcachefs_sb_fields(blkid_probe pr, const struct bcachefs_super if (!type) break; - if (type == BCACHEFS_SB_FIELD_TYPE_MEMBERS) - probe_bcachefs_sb_members(pr, bcs, field, bcs->dev_idx); + if (type == BCACHEFS_SB_FIELD_TYPE_MEMBERS_V1) { + struct bcachefs_sb_field_members_v1 *members = (struct bcachefs_sb_field_members_v1 *) field; + probe_bcachefs_sb_members(pr, bcs, field, members->members, + BCACHEFS_SB_FIELD_MEMBERS_V1_BYTES, offsetof(__typeof__(*members), members)); + } + + if (type == BCACHEFS_SB_FIELD_TYPE_MEMBERS_V2) { + struct bcachefs_sb_field_members_v2 *members = (struct bcachefs_sb_field_members_v2 *) field; + probe_bcachefs_sb_members(pr, bcs, field, members->members, + le16_to_cpu(members->member_bytes), offsetof(__typeof__(*members), members)); + } if (type == BCACHEFS_SB_FIELD_TYPE_DISK_GROUPS) probe_bcachefs_sb_disk_groups(pr, bcs, field, bcs->dev_idx); diff --git a/tests/expected/blkid/low-probe-bcachefs-3 b/tests/expected/blkid/low-probe-bcachefs-3 new file mode 100644 index 000000000..4ac5cb9cf --- /dev/null +++ b/tests/expected/blkid/low-probe-bcachefs-3 @@ -0,0 +1,12 @@ +ID_FS_BLOCK_SIZE=512 +ID_FS_FSBLOCKSIZE=512 +ID_FS_FSSIZE=8388608 +ID_FS_LABEL=FS_Label +ID_FS_LABEL_ENC=FS\x20Label +ID_FS_TYPE=bcachefs +ID_FS_USAGE=filesystem +ID_FS_UUID=2262eedd-dc30-474e-b0b4-1d02cb3aa30d +ID_FS_UUID_ENC=2262eedd-dc30-474e-b0b4-1d02cb3aa30d +ID_FS_UUID_SUB=27269a1e-68b4-4476-8d24-79c5b8c7dcad +ID_FS_UUID_SUB_ENC=27269a1e-68b4-4476-8d24-79c5b8c7dcad +ID_FS_VERSION=1.33 diff --git a/tests/ts/blkid/images-fs/bcachefs-3.img.xz b/tests/ts/blkid/images-fs/bcachefs-3.img.xz new file mode 100644 index 000000000..c98af2307 Binary files /dev/null and b/tests/ts/blkid/images-fs/bcachefs-3.img.xz differ