Dan Williams: imsm: fix family number handling

Martin F. Krafft madduck at alioth.debian.org
Tue Oct 27 19:21:45 UTC 2009


Module: mdadm
Branch: upstream
Commit: 148acb7baaa810b68d55df4c1784d6bd0dfd1b78
URL:    http://git.debian.org/?p=pkg-mdadm/mdadm.git;a=commit;h=148acb7baaa810b68d55df4c1784d6bd0dfd1b78

Author: Dan Williams <dan.j.williams at intel.com>
Date:   Fri Jul 31 17:11:41 2009 -0700

imsm: fix family number handling

The family_number field can change.  The option-rom will change the
family number when it starts a rebuild process (flags a container for
rebuild).  This was not seen previously as mdadm would usually start the
rebuild process, preserving the family number.

This is the mechanism that helps to prevent a prodigal array member from
being returned to its original system and cause a rebuild to go in the
wrong direction.  With the change we will end up with a container that
will fail to assemble unless the device with the incompatible family
number is left out of the assembly.

So, take several actions:
1/ Convert uuid generation to use orig_family_num, being careful to
   preserve the existing uuid in the case where orig_family_num is not
   set (i.e. previous mdadm created imsm arrays)
2/ Set orig_family_num at Create.  For arrays created by mdadm prior to
   this release orig_family_num will be zero, so set it to family_num at
   the first metadata write.
3/ Add checks for orig_family_num to compare_super_imsm
4/ Update the family number when initiating rebuild
5/ The option-rom mixes some random data into the family number, add
   this functionality to the mdadm implementation.

Reported-by: Marcin Labun <marcin.labun at intel.com>
Signed-off-by: Dan Williams <dan.j.williams at intel.com>


---

 mdadm.h       |    1 +
 super-ddf.c   |   11 -----------
 super-intel.c |   41 ++++++++++++++++++++++++++++++++++++-----
 util.c        |   11 +++++++++++
 4 files changed, 48 insertions(+), 16 deletions(-)

diff --git a/mdadm.h b/mdadm.h
index e564dee..4111eaf 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -848,6 +848,7 @@ extern int open_container(int fd);
 extern int mdmon_running(int devnum);
 extern int signal_mdmon(int devnum);
 extern int check_env(char *name);
+extern __u32 random32(void);
 extern int start_mdmon(int devnum);
 
 extern char *devnum2devname(int num);
diff --git a/super-ddf.c b/super-ddf.c
index 0b15275..c28d804 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -1512,17 +1512,6 @@ static int update_super_ddf(struct supertype *st, struct mdinfo *info,
 	return rv;
 }
 
