summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2012-12-05 12:56:31 +1100
committerNeilBrown <neilb@suse.de>2012-12-05 12:56:31 +1100
commit6d388a88163a8f532513e73dd035892ea8a8ead2 (patch)
treec1ad00cb9ba406ca509654ed9d2883d78c1b5528
parent8cf2eb96b2330b1507af2fa55d99f338eeff5ab5 (diff)
MISC: Add --examine-badblocks option
This will list the contents of the bad-blocks log, if one is present. Signed-off-by: NeilBrown <neilb@suse.de>
-rw-r--r--Examine.c36
-rw-r--r--ReadMe.c3
-rw-r--r--mdadm.8.in7
-rw-r--r--mdadm.c4
-rw-r--r--mdadm.h3
-rw-r--r--super1.c54
6 files changed, 107 insertions, 0 deletions
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
@@ -1427,6 +1427,13 @@ device (e.g.
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
.B \-\-assemble
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,