From: Czarnowska, Anna Sent: Monday, July 05, 2010 11:34 AM To: Neil Brown Cc: linux-raid@xxxxxxxxxxxxxxx; Czarnowska, Anna; Hawrylewicz Czarnowski, Przemyslaw; Labun, Marcin; Neubauer, Wojciech; Williams, Dan J; Ciechanowski, Ed; dledford@xxxxxxxxxx Subject: [PATCH 20/33] Added disk util functions Needed for checking suitability of a disk to use for rebuild. Signed-off-by: Anna Czarnowska <anna.czarnowska@xxxxxxxxx> --- mdadm.h | 11 +++++++++++ super-ddf.c | 36 ++++++++++++++++++++++++++++++++++++ super-intel.c | 31 +++++++++++++++++++++++++++++++ util.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+), 0 deletions(-) diff --git a/mdadm.h b/mdadm.h index b6d7933..86f5370 100644 --- a/mdadm.h +++ b/mdadm.h @@ -277,6 +277,12 @@ enum special_options { DetailPlatform, }; +enum disk_status { + unknown, + spare_disk, + failed_disk, +}; + enum domain_actions { ignore, incremental, @@ -656,6 +662,8 @@ extern struct superswitch { int (*load_super)(struct supertype *st, int fd, char *devname); struct supertype * (*match_metadata_desc)(char *arg); __u64 (*avail_size)(struct supertype *st, __u64 size); + + enum disk_status (*get_disk_status)(struct supertype *st, int major, +int minor); int (*add_internal_bitmap)(struct supertype *st, int *chunkp, int delay, int write_behind, unsigned long long size, int may_change, int major); @@ -795,6 +803,7 @@ extern struct supertype *super_by_fd(int fd); extern struct supertype *guess_super(int fd); extern struct supertype *dup_super(struct supertype *st); extern int get_dev_size(int fd, char *dname, unsigned long long *sizep); +extern int dev_size_from_id(int id, unsigned long long *ssize); extern void get_one_disk(int mdfd, mdu_array_info_t *ainf, mdu_disk_info_t *disk); void wait_for(char *dev, int fd); @@ -1023,6 +1032,8 @@ extern int get_active_array_domain(char *array_name, int fd, struct domain_ent **domain, struct subset **subset); extern int is_external(char *metadata_verison); +extern int disk_faulty(struct supertype *sty, int major, int minor); +extern int disk_faulty_from_id(int devid); static inline int dev2major(int d) { diff --git a/super-ddf.c b/super-ddf.c index b01c68d..aa5dc89 100644 --- a/super-ddf.c +++ b/super-ddf.c @@ -2436,6 +2436,41 @@ static __u64 avail_size_ddf(struct supertype *st, __u64 devsize) return devsize - 32*1024*2; } +/* Get the disk status from metadata. 1 for spare, 2 for failed disk, 0 +otherwise */ static enum disk_status get_disk_status_ddf(struct +supertype *st, int major, int minor) { + if (!st) + return unknown; + + struct ddf_super *super = st->sb; + struct phys_disk_entry disk; + struct dl *list; + int i; + + if (!super) + return unknown; + list = super->dlist; + + i = -1; + while (list) { + if (list->major == major && list->minor == minor) { + i = list->pdnum; + break; + } + list = list->next; + } + if (i == -1) + return unknown; + + disk = super->phys->entries[i]; + if (__be16_to_cpu(disk.state) & DDF_Failed) + return failed_disk; + if ((__be16_to_cpu(disk.type) & DDF_Global_Spare) || + (__be16_to_cpu(disk.type) & DDF_Spare)) + return spare_disk; + return unknown; +} + #ifndef MDASSEMBLE static int reserve_space(struct supertype *st, int raiddisks, @@ -3658,6 +3693,7 @@ struct superswitch super_ddf = { .update_super = update_super_ddf, .avail_size = avail_size_ddf, + .get_disk_status = get_disk_status_ddf, .compare_super = compare_super_ddf, diff --git a/super-intel.c b/super-intel.c index 4dcc654..6762129 100644 --- a/super-intel.c +++ b/super-intel.c @@ -1710,6 +1710,36 @@ static __u64 avail_size_imsm(struct supertype *st, __u64 devsize) return devsize - (MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS); } +static int serialcmp(__u8 *s1, __u8 *s2); + +/* Get the disk status from metadata. 1 for spare, 2 for failed disk, 0 +otherwise */ static enum disk_status get_disk_status_imsm(struct +supertype *st, int major, int minor) { + if (!st) + return unknown; + + struct intel_super *super = st->sb; + struct imsm_disk *disk; + struct dl *dlist; + + if (!super) + return unknown; + dlist = super->disks; + + while (dlist) { + disk = &dlist->disk; + if (major == dlist->major && minor == dlist->minor) { + if (disk->status & FAILED_DISK) + return failed_disk; + if (disk->status & SPARE_DISK) + return spare_disk; + return unknown; + } + dlist = dlist->next; + } + return unknown; +} + static void free_devlist(struct intel_super *super) { struct intel_dev *dv; @@ -5336,6 +5366,7 @@ struct superswitch super_imsm = { .update_super = update_super_imsm, .avail_size = avail_size_imsm, + .get_disk_status = get_disk_status_imsm, .compare_super = compare_super_imsm, diff --git a/util.c b/util.c index a746b83..fcc9e69 100644 --- a/util.c +++ b/util.c @@ -1246,6 +1246,24 @@ int get_dev_size(int fd, char *dname, unsigned long long *sizep) return 1; } +int dev_size_from_id(int id, unsigned long long *ssize) { + char *dv; + int fd; + + dv = map_dev(major(id), minor(id), 1); + if (!dv) + return 0; + fd = open(dv, O_RDONLY); + if (fd < 0) + return 0; + if (get_dev_size(fd, dv, ssize)) { + close(fd); + return 1; + } + close(fd); + return 0; +} /* Sets endofpart parameter to the last block used by the last GPT partition on the device. * Returns: 1 if successful @@ -1776,6 +1794,43 @@ char *get_devpath_from_devname(char *devname) return NULL; } +/* Check if disk has failed status in metadata*/ int disk_faulty(struct +supertype *sty, int major, int minor) { + enum disk_status status; + if (!sty) + return 1; + status = sty->ss->get_disk_status(sty, major, minor); + return status == failed_disk; +} + +int disk_faulty_from_id(int devid) +{ + struct supertype *sty; + int fd, rv = 1; + char *devname; + if (devid <= 0) + return rv; + devname = map_dev(major(devid), minor(devid), 1); + if (!devname) + return rv; + fd = open(devname, O_RDONLY); + if (fd < 0) + return rv; + sty = guess_super(fd); + if (!sty) { + close(fd); + return rv; + } + rv = sty->ss->load_super(sty, fd, devname); + if (!rv) + rv = disk_faulty(sty, major(devid), minor(devid)); + close(fd); + sty->ss->free_super(sty); + free(sty); + return rv; +} + static int sfdisk_validate(struct domain_ent *domain) { return 0; -- 1.6.4.2 -- To unsubscribe from this list: send the line "unsubscribe linux-raid" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html