From 6d388a88163a8f532513e73dd035892ea8a8ead2 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 5 Dec 2012 12:56:31 +1100 Subject: [PATCH] MISC: Add --examine-badblocks option This will list the contents of the bad-blocks log, if one is present. Signed-off-by: NeilBrown --- Examine.c | 36 ++++++++++++++++++++++++++++++++++++ ReadMe.c | 3 +++ mdadm.8.in | 7 +++++++ mdadm.c | 4 ++++ mdadm.h | 3 +++ super1.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 107 insertions(+) diff --git a/Examine.c b/Examine.c index a5b32293..90b25ec4 100644 --- a/Examine.c +++ b/Examine.c @@ -187,3 +187,39 @@ int Examine(struct mddev_dev *devlist, } return rv; } + +int ExamineBadblocks(char *devname, int brief, struct supertype *forcest) +{ + int fd = dev_open(devname, O_RDONLY); + struct supertype *st = forcest; + int err = 1; + + if (fd < 0) { + pr_err("cannot open %s: %s\n", devname, strerror(errno)); + return 1; + } + if (!st) + st = guess_super(fd); + if (!st) { + if (!brief) + pr_err("No md superblock detected on %s\n", devname); + goto out; + } + if (!st->ss->examine_badblocks) { + pr_err("%s metadata does not support badblocks\n", st->ss->name); + goto out; + } + err = st->ss->load_super(st, fd, brief ? NULL : devname); + if (err) + goto out; + err = st->ss->examine_badblocks(st, fd, devname); + +out: + if (fd >= 0) + close(fd); + if (st) { + st->ss->free_super(st); + free(st); + } + return err; +} diff --git a/ReadMe.c b/ReadMe.c index 0aa8cbd7..4214cb05 100644 --- a/ReadMe.c +++ b/ReadMe.c @@ -95,6 +95,7 @@ struct option long_options[] = { {"update-subarray", 1, 0, UpdateSubarray}, {"udev-rules", 2, 0, UdevRules}, {"offroot", 0, 0, OffRootOpt}, + {"examine-badblocks", 0, 0, ExamineBB}, /* synonyms */ {"monitor", 0, 0, 'F'}, @@ -251,6 +252,7 @@ char OptionHelp[] = " --detail -D : Display details of an array\n" " --examine -E : Examine superblock on an array component\n" " --examine-bitmap -X: Display the detail of a bitmap file\n" +" --examine-badblocks: Display list of known bad blocks on device\n" " --monitor -F : monitor (follow) some arrays\n" " --grow -G : resize/ reshape and array\n" " --incremental -I : add/remove a single device to/from an array as appropriate\n" @@ -490,6 +492,7 @@ char Help_misc[] = " --detail-platform : Display hardware/firmware details\n" " --examine -E : Examine superblock on an array component\n" " --examine-bitmap -X: Display contents of a bitmap file\n" +" --examine-badblocks: Display list of known bad blocks on device\n" " --zero-superblock : erase the MD superblock from a device.\n" " --run -R : start a partially built array\n" " --stop -S : deactivate array, releasing all resources\n" diff --git a/mdadm.8.in b/mdadm.8.in index 535cc392..c1881cd7 100644 --- a/mdadm.8.in +++ b/mdadm.8.in @@ -1426,6 +1426,13 @@ device (e.g. .BR /dev/md0 ) does not report the bitmap for that array. +.TP +.B \-\-examine\-badblocks +List the bad-blocks recorded for the device, if a bad-blocks list has +been configured. Currently only +.B 1.x +metadata supports bad-blocks lists. + .TP .BR \-R ", " \-\-run start a partially assembled array. If diff --git a/mdadm.c b/mdadm.c index 11016e7b..26e8ceca 100644 --- a/mdadm.c +++ b/mdadm.c @@ -232,6 +232,7 @@ int main(int argc, char *argv[]) case 'E': case 'X': case 'Q': + case ExamineBB: newmode = MISC; break; @@ -971,6 +972,7 @@ int main(int argc, char *argv[]) case O(MISC,'R'): case O(MISC,'S'): case O(MISC,'X'): + case O(MISC, ExamineBB): case O(MISC,'o'): case O(MISC,'w'): case O(MISC,'W'): @@ -1750,6 +1752,8 @@ static int misc_list(struct mddev_dev *devlist, rv |= Query(dv->devname); continue; case 'X': rv |= ExamineBitmap(dv->devname, c->brief, ss); continue; + case ExamineBB: + rv |= ExamineBadblocks(dv->devname, c->brief, ss); continue; case 'W': case WaitOpt: rv |= Wait(dv->devname); continue; diff --git a/mdadm.h b/mdadm.h index f1352e37..7adf7d94 100644 --- a/mdadm.h +++ b/mdadm.h @@ -337,6 +337,7 @@ enum special_options { Prefer, KillOpt, DataOffset, + ExamineBB, }; enum prefix_standard { @@ -662,6 +663,7 @@ extern struct superswitch { void (*brief_examine_super)(struct supertype *st, int verbose); void (*brief_examine_subarrays)(struct supertype *st, int verbose); void (*export_examine_super)(struct supertype *st); + int (*examine_badblocks)(struct supertype *st, int fd, char *devname); /* Used to report details of an active array. * ->load_super was possibly given a 'component' string. @@ -1145,6 +1147,7 @@ extern int Create(struct supertype *st, char *mddev, extern int Detail(char *dev, struct context *c); extern int Detail_Platform(struct superswitch *ss, int scan, int verbose, int export, char *controller_path); extern int Query(char *dev); +extern int ExamineBadblocks(char *devname, int brief, struct supertype *forcest); extern int Examine(struct mddev_dev *devlist, struct context *c, struct supertype *forcest); extern int Monitor(struct mddev_dev *devlist, diff --git a/super1.c b/super1.c index 5bb1f014..3236a7e2 100644 --- a/super1.c +++ b/super1.c @@ -648,6 +648,59 @@ static void export_detail_super1(struct supertype *st) printf("MD_NAME=%.*s\n", len, sb->set_name); } +static int examine_badblocks_super1(struct supertype *st, int fd, char *devname) +{ + struct mdp_superblock_1 *sb = st->sb; + unsigned long long offset; + int size; + __u64 *bbl, *bbp; + int i; + + if (!sb->bblog_size || __le32_to_cpu(sb->bblog_size) > 100 + || !sb->bblog_offset){ + printf("No bad-blocks list configured on %s\n", devname); + return 0; + } + if ((sb->feature_map & __cpu_to_le32(MD_FEATURE_BAD_BLOCKS)) + == 0) { + printf("Bad-blocks list is empty in %s\n", devname); + return 0; + } + + size = __le32_to_cpu(sb->bblog_size)* 512; + posix_memalign((void**)&bbl, 4096, size); + offset = __le64_to_cpu(sb->super_offset) + + (int)__le32_to_cpu(sb->bblog_offset); + offset <<= 9; + if (lseek64(fd, offset, 0) < 0) { + pr_err("Cannot seek to bad-blocks list\n"); + return 1; + } + if (read(fd, bbl, size) != size) { + pr_err("Cannot read bad-blocks list\n"); + return 1; + } + /* 64bits per entry. 10 bits is block-count, 54 bits is block + * offset. Blocks are sectors unless bblog->shift makes them bigger + */ + bbp = (__u64*)bbl; + printf("Bad-blocks on %s:\n", devname); + for (i = 0; i < size/8; i++, bbp++) { + __u64 bb = __le64_to_cpu(*bbp); + int count = bb & 0x3ff; + unsigned long long sector = bb >> 10; + + if (bb + 1 == 0) + break; + + sector <<= sb->bblog_shift; + count <<= sb->bblog_shift; + + printf("%20llu for %d sectors\n", sector, count); + } + return 0; +} + #endif static int match_home1(struct supertype *st, char *homehost) @@ -2049,6 +2102,7 @@ struct superswitch super1 = { .write_init_super = write_init_super1, .validate_geometry = validate_geometry1, .add_to_super = add_to_super1, + .examine_badblocks = examine_badblocks_super1, #endif .match_home = match_home1, .uuid_from_super = uuid_from_super1, -- 2.39.2