-__u32 random32(void)
-{
-	__u32 rv;
-	int rfd = open("/dev/urandom", O_RDONLY);
-	if (rfd < 0 || read(rfd, &rv, 4) != 4)
-		rv = random();
-	if (rfd >= 0)
-		close(rfd);
-	return rv;
-}
-
 static void make_header_guid(char *guid)
 {
 	__u32 stamp;
diff --git a/super-intel.c b/super-intel.c
index 07e3d46..6e4a7d9 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -247,6 +247,7 @@ struct intel_super {
 	int creating_imsm; /* flag to indicate container creation */
 	int current_vol; /* index of raid device undergoing creation */
 	__u32 create_offset; /* common start for 'current_vol' */
+	__u32 random; /* random data for seeding new family numbers */
 	struct intel_dev *devlist;
 	struct dl {
 		struct dl *next;
@@ -714,6 +715,7 @@ static void examine_super_imsm(struct supertype *st, char *homehost)
 	printf("          Magic : %s\n", str);
 	snprintf(str, strlen(MPB_VERSION_RAID0), "%s", get_imsm_version(mpb));
 	printf("        Version : %s\n", get_imsm_version(mpb));
+	printf("    Orig Family : %08x\n", __le32_to_cpu(mpb->orig_family_num));
 	printf("         Family : %08x\n", __le32_to_cpu(mpb->family_num));
 	printf("     Generation : %08x\n", __le32_to_cpu(mpb->generation_num));
 	getinfo_super_imsm(st, &info);
@@ -1091,7 +1093,7 @@ static int match_home_imsm(struct supertype *st, char *homehost)
 	/* the imsm metadata format does not specify any host
 	 * identification information.  We return -1 since we can never
 	 * confirm nor deny whether a given array is "meant" for this
-	 * host.  We rely on compare_super and the 'family_num' field to
+	 * host.  We rely on compare_super and the 'family_num' fields to
 	 * exclude member disks that do not belong, and we rely on
 	 * mdadm.conf to specify the arrays that should be assembled.
 	 * Auto-assembly may still pick up "foreign" arrays.
@@ -1119,7 +1121,7 @@ static void uuid_from_super_imsm(struct supertype *st, int uuid[4])
 	 */
 	/* imsm does not track uuid's so we synthesis one using sha1 on
 	 * - The signature (Which is constant for all imsm array, but no matter)
-	 * - the family_num of the container
+	 * - the orig_family_num of the container
 	 * - the index number of the volume
 	 * - the 'serial' number of the volume.
 	 * Hopefully these are all constant.
@@ -1129,10 +1131,18 @@ static void uuid_from_super_imsm(struct supertype *st, int uuid[4])
 	char buf[20];
 	struct sha1_ctx ctx;
 	struct imsm_dev *dev = NULL;
+	__u32 family_num;
 
+	/* some mdadm versions failed to set ->orig_family_num, in which
+	 * case fall back to ->family_num.  orig_family_num will be
+	 * fixed up with the first metadata update.
+	 */
+	family_num = super->anchor->orig_family_num;
+	if (family_num == 0)
+		family_num = super->anchor->family_num;
 	sha1_init_ctx(&ctx);
 	sha1_process_bytes(super->anchor->sig, MPB_SIG_LEN, &ctx);
-	sha1_process_bytes(&super->anchor->family_num, sizeof(__u32), &ctx);
+	sha1_process_bytes(&family_num, sizeof(__u32), &ctx);
 	if (super->current_vol >= 0)
 		dev = get_imsm_dev(super, super->current_vol);
 	if (dev) {
@@ -1440,7 +1450,8 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst)
 	 */
 	if (first->anchor->num_raid_devs > 0 &&
 	    sec->anchor->num_raid_devs > 0) {
-		if (first->anchor->family_num != sec->anchor->family_num)
+		if (first->anchor->orig_family_num != sec->anchor->orig_family_num ||
+		    first->anchor->family_num != sec->anchor->family_num)
 			return 3;
 	}
 
@@ -1480,6 +1491,7 @@ static int compare_super_imsm(struct supertype *st, struct supertype *tst)
 			imsm_copy_dev(get_imsm_dev(first, i), get_imsm_dev(sec, i));
 
 		first->anchor->num_raid_devs = sec->anchor->num_raid_devs;
+		first->anchor->orig_family_num = sec->anchor->orig_family_num;
 		first->anchor->family_num = sec->anchor->family_num;
 	}
 
@@ -2549,8 +2561,10 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
 
 		*_dev = *dev;
 		*_disk = dl->disk;
-		sum = __gen_imsm_checksum(mpb);
+		sum = random32();
+		sum += __gen_imsm_checksum(mpb);
 		mpb->family_num = __cpu_to_le32(sum);
+		mpb->orig_family_num = mpb->family_num;
 	}
 
 	return 0;
@@ -2647,6 +2661,7 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose)
 		mpb->disk[0] = d->disk;
 		sum = __gen_imsm_checksum(mpb);
 		mpb->family_num = __cpu_to_le32(sum);
+		mpb->orig_family_num = 0;
 		sum = __gen_imsm_checksum(mpb);
 		mpb->check_sum = __cpu_to_le32(sum);
 
@@ -2681,6 +2696,12 @@ static int write_super_imsm(struct intel_super *super, int doclose)
 	generation++;
 	mpb->generation_num = __cpu_to_le32(generation);
 
+	/* fix up cases where previous mdadm releases failed to set
+	 * orig_family_num
+	 */
+	if (mpb->orig_family_num == 0)
+		mpb->orig_family_num = mpb->family_num;
+
 	mpb_size += sizeof(struct imsm_disk) * mpb->num_disks;
 	for (d = super->disks; d; d = d->next) {
 		if (d->index == -1)
@@ -4040,6 +4061,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
 		di->data_offset = __le32_to_cpu(map->pba_of_lba0);
 		di->component_size = a->info.component_size;
 		di->container_member = inst;
+		super->random = random32();
 		di->next = rv;
 		rv = di;
 		num_spares++;
@@ -4206,6 +4228,15 @@ static void imsm_process_update(struct supertype *st,
 		set_imsm_ord_tbl_ent(map, u->slot, dl->index);
 		set_imsm_ord_tbl_ent(migr_map, u->slot, dl->index | IMSM_ORD_REBUILD);
 
+		/* update the family_num to mark a new container
+		 * generation, being careful to record the existing
+		 * family_num in orig_family_num to clean up after
+		 * earlier mdadm versions that neglected to set it.
+		 */
+		if (mpb->orig_family_num == 0)
+			mpb->orig_family_num = mpb->family_num;
+		mpb->family_num += super->random;
+
 		/* count arrays using the victim in the metadata */
 		found = 0;
 		for (a = st->arrays; a ; a = a->next) {
diff --git a/util.c b/util.c
index 00bf803..2543971 100644
--- a/util.c
+++ b/util.c
@@ -1298,6 +1298,17 @@ int check_env(char *name)
 	return 0;
 }
 
+__u32 random32(void)
+{
+	__u32 rv;
+	int rfd = open("/dev/urandom", O_RDONLY);
+	if (rfd < 0 || read(rfd, &rv, 4) != 4)
+		rv = random();
+	if (rfd >= 0)
+		close(rfd);
+	return rv;
+}
+
 #ifndef MDASSEMBLE
 int flush_metadata_updates(struct supertype *st)
 {




More information about the pkg-mdadm-commits mailing list