]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libblkid: (bcachefs) add members_v2 parsing support
authorNikita Ofitserov <himikof@gmail.com>
Sun, 4 Jan 2026 21:44:46 +0000 (00:44 +0300)
committerNikita Ofitserov <himikof@gmail.com>
Tue, 6 Jan 2026 17:26:32 +0000 (20:26 +0300)
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 <himikof@gmail.com>
libblkid/src/superblocks/bcache.c
tests/expected/blkid/low-probe-bcachefs-3 [new file with mode: 0644]
tests/ts/blkid/images-fs/bcachefs-3.img.xz [new file with mode: 0644]

index 8ad2dc0f874e6607bad3ee34c349605edb76804c..10b1c8296f0c8e570c3667cc8d877dcd247453b2 100644 (file)
@@ -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 (file)
index 0000000..4ac5cb9
--- /dev/null
@@ -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 (file)
index 0000000..c98af23
Binary files /dev/null and b/tests/ts/blkid/images-fs/bcachefs-3.img.xz differ