]> git.ipfire.org Git - thirdparty/mdadm.git/commitdiff
imsm: parse bad block log in metadata on startup
authorTomasz Majchrzak <tomasz.majchrzak@intel.com>
Tue, 29 Nov 2016 15:40:11 +0000 (16:40 +0100)
committerJes Sorensen <Jes.Sorensen@redhat.com>
Fri, 2 Dec 2016 16:02:09 +0000 (11:02 -0500)
Always allocate memory for all log entries to avoid a need for memory
allocation when monitor requests to record a bad block.

Also some extra checks added to make static code analyzer happy.

Signed-off-by: Tomasz Majchrzak <tomasz.majchrzak@intel.com>
Signed-off-by: Jes Sorensen <Jes.Sorensen@redhat.com>
super-intel.c

index 3d21f312b86d9f5f0b51b2804ba7134ccaeb4752..401ba7569ff464038fa621b00a80468124dffc24 100644 (file)
@@ -218,22 +218,24 @@ struct imsm_super {
 } __attribute__ ((packed));
 
 #define BBM_LOG_MAX_ENTRIES 254
+#define BBM_LOG_MAX_LBA_ENTRY_VAL 256          /* Represents 256 LBAs */
+#define BBM_LOG_SIGNATURE 0xabadb10c
+
+struct bbm_log_block_addr {
+       __u16 w1;
+       __u32 dw1;
+} __attribute__ ((__packed__));
 
 struct bbm_log_entry {
-       __u64 defective_block_start;
-#define UNREADABLE 0xFFFFFFFF
-       __u32 spare_block_offset;
-       __u16 remapped_marked_count;
-       __u16 disk_ordinal;
+       __u8 marked_count;              /* Number of blocks marked - 1 */
+       __u8 disk_ordinal;              /* Disk entry within the imsm_super */
+       struct bbm_log_block_addr defective_block_start;
 } __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];
+       struct bbm_log_entry marked_block_entries[BBM_LOG_MAX_ENTRIES];
 } __attribute__ ((__packed__));
 
 #ifndef MDASSEMBLE
@@ -788,6 +790,74 @@ static struct imsm_dev *get_imsm_dev(struct intel_super *super, __u8 index)
        return NULL;
 }
 
