[PATCH] 3/4: Add multiple raid_dev per physical device support to DDF

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

 



Hello,

These are preliminary patches to modify dmraid so that we can have
multiple raid_dev structures per physical device.  The DDF1
specification allows for a disk to participate in multiple RAID arrays,
which is what is gained from these patches.  They've been tested against
2.6.16.19 + dmraid45 on Ubuntu 6.06, and seem to be pretty stable.  At
this stage, I'm looking for comments about the code because it touches
core dmraid code and could (but shouldn't) break support for hardware
that I don't have.

This patch changes the DDF handler:

- Function prototypes of read_raid_dev and setup_rd are fixed up.

- Modifies setup_rd to handle cloning correctly.

- Adds a function get_config_byoffset to return the configuration record
for a given combination of a disk and the data offset.

- Modifies the other get_config_* functions in the DDF handler to demand
either the data offset or the index into the configuration record array.

- Modifies all callers of get_config_* functions to locate the correct
config record.

- Adds a function num_devs to calculate the number of raid_devs we need
to take care of a given metadata blob.  We are assured that the number
of config records in a disk's metadata == the number of arrays in which
the disk participates by the DDF spec.

--D

Signed-off-by: Darrick J. Wong <djwong@xxxxxxxxxx>
diff -Naurp v11.orig/lib/format/ataraid/ddf1.c v11-mdisk3/lib/format/ataraid/ddf1.c
--- v11.orig/lib/format/ataraid/ddf1.c	2006-05-16 17:51:35.000000000 -0700
+++ v11-mdisk3/lib/format/ataraid/ddf1.c	2006-06-01 15:17:21.000000000 -0700
@@ -182,10 +182,43 @@ static inline struct ddf1_phys_drive *ge
 }
 
 /*
+ * Find the index of the VD config record for this drive and offset.
+ */
+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 VD config record for this drive.
  * FIXME: Drives can belong to multiple VDs!
  */
-static int get_config_index(struct ddf1 *ddf1, struct ddf1_phys_drive *pd)
+static int get_config_index(struct ddf1 *ddf1, struct ddf1_phys_drive *pd,
+			    unsigned int num)
 {
 	int i, j;
 	uint32_t *ids;
@@ -198,8 +231,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 (!num)
+					return i;
+				else
+					num--;
+			}
 		}
 	}
 
@@ -211,17 +248,26 @@ static int get_config_index(struct ddf1 
  * FIXME: Drives can belong to multiple VDs!
  */
 static inline struct ddf1_config_record *get_config(struct ddf1 *ddf1,
-						    struct ddf1_phys_drive *pd)
+						    struct ddf1_phys_drive *pd,
+						    unsigned int num)
 {
-	int x = get_config_index(ddf1, pd);
+	int x = get_config_index(ddf1, pd, num);
 
 	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)
+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. */
@@ -951,10 +997,41 @@ static void file_metadata_areas(struct l
 	return;
 }
 
+/* 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;
+}
+
 static int setup_rd(struct lib_context *lc, struct raid_dev *rd,
-		    struct dev_info *di, void *meta, union read_info *info);
+		    struct dev_info *di, void *meta, union read_info *info,
+		    unsigned int num);
 static struct raid_dev *ddf1_read(struct lib_context *lc,
-					struct dev_info *di)
+				  struct dev_info *di)
 {
 	/*
 	 * NOTE: Everything called after read_metadata_areas assumes that
@@ -962,14 +1039,17 @@ static struct raid_dev *ddf1_read(struct
 	 * converted to the appropriate endianness.
 	 */
 	return read_raid_dev(lc, di, read_metadata_areas, 0, 0, NULL, NULL,
-			     file_metadata_areas, setup_rd, handler);
+			     file_metadata_areas, setup_rd, handler, num_devs);
 }
 
-static inline int compose_id(struct ddf1 *ddf1)
+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 0;
 
-	return get_offset_entry(ddf1, get_config(ddf1, pd), pd);
+	return get_offset_entry(ddf1, get_config(ddf1, pd, x), pd);
 }
 
 /* No sort. */
@@ -978,11 +1058,11 @@ static int no_sort(struct list_head *pos
 	return 0;
 }
 
-/* Sort DDF1 devices by for a RAID set. */
+/* Sort DDF1 devices by offset 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), ddf1), RD(new)) <
+	       compose_id(META(RD(pos), ddf1), RD(pos));
 }
 
 #if 0
@@ -1070,7 +1150,7 @@ 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 +1164,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;
 	}
@@ -1137,11 +1218,12 @@ static struct raid_set *ddf1_group(struc
 	struct ddf1_config_record *cr;
 	struct raid_set *rs;
 	char *set_name;
+	int j;
 
 	if (!(pd = get_this_phys_drive(ddf1)))
 		LOG_ERR(lc, NULL, "Cannot find physical drive description!\n");
 
-	set_name = name(lc, ddf1);
+	set_name = name(lc, ddf1, rd);
 	if (!set_name)
 		LOG_ERR(lc, NULL, "%s: Could not find RAID array name.\n",
 			rd->di->path);
@@ -1149,7 +1231,8 @@ static struct raid_set *ddf1_group(struc
 	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))) {
+		j = get_config_byoffset(ddf1, pd, rd->offset);
+		if (j >= 0 && (cr = get_config(ddf1, pd, j))) {
 			rs->stride = stride(cr);
 			rs->type = type(lc, ddf1, cr);
 			rd_sort = dev_sort;
@@ -1187,7 +1270,7 @@ 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, ddf1), rd->offset);
 
 	return cr ? cr->primary_element_count : 0;
 }
@@ -1509,21 +1592,38 @@ static uint64_t get_size(struct lib_cont
  * 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)
+		    struct dev_info *di, void *meta, union read_info *info,
+		    unsigned int num)
 {
 	struct ddf1 *ddf1 = meta;
 	struct meta_areas *ma;
 	struct ddf1_phys_drive *pd;
 	struct ddf1_config_record *cr;
+	struct raid_dev *orig;
 	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);
+	cr = get_config(ddf1, pd, num);
+
+	/* If num != 0, we need to find a raid_dev to clone from. */
+	if (num != 0) {
+		orig = find_raid_dev_in_chain(rd, di);
+		if (!orig)
+			LOG_ERR(lc, 0,
+				"Can't find suitable raid_dev clone target.");
+
+		clone_raid_dev(rd, orig);
 
-	/* We need multiple metadata areas */
+		goto common_init;
+	}
+
+	/*
+	 * Otherwise, we're the first raid_dev for the drive, so we must
+	 * fill out the metadata.
+	 */
 	if (ddf1->adapter)
 		md_area_count++;
 
@@ -1605,10 +1705,12 @@ static int setup_rd(struct lib_context *
 	rd->status = disk_status(pd);
 	rd->type   = (cr ? type(lc, ddf1, cr) : t_spare);
 
+	rd->name = name(lc, ddf1, rd);
+
+common_init:
+	/* We always have to set the offset and sector counts. */
 	rd->offset = get_offset(ddf1, cr, pd);
 	rd->sectors = get_size(lc, ddf1, cr, pd);
 
-	rd->name = name(lc, ddf1);
-
 	return 1;
 }
_______________________________________________

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