[PATCH] v2 of multiple volume support for DDF

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Heinz Mauelshagen wrote:

> The simple volume management some vendors (and SNIA) build into their RAID
> solutions, forced the ability to map multiple RAID sets onto the same group
> of RAID devices, hence the idea of having a special 'group' RAID set as used
> for isw.

Ok, I've reworked my previous patches; attached is version 2 of support
for multi-volume DDF configurations.  This patch is entirely
self-contained within the DDF metadata handler and requires no changes
to the core code.  Other than that, it's pretty much the same thing as
the first iteration.  It's known to work against all of my DDF samples
as well as the Dell samples that Heinz sent me.

Comments?

--D
diff -Naurp v11.orig/lib/format/ataraid/ddf1.c v11-mdisk4/lib/format/ataraid/ddf1.c
--- v11.orig/lib/format/ataraid/ddf1.c	2006-05-16 17:51:35.000000000 -0700
+++ v11-mdisk4/lib/format/ataraid/ddf1.c	2006-06-27 19:44:02.000000000 -0700
@@ -182,10 +182,42 @@ static inline struct ddf1_phys_drive *ge
 }
 
 /*
- * Find the index of the VD config record for this drive.
- * FIXME: Drives can belong to multiple VDs!
+ * Find the index of the VD config record given a physical drive and offset.
  */
-static int get_config_index(struct ddf1 *ddf1, struct ddf1_phys_drive *pd)
+static int get_config_byoffset(struct ddf1 *ddf1, struct ddf1_phys_drive *pd,
+			       uint64_t offset)
+{
+	int i;
+	uint32_t x, j;
+	struct ddf1_config_record *cfg;
+	uint32_t *cfg_drive_ids;
+	uint64_t *cfg_drive_offsets;
+
+	for (i = 0; i < NUM_CONFIG_ENTRIES(ddf1); i++) {
+		cfg = CR(ddf1, i);
+
+		if (cfg->signature != DDF1_VD_CONFIG_REC)
+			continue;
+
+		cfg_drive_ids = CR_IDS(ddf1, cfg);
+		cfg_drive_offsets = CR_OFF(ddf1, cfg);
+
+		x = cfg->primary_element_count;
+		for (j = 0; j < x; j++) {
+			if (cfg_drive_ids[j] == pd->reference &&
+			    cfg_drive_offsets[j] == offset)
+				return i;
+		}
+	}
+
+	return -ENOENT;
+}
+
+/*
+ * Find the index of the nth VD config record for this physical drive.
+ */
+static int get_config_index(struct ddf1 *ddf1, struct ddf1_phys_drive *pd,
+			    unsigned int n)
 {
 	int i, j;
 	uint32_t *ids;
@@ -198,8 +230,12 @@ static int get_config_index(struct ddf1 
 
 		ids = CR_IDS(ddf1, cr);
 		for (j = 0; j < cr->primary_element_count; j++) {
-			if (ids[j] == pd->reference)
-				return i;
+			if (ids[j] == pd->reference) {
+				if (!n)
+					return i;
+				else
+					n--;
+			}
 		}
 	}
 
@@ -207,21 +243,30 @@ static int get_config_index(struct ddf1 
 }
 
 /*
- * Find the VD config record for this drive.
- * FIXME: Drives can belong to multiple VDs!
+ * Find the nth VD config record for this physical drive.
  */
 static inline struct ddf1_config_record *get_config(struct ddf1 *ddf1,
-						    struct ddf1_phys_drive *pd)
+						    struct ddf1_phys_drive *pd,
+						    unsigned int n)
 {
-	int x = get_config_index(ddf1, pd);
+	int x = get_config_index(ddf1, pd, n);
 
 	return (x < 0) ? NULL : CR(ddf1, x);
 }
  
-/* Find this drive's config record */
-static inline struct ddf1_config_record *get_this_config(struct ddf1 *ddf1)
+/* Find a config record for this drive, given the offset of the array. */
+static inline struct ddf1_config_record *get_this_config(struct ddf1 *ddf1,
+							 uint64_t offset)
 {
-	return get_config(ddf1, get_this_phys_drive(ddf1));
+	struct ddf1_phys_drive *pd;
+	int j;
+
+	pd = get_this_phys_drive(ddf1);
+	j = get_config_byoffset(ddf1, pd, offset);
+	if (j < 0)
+		return NULL;
+
+	return get_config(ddf1, pd, j);
 }
 
 /* Find the config record disk/offset entry for this config/drive. */
@@ -262,7 +307,6 @@ static inline unsigned int stride(struct
 }
 
 /* Mapping of template types to generic types */
