[PATCH] 6/6: Add ASR reconfiguration support

Adam DiCarlo <[email protected]>
Newsgroups gmane.linux.ataraid
Message-ID <[email protected]>
Add basic support to ASR format handler to utilize reconfiguration
features in reconfig.c.

Signed-off-by: Adam DiCarlo <[email protected]>
Signed-off-by: James Simshaw <[email protected]>
Signed-off-by: Darrick J. Wong <[email protected]>

_______________________________________________
Ataraid-list mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/ataraid-list
asr.patch (text/x-patch, 11 KB)
--- 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 <[email protected]>
+ * Written by Darrick Wong <[email protected]>,
+ * James Simshaw <[email protected]>, and
+ * Adam DiCarlo <[email protected]>
  *
  * 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);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.