- Subject: [PATCH] 6/6: Add ASR reconfiguration support
- From: Adam DiCarlo <bikko@xxxxxxxxxx>
- Date: Wed, 30 Aug 2006 14:28:53 -0700
- User-agent: Thunderbird 1.5.0.5 (X11/20060728)
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
[Linux RAID]
[Linux IDE]
[Linux SCSI]
[Kernel]
[Linux Books]
[Linux Admin]
[GFS]
[RPM]
[Photos]
[Yosemite Photos]
[Yosemite News]
[AMD 64]