+static inline unsigned long long __le48_to_cpu(const struct bbm_log_block_addr
+                                              *addr)
+{
+       return ((((__u64)__le32_to_cpu(addr->dw1)) << 16) |
+               __le16_to_cpu(addr->w1));
+}
+
+static inline struct bbm_log_block_addr __cpu_to_le48(unsigned long long sec)
+{
+       struct bbm_log_block_addr addr;
+
+       addr.w1 =  __cpu_to_le16((__u16)(sec & 0xffff));
+       addr.dw1 = __cpu_to_le32((__u32)(sec >> 16) & 0xffffffff);
+       return addr;
+}
+
+#ifndef MDASSEMBLE
+/* get size of the bbm log */
+static __u32 get_imsm_bbm_log_size(struct bbm_log *log)
+{
+       if (!log || log->entry_count == 0)
+               return 0;
+
+       return sizeof(log->signature) +
+               sizeof(log->entry_count) +
+               log->entry_count * sizeof(struct bbm_log_entry);
+}
+#endif /* MDASSEMBLE */
+
+/* allocate and load BBM log from metadata */
+static int load_bbm_log(struct intel_super *super)
+{
+       struct imsm_super *mpb = super->anchor;
+       __u32 bbm_log_size =  __le32_to_cpu(mpb->bbm_log_size);
+
+       super->bbm_log = xcalloc(1, sizeof(struct bbm_log));
+       if (!super->bbm_log)
+               return 1;
+
+       if (bbm_log_size) {
+               struct bbm_log *log = (void *)mpb +
+                       __le32_to_cpu(mpb->mpb_size) - bbm_log_size;
+
+               __u32 entry_count;
+
+               if (bbm_log_size < sizeof(log->signature) +
+                   sizeof(log->entry_count))
+                       return 2;
+
+               entry_count = __le32_to_cpu(log->entry_count);
+               if ((__le32_to_cpu(log->signature) != BBM_LOG_SIGNATURE) ||
+                   (entry_count > BBM_LOG_MAX_ENTRIES))
+                       return 3;
+
+               if (bbm_log_size !=
+                   sizeof(log->signature) + sizeof(log->entry_count) +
+                   entry_count * sizeof(struct bbm_log_entry))
+                       return 4;
+
+               memcpy(super->bbm_log, log, bbm_log_size);
+       } else {
+               super->bbm_log->signature = __cpu_to_le32(BBM_LOG_SIGNATURE);
+               super->bbm_log->entry_count = 0;
+       }
+
+       return 0;
+}
+
 /*
  * for second_map:
  *  == MAP_0 get first map
@@ -1544,7 +1614,7 @@ 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(__get_imsm_disk(mpb, super->disks->index), super->disks->index, reserved);
-       if (super->bbm_log) {
+       if (get_imsm_bbm_log_size(super->bbm_log)) {
                struct bbm_log *log = super->bbm_log;
 
                printf("\n");
@@ -1552,9 +1622,6 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
                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",
-                      (unsigned long long) __le64_to_cpu(log->first_spare_lba));
        }
        for (i = 0; i < mpb->num_raid_devs; i++) {
                struct mdinfo info;
@@ -3761,19 +3828,6 @@ 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;
-}
-
 /*******************************************************************************
  * Function:   check_mpb_migr_compatibility
  * Description:        Function checks for unsupported migration features:
@@ -3926,12 +3980,6 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
                return 3;
        }
 
-       /* 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);
-
        return 0;
 }
 
@@ -3977,6 +4025,9 @@ load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd
        if (err)
                return err;
        err = parse_raid_devices(super);
+       if (err)
+               return err;
+       err = load_bbm_log(super);
        clear_hi(super);
        return err;
 }
@@ -4041,6 +4092,8 @@ static void __free_imsm(struct intel_super *super, int free_disks)
                free(elem);
                elem = next;
        }
+       if (super->bbm_log)
+               free(super->bbm_log);
        super->hba = NULL;
 }
 
@@ -4647,7 +4700,7 @@ static int get_super_block(struct intel_super **super_list, char *devnm, char *d
                *super_list = s;
        } else {
                if (s)
-                       free(s);
+                       free_imsm(s);
                if (dfd >= 0)
                        close(dfd);
        }
@@ -4710,6 +4763,8 @@ static int load_super_imsm(struct supertype *st, int fd, char *devname)
 
        super = alloc_super();
        get_dev_sector_size(fd, NULL, &super->sector_size);
+       if (!super)
+               return 1;
        /* Load hba and capabilities if they exist.
         * But do not preclude loading metadata in case capabilities or hba are
         * non-compliant and ignore_hw_compat is set.
@@ -5054,7 +5109,7 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
        super = alloc_super();
        if (super &&
            posix_memalign(&super->buf, MAX_SECTOR_SIZE, mpb_size) != 0) {
-               free(super);
+               free_imsm(super);
                super = NULL;
        }
        if (!super) {
@@ -5065,7 +5120,7 @@ static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
            MIGR_REC_BUF_SECTORS*MAX_SECTOR_SIZE) != 0) {
                pr_err("could not allocate migr_rec buffer\n");
                free(super->buf);
-               free(super);
+               free_imsm(super);
                return 0;
        }
        memset(super->buf, 0, mpb_size);
@@ -5660,11 +5715,6 @@ static int store_super_imsm(struct supertype *st, int fd)
 #endif
 }
 
-static int imsm_bbm_log_size(struct imsm_super *mpb)
-{
-       return __le32_to_cpu(mpb->bbm_log_size);
-}
-
 #ifndef MDASSEMBLE
 static int validate_geometry_imsm_container(struct supertype *st, int level,
                                            int layout, int raiddisks, int chunk,
@@ -5700,6 +5750,10 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
         * note that there is no fd for the disks in array.
         */
        super = alloc_super();
+       if (!super) {
+               close(fd);
+               return 0;
+       }
        if (!get_dev_sector_size(fd, NULL, &super->sector_size)) {
                close(fd);
                free_imsm(super);
@@ -6937,12 +6991,6 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
                pr_err("Unsupported attributes in IMSM metadata.Arrays activation is blocked.\n");
        }
 
-       /* check for bad blocks */
-       if (imsm_bbm_log_size(super->anchor)) {
-               pr_err("BBM log found in IMSM metadata.Arrays activation is blocked.\n");
-               sb_errors = 1;
-       }
-
        /* count spare devices, not used in maps
         */
        for (d = super->disks; d; d = d->next)