/* * Linux Software RAID (md) topology * -- this is fallback for old systems where the topology information is not * exported by sysfs * * Copyright (C) 2009 Karel Zak * * This file may be redistributed under the terms of the * GNU Lesser General Public License. * */ #include #include #include #include #include #include #include #include #include #include #include "topology.h" #ifndef MD_MAJOR #define MD_MAJOR 9 #endif #ifndef _IOT__IOTBASE_uint32_t #define _IOT__IOTBASE_uint32_t IOT_SIMPLE(uint32_t) #endif #define _IOT_md_array_info _IOT (_IOTS(uint32_t), 18, 0, 0, 0, 0) #define GET_ARRAY_INFO _IOR (MD_MAJOR, 0x11, struct md_array_info) struct md_array_info { /* * Generic constant information */ uint32_t major_version; uint32_t minor_version; uint32_t patch_version; 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; /* * Generic state information */ uint32_t utime; /* 0 Superblock update time */ uint32_t state; /* 1 State bits (clean, ...) */ uint32_t active_disks; /* 2 Number of currently active disks */ uint32_t working_disks; /* 3 Number of working disks */ uint32_t failed_disks; /* 4 Number of failed disks */ uint32_t spare_disks; /* 5 Number of spare disks */ /* * Personality information */ uint32_t layout; /* 0 the array's physical layout */ uint32_t chunk_size; /* 1 chunk size in bytes */ }; static int is_md_device(dev_t devno) { if (major(devno) == MD_MAJOR) return 1; return blkid_driver_has_major("md", major(devno)); } static int probe_md_tp(blkid_probe pr, const struct blkid_idmag *mag __attribute__((__unused__))) { int fd = -1; dev_t disk = 0; dev_t devno = blkid_probe_get_devno(pr); struct md_array_info md; if (!devno) goto nothing; /* probably not a block device */ if (!is_md_device(devno)) goto nothing; if (blkid_devno_to_wholedisk(devno, NULL, 0, &disk)) goto nothing; if (disk == devno) fd = pr->fd; else { char *diskpath = blkid_devno_to_devname(disk); if (!diskpath) goto nothing; fd = open(diskpath, O_RDONLY|O_CLOEXEC); free(diskpath); if (fd == -1) goto nothing; } memset(&md, 0, sizeof(md)); if (ioctl(fd, GET_ARRAY_INFO, &md)) goto nothing; if (fd >= 0 && fd != pr->fd) { close(fd); fd = -1; } /* * Ignore levels we don't want aligned (e.g. linear) * and deduct disk(s) from stripe width on RAID4/5/6 */ switch (md.level) { case 6: md.raid_disks--; /* fallthrough */ case 5: case 4: md.raid_disks--; /* fallthrough */ case 1: case 0: case 10: break; default: goto nothing; } blkid_topology_set_minimum_io_size(pr, md.chunk_size); blkid_topology_set_optimal_io_size(pr, md.chunk_size * md.raid_disks); return 0; nothing: if (fd >= 0 && fd != pr->fd) close(fd); return 1; } const struct blkid_idinfo md_tp_idinfo = { .name = "md", .probefunc = probe_md_tp, .magics = BLKID_NONE_MAGIC };