/* * Copyright (C) 2008 Karel Zak * * Inspired by libvolume_id by * Kay Sievers * * This file may be redistributed under the terms of the * GNU Lesser General Public License. */ #include #include #include #include #include #include "blkidP.h" struct mdp0_super_block { uint32_t md_magic; uint32_t major_version; uint32_t minor_version; uint32_t patch_version; uint32_t gvalid_words; uint32_t set_uuid0; uint32_t ctime; uint32_t level; uint32_t size; uint32_t nr_disks; uint32_t raid_disks; uint32_t md_minor; uint32_t not_persistent; uint32_t set_uuid1; uint32_t set_uuid2; uint32_t set_uuid3; }; struct mdp1_super_block { uint32_t magic; uint32_t major_version; uint32_t feature_map; uint32_t pad0; uint8_t set_uuid[16]; uint8_t set_name[32]; }; #define MD_RESERVED_BYTES 0x10000 #define MD_SB_MAGIC 0xa92b4efc static int probe_raid0(blkid_probe pr, off_t off) { struct mdp0_super_block *mdp0; union { uint32_t ints[4]; uint8_t bytes[16]; } uuid; if (pr->size < 0x10000) return -1; mdp0 = (struct mdp0_super_block *) blkid_probe_get_buffer(pr, off, sizeof(struct mdp0_super_block)); if (!mdp0) return -1; memset(uuid.ints, 0, sizeof(uuid.ints)); if (le32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { uuid.ints[0] = swab32(mdp0->set_uuid0); if (le32_to_cpu(mdp0->minor_version >= 90)) { uuid.ints[1] = swab32(mdp0->set_uuid1); uuid.ints[2] = swab32(mdp0->set_uuid2); uuid.ints[3] = swab32(mdp0->set_uuid3); } if (blkid_probe_sprintf_version(pr, "%u.%u.%u", le32_to_cpu(mdp0->major_version), le32_to_cpu(mdp0->minor_version), le32_to_cpu(mdp0->patch_version)) != 0) return -1; } else if (be32_to_cpu(mdp0->md_magic) == MD_SB_MAGIC) { uuid.ints[0] = mdp0->set_uuid0; if (be32_to_cpu(mdp0->minor_version >= 90)) { uuid.ints[1] = mdp0->set_uuid1; uuid.ints[2] = mdp0->set_uuid2; uuid.ints[3] = mdp0->set_uuid3; } if (blkid_probe_sprintf_version(pr, "%u.%u.%u", be32_to_cpu(mdp0->major_version), be32_to_cpu(mdp0->minor_version), be32_to_cpu(mdp0->patch_version)) != 0) return -1; } else return -1; if (blkid_probe_set_uuid(pr, (unsigned char *) uuid.bytes) != 0) return -1; return 0; } static int probe_raid1(blkid_probe pr, off_t off) { struct mdp1_super_block *mdp1; mdp1 = (struct mdp1_super_block *) blkid_probe_get_buffer(pr, off, sizeof(struct mdp1_super_block)); if (!mdp1) return -1; if (le32_to_cpu(mdp1->magic) != MD_SB_MAGIC) return -1; if (le32_to_cpu(mdp1->major_version) != 1) return -1; if (blkid_probe_set_uuid(pr, (unsigned char *) mdp1->set_uuid) != 0) return -1; if (blkid_probe_set_label(pr, mdp1->set_name, sizeof(mdp1->set_name)) != 0) return -1; return 0; } int probe_raid(blkid_probe pr, const struct blkid_idmag *mag) { const char *ver = NULL; if (pr->size > MD_RESERVED_BYTES) { /* version 0 at the end of the device */ uint64_t sboff = (pr->size & ~(MD_RESERVED_BYTES - 1)) - MD_RESERVED_BYTES; if (probe_raid0(pr, sboff) == 0) return 0; /* version 1.0 at the end of the device */ sboff = (pr->size & ~(0x1000 - 1)) - 0x2000; if (probe_raid1(pr, sboff) == 0) ver = "1.0"; } if (!ver) { /* version 1.1 at the start of the device */ if (probe_raid1(pr, 0) == 0) ver = "1.1"; /* version 1.2 at 4k offset from the start */ else if (probe_raid1(pr, 0x1000) == 0) ver = "1.2"; } if (ver) { blkid_probe_set_version(pr, ver); return 0; } return -1; } const struct blkid_idinfo linuxraid_idinfo = { .name = "linux_raid_member", .usage = BLKID_USAGE_RAID, .probefunc = probe_raid, .magics = BLKID_NONE_MAGIC };