int fd_is_raid (int fd) { struct stat st; if (!md_major()) return 0; /* not a RAID device */ if (fstat(fd, &st)) { perror("fstat()"); return 0; /* ugh.. shouldn't happen */ } return (major(st.st_rdev) == md_major()); }
/* * "md" (RAID) devices have per-member "start" offsets. * Realistically, we can only support raid1 arrays here, * and only then when all members have the same "start" offsets. */ static int get_raid1_start_lba (int fd, __u64 *start_lba) { char buf[32]; unsigned int member, raid_disks; __u64 start = 0, offset = 0; if (sysfs_get_attr(fd, "md/level", "%s", buf, NULL, 0) || sysfs_get_attr(fd, "md/raid_disks", "%u", &raid_disks, NULL, 0)) return ENODEV; if (strcmp(buf, "raid1") || !raid_disks) return EINVAL; for (member = 0; member < raid_disks; ++member) { __u64 member_start, member_offset; char member_path[32]; sprintf(member_path, "md/rd%u/offset", member); if (sysfs_get_attr(fd, member_path, "%llu", &member_offset, NULL, 0)) member_offset = 0; sprintf(member_path, "md/rd%u/block/dev", member); if (sysfs_get_attr(fd, member_path, "%s", buf, NULL, 0)) return EINVAL; if (md_major() == (unsigned)atoi(buf)) /* disallow recursive RAIDs */ return EINVAL; sprintf(member_path, "md/rd%u/block/start", member); if (sysfs_get_attr(fd, member_path, "%llu", &member_start, NULL, 0)) return ENODEV; if (member == 0) { start = member_start; offset = member_offset; } else if (member_start != start || member_offset != offset) return EINVAL; /* FIXME? Should --fibmap should account for member_offset in calculations? */ } *start_lba = start; return 0; }
static int _is_partitionable(struct device *dev) { int parts = max_partitions(MAJOR(dev->dev)); /* All MD devices are partitionable via blkext (as of 2.6.28) */ if (MAJOR(dev->dev) == md_major()) return 1; if ((parts <= 1) || (MINOR(dev->dev) % parts)) return 0; return 1; }
static int _md_sysfs_attribute_snprintf(char *path, size_t size, const char *sysfs_dir, struct device *blkdev, const char *attribute) { struct stat info; dev_t dev = blkdev->dev; int ret = -1; if (!sysfs_dir || !*sysfs_dir) return ret; if (MAJOR(dev) == blkext_major()) { /* lookup parent MD device from blkext partition */ if (!get_primary_dev(sysfs_dir, blkdev, &dev)) return ret; } if (MAJOR(dev) != md_major()) return ret; ret = dm_snprintf(path, size, "%s/dev/block/%d:%d/md/%s", sysfs_dir, (int)MAJOR(dev), (int)MINOR(dev), attribute); if (ret < 0) { log_error("dm_snprintf md %s failed", attribute); return ret; } if (stat(path, &info) == -1) { if (errno != ENOENT) { log_sys_error("stat", path); return ret; } /* old sysfs structure */ ret = dm_snprintf(path, size, "%s/block/md%d/md/%s", sysfs_dir, (int)MINOR(dev), attribute); if (ret < 0) { log_error("dm_snprintf old md %s failed", attribute); return ret; } } return ret; }