-/* FIXME: Does dm do RAID3/4/5 yet? */
 static struct types types[] = {
 	{ DDF1_RAID0,	t_raid0 },
 	{ DDF1_RAID1,	t_raid1 },
@@ -834,6 +878,36 @@ bad:
 	return 0;
 }
 
+/* Count the number of raid_devs we need to create for this drive */
+static unsigned int num_devs(struct lib_context *lc, void *meta)
+{
+	int i;
+	uint32_t x, j;
+	struct ddf1_config_record *cfg;
+	uint32_t *cfg_drive_ids;
+	struct ddf1_phys_drive *pd;
+	unsigned int num_drives = 0;
+	struct ddf1 *ddf1 = meta;
+
+	pd = get_this_phys_drive(ddf1);
+	
+	for (i = 0; i < NUM_CONFIG_ENTRIES(ddf1); i++) {
+		cfg = CR(ddf1, i);
+
+		if (cfg->signature != DDF1_VD_CONFIG_REC)
+			continue;
+
+		cfg_drive_ids = CR_IDS(ddf1, cfg);
+
+		x = cfg->primary_element_count;
+		for (j = 0; j < x; j++)
+			if (cfg_drive_ids[j] == pd->reference)
+				num_drives++;
+	}
+
+	return num_drives;
+}
+
 /* Is this DDF1 metadata? */
 static int is_ddf1(struct lib_context *lc, struct dev_info *di,
 		   struct ddf1 *ddf1)
@@ -965,11 +1039,15 @@ static struct raid_dev *ddf1_read(struct
 			     file_metadata_areas, setup_rd, handler);
 }
 
-static inline int compose_id(struct ddf1 *ddf1)
+/* Compose an "identifier" for use as a sort key for raid sets. */
+static inline int compose_id(struct ddf1 *ddf1, struct raid_dev *rd)
 {
 	struct ddf1_phys_drive *pd = get_this_phys_drive(ddf1);
+	int x = get_config_byoffset(ddf1, pd, rd->offset);
+	if (x < 0)
+		return -1;
 
-	return get_offset_entry(ddf1, get_config(ddf1, pd), pd);
+	return get_offset_entry(ddf1, get_config(ddf1, pd, x), pd);
 }
 
 /* No sort. */
