Add basic support to ASR format handler to utilize reconfiguration features in reconfig.c. Signed-off-by: Adam DiCarlo <bikko@xxxxxxxxxx> Signed-off-by: James Simshaw <simshawj@xxxxxxxxxx> Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx>
--- ORIGINAL/lib/format/ataraid/asr.c 2006-07-26 14:24:36.000000000 -0700 +++ PATCHED/lib/format/ataraid/asr.c 2006-08-29 13:55:42.000000000 -0700 @@ -2,7 +2,9 @@ * Adaptec HostRAID ASR metadata format handler. * * Copyright (C) 2005-2006 IBM, All rights reserved. - * Written by Darrick Wong <djwong@xxxxxxxxxx> + * Written by Darrick Wong <djwong@xxxxxxxxxx>, + * James Simshaw <simshawj@xxxxxxxxxx>, and + * Adam DiCarlo <bikko@xxxxxxxxxx> * * Copyright (C) 2006 Heinz Mauelshagen, Red Hat GmbH * All rights reserved. @@ -12,6 +14,7 @@ #include <errno.h> #include <netinet/in.h> +#include <time.h> #define HANDLER "asr" @@ -28,7 +31,7 @@ static const char *handler = HANDLER; #define SPARE_ARRAY ".asr_spares" -static int asr_write(struct lib_context *lc, struct raid_dev *rd, int erase); +//static int asr_write(struct lib_context *lc, struct raid_dev *rd, int erase); /* Map ASR disk status to dmraid status */ static enum status disk_status(struct asr_raid_configline *disk) { @@ -47,19 +50,25 @@ static enum status disk_status(struct as return rd_status(states, disk->raidstate, EQUAL); } -/* Get this disk's configuration */ -static struct asr_raid_configline *this_disk(struct asr *asr) +/* Extract config line from metadata */ +static struct asr_raid_configline *get_config(struct asr *asr, uint32_t magic) { unsigned int i = asr->rt->elmcnt; while (i--) { - if (asr->rt->ent[i].raidmagic == asr->rb.drivemagic) + if (asr->rt->ent[i].raidmagic == magic) return asr->rt->ent + i; } return NULL; } +/* Get this disk's configuration */ +static struct asr_raid_configline *this_disk(struct asr *asr) +{ + return get_config(asr, asr->rb.drivemagic); +} + /* Make up RAID device name. */ static size_t _name(struct lib_context *lc, struct asr *asr, char *str, size_t len) @@ -235,7 +244,7 @@ static int read_extended(struct lib_cont RVALID2); /* Have we a valid element count? */ - if (asr->rt->elmcnt >= asr->rt->maxelm) + if (asr->rt->elmcnt >= asr->rt->maxelm || asr->rt->elmcnt == 0) LOG_ERR(lc, 0, "%s: Invalid RAID config table count.\n", handler); @@ -384,6 +393,25 @@ static void *read_metadata_areas(struct return (void*) asr; } +/* Read the whole metadata chunk at once */ +static uint8_t *read_metadata_chunk(struct lib_context *lc, struct dev_info *di, + uint64_t start) +{ + uint8_t *ret; + size_t size = (di->sectors - start) * ASR_DISK_BLOCK_SIZE; + + if (!(ret = dbg_malloc(size))) + LOG_ERR(lc, ret, "%s: unable to allocate memory.", di->path); + + if (!read_file(lc, handler, di->path, ret, size, + start * ASR_DISK_BLOCK_SIZE)) { + dbg_free(ret); + LOG_ERR(lc, NULL, "%s: unable to read metadata.", di->path); + } + + return ret; +} + /* * "File the metadata areas" -- I think this function is supposed to declare * which parts of the drive are metadata and thus off-limits to dmraid. @@ -391,13 +419,20 @@ static void *read_metadata_areas(struct static void file_metadata_areas(struct lib_context *lc, struct dev_info *di, void *meta) { + uint8_t *buf; struct asr *asr = meta; + uint64_t start = asr->rb.raidtbl; + + if (!(buf = read_metadata_chunk(lc, di, start))) + return; /* Register the raid tables. */ - file_metadata(lc, handler, di->path, asr->rt, + file_metadata(lc, handler, di->path, buf, ASR_DISK_BLOCK_SIZE * 17, - (uint64_t)asr->rb.raidtbl * ASR_DISK_BLOCK_SIZE); - + start * ASR_DISK_BLOCK_SIZE); + + dbg_free(buf); + /* Record the device size if -D was specified. */ file_dev_size(lc, handler, di); } @@ -482,6 +517,16 @@ static struct asr_raid_configline *find_ return NULL; } +static struct raid_dev *find_spare(struct lib_context *lc) { + struct raid_dev *spare; + + list_for_each_entry(spare, LC_RD(lc), list) { + if (spare->type == t_spare) + return spare; + } + return NULL; +} + /* Wrapper for name() */ static char *js_name(struct lib_context *lc, struct raid_dev *rd, unsigned int subset) @@ -581,6 +626,7 @@ static struct raid_set *asr_group(struct /* Add the disk to the set. */ list_add_sorted(lc, &set->devs, &rd->devs, dev_sort); + return set; } @@ -626,12 +672,267 @@ static struct raid_set *asr_group(struct LOG_ERR(lc, NULL, "Top level array config is not FWL/FWL2?\n"); } +/* deletes configline from metadata of given asr, by index. */ +static void delete_configline(struct asr *asr, int index) +{ + struct asr_raid_configline *cl, *end; + + asr->rt->elmcnt--; + cl = asr->rt->ent + index; + end = asr->rt->ent + asr->rt->elmcnt; + while (cl < end) { + memcpy(cl, cl + 1, sizeof(*cl)); + ++cl; + } +} + +/* Find the newest configline entry in raid set and return a pointer to it. */ +static struct raid_dev *find_newest_drive(struct raid_set *rs) +{ + struct asr *asr; + struct raid_dev *device, *newest = NULL; + uint16_t newest_raidseq = 0; + int i; + + list_for_each_entry(device, &rs->devs, devs) { + asr = META(device, asr); + // FIXME: We should be able to assume each configline + // in a single drive has the same raidseq as the rest + // in that drive. We're doing too much work here. + for (i = 0; i < asr->rt->elmcnt; ++i) { + if (asr->rt->ent[i].raidseq >= newest_raidseq) { + newest_raidseq = asr->rt->ent[i].raidseq; + newest = device; + } + } + } + + return newest; +} + +/* Creates a random integer for a drive magic section */ +static uint32_t create_drivemagic() { + + srand(time(NULL)); + + return rand() + rand(); +} + +static int spare(struct lib_context *lc, struct raid_dev *rd, + struct asr *asr) +{ + struct asr_raid_configline *cl; + + /* If the magic is already 0xFFFFFFFF, exit */ + if (asr->rt->raidmagic == 0xFFFFFFFF) + return 1; + + /* Otherwise, set the magic */ + asr->rt->raidmagic = 0xFFFFFFFF; + + /* Erase all the CLs, create the two defaults and exit */ + /* FIXME: How to set blockstoragetid? */ + asr->rt->elmcnt = 2; + + /* Note the presence of an array of spares in first config + * line entry. */ + cl = asr->rt->ent; + cl->raidmagic = 0xFFFFFFFF; + cl->raidseq = 0; + cl->name[0] = 0; + cl->raidcnt = 1; + cl->raidtype = ASR_RAIDSPR; + cl->lcapcty = rd->di->sectors; + cl->raidlevel = FWL; + cl++; + + /* Actually describe the disk: it's a spare. */ + cl->raidmagic = asr->rb.drivemagic; + cl->raidseq = 0; + cl->name[0] = 0; + cl->raidcnt = 0; + cl->raidtype = ASR_RAIDSPR; + cl->lcapcty = rd->di->sectors; + cl->raidlevel = FWP; + + return 1; +} + +/* Returns (boolean) whether or not the drive described by the given configline + * is in the given raid_set. */ +static int in_raid_set(struct asr_raid_configline *cl, struct raid_set *rs) +{ + struct asr *asr; + struct raid_dev *d; + + list_for_each_entry(d, &rs->devs, devs) { + asr = META(d, asr); + if (cl->raidmagic == asr->rb.drivemagic) + return 1; + } + return 0; +} + +/* Delete extra configlines which would otherwise trip us up. */ +static int cleanup_configlines(struct raid_dev *rd, struct raid_set *rs) +{ + struct asr *a; + struct raid_dev *d; + struct asr_raid_configline *cl; + int clcnt; + + list_for_each_entry(d, &rs->devs, devs) { + a = META(d, asr); + + cl = a->rt->ent; + for (clcnt = 0; clcnt < a->rt->elmcnt; /* done in loop */ ) { + /* If it's in the seen list, or is a logical drive, + * end iteration. The idea: get rid of configlines + * which describe devices which are no longer in the + * array. + * FIXME: If our topmost level is FWL2, we could have + * FWL entries which need to be removed, right? We need + * to check for this condition, too. */ + if (cl->raidlevel != FWP || in_raid_set(cl, rs)) { + cl++; + clcnt++; + } else { + /* Delete entry. After deleting, a new entry is + * found at *cl (a->rt->ent[clcnt]), so don't + * increment counter/pointer; otherwise we'd + * skip an entry. + */ + delete_configline(a, clcnt); + } + } + } + return 1; +} + +/* Add a CL entry */ +static int create_configline(struct raid_set *rs, struct asr *asr, + struct asr *a, struct raid_dev* newest) +{ + if (asr->rt->elmcnt >= RCTBL_MAX_ENTRIES) { + return 0; + } + + struct asr *newest_asr; + struct asr_raid_configline *cl; + + newest_asr = META(newest, asr); + + cl = asr->rt->ent + asr->rt->elmcnt; + asr->rt->elmcnt++; + + /* Use first raidseq, below: FIXME - don't assume all CLS are + * consistent */ + cl->raidmagic = a->rb.drivemagic; + cl->raidseq = newest_asr->rt->ent[0].raidseq; + cl->strpsize = newest_asr->rt->ent[0].strpsize; + strcpy((char*) cl->name, &rs->name[4]); /* starts after "asr_" */ + cl->raidcnt = 0; + + /* Convert rs->type to an ASR_RAID type for the CL */ + switch (rs->type) { + case t_raid0: + cl->raidtype = ASR_RAID0; + break; + case t_raid1: + cl->raidtype = ASR_RAID1; + break; + default: + return 0; + } + cl->lcapcty = newest_asr->rt->ent[0].lcapcty; + cl->raidlevel = FWP; + return 1; +} + +/* Update metadata to reflect the current raid set configuration. + * Returns boolean success. */ +static int update_metadata(struct lib_context *lc, struct raid_dev *rd, + struct asr *asr) +{ + struct raid_set *rs; + struct asr_raid_configline *cl; + struct raid_dev *d, *newest; + struct asr *a; + + /* Find the raid set */ + rs = get_raid_set(lc, rd); + if (!rs) { + /* Array-less disks ... have no CLs ? */ + asr->rt->elmcnt = 0; + return 1; + } + + /* If this is the spare array... */ + if (!strcmp(SPARE_ARRAY, rs->name)) { + return spare(lc, rd, asr); + } + + /* Find newest drive for use below */ + if (!(newest = find_newest_drive(rs))) + return 0; + + /* If the drive magic is 0xFFFFFFFF, assign a random one. */ + if (asr->rb.drivemagic == 0xFFFFFFFF) + asr->rb.drivemagic = create_drivemagic(); + + /* Make sure the raid type agrees with the metadata */ + if (type(this_disk(asr)) == t_spare) { + struct asr *newest_asr = META(newest, asr); + + /* copy entire table from newest drive */ + asr->rt->elmcnt = newest_asr->rt->elmcnt; + memcpy(asr->rt->ent, newest_asr->rt->ent, + asr->rt->elmcnt * sizeof(*asr->rt->ent)); + } + + /* Increment the top level CL's raid count */ + /* Fixme: What about the the FWLs in a FWL2 setting? */ + cl = asr->rt->ent + find_toplevel(lc, asr); + cl->raidseq++; + + /* For each disk in the rs */ + list_for_each_entry(d, &rs->devs, devs) { + a = META(d, asr); + + /* If it's in the CL already... */ + if ((cl = get_config(asr, a->rb.drivemagic))) { + /* Increment seq number */ + cl->raidseq++; + continue; + } + + /* If the magic is 0xFFFFFFFF, assign a random one */ + if (a->rb.drivemagic == 0xFFFFFFFF) { + a->rb.drivemagic = create_drivemagic(); + } + + if (!(newest = find_newest_drive(rs))) + return 0; + + create_configline(rs, asr, a, newest); + } + + cleanup_configlines(rd, rs); + + return 1; +} + + /* Write metadata. */ static int asr_write(struct lib_context *lc, struct raid_dev *rd, int erase) { struct asr *asr = META(rd, asr); int elmcnt = asr->rt->elmcnt, i, ret; + /* Update the metadata if we're not erasing it. */ + if (!erase) + update_metadata(lc, rd, asr); + /* Untruncate trailing whitespace in the name. */ for (i = 0; i < elmcnt; i++) handle_white_space(asr->rt->ent[i].name, UNTRUNCATE);
_______________________________________________ Ataraid-list mailing list Ataraid-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/ataraid-list