]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
imsm: bad block management (phase1)
authorJacek Danecki <jacek.danecki@intel.com>
Thu, 7 Aug 2008 06:55:53 +0000 (23:55 -0700)
committerDan Williams <dan.j.williams@intel.com>
Thu, 7 Aug 2008 06:55:53 +0000 (23:55 -0700)
This is the initial defensive implementation of bad block management
support.  It simply precludes assembly if there are entries in the bad
block logs.  This is sufficient for now as the conditions that lead to
an entry in the bad block log would cause the array to be failed by MD
(as of 2.6.27).

[dan.j.williams@intel.com: general cleanups]
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
super-intel.c

index 1017a447fa5bcfba2286a19ed25580e597557571..a2396e174df724f91a00d679da55eae7be123091 100644 (file)
@@ -100,16 +100,43 @@ struct imsm_super {
        __u32 mpb_size;                 /* 0x24 - 0x27 Size of MPB */
        __u32 family_num;               /* 0x28 - 0x2B Checksum from first time this config was written */
        __u32 generation_num;           /* 0x2C - 0x2F Incremented each time this array's MPB is written */
-       __u32 reserved[2];              /* 0x30 - 0x37 */
+       __u32 error_log_size;           /* 0x30 - 0x33 in bytes */
+       __u32 attributes;               /* 0x34 - 0x37 */
        __u8 num_disks;                 /* 0x38 Number of configured disks */
        __u8 num_raid_devs;             /* 0x39 Number of configured volumes */
-       __u8 fill[2];                   /* 0x3A - 0x3B */
-#define IMSM_FILLERS 39
-       __u32 filler[IMSM_FILLERS];     /* 0x3C - 0xD7 RAID_MPB_FILLERS */
+       __u8 error_log_pos;             /* 0x3A  */
+       __u8 fill[1];                   /* 0x3B */
+       __u32 cache_size;               /* 0x3c - 0x40 in mb */
+       __u32 orig_family_num;          /* 0x40 - 0x43 original family num */
+       __u32 pwr_cycle_count;          /* 0x44 - 0x47 simulated power cycle count for array */
+       __u32 bbm_log_size;             /* 0x48 - 0x4B - size of bad Block Mgmt Log in bytes */
+#define IMSM_FILLERS 35
+       __u32 filler[IMSM_FILLERS];     /* 0x4C - 0xD7 RAID_MPB_FILLERS */
        struct imsm_disk disk[1];       /* 0xD8 diskTbl[numDisks] */
        /* here comes imsm_dev[num_raid_devs] */
+       /* here comes BBM logs */
 } __attribute__ ((packed));
 
+#define BBM_LOG_MAX_ENTRIES 254
+
+struct bbm_log_entry {
+       __u64 defective_block_start;
+#define UNREADABLE 0xFFFFFFFF
+       __u32 spare_block_offset;
+       __u16 remapped_marked_count;
+       __u16 disk_ordinal;
+} __attribute__ ((__packed__));
+
+struct bbm_log {
+       __u32 signature; /* 0xABADB10C */
+       __u32 entry_count;
+       __u32 reserved_spare_block_count; /* 0 */
+       __u32 reserved; /* 0xFFFF */
+       __u64 first_spare_lba;
+       struct bbm_log_entry mapped_block_entries[BBM_LOG_MAX_ENTRIES];
+} __attribute__ ((__packed__));
+
+
 #ifndef MDASSEMBLE
 static char *map_state_str[] = { "normal", "uninitialized", "degraded", "failed" };
 #endif
@@ -146,6 +173,7 @@ struct intel_super {
                char *devname;
                int fd;
        } *disks;
+    struct bbm_log *bbm_log;
 };
 
 struct extent {
@@ -447,6 +475,17 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
        printf("          Disks : %d\n", mpb->num_disks);
        printf("   RAID Devices : %d\n", mpb->num_raid_devs);
        print_imsm_disk(mpb, super->disks->index);
+       if (super->bbm_log) {
+               struct bbm_log *log = super->bbm_log;
+
+               printf("\n");
+               printf("Bad Block Management Log:\n");
+               printf("       Log Size : %d\n", __le32_to_cpu(mpb->bbm_log_size));
+               printf("      Signature : %x\n", __le32_to_cpu(log->signature));
+               printf("    Entry Count : %d\n", __le32_to_cpu(log->entry_count));
+               printf("   Spare Blocks : %d\n",  __le32_to_cpu(log->reserved_spare_block_count));
+               printf("    First Spare : %llx\n", __le64_to_cpu(log->first_spare_lba));
+       }
        for (i = 0; i < mpb->num_raid_devs; i++)
                print_imsm_dev(__get_imsm_dev(mpb, i), super->disks->index);
        for (i = 0; i < mpb->num_disks; i++) {
@@ -870,6 +909,19 @@ static int parse_raid_devices(struct intel_super *super)
        return 0;
 }
 
+/* retrieve a pointer to the bbm log which starts after all raid devices */
+struct bbm_log *__get_imsm_bbm_log(struct imsm_super *mpb)
+{
+       void *ptr = NULL;
+
+       if (__le32_to_cpu(mpb->bbm_log_size)) {
+               ptr = mpb;
+               ptr += mpb->mpb_size - __le32_to_cpu(mpb->bbm_log_size);
+       } 
+
+       return ptr;
+}
+
 static void __free_imsm(struct intel_super *super);
 
 /* load_imsm_mpb - read matrix metadata
@@ -967,6 +1019,12 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
                return 2;
        }
 
+       /* FIXME the BBM log is disk specific so we cannot use this global
+        * buffer for all disks.  Ok for now since we only look at the global
+        * bbm_log_size parameter to gate assembly
+        */
+       super->bbm_log = __get_imsm_bbm_log(super->anchor);
+
        rc = load_imsm_disk(fd, super, devname, 0);
        if (rc == 0)
                rc = parse_raid_devices(super);
@@ -1692,6 +1750,11 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
        return 1;
 }
 
+int imsm_bbm_log_size(struct imsm_super *mpb)
+{
+       return __le32_to_cpu(mpb->bbm_log_size);
+}
+
 static int validate_geometry_imsm(struct supertype *st, int level, int layout,
                                  int raiddisks, int chunk, unsigned long long size,
                                  char *dev, unsigned long long *freesize,
@@ -1795,6 +1858,13 @@ static struct mdinfo *container_content_imsm(struct supertype *st)
        struct mdinfo *rest = NULL;
        int i;
 
+       /* do not assemble arrays that might have bad blocks */
+       if (imsm_bbm_log_size(super->anchor)) {
+               fprintf(stderr, Name ": BBM log found in metadata. "
+                               "Cannot activate array(s).\n");
+               return NULL;
+       }
+
        for (i = 0; i < mpb->num_raid_devs; i++) {
                struct imsm_dev *dev = get_imsm_dev(super, i);
                struct imsm_vol *vol = &dev->vol;