@@ -981,61 +1059,10 @@ static int no_sort(struct list_head *pos
 /* Sort DDF1 devices by for a RAID set. */
 static int dev_sort(struct list_head *pos, struct list_head *new)
 {
-	return compose_id(META(RD(new), ddf1)) <
-	       compose_id(META(RD(pos), ddf1));
+	return compose_id(META(RD(new)->private.ptr, ddf1), RD(new)) <
+	       compose_id(META(RD(pos)->private.ptr, ddf1), RD(pos));
 }
 
-#if 0
-/*
- * Find the top-level RAID set for an DDF1 context.
- */
-static int find_toplevel(struct lib_context *lc, struct ddf1 *ddf1)
-{
-	int i, toplevel = -1;
-
-	for (i = 0; i < ddf1->rt.elmcnt; i++) {
-		if (ddf1->rt.ent[i].raidlevel == FWL)
-			toplevel = i;
-		else if (ddf1->rt.ent[i].raidlevel == FWL_2)
-		{
-			toplevel = i;
-			break;
-		}
-	}
-	
-	return toplevel;
-}
-
-/*
- * Find the logical drive configuration that goes with this
- * physical disk configuration.
- */
-static struct ddf1_raid_configline *find_logical(struct ddf1 *ddf1)
-{
-	int i, j;
-
-	/* This MUST be done backwards! */
-	for (i = ddf1->rt.elmcnt - 1; i > -1; i--) {
-		if (ddf1->rt.ent[i].raidmagic == ddf1->rb.drivemagic)
-		{
-			for (j = i - 1; j > -1; j--) {
-				if (ddf1->rt.ent[j].raidlevel == FWL)
-					return ddf1->rt.ent + j;
-			}
-		}
-	}
-
-	return NULL;
-}
-
-/* Wrapper for name() */
-static char *js_name(struct lib_context *lc, struct raid_dev *rd,
-		     unsigned int subset)
-{
-	return name(lc, META(rd, ddf1));
-}
-#endif
-
 /*
  * IO error event handler.
  */
@@ -1048,6 +1075,7 @@ static int event_io(struct lib_context *
 }
 
 #if 0
+	/* FIXME: This should not use META() directly? */
 	struct raid_dev *rd = e_io->rd;
 	struct ddf1 *ddf1 = META(rd, ddf1);
 	struct ddf1_raid_configline *cl = this_disk(ddf1);
@@ -1070,7 +1098,8 @@ static int event_io(struct lib_context *
 
 #define NAME_SIZE 64
 /* Formulate a RAID set name for this disk. */
-static char *name(struct lib_context *lc, struct ddf1 *ddf1)
+static char *name(struct lib_context *lc, struct ddf1 *ddf1,
+		  struct raid_dev *rd)
 {
 	struct ddf1_phys_drive *pd;
 	struct ddf1_virt_drive *vd;
@@ -1084,7 +1113,8 @@ static char *name(struct lib_context *lc
 	if (!(pd = get_this_phys_drive(ddf1)))
 		LOG_ERR(lc, NULL, "Cannot find physical drive description!");
 
- 	if (!(cr = get_config(ddf1, pd))) {
+	j = get_config_byoffset(ddf1, pd, rd->offset);
+ 	if (j < 0 || !(cr = get_config(ddf1, pd, j))) {
 		memcpy(buf, ".ddf1_spares", 13);
 		return buf;
 	}
@@ -1122,6 +1152,83 @@ static char *name(struct lib_context *lc
 	return buf;
 }
 
+/* Figure out the real size of a disk... */
+static uint64_t get_size(struct lib_context *lc, struct ddf1 *ddf1,
+			 struct ddf1_config_record *cr,
+			 struct ddf1_phys_drive *pd)
+{
+	if (!cr)
+		return pd->size;
+
+	switch (type(lc, ddf1, cr)) {
+		case t_raid0:
+			/* Some Adaptec controllers need this clamping. */
+			return cr->sectors - cr->sectors %
+			       (1 << cr->stripe_size);
+
+		default:
+			return cr->sectors;
+	}
+}
+
+/*
+ * Create all the volumes of a DDF disk as subsets of the top level DDF
+ * disk group.  rs_group points to that raid set and is returned if the
+ * function is successful, NULL if not.  rd_group is the raid_dev that
+ * represents the entire disk drive.
+ */
+static struct raid_set *group_rd(struct lib_context *lc,
+				 struct raid_set *rs_group,
+				 struct raid_dev *rd_group)
+{
+	struct ddf1 *ddf1 = META(rd_group, ddf1);
+	struct raid_set *rs = NULL;
+	struct raid_dev *rd;
+	struct ddf1_config_record *cr;
+	struct ddf1_phys_drive *pd;
+	unsigned int i;
+	
+	if (!(pd = get_this_phys_drive(ddf1)))
+		return NULL;
+
+	for (i = 0; i < num_devs(lc, ddf1); i++) {
+		/* Allocate a raid_dev for this volume */
+		cr = get_config(ddf1, pd, i);
+
+		if (!(rd = alloc_raid_dev(lc, handler)))
+			return NULL;
+
+		rd->di = rd_group->di;
+		rd->fmt = rd_group->fmt;
+		rd->type = type(lc, ddf1, cr);
+
+		rd->offset = get_offset(ddf1, cr, pd);
+		rd->sectors = get_size(lc, ddf1, cr, pd);
+
+		rd->name = name(lc, ddf1, rd);
+
+		/* Stuff it into the appropriate raid set. */
+		if (!(rs = find_or_alloc_raid_set(lc, rd->name, FIND_ALL,
+						  rd, &rs_group->sets,
+						  NO_CREATE, NO_CREATE_ARG))) {
+			free_raid_dev(lc, &rd);
+			return NULL;
+		}
+
+		rs->stride = stride(cr);
+		rs->type = type(lc, ddf1, cr);
+		rs->status = s_ok;
+
+		if (!(rd->private.ptr = alloc_private(lc, handler, sizeof(*rd_group))))
+			return NULL;
+
+		memcpy(rd->private.ptr, rd_group, sizeof (*rd_group));
+		list_add_sorted(lc, &rs->devs, &rd->devs, dev_sort);
+	}
+
+	return rs_group;
+}
+
 /* 
  * Add an DDF1 device to a RAID set.  This involves finding the raid set to
  * which this disk belongs, and then attaching it.  Note that there are other
@@ -1131,39 +1238,36 @@ static char *name(struct lib_context *lc
  */
 static struct raid_set *ddf1_group(struct lib_context *lc, struct raid_dev *rd)
 {
-	int (*rd_sort)();
 	struct ddf1 *ddf1 = META(rd, ddf1);
 	struct ddf1_phys_drive *pd;
-	struct ddf1_config_record *cr;
 	struct raid_set *rs;
 	char *set_name;
 
 	if (!(pd = get_this_phys_drive(ddf1)))
 		LOG_ERR(lc, NULL, "Cannot find physical drive description!\n");
 
-	set_name = name(lc, ddf1);
+	set_name = rd->name;
 	if (!set_name)
 		LOG_ERR(lc, NULL, "%s: Could not find RAID array name.\n",
 			rd->di->path);
 
-	if ((rs = find_or_alloc_raid_set(lc, set_name, FIND_TOP, rd,
-					 LC_RS(lc), NO_CREATE,
-					 NO_CREATE_ARG))) {
-		if ((cr = get_config(ddf1, pd))) {
-			rs->stride = stride(cr);
-			rs->type = type(lc, ddf1, cr);
-			rd_sort = dev_sort;
-		} else {
-			rs->stride = 0;
-			rs->type = t_linear;
-			rd_sort = no_sort;
-		}
+	/*
+	 * Find/create a raid set for all DDF drives and put this disk
+	 * into that set.  The raid_sets for the real arrays will be created
+	 * as children of the disk's raid_set.
+	 *
+	 * (Is this really necessary?)
+	 */
+	if (!(rs = find_or_alloc_raid_set(lc, set_name, FIND_TOP, rd,
+					  LC_RS(lc), NO_CREATE,
+					  NO_CREATE_ARG)))
+		return NULL;
 
-		rs->status = s_ok;
-		list_add_sorted(lc, &rs->devs, &rd->devs, rd_sort);
-	}
-	
-	return rs;
+	rs->type = t_group;
+	list_add_sorted(lc, &rs->devs, &rd->devs, no_sort);
+
+	/* Go deal with the real arrays. */
+	return group_rd(lc, rs, rd);
 }
 
 /* Write metadata. */
@@ -1187,7 +1291,8 @@ static int ddf1_write(struct lib_context
 static unsigned int device_count(struct raid_dev *rd, void *context)
 {
 	/* Get the logical drive */
-	struct ddf1_config_record *cr = get_this_config(META(rd, ddf1));
+	struct ddf1_config_record *cr = get_this_config(META(rd->private.ptr, ddf1),
+							rd->offset);
 
 	return cr ? cr->primary_element_count : 0;
 }
@@ -1485,28 +1590,8 @@ int register_ddf1(struct lib_context *lc
 	return register_format_handler(lc, &ddf1_format);
 }
 
-/* Figure out the real size of a disk... */
-static uint64_t get_size(struct lib_context *lc, struct ddf1 *ddf1,
-			 struct ddf1_config_record *cr,
-			 struct ddf1_phys_drive *pd)
-{
-	if (!cr)
-		return pd->size;
-
-	switch (type(lc, ddf1, cr)) {
-		case t_raid0:
-			/* Some Adaptec controllers need this clamping. */
-			return cr->sectors - cr->sectors %
-			       (1 << cr->stripe_size);
-
-		default:
-			return cr->sectors;
-	}
-}
-
 /*
  * Set up a RAID device from what we've assembled out of the metadata.
- * FIXME: What if we have more than one array per disk?
  */
 static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
 		    struct dev_info *di, void *meta, union read_info *info)
@@ -1514,15 +1599,12 @@ static int setup_rd(struct lib_context *
 	struct ddf1 *ddf1 = meta;
 	struct meta_areas *ma;
 	struct ddf1_phys_drive *pd;
-	struct ddf1_config_record *cr;
 	int md_area_count = 5;
 
 	pd = get_this_phys_drive(ddf1);
 	if (!pd)
 		LOG_ERR(lc, 0, "Cannot find physical drive description!\n");
 
-	cr = get_config(ddf1, pd);
-
 	/* We need multiple metadata areas */
 	if (ddf1->adapter)
 		md_area_count++;
@@ -1603,12 +1685,12 @@ static int setup_rd(struct lib_context *
 	rd->fmt = &ddf1_format;
 
 	rd->status = disk_status(pd);
-	rd->type   = (cr ? type(lc, ddf1, cr) : t_spare);
+	rd->type   = t_group;
 
-	rd->offset = get_offset(ddf1, cr, pd);
-	rd->sectors = get_size(lc, ddf1, cr, pd);
+	rd->offset = 0;
+	rd->sectors = info->u64 >> 9;
 
-	rd->name = name(lc, ddf1);
+	rd->name = strdup(".ddf_disks");
 
 	return 1;
 }

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________

Ataraid-list@xxxxxxxxxx
https://www.redhat.com/mailman/listinfo/ataraid-list

[Index of Archives]     [Linux RAID]     [Linux Device Mapper]     [Linux IDE]     [Linux SCSI]     [Kernel]     [Linux Books]     [Linux Admin]     [GFS]     [RPM]     [Yosemite Campgrounds]     [AMD 64]

  Powered by Linux