From 8d67477fd13086471fe08826f3f6333819cc8a71 Mon Sep 17 00:00:00 2001 From: Tomasz Majchrzak Date: Tue, 29 Nov 2016 16:40:11 +0100 Subject: [PATCH] imsm: parse bad block log in metadata on startup 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 Signed-off-by: Jes Sorensen --- super-intel.c | 140 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 94 insertions(+), 46 deletions(-) diff --git a/super-intel.c b/super-intel.c index 3d21f312..401ba756 100644 --- a/super-intel.c +++ b/super-intel.c @@ -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) -- 2.39.2