[mdadm] Fix a large number of bzs:

Jes Sorensen jsorensen at fedoraproject.org
Mon Apr 30 15:53:48 UTC 2012


commit 6148d71c1decc8355d58553da944fd7b6a7fbf35
Author: Jes Sorensen <Jes.Sorensen at redhat.com>
Date:   Mon Apr 30 17:46:25 2012 +0200

    Fix a large number of bzs:
    
    - Fix Monitor mode sometimes crashes when a resync completes
    - Fix missing symlink for mdadm container device when incremental creates
      the array
    - Make sure when creating a second array in a container that the second
      array uses all available space since leaving space for a third array
      is invalid
    - Validate the number of imsm volumes per controller
    - Fix issues with imsm arrays and disks larger than 2TB
    - Add support for expanding imsm arrays/containers
    - The support for expanding imsm arrays/containers was accepted upstream,
      update to the official patches from there
    - Fix for the issue of --add not being very smart
    - Fix an issue causing rebuilds to fail to restart on reboot (data
      corrupter level problem)
    - Reset the bad flag on map file updates
    - Correctly fix failure when trying to add internal bitmap to 1.0 arrays
    - Resolves: bz817023 (f17) bz817024 (f17) bz817026 (f17) bz817028 (f17)
    - Resolves: bz817029 (f17) bz817032 (f17) bz817038 (f17) bz808774 (f17)
    - Resolves: bz817039 (f17) bz817042 (f17)
    
    Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>

 mdadm-3.2.3-Bitmap_offset-is-a-signed-number.patch |   66 +++
 ...ed-second-array-is-in-read-only-state-dur.patch |   85 ++++
 ....3-FIX-Detect-error-and-rollback-metadata.patch |   62 +++
 mdadm-3.2.3-FIX-Extend-size-of-raid0-array.patch   |   84 ++++
 ...2.3-FIX-Respect-metadata-size-limitations.patch |   50 ++
 ...ange-is-possible-as-standalone-change-onl.patch |   30 ++
 ...2.3-FIX-Support-metadata-changes-rollback.patch |  118 +++++
 ...gn-extension-of-bitmap_offset-in-super1.c.patch |   40 ++
 ...ysfs_set_num_signed-and-use-it-to-set-bit.patch |   68 +++
 ...3.2.3-Manage-allow-re-add-to-failed-array.patch |   66 +++
 ...ze-recovery-while-adding-multiple-devices.patch |   66 +++
 ...3-Manage-replace-return-1-with-goto-abort.patch |  347 ++++++++++++++
 ...d-limit-of-1024-when-scanning-for-devices.patch |   81 ++++
 ...lax-restrictions-on-when-add-is-permitted.patch |   85 ++++
 ...-3.2.3-Remove-avail_disks-arg-from-enough.patch |  171 +++++++
 mdadm-3.2.3-Reset-bad-flag-on-map-update.patch     |   32 ++
 ...no-disk-over-2TB-is-used-to-create-contai.patch |   52 ++
 ...olume-size-in-validate_geometry_imsm_orom.patch |   69 +++
 ...ts-if-not-used-after-loading-metadata-fro.patch |   72 +++
 mdadm-3.2.3-fix-Monitor-sometimes-crashes.patch    |   34 ++
 ...-container-creation-with-incremental-used.patch |   34 ++
 ...fix-correct-extending-size-of-raid0-array.patch |   31 ++
 ....2.3-imsm-Add-function-imsm_get_free_size.patch |   63 +++
 ...w-metadata-update-for-volume-size-expansi.patch |  238 ++++++++++
 ...xecute-size-change-for-external-metatdata.patch |  129 +++++
 ...d-volume-size-expand-support-to-imsm_anal.patch |  103 ++++
 ...3-imsm-FIX-Component-size-alignment-check.patch |  126 +++++
 ...msm-FIX-Support-metadata-changes-rollback.patch |  130 +++++
 ...date-function-imsm_num_data_members-for-R.patch |   36 ++
 ...t-setting-max-size-for-size-change-operat.patch |   60 +++
 ...3-imsm-avoid-overflows-for-disks-over-1TB.patch |  484 +++++++++++++++++++
 ...y-maximum-volumes-per-controller-in-detai.patch |   29 ++
 ...ix-rebuild-does-not-continue-after-reboot.patch |   62 +++
 ...e-second-array-need-to-have-the-whole-ava.patch |   40 ++
 ...sm-fix-thunderdome-may-drop-2tb-attribute.patch |   33 ++
 ...msm_super_all-supports-loading-metadata-f.patch |  157 ++++++
 ...-load_super_imsm_all-function-refactoring.patch |  261 ++++++++++
 ...2.3-imsm-set-2tb-disk-attribute-for-spare.patch |   30 ++
 ...te-the-number-of-imsm-volumes-per-control.patch |  497 ++++++++++++++++++++
 ...-volumes-disks-support-in-detail-platform.patch |   39 ++
 ...m-3.2.3-simplify-calculating-array_blocks.patch |   47 ++
 mdadm.spec                                         |  107 +++++-
 42 files changed, 4413 insertions(+), 1 deletions(-)
---
diff --git a/mdadm-3.2.3-Bitmap_offset-is-a-signed-number.patch b/mdadm-3.2.3-Bitmap_offset-is-a-signed-number.patch
new file mode 100644
index 0000000..f40fe62
--- /dev/null
+++ b/mdadm-3.2.3-Bitmap_offset-is-a-signed-number.patch
@@ -0,0 +1,66 @@
+From fbdef49811c9e2b54e2064d9af68cfffa77c6e77 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb at suse.de>
+Date: Wed, 4 Apr 2012 14:00:42 +1000
+Subject: [PATCH] Bitmap_offset is a signed number
+
+As the bitmap can be before the superblock, bitmap_offset is signed.
+But some of the code didn't honour that :-(
+
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ mdadm.h  |    2 +-
+ super1.c |    4 ++--
+ sysfs.c  |    2 +-
+ 3 files changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/mdadm.h b/mdadm.h
+index 941cffa..9f58800 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -211,7 +211,7 @@ struct mdinfo {
+ 		unsigned long long recovery_start; /* per-device rebuild position */
+ 		#define MaxSector  (~0ULL) /* resync/recovery complete position */
+ 	};
+-	unsigned long		bitmap_offset;	/* 0 == none, 1 == a file */
++	long			bitmap_offset;	/* 0 == none, 1 == a file */
+ 	unsigned long		safe_mode_delay; /* ms delay to mark clean */
+ 	int			new_level, delta_disks, new_layout, new_chunk;
+ 	int			errors;
+diff --git a/super1.c b/super1.c
+index 20f4c86..2770a7f 100644
+--- a/super1.c
++++ b/super1.c
+@@ -620,7 +620,7 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map)
+ 	info->data_offset = __le64_to_cpu(sb->data_offset);
+ 	info->component_size = __le64_to_cpu(sb->size);
+ 	if (sb->feature_map & __le32_to_cpu(MD_FEATURE_BITMAP_OFFSET))
+-		info->bitmap_offset = __le32_to_cpu(sb->bitmap_offset);
++		info->bitmap_offset = (long)__le32_to_cpu(sb->bitmap_offset);
+ 
+ 	info->disk.major = 0;
+ 	info->disk.minor = 0;
+@@ -1636,7 +1636,7 @@ add_internal_bitmap1(struct supertype *st,
+ 		offset = -room;
+ 	}
+ 
+-	sb->bitmap_offset = __cpu_to_le32(offset);
++	sb->bitmap_offset = (long)__cpu_to_le32(offset);
+ 
+ 	sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map)
+ 					| MD_FEATURE_BITMAP_OFFSET);
+diff --git a/sysfs.c b/sysfs.c
+index cddabae..a1007cf 100644
+--- a/sysfs.c
++++ b/sysfs.c
+@@ -226,7 +226,7 @@ struct mdinfo *sysfs_read(int fd, int devnum, unsigned long options)
+ 		else if (strncmp(buf, "none", 4) == 0)
+ 			sra->bitmap_offset = 0;
+ 		else if (buf[0] == '+')
+-			sra->bitmap_offset = strtoul(buf+1, NULL, 10);
++			sra->bitmap_offset = strtol(buf+1, NULL, 10);
+ 		else
+ 			goto abort;
+ 	}
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-FIX-Assembled-second-array-is-in-read-only-state-dur.patch b/mdadm-3.2.3-FIX-Assembled-second-array-is-in-read-only-state-dur.patch
new file mode 100644
index 0000000..4f8d3b0
--- /dev/null
+++ b/mdadm-3.2.3-FIX-Assembled-second-array-is-in-read-only-state-dur.patch
@@ -0,0 +1,85 @@
+From 4aecb54a211a77aa0589aa2abb8acd992ae8795a Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:52:08 +0200
+Subject: [PATCH 14/14] FIX: Assembled second array is in read only state
+ during reshape
+
+When arrays using external metadata are assembled, and one of array
+in container is under reshape, second array will remain in read only
+state (not auto read only). It is caused by array fact that array
+is frozen and mdmon doesn't has opportunity to switch array in r/w mode.
+
+Freezing not reshaped array just after it is being assembled allows mdmon
+to enable it for writing.
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Assemble.c |   29 +++++++++++++++++++++--------
+ 1 files changed, 21 insertions(+), 8 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index 23695e7..080993d 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -1558,6 +1558,7 @@ int assemble_container_content(struct supertype *st, int mdfd,
+ 	int expansion = 0;
+ 	struct map_ent *map = NULL;
+ 	int old_raid_disks;
++	int start_reshape;
+ 
+ 	sysfs_init(content, mdfd, 0);
+ 
+@@ -1569,7 +1570,17 @@ int assemble_container_content(struct supertype *st, int mdfd,
+ 			return 1;
+ 		}
+ 
+-	if (st->ss->external && content->recovery_blocked)
++	/* There are two types of reshape: container wide or sub-array specific
++	 * Check if metadata requests blocking container wide reshapes
++	 */
++	start_reshape = (content->reshape_active &&
++		!((content->reshape_active == CONTAINER_RESHAPE) &&
++		(content->array.state & (1<<MD_SB_BLOCK_CONTAINER_RESHAPE))));
++
++	/* Block subarray here if it is under reshape now
++	 * Do not allow for any changes in this array
++	 */
++	if (st->ss->external && content->recovery_blocked && start_reshape)
+ 		block_subarray(content);
+ 
+ 	if (sra)
+@@ -1595,14 +1606,7 @@ int assemble_container_content(struct supertype *st, int mdfd,
+ 		 (working + preexist + expansion) >=
+ 			content->array.working_disks) {
+ 		int err;
+-		int start_reshape;
+ 
+-		/* There are two types of reshape: container wide or sub-array specific
+-		 * Check if metadata requests blocking container wide reshapes
+-		 */
+-		start_reshape = (content->reshape_active &&
+-				 !((content->reshape_active == CONTAINER_RESHAPE) &&
+-				   (content->array.state & (1<<MD_SB_BLOCK_CONTAINER_RESHAPE))));
+ 		if (start_reshape) {
+ 			int spare = content->array.raid_disks + expansion;
+ 			if (restore_backup(st, content,
+@@ -1646,6 +1650,15 @@ int assemble_container_content(struct supertype *st, int mdfd,
+ 		}
+ 		if (!err)
+ 			sysfs_set_safemode(content, content->safe_mode_delay);
++
++		/* Block subarray here if it is not reshaped now
++		 * It has be blocked a little later to allow mdmon to switch in
++		 * in to R/W state
++		 */
++		if (st->ss->external && content->recovery_blocked &&
++		    !start_reshape)
++			block_subarray(content);
++
+ 		if (verbose >= 0) {
+ 			if (err)
+ 				fprintf(stderr, Name
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-FIX-Detect-error-and-rollback-metadata.patch b/mdadm-3.2.3-FIX-Detect-error-and-rollback-metadata.patch
new file mode 100644
index 0000000..a9bf745
--- /dev/null
+++ b/mdadm-3.2.3-FIX-Detect-error-and-rollback-metadata.patch
@@ -0,0 +1,62 @@
+From 65a9798b58b4e4de0157043e2b30a738c27eff43 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:52:03 +0200
+Subject: [PATCH 09/14] FIX: Detect error and rollback metadata
+
+Some setting size error cases were not detected.
+When error occurs, stop setting new size action and rollback metadata
+changes.
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Grow.c |   13 +++++++++++--
+ 1 files changed, 11 insertions(+), 2 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index 86d1020..1b45199 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1665,9 +1665,12 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 		 * understands '0' to mean 'max'.
+ 		 */
+ 		min_csize = 0;
++		rv = 0;
+ 		for (mdi = sra->devs; mdi; mdi = mdi->next) {
+-			if (sysfs_set_num(sra, mdi, "size", size) < 0)
++			if (sysfs_set_num(sra, mdi, "size", size) < 0) {
++				rv = 1;
+ 				break;
++			}
+ 			if (array.not_persistent == 0 &&
+ 			    array.major_version == 0 &&
+ 			    get_linux_version() < 3001000) {
+@@ -1682,11 +1685,16 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 				}
+ 			}
+ 		}
++		if (rv) {
++			fprintf(stderr, Name ": Cannot set size on "
++				"array members.\n");
++			goto size_change_error;
++		}
+ 		if (min_csize && size > min_csize) {
+ 			fprintf(stderr, Name ": Cannot safely make this array "
+ 				"use more than 2TB per device on this kernel.\n");
+ 			rv = 1;
+-			goto release;
++			goto size_change_error;
+ 		}
+ 		if (min_csize && size == 0) {
+ 			/* Don't let the kernel choose a size - it will get
+@@ -1748,6 +1756,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 			ioctl(fd, GET_ARRAY_INFO, &array);
+ 		}
+ 
++size_change_error:
+ 		if (rv != 0) {
+ 			int err = errno;
+ 
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-FIX-Extend-size-of-raid0-array.patch b/mdadm-3.2.3-FIX-Extend-size-of-raid0-array.patch
new file mode 100644
index 0000000..d36ca59
--- /dev/null
+++ b/mdadm-3.2.3-FIX-Extend-size-of-raid0-array.patch
@@ -0,0 +1,84 @@
+From 44f6f18113b1764a9d1234d3ff9a6bac968b03b8 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:52:01 +0200
+Subject: [PATCH 07/14] FIX: Extend size of raid0 array
+
+For raid0, takeover operation is required for size change.
+Add takeover to degraded raid4 before size change and back to raid0 after.
+Array information has to be read again from md after takeover.
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Grow.c |   35 +++++++++++++++++++++++++++++++++++
+ 1 files changed, 35 insertions(+), 0 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index 8c7bafc..e8f6554 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1626,6 +1626,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 		long long orig_size = get_component_size(fd)/2;
+ 		long long min_csize;
+ 		struct mdinfo *mdi;
++		int raid0_takeover = 0;
+ 
+ 		if (orig_size == 0)
+ 			orig_size = array.size;
+@@ -1674,6 +1675,28 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 				"2TB per device\n");
+ 			size = min_csize;
+ 		}
++		if (st->ss->external) {
++			if (sra->array.level == 0) {
++				rv = sysfs_set_str(sra, NULL, "level",
++						   "raid5");
++				if (!rv) {
++					raid0_takeover = 1;
++					/* get array parametes after takeover
++					 * to chane one parameter at time only
++					 */
++					rv = ioctl(fd, GET_ARRAY_INFO, &array);
++				}
++			}
++			/* make sure mdmon is
++			 * aware of the new level */
++			if (!mdmon_running(st->container_dev))
++				start_mdmon(st->container_dev);
++			ping_monitor(container);
++			if (mdmon_running(st->container_dev) &&
++					st->update_tail == NULL)
++				st->update_tail = &st->updates;
++		}
++
+ 		array.size = size;
+ 		if (array.size != size) {
+ 			/* got truncated to 32bit, write to
+@@ -1686,12 +1709,24 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 				rv = -1;
+ 		} else {
+ 			rv = ioctl(fd, SET_ARRAY_INFO, &array);
++
+ 			/* manage array size when it is managed externally
+ 			 */
+ 			if ((rv == 0) && st->ss->external)
+ 				rv = set_array_size(st, sra, sra->text_version);
+ 		}
+ 
++		if (raid0_takeover) {
++			/* do not recync non-existing parity,
++			 * we will drop it anyway
++			 */
++			sysfs_set_str(sra, NULL, "sync_action", "idle");
++			/* go back to raid0, drop parity disk
++			 */
++			sysfs_set_str(sra, NULL, "level", "raid0");
++			ioctl(fd, GET_ARRAY_INFO, &array);
++		}
++
+ 		if (rv != 0) {
+ 			int err = errno;
+ 
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-FIX-Respect-metadata-size-limitations.patch b/mdadm-3.2.3-FIX-Respect-metadata-size-limitations.patch
new file mode 100644
index 0000000..0a76c6c
--- /dev/null
+++ b/mdadm-3.2.3-FIX-Respect-metadata-size-limitations.patch
@@ -0,0 +1,50 @@
+From 7e7e9a4d72323fe0298c9f5741245b0f11165a31 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:52:02 +0200
+Subject: [PATCH 08/14] FIX: Respect metadata size limitations
+
+When reshape_super() updates metadata with new size, due to some metadata
+limitations saved value can be different than requested value by user.
+Update size (read it from metadata) for setting it in md.
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Grow.c |   21 +++++++++++++++++++++
+ 1 files changed, 21 insertions(+), 0 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index e8f6554..86d1020 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1637,6 +1637,27 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 			goto release;
+ 		}
+ 		sync_metadata(st);
++		if (st->ss->external) {
++			/* metadata can have size limitation
++			 * update size value according to metadata information
++			 */
++			struct mdinfo *sizeinfo =
++				st->ss->container_content(st, subarray);
++			if (sizeinfo) {
++				unsigned long long new_size =
++					sizeinfo->custom_array_size/2;
++				int data_disks = get_data_disks(
++						sizeinfo->array.level,
++						sizeinfo->array.layout,
++						sizeinfo->array.raid_disks);
++				new_size /= data_disks;
++				dprintf("Metadata size correction from %llu to "
++					"%llu (%llu)\n", orig_size, new_size,
++					new_size * data_disks);
++				size = new_size;
++				sysfs_free(sizeinfo);
++			}
++		}
+ 
+ 		/* Update the size of each member device in case
+ 		 * they have been resized.  This will never reduce
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-FIX-Size-change-is-possible-as-standalone-change-onl.patch b/mdadm-3.2.3-FIX-Size-change-is-possible-as-standalone-change-onl.patch
new file mode 100644
index 0000000..30e703c
--- /dev/null
+++ b/mdadm-3.2.3-FIX-Size-change-is-possible-as-standalone-change-onl.patch
@@ -0,0 +1,30 @@
+From 58d26a2a81c4ad93ccce88865f2c4ac2588bec69 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:52:07 +0200
+Subject: [PATCH 13/14] FIX: Size change is possible as standalone change only
+
+Size change is possible as standalone change only. To make sure size change
+is not requested pass '-1' as size parameter.
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Grow.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index 1b45199..389992e 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1973,7 +1973,7 @@ size_change_error:
+ 		/* Impose these changes on a single array.  First
+ 		 * check that the metadata is OK with the change. */
+ 
+-		if (reshape_super(st, info.component_size, info.new_level,
++		if (reshape_super(st, -1, info.new_level,
+ 				  info.new_layout, info.new_chunk,
+ 				  info.array.raid_disks, info.delta_disks,
+ 				  backup_file, devname, APPLY_METADATA_CHANGES,
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-FIX-Support-metadata-changes-rollback.patch b/mdadm-3.2.3-FIX-Support-metadata-changes-rollback.patch
new file mode 100644
index 0000000..6fce01f
--- /dev/null
+++ b/mdadm-3.2.3-FIX-Support-metadata-changes-rollback.patch
@@ -0,0 +1,118 @@
+From 016e00f54635138ce34b9e4ba18d37e182288bd1 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:51:59 +0200
+Subject: [PATCH 05/14] FIX: Support metadata changes rollback
+
+Function reshape_super() guards metadata changes.
+It is used to apply changes rollback in error case also.
+As change (apply and rollback) can be not bi-directional reshape_super()
+has to know if current action is metadata change that should be guarded
+using metadata restrictions, or this is metadata rollback change
+executed due to error occurrence.
+
+In second case change has to be unconditional.
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Grow.c        |   16 ++++++++++------
+ mdadm.h       |    4 ++++
+ super-intel.c |    2 +-
+ 3 files changed, 15 insertions(+), 7 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index 5fd44aa..8c7bafc 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -650,7 +650,7 @@ static void wait_reshape(struct mdinfo *sra)
+ static int reshape_super(struct supertype *st, long long size, int level,
+ 			 int layout, int chunksize, int raid_disks,
+ 			 int delta_disks, char *backup_file, char *dev,
+-			 int verbose)
++			 int direction, int verbose)
+ {
+ 	/* nothing extra to check in the native case */
+ 	if (!st->ss->external)
+@@ -664,7 +664,7 @@ static int reshape_super(struct supertype *st, long long size, int level,
+ 
+ 	return st->ss->reshape_super(st, size, level, layout, chunksize,
+ 				     raid_disks, delta_disks, backup_file, dev,
+-				     verbose);
++				     direction, verbose);
+ }
+ 
+ static void sync_metadata(struct supertype *st)
+@@ -1631,7 +1631,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 			orig_size = array.size;
+ 
+ 		if (reshape_super(st, size, UnSet, UnSet, 0, 0, UnSet, NULL,
+-				  devname, !quiet)) {
++				  devname, APPLY_METADATA_CHANGES, !quiet)) {
+ 			rv = 1;
+ 			goto release;
+ 		}
+@@ -1697,7 +1697,9 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 
+ 			/* restore metadata */
+ 			if (reshape_super(st, orig_size, UnSet, UnSet, 0, 0,
+-					  UnSet, NULL, devname, !quiet) == 0)
++					  UnSet, NULL, devname,
++					  ROLLBACK_METADATA_CHANGES,
++					  !quiet) == 0)
+ 				sync_metadata(st);
+ 			fprintf(stderr, Name ": Cannot set device size for %s: %s\n",
+ 				devname, strerror(err));
+@@ -1909,7 +1911,8 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 		if (reshape_super(st, info.component_size, info.new_level,
+ 				  info.new_layout, info.new_chunk,
+ 				  info.array.raid_disks, info.delta_disks,
+-				  backup_file, devname, quiet)) {
++				  backup_file, devname, APPLY_METADATA_CHANGES,
++				  quiet)) {
+ 			rv = 1;
+ 			goto release;
+ 		}
+@@ -2608,7 +2611,8 @@ int reshape_container(char *container, char *devname,
+ 	    reshape_super(st, -1, info->new_level,
+ 			  info->new_layout, info->new_chunk,
+ 			  info->array.raid_disks, info->delta_disks,
+-			  backup_file, devname, quiet)) {
++			  backup_file, devname, APPLY_METADATA_CHANGES,
++			  quiet)) {
+ 		unfreeze(st);
+ 		return 1;
+ 	}
+diff --git a/mdadm.h b/mdadm.h
+index 9f58800..686d4b4 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -740,9 +740,13 @@ extern struct superswitch {
+ 	 * initialized to indicate if reshape is being performed at the
+ 	 * container or subarray level
+ 	 */
++#define APPLY_METADATA_CHANGES		1
++#define ROLLBACK_METADATA_CHANGES	0
++
+ 	int (*reshape_super)(struct supertype *st, long long size, int level,
+ 			     int layout, int chunksize, int raid_disks,
+ 			     int delta_disks, char *backup, char *dev,
++			     int direction,
+ 			     int verbose); /* optional */
+ 	int (*manage_reshape)( /* optional */
+ 		int afd, struct mdinfo *sra, struct reshape *reshape,
+diff --git a/super-intel.c b/super-intel.c
+index ac8922f..32a53d1 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -10018,7 +10018,7 @@ int imsm_takeover(struct supertype *st, struct geo_params *geo)
+ static int imsm_reshape_super(struct supertype *st, long long size, int level,
+ 			      int layout, int chunksize, int raid_disks,
+ 			      int delta_disks, char *backup, char *dev,
+-			      int verbose)
++			      int direction, int verbose)
+ {
+ 	int ret_val = 1;
+ 	struct geo_params geo;
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-Fix-sign-extension-of-bitmap_offset-in-super1.c.patch b/mdadm-3.2.3-Fix-sign-extension-of-bitmap_offset-in-super1.c.patch
new file mode 100644
index 0000000..cf4528e
--- /dev/null
+++ b/mdadm-3.2.3-Fix-sign-extension-of-bitmap_offset-in-super1.c.patch
@@ -0,0 +1,40 @@
+From 119374a0ac7d6a73cd296134b0151aa213bbee42 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <Jes.Sorensen at redhat.com>
+Date: Thu, 26 Apr 2012 16:55:10 +0200
+Subject: [PATCH 1/2] Fix sign extension of bitmap_offset in super1.c
+
+fbdef49811c9e2b54e2064d9af68cfffa77c6e77 incorrectly tried to fix sign
+extension of the bitmap offset. However mdinfo->bitmap_offset is a u32
+and needs to be converted to a 32 bit signed integer before the sign
+extension.
+
+Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
+---
+ super1.c |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/super1.c b/super1.c
+index 36369d8..be77c33 100644
+--- a/super1.c
++++ b/super1.c
+@@ -620,7 +620,7 @@ static void getinfo_super1(struct supertype *st, struct mdinfo *info, char *map)
+ 	info->data_offset = __le64_to_cpu(sb->data_offset);
+ 	info->component_size = __le64_to_cpu(sb->size);
+ 	if (sb->feature_map & __le32_to_cpu(MD_FEATURE_BITMAP_OFFSET))
+-		info->bitmap_offset = (long)__le32_to_cpu(sb->bitmap_offset);
++		info->bitmap_offset = (int32_t)__le32_to_cpu(sb->bitmap_offset);
+ 
+ 	info->disk.major = 0;
+ 	info->disk.minor = 0;
+@@ -1651,7 +1651,7 @@ add_internal_bitmap1(struct supertype *st,
+ 		offset = -room;
+ 	}
+ 
+-	sb->bitmap_offset = (long)__cpu_to_le32(offset);
++	sb->bitmap_offset = (int32_t)__cpu_to_le32(offset);
+ 
+ 	sb->feature_map = __cpu_to_le32(__le32_to_cpu(sb->feature_map)
+ 					| MD_FEATURE_BITMAP_OFFSET);
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-Introduce-sysfs_set_num_signed-and-use-it-to-set-bit.patch b/mdadm-3.2.3-Introduce-sysfs_set_num_signed-and-use-it-to-set-bit.patch
new file mode 100644
index 0000000..6476bb6
--- /dev/null
+++ b/mdadm-3.2.3-Introduce-sysfs_set_num_signed-and-use-it-to-set-bit.patch
@@ -0,0 +1,68 @@
+From 7b5ec34bb072781c0efbba8b21a941fff4d6ae7f Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <Jes.Sorensen at redhat.com>
+Date: Thu, 26 Apr 2012 17:05:22 +0200
+Subject: [PATCH 2/2] Introduce sysfs_set_num_signed() and use it to set
+ bitmap/offset
+
+mdinfo->bitmap_offset is a signed long and needs to be treated as
+such when passed to the kernel.
+
+This resolves the problem with adding internal bitmaps to a 1.0 array.
+
+Signed-off-by: Jes Sorensen <Jes.Sorensen at redhat.com>
+---
+ Grow.c  |    4 ++--
+ mdadm.h |    2 ++
+ sysfs.c |    8 ++++++++
+ 3 files changed, 12 insertions(+), 2 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index b4b9ff2..0b0d718 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -424,8 +424,8 @@ int Grow_addbitmap(char *devname, int fd, char *file, int chunk, int delay, int
+ 		if (offset_setable) {
+ 			st->ss->getinfo_super(st, mdi, NULL);
+ 			sysfs_init(mdi, fd, -1);
+-			rv = sysfs_set_num(mdi, NULL, "bitmap/location",
+-					   mdi->bitmap_offset);
++			rv = sysfs_set_num_signed(mdi, NULL, "bitmap/location",
++						  mdi->bitmap_offset);
+ 		} else {
+ 			array.state |= (1<<MD_SB_BITMAP_PRESENT);
+ 			rv = ioctl(fd, SET_ARRAY_INFO, &array);
+diff --git a/mdadm.h b/mdadm.h
+index e60a706..0c91a34 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -473,6 +473,8 @@ extern int sysfs_set_str(struct mdinfo *sra, struct mdinfo *dev,
+ 			 char *name, char *val);
+ extern int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev,
+ 			 char *name, unsigned long long val);
++extern int sysfs_set_num_signed(struct mdinfo *sra, struct mdinfo *dev,
++				char *name, long long val);
+ extern int sysfs_uevent(struct mdinfo *sra, char *event);
+ extern int sysfs_get_fd(struct mdinfo *sra, struct mdinfo *dev,
+ 			char *name);
+diff --git a/sysfs.c b/sysfs.c
+index a1007cf..8e9d0c5 100644
+--- a/sysfs.c
++++ b/sysfs.c
+@@ -428,6 +428,14 @@ int sysfs_set_num(struct mdinfo *sra, struct mdinfo *dev,
+ 	return sysfs_set_str(sra, dev, name, valstr);
+ }
+ 
++int sysfs_set_num_signed(struct mdinfo *sra, struct mdinfo *dev,
++			 char *name, long long val)
++{
++	char valstr[50];
++	sprintf(valstr, "%lli", val);
++	return sysfs_set_str(sra, dev, name, valstr);
++}
++
+ int sysfs_uevent(struct mdinfo *sra, char *event)
+ {
+ 	char fname[50];
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-Manage-allow-re-add-to-failed-array.patch b/mdadm-3.2.3-Manage-allow-re-add-to-failed-array.patch
new file mode 100644
index 0000000..4c9e6a1
--- /dev/null
+++ b/mdadm-3.2.3-Manage-allow-re-add-to-failed-array.patch
@@ -0,0 +1,66 @@
+From c69ffac0d6a068823a1365c3b155ff72f8c4686f Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb at suse.de>
+Date: Wed, 7 Mar 2012 15:25:57 +1100
+Subject: [PATCH] Manage: allow --re-add to failed array.
+
+If both "legs" of a RAID1 (or equivalent in RAID10) fail, then one
+of the becomes available again it maybe appropriate to re-add the
+failed device(s).
+So remove the restriction that an array must has 'enough' devices
+before being re-added, and if there is no-where to read a superblock
+from for matching, then assume the kernel will do necessary checks.
+
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Manage.c |   16 +++++++++++++---
+ 1 files changed, 13 insertions(+), 3 deletions(-)
+
+diff --git a/Manage.c b/Manage.c
+index d9775de..4cf6e58 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -723,7 +723,13 @@ int Manage_subdevs(char *devname, int fd,
+ 					break;
+ 				}
+ 				/* FIXME this is a bad test to be using */
+-				if (!tst->sb) {
++				if (!tst->sb &&
++				    dv->re_add) {
++					/* we are re-adding a device to a
++					 * completely dead array - have to depend
++					 * on kernel to check
++					 */
++				} else if (!tst->sb) {
+ 					close(tfd);
+ 					st->ss->free_super(st);
+ 					fprintf(stderr, Name ": cannot load array metadata from %s\n", devname);
+@@ -747,12 +753,16 @@ int Manage_subdevs(char *devname, int fd,
+ 				 * and was temporarily removed, and is now being re-added.
+ 				 * If so, we can simply re-add it.
+ 				 */
+-				tst->ss->uuid_from_super(tst, duuid);
+ 
+ 				if (st->sb) {
+ 					struct mdinfo mdi;
+ 					st->ss->getinfo_super(st, &mdi, NULL);
+ 					st->ss->uuid_from_super(st, ouuid);
++					if (tst->sb)
++						tst->ss->uuid_from_super(tst, duuid);
++					else
++						/* Assume uuid matches: kernel will check */
++						memcpy(duuid, ouuid, sizeof(ouuid));
+ 					if ((mdi.disk.state & (1<<MD_DISK_ACTIVE)) &&
+ 					    !(mdi.disk.state & (1<<MD_DISK_FAULTY)) &&
+ 					    memcmp(duuid, ouuid, sizeof(ouuid))==0) {
+@@ -768,7 +778,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						disc.number = mdi.disk.number;
+ 						if (ioctl(fd, GET_DISK_INFO, &disc) != 0
+ 						    || disc.major != 0 || disc.minor != 0
+-						    || !enough_fd(fd))
++							)
+ 							goto skip_re_add;
+ 						disc.major = major(stb.st_rdev);
+ 						disc.minor = minor(stb.st_rdev);
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-Manage-freeze-recovery-while-adding-multiple-devices.patch b/mdadm-3.2.3-Manage-freeze-recovery-while-adding-multiple-devices.patch
new file mode 100644
index 0000000..6d2b739
--- /dev/null
+++ b/mdadm-3.2.3-Manage-freeze-recovery-while-adding-multiple-devices.patch
@@ -0,0 +1,66 @@
+From 9f58469128c99c0d7f434d28657f86789334f253 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb at suse.de>
+Date: Thu, 22 Mar 2012 16:15:03 +1100
+Subject: [PATCH 3/3] Manage: freeze recovery while adding multiple devices.
+
+If the kernel supports it, freeze recovery over multiple adds,
+so that they can all be added to the array at the same time and
+be recovered in parallel.
+
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Manage.c |   13 +++++++++++++
+ 1 files changed, 13 insertions(+), 0 deletions(-)
+
+diff --git a/Manage.c b/Manage.c
+index f53fe27..7deba3a 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -416,12 +416,15 @@ int Manage_subdevs(char *devname, int fd,
+ 	int lfd = -1;
+ 	int sysfd = -1;
+ 	int count = 0; /* number of actions taken */
++	struct mdinfo info;
++	int frozen = 0;
+ 
+ 	if (ioctl(fd, GET_ARRAY_INFO, &array)) {
+ 		fprintf(stderr, Name ": cannot get array info for %s\n",
+ 			devname);
+ 		goto abort;
+ 	}
++	sysfs_init(&info, fd, 0);
+ 
+ 	/* array.size is only 32 bit and may be truncated.
+ 	 * So read from sysfs if possible, and record number of sectors
+@@ -629,6 +632,12 @@ int Manage_subdevs(char *devname, int fd,
+ 					dv->devname, strerror(errno));
+ 				goto abort;
+ 			}
++			if (!frozen) {
++				if (sysfs_freeze_array(&info) == 1)
++					frozen = 1;
++				else
++					frozen = -1;
++			}
+ 
+ 			st = dup_super(tst);
+ 
+@@ -1166,11 +1175,15 @@ int Manage_subdevs(char *devname, int fd,
+ 			break;
+ 		}
+ 	}
++	if (frozen > 0)
++		sysfs_set_str(&info, NULL, "sync_action","idle");
+ 	if (test && count == 0)
+ 		return 2;
+ 	return 0;
+ 
+ abort:
++	if (frozen > 0)
++		sysfs_set_str(&info, NULL, "sync_action","idle");
+ 	return 1;
+ }
+ 
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-Manage-replace-return-1-with-goto-abort.patch b/mdadm-3.2.3-Manage-replace-return-1-with-goto-abort.patch
new file mode 100644
index 0000000..a9d594d
--- /dev/null
+++ b/mdadm-3.2.3-Manage-replace-return-1-with-goto-abort.patch
@@ -0,0 +1,347 @@
+From bcbb3112d2801594358153956191e4cff6021de3 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb at suse.de>
+Date: Thu, 22 Mar 2012 16:07:02 +1100
+Subject: [PATCH 2/3] Manage: replace 'return 1' with 'goto abort'.
+
+This will allow exit processing in next patch
+
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Manage.c |   75 ++++++++++++++++++++++++++++++++-----------------------------
+ 1 files changed, 39 insertions(+), 36 deletions(-)
+
+diff --git a/Manage.c b/Manage.c
+index 4cf6e58..f53fe27 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -420,7 +420,7 @@ int Manage_subdevs(char *devname, int fd,
+ 	if (ioctl(fd, GET_ARRAY_INFO, &array)) {
+ 		fprintf(stderr, Name ": cannot get array info for %s\n",
+ 			devname);
+-		return 1;
++		goto abort;
+ 	}
+ 
+ 	/* array.size is only 32 bit and may be truncated.
+@@ -435,7 +435,7 @@ int Manage_subdevs(char *devname, int fd,
+ 	if (!tst) {
+ 		fprintf(stderr, Name ": unsupport array - version %d.%d\n",
+ 			array.major_version, array.minor_version);
+-		return 1;
++		goto abort;
+ 	}
+ 
+ 	stb.st_rdev = 0;
+@@ -457,7 +457,7 @@ int Manage_subdevs(char *devname, int fd,
+ 				fprintf(stderr, Name ": %s only meaningful "
+ 					"with -r, not -%c\n",
+ 					dv->devname, dv->disposition);
+-				return 1;
++				goto abort;
+ 			}
+ 			for (; j < 1024 && remaining_disks > 0; j++) {
+ 				unsigned dev;
+@@ -490,7 +490,7 @@ int Manage_subdevs(char *devname, int fd,
+ 				fprintf(stderr, Name ": %s only meaningful "
+ 					"with -r of -f, not -%c\n",
+ 					dv->devname, dv->disposition);
+-				return 1;
++				goto abort;
+ 			}
+ 			for (; j < 1024 && remaining_disks > 0; j++) {
+ 				int sfd;
+@@ -530,7 +530,7 @@ int Manage_subdevs(char *devname, int fd,
+ 			if (dv->disposition != 'a' || dv->re_add == 0) {
+ 				fprintf(stderr, Name ": 'missing' only meaningful "
+ 					"with --re-add\n");
+-				return 1;
++				goto abort;
+ 			}
+ 			if (add_devlist == NULL)
+ 				add_devlist = conf_get_devs();
+@@ -554,7 +554,7 @@ int Manage_subdevs(char *devname, int fd,
+ 				fprintf(stderr, Name ": %s only meaningful "
+ 					"with -r or -f, not -%c\n",
+ 					dv->devname, dv->disposition);
+-				return 1;
++				goto abort;
+ 			}
+ 
+ 			sprintf(dname, "dev-%s", dv->devname);
+@@ -576,7 +576,7 @@ int Manage_subdevs(char *devname, int fd,
+ 					fprintf(stderr, Name ": %s does not appear "
+ 						"to be a component of %s\n",
+ 						dv->devname, devname);
+-					return 1;
++					goto abort;
+ 				}
+ 			}
+ 		} else {
+@@ -595,7 +595,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						dv->devname, strerror(errno));
+ 					if (tfd >= 0)
+ 						close(tfd);
+-					return 1;
++					goto abort;
+ 				}
+ 				close(tfd);
+ 				tfd = -1;
+@@ -604,21 +604,21 @@ int Manage_subdevs(char *devname, int fd,
+ 				fprintf(stderr, Name ": %s is not a "
+ 					"block device.\n",
+ 					dv->devname);
+-				return 1;
++				goto abort;
+ 			}
+ 		}
+ 		switch(dv->disposition){
+ 		default:
+ 			fprintf(stderr, Name ": internal error - devmode[%s]=%d\n",
+ 				dv->devname, dv->disposition);
+-			return 1;
++			goto abort;
+ 		case 'a':
+ 			/* add the device */
+ 			if (subarray) {
+ 				fprintf(stderr, Name ": Cannot add disks to a"
+ 					" \'member\' array, perform this"
+ 					" operation on the parent container\n");
+-				return 1;
++				goto abort;
+ 			}
+ 			/* Make sure it isn't in use (in 2.6 or later) */
+ 			tfd = dev_open(add_dev, O_RDONLY|O_EXCL|O_DIRECT);
+@@ -627,7 +627,7 @@ int Manage_subdevs(char *devname, int fd,
+ 			if (tfd < 0) {
+ 				fprintf(stderr, Name ": Cannot open %s: %s\n",
+ 					dv->devname, strerror(errno));
+-				return 1;
++				goto abort;
+ 			}
+ 
+ 			st = dup_super(tst);
+@@ -639,7 +639,7 @@ int Manage_subdevs(char *devname, int fd,
+ 				if (!get_dev_size(tfd, dv->devname, &ldsize)) {
+ 					st->ss->free_super(st);
+ 					close(tfd);
+-					return 1;
++					goto abort;
+ 				}
+ 			} else if (!get_dev_size(tfd, NULL, &ldsize)) {
+ 				st->ss->free_super(st);
+@@ -661,7 +661,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						add_dev, devname);
+ 					st->ss->free_super(st);
+ 					close(tfd);
+-					return 1;
++					goto abort;
+ 				}
+ 				fprintf(stderr, Name
+ 					": %s is larger than %s can "
+@@ -686,7 +686,7 @@ int Manage_subdevs(char *devname, int fd,
+ 
+ 				fprintf(stderr, Name ": hot add failed for %s: %s\n",
+ 					add_dev, strerror(errno));
+-				return 1;
++				goto abort;
+ 			}
+ 
+ 			if (array.not_persistent == 0 || tst->ss->external) {
+@@ -733,7 +733,7 @@ int Manage_subdevs(char *devname, int fd,
+ 					close(tfd);
+ 					st->ss->free_super(st);
+ 					fprintf(stderr, Name ": cannot load array metadata from %s\n", devname);
+-					return 1;
++					goto abort;
+ 				}
+ 
+ 				/* Make sure device is large enough */
+@@ -746,7 +746,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						continue;
+ 					fprintf(stderr, Name ": %s not large enough to join array\n",
+ 						dv->devname);
+-					return 1;
++					goto abort;
+ 				}
+ 
+ 				/* Possibly this device was recently part of the array
+@@ -799,7 +799,7 @@ int Manage_subdevs(char *devname, int fd,
+ 								fprintf(stderr, Name ": failed to open %s for"
+ 									" superblock update during re-add\n", dv->devname);
+ 								st->ss->free_super(st);
+-								return 1;
++								goto abort;
+ 							}
+ 
+ 							if (dv->writemostly == 1)
+@@ -822,7 +822,7 @@ int Manage_subdevs(char *devname, int fd,
+ 								fprintf(stderr, Name ": failed to update"
+ 									" superblock during re-add\n");
+ 								st->ss->free_super(st);
+-								return 1;
++								goto abort;
+ 							}
+ 						}
+ 						/* don't even try if disk is marked as faulty */
+@@ -840,7 +840,7 @@ int Manage_subdevs(char *devname, int fd,
+ 							st->ss->free_super(st);
+ 							if (add_dev != dv->devname)
+ 								continue;
+-							return 1;
++							goto abort;
+ 						}
+ 					skip_re_add:
+ 						re_add_failed = 1;
+@@ -864,7 +864,7 @@ int Manage_subdevs(char *devname, int fd,
+ 					fprintf(stderr, Name
+ 						": --re-add for %s to %s is not possible\n",
+ 						dv->devname, devname);
+-					return 1;
++					goto abort;
+ 				}
+ 				if (re_add_failed) {
+ 					fprintf(stderr, Name ": %s reports being an active member for %s, but a --re-add fails.\n",
+@@ -875,7 +875,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						dv->devname);
+ 					if (tfd >= 0)
+ 						close(tfd);
+-					return 1;
++					goto abort;
+ 				}
+ 			} else {
+ 				/* non-persistent. Must ensure that new drive
+@@ -886,7 +886,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						dv->devname);
+ 					if (tfd >= 0)
+ 						close(tfd);
+-					return 1;
++					goto abort;
+ 				}
+ 			}
+ 			/* committed to really trying this device now*/
+@@ -921,11 +921,11 @@ int Manage_subdevs(char *devname, int fd,
+ 				if (tst->ss->add_to_super(tst, &disc, dfd,
+ 							  dv->devname)) {
+ 					close(dfd);
+-					return 1;
++					goto abort;
+ 				}
+ 				if (tst->ss->write_init_super(tst)) {
+ 					close(dfd);
+-					return 1;
++					goto abort;
+ 				}
+ 			} else if (dv->re_add) {
+ 				/*  this had better be raid1.
+@@ -974,7 +974,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						" could not get exclusive access to container\n",
+ 						dv->devname);
+ 					tst->ss->free_super(tst);
+-					return 1;
++					goto abort;
+ 				}
+ 
+ 				dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT);
+@@ -984,7 +984,7 @@ int Manage_subdevs(char *devname, int fd,
+ 							  dv->devname)) {
+ 					close(dfd);
+ 					close(container_fd);
+-					return 1;
++					goto abort;
+ 				}
+ 				if (tst->update_tail)
+ 					flush_metadata_updates(tst);
+@@ -997,7 +997,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						dv->devname);
+ 					close(container_fd);
+ 					tst->ss->free_super(tst);
+-					return 1;
++					goto abort;
+ 				}
+ 				sra->array.level = LEVEL_CONTAINER;
+ 				/* Need to set data_offset and component_size */
+@@ -1013,7 +1013,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						" failed for %s\n", dv->devname);
+ 					close(container_fd);
+ 					sysfs_free(sra);
+-					return 1;
++					goto abort;
+ 				}
+ 				ping_monitor_by_id(devnum);
+ 				sysfs_free(sra);
+@@ -1023,7 +1023,7 @@ int Manage_subdevs(char *devname, int fd,
+ 				if (ioctl(fd, ADD_NEW_DISK, &disc)) {
+ 					fprintf(stderr, Name ": add new device failed for %s as %d: %s\n",
+ 						dv->devname, j, strerror(errno));
+-					return 1;
++					goto abort;
+ 				}
+ 			}
+ 			if (verbose >= 0)
+@@ -1038,7 +1038,7 @@ int Manage_subdevs(char *devname, int fd,
+ 					" operation on the parent container\n");
+ 				if (sysfd >= 0)
+ 					close(sysfd);
+-				return 1;
++				goto abort;
+ 			}
+ 			if (tst->ss->external) {
+ 				/* To remove a device from a container, we must
+@@ -1058,7 +1058,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						" to container - odd\n");
+ 					if (sysfd >= 0)
+ 						close(sysfd);
+-					return 1;
++					goto abort;
+ 				}
+ 				/* in the detached case it is not possible to
+ 				 * check if we are the unique holder, so just
+@@ -1075,7 +1075,7 @@ int Manage_subdevs(char *devname, int fd,
+ 						errno == EEXIST ? "still in use":
+ 						"not a member");
+ 					close(lfd);
+-					return 1;
++					goto abort;
+ 				}
+ 			}
+ 			/* FIXME check that it is a current member */
+@@ -1118,7 +1118,7 @@ int Manage_subdevs(char *devname, int fd,
+ 					strerror(errno));
+ 				if (lfd >= 0)
+ 					close(lfd);
+-				return 1;
++				goto abort;
+ 			}
+ 			if (tst->ss->external) {
+ 				/*
+@@ -1131,7 +1131,7 @@ int Manage_subdevs(char *devname, int fd,
+ 
+ 				if (!name) {
+ 					fprintf(stderr, Name ": unable to get container name\n");
+-					return 1;
++					goto abort;
+ 				}
+ 
+ 				ping_manager(name);
+@@ -1154,7 +1154,7 @@ int Manage_subdevs(char *devname, int fd,
+ 					dnprintable, strerror(errno));
+ 				if (sysfd >= 0)
+ 					close(sysfd);
+-				return 1;
++				goto abort;
+ 			}
+ 			if (sysfd >= 0)
+ 				close(sysfd);
+@@ -1169,6 +1169,9 @@ int Manage_subdevs(char *devname, int fd,
+ 	if (test && count == 0)
+ 		return 2;
+ 	return 0;
++
++abort:
++	return 1;
+ }
+ 
+ int autodetect(void)
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-Raid-limit-of-1024-when-scanning-for-devices.patch b/mdadm-3.2.3-Raid-limit-of-1024-when-scanning-for-devices.patch
new file mode 100644
index 0000000..07e8671
--- /dev/null
+++ b/mdadm-3.2.3-Raid-limit-of-1024-when-scanning-for-devices.patch
@@ -0,0 +1,81 @@
+From 480f3566411675ec41f18e5f6e15429f891e144c Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb at suse.de>
+Date: Wed, 18 Apr 2012 09:06:02 +1000
+Subject: [PATCH] Raid limit of 1024 when scanning for devices.
+
+When we can for devices using GET_DISK_INFO we currently
+limit to 1024.  But some arrays can have more than this.
+So raise it to 4096 and make the constant a #define.
+
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Manage.c |    4 ++--
+ mdadm.h  |    8 ++++++++
+ util.c   |    4 ++--
+ 3 files changed, 12 insertions(+), 4 deletions(-)
+
+diff --git a/Manage.c b/Manage.c
+index 102c013..3767f01 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -462,7 +462,7 @@ int Manage_subdevs(char *devname, int fd,
+ 					dv->devname, dv->disposition);
+ 				goto abort;
+ 			}
+-			for (; j < 1024 && remaining_disks > 0; j++) {
++			for (; j < MAX_DISKS && remaining_disks > 0; j++) {
+ 				unsigned dev;
+ 				disc.number = j;
+ 				if (ioctl(fd, GET_DISK_INFO, &disc))
+@@ -495,7 +495,7 @@ int Manage_subdevs(char *devname, int fd,
+ 					dv->devname, dv->disposition);
+ 				goto abort;
+ 			}
+-			for (; j < 1024 && remaining_disks > 0; j++) {
++			for (; j < MAX_DISKS && remaining_disks > 0; j++) {
+ 				int sfd;
+ 				unsigned dev;
+ 				disc.number = j;
+diff --git a/mdadm.h b/mdadm.h
+index 686d4b4..71cef38 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1388,4 +1388,13 @@ static inline int xasprintf(char **strp, const char *fmt, ...) {
+ #define PROCESS_DELAYED -2
+ #define PROCESS_PENDING -3
+ 
+ extern int __offroot;
++ 
++/* When using "GET_DISK_INFO" it isn't certain how high
++ * we need to check.  So we impose an absolute limit of
++ * MAX_DISKS.  This needs to be much more than the largest
++ * number of devices any metadata can support.  Currently
++ * v1.x can support 1920
++ */
++#define MAX_DISKS	4096
++
+diff --git a/util.c b/util.c
+index b942058..ac0f78c 100644
+--- a/util.c
++++ b/util.c
+@@ -378,7 +378,7 @@ int enough_fd(int fd)
+ 	    array.raid_disks <= 0)
+ 		return 0;
+ 	avail = calloc(array.raid_disks, 1);
+-	for (i=0; i < 1024 && array.nr_disks > 0; i++) {
++	for (i=0; i < MAX_DISKS && array.nr_disks > 0; i++) {
+ 		disk.number = i;
+ 		if (ioctl(fd, GET_DISK_INFO, &disk) != 0)
+ 			continue;
+@@ -1275,7 +1275,7 @@ void get_one_disk(int mdfd, mdu_array_info_t *ainf, mdu_disk_info_t *disk)
+ 	int d;
+ 
+ 	ioctl(mdfd, GET_ARRAY_INFO, ainf);
+-	for (d = 0 ; d < 1024 ; d++) {
++	for (d = 0 ; d < MAX_DISKS ; d++) {
+ 		if (ioctl(mdfd, GET_DISK_INFO, disk) == 0 &&
+ 		    (disk->major || disk->minor))
+ 			return;
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-Relax-restrictions-on-when-add-is-permitted.patch b/mdadm-3.2.3-Relax-restrictions-on-when-add-is-permitted.patch
new file mode 100644
index 0000000..58c48bc
--- /dev/null
+++ b/mdadm-3.2.3-Relax-restrictions-on-when-add-is-permitted.patch
@@ -0,0 +1,85 @@
+From 0a999759b54f94fd63ac0ee298a549acef6f7d6f Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb at suse.de>
+Date: Wed, 18 Apr 2012 14:19:49 +1000
+Subject: [PATCH 1/3] Relax restrictions on when --add is permitted.
+
+The restriction that --add was not allowed on a device which
+looked like a recent member of an array was overly harsh.
+
+The real requirement was to avoid using --add when the array had
+failed, and the device being added might contain necessary
+information which can only be incorporated by stopping and
+re-assembling with --force.
+
+So change the test to reflect the need.
+
+Reported-by: Doug Ledford <dledford at redhat.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Manage.c |   35 ++++++++++++++++++++++++++---------
+ 1 files changed, 26 insertions(+), 9 deletions(-)
+
+diff --git a/Manage.c b/Manage.c
+index 3767f01..95aa270 100644
+--- a/Manage.c
++++ b/Manage.c
+@@ -448,7 +448,7 @@ int Manage_subdevs(char *devname, int fd,
+ 		char *dnprintable = dv->devname;
+ 		char *add_dev = dv->devname;
+ 		int err;
+-		int re_add_failed = 0;
++		int array_failed;
+ 
+ 		next = dv->next;
+ 		jnext = 0;
+@@ -851,9 +851,8 @@ int Manage_subdevs(char *devname, int fd,
+ 								continue;
+ 							goto abort;
+ 						}
+-					skip_re_add:
+-						re_add_failed = 1;
+ 					}
++				skip_re_add:
+ 					st->ss->free_super(st);
+ 				}
+ 				if (add_dev != dv->devname) {
+@@ -875,12 +874,30 @@ int Manage_subdevs(char *devname, int fd,
+ 						dv->devname, devname);
+ 					goto abort;
+ 				}
+-				if (re_add_failed) {
+-					fprintf(stderr, Name ": %s reports being an active member for %s, but a --re-add fails.\n",
+-						dv->devname, devname);
+-					fprintf(stderr, Name ": not performing --add as that would convert %s in to a spare.\n",
+-						dv->devname);
+-					fprintf(stderr, Name ": To make this a spare, use \"mdadm --zero-superblock %s\" first.\n",	
++				if (array.active_disks < array.raid_disks) {
++					char *avail = calloc(array.raid_disks, 1);
++					int d;
++					int found = 0;
++
++					for (d = 0; d < MAX_DISKS && found < array.active_disks; d++) {
++						disc.number = d;
++						if (ioctl(fd, GET_DISK_INFO, &disc))
++							continue;
++						if (disc.major == 0 && disc.minor == 0)
++							continue;
++						if (!(disc.state & (1<<MD_DISK_SYNC)))
++							continue;
++						avail[disc.raid_disk] = 1;
++						found++;
++					}
++					array_failed = !enough(array.level, array.raid_disks, 
++							       array.layout, 1, avail);
++				} else
++					array_failed = 0;
++				if (array_failed) {
++					fprintf(stderr, Name ": %s has failed so using --add cannot work and might destroy\n",
++						devname);
++					fprintf(stderr, Name ": data on %s.  You should stop the array and re-assemble it.\n",
+ 						dv->devname);
+ 					if (tfd >= 0)
+ 						close(tfd);
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-Remove-avail_disks-arg-from-enough.patch b/mdadm-3.2.3-Remove-avail_disks-arg-from-enough.patch
new file mode 100644
index 0000000..1dda32a
--- /dev/null
+++ b/mdadm-3.2.3-Remove-avail_disks-arg-from-enough.patch
@@ -0,0 +1,171 @@
+From de5a472ea32867d002558bac0d2d2b4faf45c7c4 Mon Sep 17 00:00:00 2001
+From: NeilBrown <neilb at suse.de>
+Date: Tue, 7 Feb 2012 14:04:47 +1100
+Subject: [PATCH] Remove avail_disks arg from 'enough'.
+
+It can easily be calculated from 'avail' and  'raid_disks', and we
+will soon have a case where we don't have it easily available to pass
+in.
+
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Assemble.c    |   16 ++++++++--------
+ Detail.c      |    4 ++--
+ Incremental.c |    2 +-
+ mdadm.h       |    2 +-
+ util.c        |   11 ++++++++---
+ 5 files changed, 20 insertions(+), 15 deletions(-)
+
+diff --git a/Assemble.c b/Assemble.c
+index fd94461..972398e 100644
+--- a/Assemble.c
++++ b/Assemble.c
+@@ -934,7 +934,7 @@ int Assemble(struct supertype *st, char *mddev,
+ 				}
+ 				continue;
+ 			}
+-		/* If this devices thinks that 'most_recent' has failed, then
++		/* If this device thinks that 'most_recent' has failed, then
+ 		 * we must reject this device.
+ 		 */
+ 		if (j != most_recent &&
+@@ -965,7 +965,7 @@ int Assemble(struct supertype *st, char *mddev,
+ 	free(devmap);
+ 	while (force && !enough(content->array.level, content->array.raid_disks,
+ 				content->array.layout, 1,
+-				avail, okcnt)) {
++				avail)) {
+ 		/* Choose the newest best drive which is
+ 		 * not up-to-date, update the superblock
+ 		 * and add it.
+@@ -1132,7 +1132,7 @@ int Assemble(struct supertype *st, char *mddev,
+ 	if (force && !clean &&
+ 	    !enough(content->array.level, content->array.raid_disks,
+ 		    content->array.layout, clean,
+-		    avail, okcnt)) {
++		    avail)) {
+ 		change += st->ss->update_super(st, content, "force-array",
+ 					devices[chosen_drive].devname, verbose,
+ 					       0, NULL);
+@@ -1331,7 +1331,7 @@ int Assemble(struct supertype *st, char *mddev,
+ 		if (runstop == 1 ||
+ 		    (runstop <= 0 &&
+ 		     ( enough(content->array.level, content->array.raid_disks,
+-			      content->array.layout, clean, avail, okcnt) &&
++			      content->array.layout, clean, avail) &&
+ 		       (okcnt + rebuilding_cnt >= req_cnt || start_partial_ok)
+ 			     ))) {
+ 			/* This array is good-to-go.
+@@ -1437,13 +1437,13 @@ int Assemble(struct supertype *st, char *mddev,
+ 				mddev, strerror(errno));
+ 
+ 			if (!enough(content->array.level, content->array.raid_disks,
+-				    content->array.layout, 1, avail, okcnt))
++				    content->array.layout, 1, avail))
+ 				fprintf(stderr, Name ": Not enough devices to "
+ 					"start the array.\n");
+ 			else if (!enough(content->array.level,
+ 					 content->array.raid_disks,
+ 					 content->array.layout, clean,
+-					 avail, okcnt))
++					 avail))
+ 				fprintf(stderr, Name ": Not enough devices to "
+ 					"start the array while not clean "
+ 					"- consider --force.\n");
+@@ -1471,12 +1471,12 @@ int Assemble(struct supertype *st, char *mddev,
+ 			if (sparecnt)
+ 				fprintf(stderr, " and %d spare%s", sparecnt, sparecnt==1?"":"s");
+ 			if (!enough(content->array.level, content->array.raid_disks,
+-				    content->array.layout, 1, avail, okcnt))
++				    content->array.layout, 1, avail))
+ 				fprintf(stderr, " - not enough to start the array.\n");
+ 			else if (!enough(content->array.level,
+ 					 content->array.raid_disks,
+ 					 content->array.layout, clean,
+-					 avail, okcnt))
++					 avail))
+ 				fprintf(stderr, " - not enough to start the "
+ 					"array while not clean - consider "
+ 					"--force.\n");
+diff --git a/Detail.c b/Detail.c
+index e7d1681..1d7e3a1 100644
+--- a/Detail.c
++++ b/Detail.c
+@@ -367,7 +367,7 @@ int Detail(char *dev, int brief, int export, int test, char *homehost)
+ 			if (avail_disks == array.raid_disks)
+ 				st = "";
+ 			else if (!enough(array.level, array.raid_disks,
+-					 array.layout, 1, avail, avail_disks))
++					 array.layout, 1, avail))
+ 				st = ", FAILED";
+ 			else
+ 				st = ", degraded";
+@@ -580,7 +580,7 @@ This is pretty boring
+ 	if (brief) printf("\n");
+ 	if (test &&
+ 	    !enough(array.level, array.raid_disks, array.layout,
+-		    1, avail, avail_disks))
++		    1, avail))
+ 		rv = 2;
+ 
+ 	free(disks);
+diff --git a/Incremental.c b/Incremental.c
+index 60175af..b457bf3 100644
+--- a/Incremental.c
++++ b/Incremental.c
+@@ -486,7 +486,7 @@ int Incremental(char *devname, int verbose, int runstop,
+ 	active_disks = count_active(st, sra, mdfd, &avail, &info);
+ 	if (enough(info.array.level, info.array.raid_disks,
+ 		   info.array.layout, info.array.state & 1,
+-		   avail, active_disks) == 0) {
++		   avail) == 0) {
+ 		if (verbose >= 0)
+ 			fprintf(stderr, Name
+ 			     ": %s attached to %s, not enough to start (%d).\n",
+diff --git a/mdadm.h b/mdadm.h
+index d862b3e..45198bb 100644
+--- a/mdadm.h
++++ b/mdadm.h
+@@ -1164,7 +1164,7 @@ extern char *fname_from_uuid(struct supertype *st,
+ 			     struct mdinfo *info, char *buf, char sep);
+ extern unsigned long calc_csum(void *super, int bytes);
+ extern int enough(int level, int raid_disks, int layout, int clean,
+-		   char *avail, int avail_disks);
++		   char *avail);
+ extern int enough_fd(int fd);
+ extern int ask(char *mesg);
+ extern unsigned long long get_component_size(int fd);
+diff --git a/util.c b/util.c
+index 4ba44e6..e5f7a20 100644
+--- a/util.c
++++ b/util.c
+@@ -311,10 +311,15 @@ int test_partition_from_id(dev_t id)
+ 	return rv;
+ }
+ 
+-int enough(int level, int raid_disks, int layout, int clean,
+-	   char *avail, int avail_disks)
++int enough(int level, int raid_disks, int layout, int clean, char *avail)
+ {
+ 	int copies, first;
++	int i;
++	int avail_disks = 0;
++
++	for (i = 0; i < raid_disks; i++)
++		avail_disks += !!avail[i];
++
+ 	switch (level) {
+ 	case 10:
+ 		/* This is the tricky one - we need to check
+@@ -389,7 +394,7 @@ int enough_fd(int fd)
+ 	}
+ 	/* This is used on an active array, so assume it is clean */
+ 	rv = enough(array.level, array.raid_disks, array.layout,
+-		    1, avail, avail_disks);
++		    1, avail);
+ 	free(avail);
+ 	return rv;
+ }
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-Reset-bad-flag-on-map-update.patch b/mdadm-3.2.3-Reset-bad-flag-on-map-update.patch
new file mode 100644
index 0000000..cbbc5a3
--- /dev/null
+++ b/mdadm-3.2.3-Reset-bad-flag-on-map-update.patch
@@ -0,0 +1,32 @@
+From 52f07f57195229809c7b6d71ca81d2182d303058 Mon Sep 17 00:00:00 2001
+From: "Czarnowska, Anna" <anna.czarnowska at intel.com>
+Date: Wed, 7 Mar 2012 12:51:30 +0000
+Subject: [PATCH] Reset bad flag on map update
+
+Map file may miss an entry if bad flag is not cleared on update.
+
+This happens for example when an old entry exists in map that
+has no mdstat counterpart and we create a new array with the same devnum.
+Newly created array will not appear in map if update doesnt clear bad flag.
+
+Signed-off-by: Anna Czarnowska <anna.czarnowska at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ mapfile.c |    1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/mapfile.c b/mapfile.c
+index 0bfecd0..9e2c893 100644
+--- a/mapfile.c
++++ b/mapfile.c
+@@ -246,6 +246,7 @@ int map_update(struct map_ent **mpp, int devnum, char *metadata,
+ 			memcpy(mp->uuid, uuid, 16);
+ 			free(mp->path);
+ 			mp->path = path ? strdup(path) : NULL;
++			mp->bad = 0;
+ 			break;
+ 		}
+ 	if (!mp)
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-check-that-no-disk-over-2TB-is-used-to-create-contai.patch b/mdadm-3.2.3-check-that-no-disk-over-2TB-is-used-to-create-contai.patch
new file mode 100644
index 0000000..c10edbe
--- /dev/null
+++ b/mdadm-3.2.3-check-that-no-disk-over-2TB-is-used-to-create-contai.patch
@@ -0,0 +1,52 @@
+From 9126b9a816b1576f58718dbb71bcaff2bfc274e3 Mon Sep 17 00:00:00 2001
+From: "Czarnowska, Anna" <anna.czarnowska at intel.com>
+Date: Mon, 2 Apr 2012 10:18:37 +1000
+Subject: [PATCH 6/7] check that no disk over 2TB is used to create container
+ when no support
+
+Creation of a container using disks over 2TB should be allowed only when orom supports large disks
+
+Signed-off-by: Anna Czarnowska <anna.czarnowska at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |   24 ++++++++++++++++--------
+ 1 files changed, 16 insertions(+), 8 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 7803a2e..1bc9e9c 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -5331,14 +5331,22 @@ static int validate_geometry_imsm_container(struct supertype *st, int level,
+ 		return 0;
+ 	}
+ 	close(fd);
+-	if (super->orom && raiddisks > super->orom->tds) {
+-		if (verbose)
+-			fprintf(stderr, Name ": %d exceeds maximum number of"
+-				" platform supported disks: %d\n",
+-				raiddisks, super->orom->tds);
+-
+-		free_imsm(super);
+-		return 0;
++	if (super->orom) {
++		if (raiddisks > super->orom->tds) {
++			if (verbose)
++				fprintf(stderr, Name ": %d exceeds maximum number of"
++					" platform supported disks: %d\n",
++					raiddisks, super->orom->tds);
++			free_imsm(super);
++			return 0;
++		}
++		if ((super->orom->attr & IMSM_OROM_ATTR_2TB_DISK) == 0 &&
++		    (ldsize >> 9) >> 32 > 0) {
++			if (verbose)
++				fprintf(stderr, Name ": %s exceeds maximum platform supported size\n", dev);
++			free_imsm(super);
++			return 0;
++		}
+ 	}
+ 
+ 	*freesize = avail_size_imsm(st, ldsize >> 9);
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-check-volume-size-in-validate_geometry_imsm_orom.patch b/mdadm-3.2.3-check-volume-size-in-validate_geometry_imsm_orom.patch
new file mode 100644
index 0000000..96c46f6
--- /dev/null
+++ b/mdadm-3.2.3-check-volume-size-in-validate_geometry_imsm_orom.patch
@@ -0,0 +1,69 @@
+From 2cc699afbf0a05baf02d26309eb4ad0e4e81c5d5 Mon Sep 17 00:00:00 2001
+From: "Czarnowska, Anna" <anna.czarnowska at intel.com>
+Date: Mon, 2 Apr 2012 10:17:55 +1000
+Subject: [PATCH 5/7] check volume size in validate_geometry_imsm_orom
+
+When orom does not support volumes over 2TB the creation should be disallowed
+
+Signed-off-by: Anna Czarnowska <anna.czarnowska at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |   14 ++++++++++----
+ 1 files changed, 10 insertions(+), 4 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 0c38b45..7803a2e 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -5860,7 +5860,7 @@ static int imsm_default_chunk(const struct imsm_orom *orom)
+ 
+ static int
+ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
+-			    int raiddisks, int *chunk, int verbose)
++			    int raiddisks, int *chunk, unsigned long long size, int verbose)
+ {
+ 	/* check/set platform and metadata limits/defaults */
+ 	if (super->orom && raiddisks > super->orom->dpa) {
+@@ -5895,6 +5895,12 @@ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
+ 				layout, level);
+ 		return 0;
+ 	}
++
++	if (super->orom && (super->orom->attr & IMSM_OROM_ATTR_2TB) == 0 && chunk &&
++			(calc_array_size(level, raiddisks, layout, *chunk, size) >> 32) > 0) {
++		pr_vrb(": platform does not support a volume size over 2TB\n");
++		return 0;
++	}
+ 	return 1;
+ }
+ 
+@@ -5922,7 +5928,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
+ 
+ 	mpb = super->anchor;
+ 
+-	if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, verbose)) {
++	if (!validate_geometry_imsm_orom(super, level, layout, raiddisks, chunk, size, verbose)) {
+ 		fprintf(stderr, Name ": RAID gemetry validation failed. "
+ 			"Cannot proceed with the action(s).\n");
+ 		return 0;
+@@ -6187,7 +6193,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+ 		if (st->sb) {
+ 			struct intel_super *super = st->sb;
+ 			if (!validate_geometry_imsm_orom(st->sb, level, layout,
+-							 raiddisks, chunk,
++							 raiddisks, chunk, size,
+ 							 verbose))
+ 				return 0;
+ 			/* we are being asked to automatically layout a
+@@ -6598,7 +6604,7 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
+ 						 get_imsm_raid_level(map), /* RAID level */
+ 						 imsm_level_to_layout(get_imsm_raid_level(map)),
+ 						 map->num_members, /* raid disks */
+-						 &chunk,
++						 &chunk, join_u32(dev->size_low, dev->size_high),
+ 						 1 /* verbose */)) {
+ 			fprintf(stderr, Name ": IMSM RAID geometry validation"
+ 				" failed.  Array %s activation is blocked.\n",
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-clear-hi-bits-if-not-used-after-loading-metadata-fro.patch b/mdadm-3.2.3-clear-hi-bits-if-not-used-after-loading-metadata-fro.patch
new file mode 100644
index 0000000..eb07579
--- /dev/null
+++ b/mdadm-3.2.3-clear-hi-bits-if-not-used-after-loading-metadata-fro.patch
@@ -0,0 +1,72 @@
+From 97f81ee2635d8c1283ef857bc46d7314acffa1c3 Mon Sep 17 00:00:00 2001
+From: "Czarnowska, Anna" <anna.czarnowska at intel.com>
+Date: Mon, 2 Apr 2012 10:15:08 +1000
+Subject: [PATCH 2/7] clear hi bits if not used after loading metadata from
+ disk
+
+Functions retrieving sizes from metadata do not need to check
+2TB attribute only when we can guarantee the hi bits are always
+clear when the MPB_ATTR_2TB_DISK attribute is not set.
+
+Therefore the following fields are cleared on metadata load
+when not in use according to attribute:
+struct imsm_disk.total_blocks_hi
+struct imsm_map.pba_of_lba0_hi
+struct imsm_map.blocks_per_member_hi
+struct imsm_map.num_data_stripes_hi
+
+Signed-off-by: Anna Czarnowska <anna.czarnowska at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |   28 +++++++++++++++++++++++++++-
+ 1 files changed, 27 insertions(+), 1 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index c65d39b..480b379 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -3590,6 +3590,32 @@ static int load_imsm_mpb(int fd, struct intel_super *super, char *devname)
+ 
+ static int read_imsm_migr_rec(int fd, struct intel_super *super);
+ 
++/* clears hi bits in metadata if MPB_ATTRIB_2TB_DISK not set */
++static void clear_hi(struct intel_super *super)
++{
++	struct imsm_super *mpb = super->anchor;
++	int i, n;
++	if (mpb->attributes & MPB_ATTRIB_2TB_DISK)
++		return;
++	for (i = 0; i < mpb->num_disks; ++i) {
++		struct imsm_disk *disk = &mpb->disk[i];
++		disk->total_blocks_hi = 0;
++	}
++	for (i = 0; i < mpb->num_raid_devs; ++i) {
++		struct imsm_dev *dev = get_imsm_dev(super, i);
++		if (!dev)
++			return;
++		for (n = 0; n < 2; ++n) {
++			struct imsm_map *map = get_imsm_map(dev, n);
++			if (!map)
++				continue;
++			map->pba_of_lba0_hi = 0;
++			map->blocks_per_member_hi = 0;
++			map->num_data_stripes_hi = 0;
++		}
++	}
++}
++
+ static int
+ load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd)
+ {
+@@ -3602,7 +3628,7 @@ load_and_parse_mpb(int fd, struct intel_super *super, char *devname, int keep_fd
+ 	if (err)
+ 		return err;
+ 	err = parse_raid_devices(super);
+-
++	clear_hi(super);
+ 	return err;
+ }
+ 
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-fix-Monitor-sometimes-crashes.patch b/mdadm-3.2.3-fix-Monitor-sometimes-crashes.patch
new file mode 100644
index 0000000..b67b501
--- /dev/null
+++ b/mdadm-3.2.3-fix-Monitor-sometimes-crashes.patch
@@ -0,0 +1,34 @@
+From 8453f8d0df0111cfd25e984afb7a64153b04bc27 Mon Sep 17 00:00:00 2001
+From: Lukasz Dorau <lukasz.dorau at intel.com>
+Date: Thu, 12 Jan 2012 10:40:00 +1100
+Subject: [PATCH] fix: Monitor sometimes crashes
+
+The "char cnt [40]" buffer is sometimes too small to hold all message
+- in such case monitor crashes.
+The buffer must be larger to be able to hold all message.
+
+Signed-off-by: Lukasz Dorau <lukasz.dorau at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Monitor.c |    5 +++--
+ 1 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/Monitor.c b/Monitor.c
+index 8bc8824..77f22aa 100644
+--- a/Monitor.c
++++ b/Monitor.c
+@@ -563,8 +563,9 @@ static int check_array(struct state *st, struct mdstat_ent *mdstat,
+ 		struct mdinfo *sra =
+ 			sysfs_read(-1, st->devnum, GET_MISMATCH);
+ 		if (sra && sra->mismatch_cnt > 0) {
+-			char cnt[40];
+-			sprintf(cnt, " mismatches found: %d (on raid level %d)",
++			char cnt[80];
++			snprintf(cnt, sizeof(cnt),
++				 " mismatches found: %d (on raid level %d)",
+ 				sra->mismatch_cnt, array.level);
+ 			alert("RebuildFinished", dev, cnt, ainfo);
+ 		} else
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-fix-container-creation-with-incremental-used.patch b/mdadm-3.2.3-fix-container-creation-with-incremental-used.patch
new file mode 100644
index 0000000..6a00d99
--- /dev/null
+++ b/mdadm-3.2.3-fix-container-creation-with-incremental-used.patch
@@ -0,0 +1,34 @@
+From 0c4304ca8b3328132537922fed8ee9e3bbb8a0fa Mon Sep 17 00:00:00 2001
+From: Lukasz Dorau <lukasz.dorau at intel.com>
+Date: Thu, 12 Jan 2012 10:57:20 +1100
+Subject: [PATCH] fix: container creation with --incremental used.
+
+If there is no name provided for a container by the metadata it is
+always appropriate to use the metadata version name.  create_mddev
+will still add a uniquifying digit to the end so there is little risk
+of confusion.
+This makes the --incremental code behave the same as the --assemble code.
+
+Signed-off-by: Lukasz Dorau <lukasz.dorau at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Incremental.c |    3 +--
+ 1 files changed, 1 insertions(+), 2 deletions(-)
+
+diff --git a/Incremental.c b/Incremental.c
+index 78c9712..60175af 100644
+--- a/Incremental.c
++++ b/Incremental.c
+@@ -259,8 +259,7 @@ int Incremental(char *devname, int verbose, int runstop,
+ 
+ 	name_to_use = info.name;
+ 	if (name_to_use[0] == 0 &&
+-	    info.array.level == LEVEL_CONTAINER &&
+-	    trustworthy == LOCAL) {
++	    info.array.level == LEVEL_CONTAINER) {
+ 		name_to_use = info.text_version;
+ 		trustworthy = METADATA;
+ 	}
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-fix-correct-extending-size-of-raid0-array.patch b/mdadm-3.2.3-fix-correct-extending-size-of-raid0-array.patch
new file mode 100644
index 0000000..8a469df
--- /dev/null
+++ b/mdadm-3.2.3-fix-correct-extending-size-of-raid0-array.patch
@@ -0,0 +1,31 @@
+From b51702b82767b726e34d205c9e00a4f61d3044a7 Mon Sep 17 00:00:00 2001
+From: Lukasz Dorau <lukasz.dorau at intel.com>
+Date: Fri, 20 Apr 2012 11:00:25 +0200
+Subject: [PATCH 3/3] fix: correct extending size of raid0 array
+
+Setting "sync_action" to "idle" while extending size of raid0 array
+is racy and sometimes fails.
+"sync_action" should be set to "frozen" instead.
+
+Signed-off-by: Lukasz Dorau <lukasz.dorau at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Grow.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index 389992e..b4b9ff2 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1749,7 +1749,7 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 			/* do not recync non-existing parity,
+ 			 * we will drop it anyway
+ 			 */
+-			sysfs_set_str(sra, NULL, "sync_action", "idle");
++			sysfs_set_str(sra, NULL, "sync_action", "frozen");
+ 			/* go back to raid0, drop parity disk
+ 			 */
+ 			sysfs_set_str(sra, NULL, "level", "raid0");
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-Add-function-imsm_get_free_size.patch b/mdadm-3.2.3-imsm-Add-function-imsm_get_free_size.patch
new file mode 100644
index 0000000..7658ae7
--- /dev/null
+++ b/mdadm-3.2.3-imsm-Add-function-imsm_get_free_size.patch
@@ -0,0 +1,63 @@
+From 13bcac9059b6aef7bf9e828fbdea285cf6adcbd2 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:52:04 +0200
+Subject: [PATCH 10/14] imsm: Add function imsm_get_free_size()
+
+Add function imsm_imsm_get_free_size() using part of code from function
+reserve_space().
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |   25 ++++++++++++++++++++++++-
+ 1 files changed, 24 insertions(+), 1 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 49e383f..7cc0ed5 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -6108,7 +6108,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
+ 	return 1;
+ }
+ 
+-static int reserve_space(struct supertype *st, int raiddisks,
++static int imsm_get_free_size(struct supertype *st, int raiddisks,
+ 			 unsigned long long size, int chunk,
+ 			 unsigned long long *freesize)
+ {
+@@ -6186,9 +6186,32 @@ static int reserve_space(struct supertype *st, int raiddisks,
+ 
+ 	*freesize = size;
+ 
++	dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
++
+ 	return 1;
+ }
+ 
++static int reserve_space(struct supertype *st, int raiddisks,
++			 unsigned long long size, int chunk,
++			 unsigned long long *freesize)
++{
++	struct intel_super *super = st->sb;
++	struct dl *dl;
++	int cnt;
++	int rv = 0;
++
++	rv = imsm_get_free_size(st, raiddisks, size, chunk, freesize);
++	if (rv) {
++		cnt = 0;
++		for (dl = super->disks; dl; dl = dl->next)
++			if (dl->e)
++				dl->raiddisk = cnt++;
++		rv = 1;
++	}
++
++	return rv;
++}
++
+ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+ 				  int raiddisks, int *chunk, unsigned long long size,
+ 				  char *dev, unsigned long long *freesize,
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-Add-new-metadata-update-for-volume-size-expansi.patch b/mdadm-3.2.3-imsm-Add-new-metadata-update-for-volume-size-expansi.patch
new file mode 100644
index 0000000..f7b0b08
--- /dev/null
+++ b/mdadm-3.2.3-imsm-Add-new-metadata-update-for-volume-size-expansi.patch
@@ -0,0 +1,238 @@
+From f3871fdc6841a0505d3a987f4ea1cfb16f6cc201 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:51:57 +0200
+Subject: [PATCH 03/14] imsm: Add new metadata update for volume size
+ expansion
+
+Add new meatdata update type imsm_update_size_change, and update metadata
+for volume size expansion operation.
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |  132 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
+ 1 files changed, 124 insertions(+), 8 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 2e6a899..ac8922f 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -419,6 +419,7 @@ enum imsm_update_type {
+ 	update_reshape_migration,
+ 	update_takeover,
+ 	update_general_migration_checkpoint,
++	update_size_change,
+ };
+ 
+ struct imsm_update_activate_spare {
+@@ -471,6 +472,12 @@ struct imsm_update_reshape_migration {
+ 	int new_disks[1]; /* new_raid_disks - old_raid_disks makedev number */
+ };
+ 
++struct imsm_update_size_change {
++	enum imsm_update_type type;
++	int subdev;
++	long long new_size;
++};
++
+ struct imsm_update_general_migration_checkpoint {
+ 	enum imsm_update_type type;
+ 	__u32 curr_migr_unit;
+@@ -6974,7 +6981,8 @@ static void handle_missing(struct intel_super *super, struct imsm_dev *dev)
+ 	super->updates_pending++;
+ }
+ 
+-static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
++static unsigned long long imsm_set_array_size(struct imsm_dev *dev,
++					      long long new_size)
+ {
+ 	int used_disks = imsm_num_data_members(dev, MAP_0);
+ 	unsigned long long array_blocks;
+@@ -6993,8 +7001,17 @@ static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
+ 
+ 	/* set array size in metadata
+ 	 */
+-	map = get_imsm_map(dev, MAP_0);
+-	array_blocks = blocks_per_member(map) * used_disks;
++	if (new_size <= 0) {
++		/* OLCE size change is caused by added disks
++		 */
++		map = get_imsm_map(dev, MAP_0);
++		array_blocks = blocks_per_member(map) * used_disks;
++	} else {
++		/* Online Volume Size Change
++		 * Using  available free space
++		 */
++		array_blocks = new_size;
++	}
+ 
+ 	/* round array size down to closest MB
+ 	 */
+@@ -7051,7 +7068,7 @@ static void imsm_progress_container_reshape(struct intel_super *super)
+ 		memcpy(map2, map, copy_map_size);
+ 		map2->num_members = prev_num_members;
+ 
+-		imsm_set_array_size(dev);
++		imsm_set_array_size(dev, -1);
+ 		super->clean_migration_record_by_mdmon = 1;
+ 		super->updates_pending++;
+ 	}
+@@ -7941,7 +7958,7 @@ skip_disk_add:
+ 			*tofree = *space_list;
+ 			/* calculate new size
+ 			 */
+-			imsm_set_array_size(new_dev);
++			imsm_set_array_size(new_dev, -1);
+ 
+ 			ret_val = 1;
+ 		}
+@@ -7956,6 +7973,44 @@ error_disk_add:
+ 	return ret_val;
+ }
+ 
++static int apply_size_change_update(struct imsm_update_size_change *u,
++		struct intel_super *super)
++{
++	struct intel_dev *id;
++	int ret_val = 0;
++
++	dprintf("apply_size_change_update()\n");
++	if ((u->subdev < 0) ||
++	    (u->subdev > 1)) {
++		dprintf("imsm: Error: Wrong subdev: %i\n", u->subdev);
++		return ret_val;
++	}
++
++	for (id = super->devlist ; id; id = id->next) {
++		if (id->index == (unsigned)u->subdev) {
++			struct imsm_dev *dev = get_imsm_dev(super, u->subdev);
++			struct imsm_map *map = get_imsm_map(dev, MAP_0);
++			int used_disks = imsm_num_data_members(dev, MAP_0);
++			unsigned long long blocks_per_member;
++
++			/* calculate new size
++			 */
++			blocks_per_member = u->new_size / used_disks;
++			dprintf("imsm: apply_size_change_update(size: %llu, "
++				"blocks per member: %llu)\n",
++				u->new_size, blocks_per_member);
++			set_blocks_per_member(map, blocks_per_member);
++			imsm_set_array_size(dev, u->new_size);
++
++			ret_val = 1;
++			break;
++		}
++	}
++
++	return ret_val;
++}
++
++
+ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
+ 				       struct intel_super *super,
+ 				       struct active_array *active_array)
+@@ -8155,7 +8210,7 @@ static int apply_reshape_container_disks_update(struct imsm_update_reshape *u,
+ 			newmap = get_imsm_map(newdev, MAP_1);
+ 			memcpy(newmap, oldmap, sizeof_imsm_map(oldmap));
+ 
+-			imsm_set_array_size(newdev);
++			imsm_set_array_size(newdev, -1);
+ 		}
+ 
+ 		sp = (void **)id->dev;
+@@ -8363,6 +8418,12 @@ static void imsm_process_update(struct supertype *st,
+ 			super->updates_pending++;
+ 		break;
+ 	}
++	case update_size_change: {
++		struct imsm_update_size_change *u = (void *)update->buf;
++		if (apply_size_change_update(u, super))
++			super->updates_pending++;
++		break;
++	}
+ 	case update_activate_spare: {
+ 		struct imsm_update_activate_spare *u = (void *) update->buf; 
+ 		if (apply_update_activate_spare(u, super, st->arrays))
+@@ -8757,6 +8818,9 @@ static void imsm_prepare_update(struct supertype *st,
+ 		dprintf("New anchor length is %llu\n", (unsigned long long)len);
+ 		break;
+ 	}
++	case update_size_change: {
++		break;
++	}
+ 	case update_create_array: {
+ 		struct imsm_update_create_array *u = (void *) update->buf;
+ 		struct intel_dev *dv;
+@@ -9614,6 +9678,43 @@ abort:
+ 	return 0;
+ }
+ 
++
++/******************************************************************************
++ * function: imsm_create_metadata_update_for_size_change()
++ *           Creates update for IMSM array for array size change.
++ *
++ ******************************************************************************/
++static int imsm_create_metadata_update_for_size_change(
++				struct supertype *st,
++				struct geo_params *geo,
++				struct imsm_update_size_change **updatep)
++{
++	struct intel_super *super = st->sb;
++	int update_memory_size = 0;
++	struct imsm_update_size_change *u = NULL;
++
++	dprintf("imsm_create_metadata_update_for_size_change(enter)"
++		" New size = %llu\n", geo->size);
++
++	/* size of all update data without anchor */
++	update_memory_size = sizeof(struct imsm_update_size_change);
++
++	u = calloc(1, update_memory_size);
++	if (u == NULL) {
++		dprintf("error: cannot get memory for "
++			"imsm_create_metadata_update_for_size_change\n");
++		return 0;
++	}
++	u->type = update_size_change;
++	u->subdev = super->current_vol;
++	u->new_size = geo->size;
++
++	dprintf("imsm: reshape update preparation : OK\n");
++	*updatep = u;
++
++	return update_memory_size;
++}
++
+ /******************************************************************************
+  * function: imsm_create_metadata_update_for_migration()
+  *           Creates update for IMSM array.
+@@ -10023,8 +10124,23 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
+ 		}
+ 		break;
+ 		case CH_ARRAY_SIZE: {
+-			/* ToDo: Prepare metadata update here
+-			 */
++			struct imsm_update_size_change *u = NULL;
++			int len =
++				imsm_create_metadata_update_for_size_change(
++					st, &geo, &u);
++			if (len < 1) {
++				dprintf("imsm: "
++					"Cannot prepare update\n");
++				break;
++			}
++			ret_val = 0;
++			/* update metadata locally */
++			imsm_update_metadata_locally(st, u, len);
++			/* and possibly remotely */
++			if (st->update_tail)
++				append_metadata_update(st, u, len);
++			else
++				free(u);
+ 		}
+ 		break;
+ 		default:
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-Execute-size-change-for-external-metatdata.patch b/mdadm-3.2.3-imsm-Execute-size-change-for-external-metatdata.patch
new file mode 100644
index 0000000..ee91683
--- /dev/null
+++ b/mdadm-3.2.3-imsm-Execute-size-change-for-external-metatdata.patch
@@ -0,0 +1,129 @@
+From 54397ed97af065b1e3a12d6beab09bc05a07a9d0 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:51:58 +0200
+Subject: [PATCH 04/14] imsm: Execute size change for external metatdata
+
+For external metatdata ioctl doesn't set new size. Set new size using sysfs.
+Put code for size change in to function to re-use the same code as during
+On-line Capacity Expansion
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ Grow.c |   78 ++++++++++++++++++++++++++++++++++++++-------------------------
+ 1 files changed, 47 insertions(+), 31 deletions(-)
+
+diff --git a/Grow.c b/Grow.c
+index e3ef8d4..5fd44aa 100644
+--- a/Grow.c
++++ b/Grow.c
+@@ -1386,6 +1386,44 @@ char *analyse_change(struct mdinfo *info, struct reshape *re)
+ 	return NULL;
+ }
+ 
++static int set_array_size(struct supertype *st, struct mdinfo *sra,
++			  char *text_version)
++{
++	struct mdinfo *info;
++	char *subarray;
++	int ret_val = -1;
++
++	if ((st == NULL) || (sra == NULL))
++		return ret_val;
++
++	if (text_version == NULL)
++		text_version = sra->text_version;
++	subarray = strchr(text_version+1, '/')+1;
++	info = st->ss->container_content(st, subarray);
++	if (info) {
++		unsigned long long current_size = 0;
++		unsigned long long new_size =
++			info->custom_array_size/2;
++
++		if (sysfs_get_ll(sra, NULL, "array_size", &current_size) == 0 &&
++		    new_size > current_size) {
++			if (sysfs_set_num(sra, NULL, "array_size", new_size)
++					< 0)
++				dprintf("Error: Cannot set array size");
++			else {
++				ret_val = 0;
++				dprintf("Array size changed");
++			}
++			dprintf(" from %llu to %llu.\n",
++				current_size, new_size);
++		}
++		sysfs_free(info);
++	} else
++		dprintf("Error: set_array_size(): info pointer in NULL\n");
++
++	return ret_val;
++}
++
+ static int reshape_array(char *container, int fd, char *devname,
+ 			 struct supertype *st, struct mdinfo *info,
+ 			 int force, struct mddev_dev *devlist,
+@@ -1636,7 +1674,6 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 				"2TB per device\n");
+ 			size = min_csize;
+ 		}
+-
+ 		array.size = size;
+ 		if (array.size != size) {
+ 			/* got truncated to 32bit, write to
+@@ -1647,8 +1684,14 @@ int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
+ 						   "component_size", size);
+ 			else
+ 				rv = -1;
+-		} else
++		} else {
+ 			rv = ioctl(fd, SET_ARRAY_INFO, &array);
++			/* manage array size when it is managed externally
++			 */
++			if ((rv == 0) && st->ss->external)
++				rv = set_array_size(st, sra, sra->text_version);
++		}
++
+ 		if (rv != 0) {
+ 			int err = errno;
+ 
+@@ -2507,35 +2550,8 @@ started:
+ 	 */
+ 	if (reshape.before.data_disks !=
+ 	    reshape.after.data_disks &&
+-	    info->custom_array_size) {
+-		struct mdinfo *info2;
+-		char *subarray = strchr(info->text_version+1, '/')+1;
+-
+-		info2 = st->ss->container_content(st, subarray);
+-		if (info2) {
+-			unsigned long long current_size = 0;
+-			unsigned long long new_size =
+-				info2->custom_array_size/2;
+-
+-			if (sysfs_get_ll(sra,
+-					 NULL,
+-					 "array_size",
+-					 &current_size) == 0 &&
+-			    new_size > current_size) {
+-				if (sysfs_set_num(sra, NULL,
+-						  "array_size", new_size)
+-				    < 0)
+-					dprintf("Error: Cannot"
+-						" set array size");
+-				else
+-					dprintf("Array size "
+-						"changed");
+-				dprintf(" from %llu to %llu.\n",
+-					current_size, new_size);
+-			}
+-			sysfs_free(info2);
+-		}
+-	}
++	    info->custom_array_size)
++		set_array_size(st, info, info->text_version);
+ 
+ 	if (info->new_level != reshape.level) {
+ 
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-FIX-Add-volume-size-expand-support-to-imsm_anal.patch b/mdadm-3.2.3-imsm-FIX-Add-volume-size-expand-support-to-imsm_anal.patch
new file mode 100644
index 0000000..df20e39
--- /dev/null
+++ b/mdadm-3.2.3-imsm-FIX-Add-volume-size-expand-support-to-imsm_anal.patch
@@ -0,0 +1,103 @@
+From 7abc98717c32d08a2aab366e79c12a91573fb538 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:51:56 +0200
+Subject: [PATCH 02/14] imsm: FIX: Add volume size expand support to
+ imsm_analyze_change()
+
+Patch adds ability to function imsm_analyze_change() for:
+1. Detect size change request for volume operation.
+2. Check and correct size for change.
+3. Set new change kind to CH_ARRAY_SIZE
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 51 insertions(+), 0 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 5f86539..2e6a899 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -405,6 +405,7 @@ struct extent {
+ enum imsm_reshape_type {
+ 	CH_TAKEOVER,
+ 	CH_MIGRATION,
++	CH_ARRAY_SIZE,
+ };
+ 
+ /* definition of messages passed to imsm_process_update */
+@@ -9726,6 +9727,10 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 	int devNumChange = 0;
+ 	/* imsm compatible layout value for array geometry verification */
+ 	int imsm_layout = -1;
++	int data_disks;
++	struct imsm_dev *dev;
++	struct intel_super *super;
++	long long current_size;
+ 
+ 	getinfo_super_imsm_volume(st, &info, NULL);
+ 	if ((geo->level != info.array.level) &&
+@@ -9807,6 +9812,47 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 		geo->chunksize = info.array.chunk_size;
+ 
+ 	chunk = geo->chunksize / 1024;
++
++	super = st->sb;
++	dev = get_imsm_dev(super, super->current_vol);
++	data_disks = imsm_num_data_members(dev , MAP_0);
++	/* compute current size in K per disk member
++	 */
++	current_size = info.custom_array_size / 2 / data_disks;
++
++	if ((current_size != geo->size) && (geo->size > 0)) {
++		if (change != -1) {
++			fprintf(stderr,
++				Name " Error. Size change should be the only "
++				"one at a time.\n");
++			change = -1;
++			goto analyse_change_exit;
++		}
++		if ((super->current_vol + 1) != super->anchor->num_raid_devs) {
++			fprintf(stderr,
++				Name " Error. The last volume in container "
++				"can be expanded only (%i/%i).\n",
++				super->current_vol, st->devnum);
++			goto analyse_change_exit;
++		}
++		geo->size *= 2;
++		/* round size due to metadata compatibility
++		 */
++		geo->size = (geo->size >> SECT_PER_MB_SHIFT)
++			    << SECT_PER_MB_SHIFT;
++		dprintf("Prepare update for size change to %llu\n", geo->size );
++		if (current_size >= geo->size) {
++			fprintf(stderr,
++				Name " Error. Size expanssion is supported only"
++				" (current size is %llu, requested size "
++				"/rounded/ is %llu).\n",
++				current_size, geo->size);
++			goto analyse_change_exit;
++		}
++		geo->size *= data_disks;
++		geo->raid_disks = dev->vol.map->num_members;
++		change = CH_ARRAY_SIZE;
++	}
+ 	if (!validate_geometry_imsm(st,
+ 				    geo->level,
+ 				    imsm_layout,
+@@ -9976,6 +10022,11 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
+ 				free(u);
+ 		}
+ 		break;
++		case CH_ARRAY_SIZE: {
++			/* ToDo: Prepare metadata update here
++			 */
++		}
++		break;
+ 		default:
+ 			ret_val = 1;
+ 		}
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-FIX-Component-size-alignment-check.patch b/mdadm-3.2.3-imsm-FIX-Component-size-alignment-check.patch
new file mode 100644
index 0000000..b6ed8ce
--- /dev/null
+++ b/mdadm-3.2.3-imsm-FIX-Component-size-alignment-check.patch
@@ -0,0 +1,126 @@
+From c41e00b2e68aed0ab9d41f70a3e119d86a92cf29 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:52:06 +0200
+Subject: [PATCH 12/14] imsm: FIX: Component size alignment check
+
+Put currently existing code for alignment correction in to function
+imsm_component_size_aligment_check() and use it for align component size
+to chunk size during volume size expansion operation.
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |   68 ++++++++++++++++++++++++++++++++++++++++----------------
+ 1 files changed, 48 insertions(+), 20 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 1f47234..9685726 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -2454,6 +2454,32 @@ int imsm_reshape_blocks_arrays_changes(struct intel_super *super)
+ 	}
+ 	return rv;
+ }
++static unsigned long long imsm_component_size_aligment_check(int level,
++					      int chunk_size,
++					      unsigned long long component_size)
++{
++	unsigned int component_size_alligment;
++
++	/* check component size aligment
++	*/
++	component_size_alligment = component_size % (chunk_size/512);
++
++	dprintf("imsm_component_size_aligment_check(Level: %i, "
++		"chunk_size = %i, component_size = %llu), "
++		"component_size_alligment = %u\n",
++		level, chunk_size, component_size,
++		component_size_alligment);
++
++	if (component_size_alligment && (level != 1) && (level != UnSet)) {
++		dprintf("imsm: reported component size alligned from %llu ",
++			component_size);
++		component_size -= component_size_alligment;
++		dprintf("to %llu (%i).\n",
++			component_size, component_size_alligment);
++	}
++
++	return component_size;
++}
+ 
+ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info, char *dmap)
+ {
+@@ -2465,7 +2491,6 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
+ 	struct imsm_map *map_to_analyse = map;
+ 	struct dl *dl;
+ 	char *devname;
+-	unsigned int component_size_alligment;
+ 	int map_disks = info->array.raid_disks;
+ 
+ 	memset(info, 0, sizeof(*info));
+@@ -2548,19 +2573,10 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
+ 	info->data_offset	  = pba_of_lba0(map_to_analyse);
+ 	info->component_size	  = blocks_per_member(map_to_analyse);
+ 
+-	/* check component size aligment
+-	 */
+-	component_size_alligment =
+-		info->component_size % (info->array.chunk_size/512);
+-
+-	if (component_size_alligment &&
+-	    (info->array.level != 1) && (info->array.level != UnSet)) {
+-		dprintf("imsm: reported component size alligned from %llu ",
+-			info->component_size);
+-		info->component_size -= component_size_alligment;
+-		dprintf("to %llu (%i).\n",
+-			info->component_size, component_size_alligment);
+-	}
++	info->component_size = imsm_component_size_aligment_check(
++							info->array.level,
++							info->array.chunk_size,
++							info->component_size);
+ 
+ 	memset(info->uuid, 0, sizeof(info->uuid));
+ 	info->recovery_start = MaxSector;
+@@ -9949,9 +9965,18 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 	super = st->sb;
+ 	dev = get_imsm_dev(super, super->current_vol);
+ 	data_disks = imsm_num_data_members(dev , MAP_0);
+-	/* compute current size in K per disk member
++	/* compute current size per disk member
+ 	 */
+-	current_size = info.custom_array_size / 2 / data_disks;
++	current_size = info.custom_array_size / data_disks;
++
++	if (geo->size > 0) {
++		/* align component size
++		 */
++		geo->size = imsm_component_size_aligment_check(
++				    get_imsm_raid_level(dev->vol.map),
++				    chunk * 1024,
++				    geo->size * 2);
++	}
+ 
+ 	if ((current_size != geo->size) && (geo->size >= 0)) {
+ 		if (change != -1) {
+@@ -9984,10 +10009,13 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 			}
+ 			geo->size = freesize + current_size;
+ 
+-			/* round to chunk size */
+-			geo->size &= ~(chunk-1);
+-		} else
+-			geo->size *= 2;
++			/* align component size
++			 */
++			geo->size = imsm_component_size_aligment_check(
++					      get_imsm_raid_level(dev->vol.map),
++					      chunk * 1024,
++					      geo->size);
++		}
+ 
+ 		if ((direction == ROLLBACK_METADATA_CHANGES)) {
+ 			/* accept size for rollback only
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-FIX-Support-metadata-changes-rollback.patch b/mdadm-3.2.3-imsm-FIX-Support-metadata-changes-rollback.patch
new file mode 100644
index 0000000..412105d
--- /dev/null
+++ b/mdadm-3.2.3-imsm-FIX-Support-metadata-changes-rollback.patch
@@ -0,0 +1,130 @@
+From fbf3d20214537e5e4bf6fb04f191418a58e88463 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:52:00 +0200
+Subject: [PATCH 06/14] imsm: FIX: Support metadata changes rollback
+
+Add metadata rollback specific code for imsm.
+Let reshape_super() ability to differentiate metadata apply and rollback
+actions.
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |   56 ++++++++++++++++++++++++++++++++++++++------------------
+ 1 files changed, 38 insertions(+), 18 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 32a53d1..49e383f 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -9470,7 +9470,8 @@ static int imsm_find_array_minor_by_subdev(int subdev, int container, int *minor
+ 
+ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
+ 						struct geo_params *geo,
+-						int *old_raid_disks)
++						int *old_raid_disks,
++						int direction)
+ {
+ 	/* currently we only support increasing the number of devices
+ 	 * for a container.  This increases the number of device for each
+@@ -9494,6 +9495,12 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
+ 		return ret_val;
+ 	}
+ 
++	if (direction == ROLLBACK_METADATA_CHANGES) {
++		dprintf("imsm: Metadata changes rollback is not supported for "
++			"container operation.\n");
++		return ret_val;
++	}
++
+ 	info = container_content_imsm(st, NULL);
+ 	for (member = info; member; member = member->next) {
+ 		int result;
+@@ -9814,11 +9821,13 @@ static void imsm_update_metadata_locally(struct supertype *st,
+ * Function:	imsm_analyze_change
+ * Description:	Function analyze change for single volume
+ * 		and validate if transition is supported
+-* Parameters:	Geometry parameters, supertype structure
++* Parameters:	Geometry parameters, supertype structure,
++*		metadata change direction (apply/rollback)
+ * Returns:	Operation type code on success, -1 if fail
+ ****************************************************************************/
+ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+-					   struct geo_params *geo)
++					   struct geo_params *geo,
++					   int direction)
+ {
+ 	struct mdinfo info;
+ 	int change = -1;
+@@ -9937,18 +9946,24 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 			goto analyse_change_exit;
+ 		}
+ 		geo->size *= 2;
+-		/* round size due to metadata compatibility
+-		 */
+-		geo->size = (geo->size >> SECT_PER_MB_SHIFT)
+-			    << SECT_PER_MB_SHIFT;
+-		dprintf("Prepare update for size change to %llu\n", geo->size );
+-		if (current_size >= geo->size) {
+-			fprintf(stderr,
+-				Name " Error. Size expanssion is supported only"
+-				" (current size is %llu, requested size "
+-				"/rounded/ is %llu).\n",
+-				current_size, geo->size);
+-			goto analyse_change_exit;
++		if ((direction == ROLLBACK_METADATA_CHANGES)) {
++			/* accept size for rollback only
++			*/
++		} else {
++			/* round size due to metadata compatibility
++			*/
++			geo->size = (geo->size >> SECT_PER_MB_SHIFT)
++				    << SECT_PER_MB_SHIFT;
++			dprintf("Prepare update for size change to %llu\n",
++				geo->size );
++			if (current_size >= geo->size) {
++				fprintf(stderr,
++					Name " Error. Size expanssion is "
++					"supported only (current size is %llu, "
++					"requested size /rounded/ is %llu).\n",
++					current_size, geo->size);
++				goto analyse_change_exit;
++			}
+ 		}
+ 		geo->size *= data_disks;
+ 		geo->raid_disks = dev->vol.map->num_members;
+@@ -9978,7 +9993,12 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 	}
+ 
+ analyse_change_exit:
+-
++	if ((direction == ROLLBACK_METADATA_CHANGES) &&
++	     ((change == CH_MIGRATION) || (change == CH_TAKEOVER))) {
++		dprintf("imsm: Metadata changes rollback is not supported for "
++			"migration and takeover operations.\n");
++		change = -1;
++	}
+ 	return change;
+ }
+ 
+@@ -10049,7 +10069,7 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
+ 		int old_raid_disks = 0;
+ 
+ 		if (imsm_reshape_is_allowed_on_container(
+-			    st, &geo, &old_raid_disks)) {
++			    st, &geo, &old_raid_disks, direction)) {
+ 			struct imsm_update_reshape *u = NULL;
+ 			int len;
+ 
+@@ -10098,7 +10118,7 @@ static int imsm_reshape_super(struct supertype *st, long long size, int level,
+ 			goto exit_imsm_reshape_super;
+ 		}
+ 		super->current_vol = dev->index;
+-		change = imsm_analyze_change(st, &geo);
++		change = imsm_analyze_change(st, &geo, direction);
+ 		switch (change) {
+ 		case CH_TAKEOVER:
+ 			ret_val = imsm_takeover(st, &geo);
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-FIX-Update-function-imsm_num_data_members-for-R.patch b/mdadm-3.2.3-imsm-FIX-Update-function-imsm_num_data_members-for-R.patch
new file mode 100644
index 0000000..9269851
--- /dev/null
+++ b/mdadm-3.2.3-imsm-FIX-Update-function-imsm_num_data_members-for-R.patch
@@ -0,0 +1,36 @@
+From 36fd8ccc0e755042e3983a2bd02523461b5f8307 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:51:55 +0200
+Subject: [PATCH 01/14] imsm: FIX: Update function imsm_num_data_members() for
+ Raid1/10
+
+Function imsm_num_data_members() returns wrong value for raid 1 and 10.
+It returns all data member but it should return number of unique data
+members (excluding mirror devices)
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |    4 +++-
+ 1 files changed, 3 insertions(+), 1 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 088e6bc..5f86539 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -2032,9 +2032,11 @@ static __u8 imsm_num_data_members(struct imsm_dev *dev, int second_map)
+ 
+ 	switch (get_imsm_raid_level(map)) {
+ 	case 0:
++		return map->num_members;
++		break;
+ 	case 1:
+ 	case 10:
+-		return map->num_members;
++		return map->num_members/2;
+ 	case 5:
+ 		return map->num_members - 1;
+ 	default:
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-Support-setting-max-size-for-size-change-operat.patch b/mdadm-3.2.3-imsm-Support-setting-max-size-for-size-change-operat.patch
new file mode 100644
index 0000000..53f8cc9
--- /dev/null
+++ b/mdadm-3.2.3-imsm-Support-setting-max-size-for-size-change-operat.patch
@@ -0,0 +1,60 @@
+From b130333f39734eed08d38d6c36025fa4d618bc52 Mon Sep 17 00:00:00 2001
+From: Adam Kwolek <adam.kwolek at intel.com>
+Date: Fri, 13 Apr 2012 16:52:05 +0200
+Subject: [PATCH 11/14] imsm: Support setting max size for size change
+ operation
+
+Add support for setting max size for size change operation using
+imsm_get_free_size() function for computing maximum available space.
+
+Signed-off-by: Adam Kwolek <adam.kwolek at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |   24 ++++++++++++++++++++++--
+ 1 files changed, 22 insertions(+), 2 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 7cc0ed5..1f47234 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -9953,7 +9953,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 	 */
+ 	current_size = info.custom_array_size / 2 / data_disks;
+ 
+-	if ((current_size != geo->size) && (geo->size > 0)) {
++	if ((current_size != geo->size) && (geo->size >= 0)) {
+ 		if (change != -1) {
+ 			fprintf(stderr,
+ 				Name " Error. Size change should be the only "
+@@ -9968,7 +9968,27 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
+ 				super->current_vol, st->devnum);
+ 			goto analyse_change_exit;
+ 		}
+-		geo->size *= 2;
++		if (geo->size == 0) {
++			/* requested size change to the maximum available size
++			 */
++			unsigned long long freesize;
++			int rv;
++
++			rv =  imsm_get_free_size(st, dev->vol.map->num_members,
++						 0, chunk, &freesize);
++			if (rv == 0) {
++				fprintf(stderr, Name " Error. Cannot find "
++					"maximum available space.\n");
++				change = -1;
++				goto analyse_change_exit;
++			}
++			geo->size = freesize + current_size;
++
++			/* round to chunk size */
++			geo->size &= ~(chunk-1);
++		} else
++			geo->size *= 2;
++
+ 		if ((direction == ROLLBACK_METADATA_CHANGES)) {
+ 			/* accept size for rollback only
+ 			*/
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-avoid-overflows-for-disks-over-1TB.patch b/mdadm-3.2.3-imsm-avoid-overflows-for-disks-over-1TB.patch
new file mode 100644
index 0000000..7908028
--- /dev/null
+++ b/mdadm-3.2.3-imsm-avoid-overflows-for-disks-over-1TB.patch
@@ -0,0 +1,484 @@
+From 5551b113dc18a6275fb04c7e7e3b76c656926e0a Mon Sep 17 00:00:00 2001
+From: "Czarnowska, Anna" <anna.czarnowska at intel.com>
+Date: Mon, 2 Apr 2012 10:15:03 +1000
+Subject: [PATCH 1/7] imsm: avoid overflows for disks over 1TB
+
+Calculating array_blocks using info->size causes error on activation of
+volume using disks over 1 TB. unsigned long long size parameter
+is used instead.
+
+total_blocks, pba_of_lba0, blocks_per_member and num_data_stripes overflow
+when using disks over 2TB.
+
+Part of fillers in metadata is used to contain hi bits of the numbers
+that are likely to go over 32 bit limit.
+Functions are added to get and set such fields as the hi bits are not
+adjacent with low bits in the structures.
+
+Acked-by: Dan Williams <dan.j.williams at intel.com>
+Signed-off-by: Anna Czarnowska <anna.czarnowska at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |  198 +++++++++++++++++++++++++++++++++++++-------------------
+ 1 files changed, 131 insertions(+), 67 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index a351b60..c65d39b 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -95,15 +95,16 @@
+ #define IMSM_MAX_DEVICES 255
+ struct imsm_disk {
+ 	__u8 serial[MAX_RAID_SERIAL_LEN];/* 0xD8 - 0xE7 ascii serial number */
+-	__u32 total_blocks;		 /* 0xE8 - 0xEB total blocks */
++	__u32 total_blocks_lo;		 /* 0xE8 - 0xEB total blocks lo */
+ 	__u32 scsi_id;			 /* 0xEC - 0xEF scsi ID */
+ #define SPARE_DISK      __cpu_to_le32(0x01)  /* Spare */
+ #define CONFIGURED_DISK __cpu_to_le32(0x02)  /* Member of some RaidDev */
+ #define FAILED_DISK     __cpu_to_le32(0x04)  /* Permanent failure */
+ 	__u32 status;			 /* 0xF0 - 0xF3 */
+ 	__u32 owner_cfg_num; /* which config 0,1,2... owns this disk */ 
+-#define	IMSM_DISK_FILLERS	4
+-	__u32 filler[IMSM_DISK_FILLERS]; /* 0xF4 - 0x107 MPB_DISK_FILLERS for future expansion */
++	__u32 total_blocks_hi;		 /* 0xF4 - 0xF5 total blocks hi */
++#define	IMSM_DISK_FILLERS	3
++	__u32 filler[IMSM_DISK_FILLERS]; /* 0xF5 - 0x107 MPB_DISK_FILLERS for future expansion */
+ };
+ 
+ /* map selector for map managment
+@@ -114,9 +115,9 @@ struct imsm_disk {
+ 
+ /* RAID map configuration infos. */
+ struct imsm_map {
+-	__u32 pba_of_lba0;	/* start address of partition */
+-	__u32 blocks_per_member;/* blocks per member */
+-	__u32 num_data_stripes;	/* number of data stripes */
++	__u32 pba_of_lba0_lo;	/* start address of partition */
++	__u32 blocks_per_member_lo;/* blocks per member */
++	__u32 num_data_stripes_lo;	/* number of data stripes */
+ 	__u16 blocks_per_strip;
+ 	__u8  map_state;	/* Normal, Uninitialized, Degraded, Failed */
+ #define IMSM_T_STATE_NORMAL 0
+@@ -131,7 +132,10 @@ struct imsm_map {
+ 	__u8  num_domains;	/* number of parity domains */
+ 	__u8  failed_disk_num;  /* valid only when state is degraded */
+ 	__u8  ddf;
+-	__u32 filler[7];	/* expansion area */
++	__u32 pba_of_lba0_hi;
++	__u32 blocks_per_member_hi;
++	__u32 num_data_stripes_hi;
++	__u32 filler[4];	/* expansion area */
+ #define IMSM_ORD_REBUILD (1 << 24)
+ 	__u32 disk_ord_tbl[1];	/* disk_ord_tbl[num_members],
+ 				 * top byte contains some flags
+@@ -361,7 +365,7 @@ struct intel_super {
+ 	size_t next_len;
+ 	int updates_pending; /* count of pending updates for mdmon */
+ 	int current_vol; /* index of raid device undergoing creation */
+-	__u32 create_offset; /* common start for 'current_vol' */
++	unsigned long long create_offset; /* common start for 'current_vol' */
+ 	__u32 random; /* random data for seeding new family numbers */
+ 	struct intel_dev *devlist;
+ 	struct dl {
+@@ -870,6 +874,69 @@ static int count_memberships(struct dl *dl, struct intel_super *super)
+ 
+ static __u32 imsm_min_reserved_sectors(struct intel_super *super);
+ 
++static int split_ull(unsigned long long n, __u32 *lo, __u32 *hi)
++{
++	if (lo == 0 || hi == 0)
++		return 1;
++	*lo = __le32_to_cpu((unsigned)n);
++	*hi = __le32_to_cpu((unsigned)(n >> 32));
++	return 0;
++}
++
++static unsigned long long join_u32(__u32 lo, __u32 hi)
++{
++	return (unsigned long long)__le32_to_cpu(lo) |
++	       (((unsigned long long)__le32_to_cpu(hi)) << 32);
++}
++
++static unsigned long long total_blocks(struct imsm_disk *disk)
++{
++	if (disk == NULL)
++		return 0;
++	return join_u32(disk->total_blocks_lo, disk->total_blocks_hi);
++}
++
++static unsigned long long pba_of_lba0(struct imsm_map *map)
++{
++	if (map == NULL)
++		return 0;
++	return join_u32(map->pba_of_lba0_lo, map->pba_of_lba0_hi);
++}
++
++static unsigned long long blocks_per_member(struct imsm_map *map)
++{
++	if (map == NULL)
++		return 0;
++	return join_u32(map->blocks_per_member_lo, map->blocks_per_member_hi);
++}
++
++static unsigned long long num_data_stripes(struct imsm_map *map)
++{
++	if (map == NULL)
++		return 0;
++	return join_u32(map->num_data_stripes_lo, map->num_data_stripes_hi);
++}
++
++static void set_total_blocks(struct imsm_disk *disk, unsigned long long n)
++{
++	split_ull(n, &disk->total_blocks_lo, &disk->total_blocks_hi);
++}
++
++static void set_pba_of_lba0(struct imsm_map *map, unsigned long long n)
++{
++	split_ull(n, &map->pba_of_lba0_lo, &map->pba_of_lba0_hi);
++}
++
++static void set_blocks_per_member(struct imsm_map *map, unsigned long long n)
++{
++	split_ull(n, &map->blocks_per_member_lo, &map->blocks_per_member_hi);
++}
++
++static void set_num_data_stripes(struct imsm_map *map, unsigned long long n)
++{
++	split_ull(n, &map->num_data_stripes_lo, &map->num_data_stripes_hi);
++}
++
+ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
+ {
+ 	/* find a list of used extents on the given physical device */
+@@ -897,8 +964,8 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
+ 		struct imsm_map *map = get_imsm_map(dev, MAP_0);
+ 
+ 		if (get_imsm_disk_slot(map, dl->index) >= 0) {
+-			e->start = __le32_to_cpu(map->pba_of_lba0);
+-			e->size = __le32_to_cpu(map->blocks_per_member);
++			e->start = pba_of_lba0(map);
++			e->size = blocks_per_member(map);
+ 			e++;
+ 		}
+ 	}
+@@ -911,10 +978,9 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
+ 	 */
+ 	if (memberships) {
+ 		struct extent *last = &rv[memberships - 1];
+-		__u32 remainder;
++		unsigned long long remainder;
+ 
+-		remainder = __le32_to_cpu(dl->disk.total_blocks) - 
+-			    (last->start + last->size);
++		remainder = total_blocks(&dl->disk) - (last->start + last->size);
+ 		/* round down to 1k block to satisfy precision of the kernel
+ 		 * 'size' interface
+ 		 */
+@@ -925,7 +991,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl)
+ 		if (reservation > remainder)
+ 			reservation = remainder;
+ 	}
+-	e->start = __le32_to_cpu(dl->disk.total_blocks) - reservation;
++	e->start = total_blocks(&dl->disk) - reservation;
+ 	e->size = 0;
+ 	return rv;
+ }
+@@ -954,7 +1020,7 @@ static __u32 imsm_reserved_sectors(struct intel_super *super, struct dl *dl)
+ 	for (i = 0; e[i].size; i++)
+ 		continue;
+ 
+-	rv = __le32_to_cpu(dl->disk.total_blocks) - e[i].start;
++	rv = total_blocks(&dl->disk) - e[i].start;
+ 
+ 	free(e);
+ 
+@@ -984,7 +1050,8 @@ static __u32 imsm_min_reserved_sectors(struct intel_super *super)
+ {
+ 	struct extent *e;
+ 	int i;
+-	__u32 min_active, remainder;
++	unsigned long long min_active;
++	__u32 remainder;
+ 	__u32 rv = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
+ 	struct dl *dl, *dl_min = NULL;
+ 
+@@ -995,9 +1062,10 @@ static __u32 imsm_min_reserved_sectors(struct intel_super *super)
+ 	for (dl = super->disks; dl; dl = dl->next) {
+ 		if (dl->index < 0)
+ 			continue;
+-		if (dl->disk.total_blocks < min_active || min_active == 0) {
++		unsigned long long blocks = total_blocks(&dl->disk);
++		if (blocks < min_active || min_active == 0) {
+ 			dl_min = dl;
+-			min_active = dl->disk.total_blocks;
++			min_active = blocks;
+ 		}
+ 	}
+ 	if (!dl_min)
+@@ -1115,13 +1183,13 @@ static void print_imsm_dev(struct intel_super *super,
+ 	sz += __le32_to_cpu(dev->size_low);
+ 	printf("     Array Size : %llu%s\n", (unsigned long long)sz,
+ 	       human_size(sz * 512));
+-	sz = __le32_to_cpu(map->blocks_per_member);
++	sz = blocks_per_member(map);
+ 	printf("   Per Dev Size : %llu%s\n", (unsigned long long)sz,
+ 	       human_size(sz * 512));
+-	printf("  Sector Offset : %u\n",
+-		__le32_to_cpu(map->pba_of_lba0));
+-	printf("    Num Stripes : %u\n",
+-		__le32_to_cpu(map->num_data_stripes));
++	printf("  Sector Offset : %llu\n",
++		pba_of_lba0(map));
++	printf("    Num Stripes : %llu\n",
++		num_data_stripes(map));
+ 	printf("     Chunk Size : %u KiB",
+ 		__le16_to_cpu(map->blocks_per_strip) / 2);
+ 	if (map2)
+@@ -1182,7 +1250,7 @@ static void print_imsm_disk(struct imsm_disk *disk, int index, __u32 reserved)
+ 					    is_configured(disk) ? " active" : "",
+ 					    is_failed(disk) ? " failed" : "");
+ 	printf("             Id : %08x\n", __le32_to_cpu(disk->scsi_id));
+-	sz = __le32_to_cpu(disk->total_blocks) - reserved;
++	sz = total_blocks(disk) - reserved;
+ 	printf("    Usable Size : %llu%s\n", (unsigned long long)sz,
+ 	       human_size(sz * 512));
+ }
+@@ -2462,9 +2530,8 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
+ 							  dl->index);
+ 	}
+ 
+-	info->data_offset	  = __le32_to_cpu(map_to_analyse->pba_of_lba0);
+-	info->component_size	  =
+-		__le32_to_cpu(map_to_analyse->blocks_per_member);
++	info->data_offset	  = pba_of_lba0(map_to_analyse);
++	info->component_size	  = blocks_per_member(map_to_analyse);
+ 
+ 	/* check component size aligment
+ 	 */
+@@ -2525,7 +2592,7 @@ static void getinfo_super_imsm_volume(struct supertype *st, struct mdinfo *info,
+ 
+ 			used_disks = imsm_num_data_members(dev, MAP_1);
+ 			if (used_disks > 0) {
+-				array_blocks = map->blocks_per_member *
++				array_blocks = blocks_per_member(map) *
+ 					used_disks;
+ 				/* round array size down to closest MB
+ 				 */
+@@ -2709,7 +2776,7 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
+ 		__u32 reserved = imsm_reserved_sectors(super, super->disks);
+ 
+ 		disk = &super->disks->disk;
+-		info->data_offset = __le32_to_cpu(disk->total_blocks) - reserved;
++		info->data_offset = total_blocks(&super->disks->disk) - reserved;
+ 		info->component_size = reserved;
+ 		info->disk.state  = is_configured(disk) ? (1 << MD_DISK_ACTIVE) : 0;
+ 		/* we don't change info->disk.raid_disk here because
+@@ -3377,7 +3444,7 @@ int check_mpb_migr_compatibility(struct intel_super *super)
+ 			/* This device is migrating */
+ 			map0 = get_imsm_map(dev_iter, MAP_0);
+ 			map1 = get_imsm_map(dev_iter, MAP_1);
+-			if (map0->pba_of_lba0 != map1->pba_of_lba0)
++			if (pba_of_lba0(map0) != pba_of_lba0(map1))
+ 				/* migration optimization area was used */
+ 				return -1;
+ 			if (migr_rec->ascending_migr == 0
+@@ -3626,7 +3693,7 @@ static struct intel_super *alloc_super(void)
+ 	if (super) {
+ 		memset(super, 0, sizeof(*super));
+ 		super->current_vol = -1;
+-		super->create_offset = ~((__u32 ) 0);
++		super->create_offset = ~((unsigned long long) 0);
+ 	}
+ 	return super;
+ }
+@@ -4346,22 +4413,13 @@ static __u16 info_to_blocks_per_strip(mdu_array_info_t *info)
+ 	return info->chunk_size >> 9;
+ }
+ 
+-static __u32 info_to_num_data_stripes(mdu_array_info_t *info, int num_domains)
+-{
+-	__u32 num_stripes;
+-
+-	num_stripes = (info->size * 2) / info_to_blocks_per_strip(info);
+-	num_stripes /= num_domains;
+-
+-	return num_stripes;
+-}
+-
+-static __u32 info_to_blocks_per_member(mdu_array_info_t *info)
++static unsigned long long info_to_blocks_per_member(mdu_array_info_t *info,
++						    unsigned long long size)
+ {
+ 	if (info->level == 1)
+-		return info->size * 2;
++		return size * 2;
+ 	else
+-		return (info->size * 2) & ~(info_to_blocks_per_strip(info) - 1);
++		return (size * 2) & ~(info_to_blocks_per_strip(info) - 1);
+ }
+ 
+ static void imsm_update_version_info(struct intel_super *super)
+@@ -4452,7 +4510,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
+ 	int i;
+ 	unsigned long long array_blocks;
+ 	size_t size_old, size_new;
+-	__u32 num_data_stripes;
++	unsigned long long num_data_stripes;
+ 
+ 	if (super->orom && mpb->num_raid_devs >= super->orom->vpa) {
+ 		fprintf(stderr, Name": This imsm-container already has the "
+@@ -4540,11 +4598,11 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
+ 
+ 	strncpy((char *) dev->volume, name, MAX_RAID_SERIAL_LEN);
+ 	if (info->level == 1)
+-		array_blocks = info_to_blocks_per_member(info);
++		array_blocks = info_to_blocks_per_member(info, size);
+ 	else
+ 		array_blocks = calc_array_size(info->level, info->raid_disks,
+ 					       info->layout, info->chunk_size,
+-					       info->size*2);
++					       size * 2);
+ 	/* round array size down to closest MB */
+ 	array_blocks = (array_blocks >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT;
+ 
+@@ -4557,8 +4615,8 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
+ 	vol->dirty = !info->state;
+ 	vol->curr_migr_unit = 0;
+ 	map = get_imsm_map(dev, MAP_0);
+-	map->pba_of_lba0 = __cpu_to_le32(super->create_offset);
+-	map->blocks_per_member = __cpu_to_le32(info_to_blocks_per_member(info));
++	set_pba_of_lba0(map, super->create_offset);
++	set_blocks_per_member(map, info_to_blocks_per_member(info, size));
+ 	map->blocks_per_strip = __cpu_to_le16(info_to_blocks_per_strip(info));
+ 	map->failed_disk_num = ~0;
+ 	if (info->level > 0)
+@@ -4585,8 +4643,10 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
+ 	else
+ 		map->num_domains = 1;
+ 
+-	num_data_stripes = info_to_num_data_stripes(info, map->num_domains);
+-	map->num_data_stripes = __cpu_to_le32(num_data_stripes);
++	/* info->size is only int so use the 'size' parameter instead */
++	num_data_stripes = (size * 2) / info_to_blocks_per_strip(info);
++	num_data_stripes /= map->num_domains;
++	set_num_data_stripes(map, num_data_stripes);
+ 
+ 	map->num_members = info->raid_disks;
+ 	for (i = 0; i < map->num_members; i++) {
+@@ -4729,8 +4789,8 @@ static int add_to_super_imsm_volume(struct supertype *st, mdu_disk_info_t *dk,
+ 	 */
+ 	if (super->current_vol == 0) {
+ 		for (df = super->missing; df; df = df->next) {
+-			if (dl->disk.total_blocks > df->disk.total_blocks)
+-				df->disk.total_blocks = dl->disk.total_blocks;
++			if (total_blocks(&dl->disk) > total_blocks(&df->disk))
++				set_total_blocks(&df->disk, total_blocks(&dl->disk));
+ 			_disk = __get_imsm_disk(mpb, df->index);
+ 			*_disk = df->disk;
+ 		}
+@@ -4869,7 +4929,11 @@ static int add_to_super_imsm(struct supertype *st, mdu_disk_info_t *dk,
+ 	get_dev_size(fd, NULL, &size);
+ 	size /= 512;
+ 	serialcpy(dd->disk.serial, dd->serial);
+-	dd->disk.total_blocks = __cpu_to_le32(size);
++	set_total_blocks(&dd->disk, size);
++	if (__le32_to_cpu(dd->disk.total_blocks_hi) > 0) {
++		struct imsm_super *mpb = super->anchor;
++		mpb->attributes |= MPB_ATTRIB_2TB_DISK;
++	}
+ 	mark_spare(dd);
+ 	if (sysfs_disk_to_scsi_id(fd, &id) == 0)
+ 		dd->disk.scsi_id = __cpu_to_le32(id);
+@@ -5356,7 +5420,7 @@ static unsigned long long merge_extents(struct intel_super *super, int sum_exten
+ 	if (maxsize < reserve)
+ 		return 0;
+ 
+-	super->create_offset = ~((__u32) 0);
++	super->create_offset = ~((unsigned long long) 0);
+ 	if (start + reserve > super->create_offset)
+ 		return 0; /* start overflows create_offset */
+ 	super->create_offset = start + reserve;
+@@ -6597,8 +6661,8 @@ static struct mdinfo *container_content_imsm(struct supertype *st, char *subarra
+ 				this->array.working_disks++;
+ 
+ 			info_d->events = __le32_to_cpu(mpb->generation_num);
+-			info_d->data_offset = __le32_to_cpu(map->pba_of_lba0);
+-			info_d->component_size = __le32_to_cpu(map->blocks_per_member);
++			info_d->data_offset = pba_of_lba0(map);
++			info_d->component_size = blocks_per_member(map);
+ 		}
+ 		/* now that the disk list is up-to-date fixup recovery_start */
+ 		update_recovery_start(super, dev, this);
+@@ -6882,7 +6946,7 @@ static unsigned long long imsm_set_array_size(struct imsm_dev *dev)
+ 	/* set array size in metadata
+ 	 */
+ 	map = get_imsm_map(dev, MAP_0);
+-	array_blocks = map->blocks_per_member * used_disks;
++	array_blocks = blocks_per_member(map) * used_disks;
+ 
+ 	/* round array size down to closest MB
+ 	 */
+@@ -6997,7 +7061,7 @@ static int imsm_set_array_state(struct active_array *a, int consistent)
+ 				used_disks = imsm_num_data_members(dev, MAP_0);
+ 				if (used_disks > 0) {
+ 					array_blocks =
+-						map->blocks_per_member *
++						blocks_per_member(map) *
+ 						used_disks;
+ 					/* round array size down to closest MB
+ 					 */
+@@ -7364,9 +7428,9 @@ static struct dl *imsm_add_spare(struct intel_super *super, int slot,
+ 			found = 0;
+ 			j = 0;
+ 			pos = 0;
+-			array_start = __le32_to_cpu(map->pba_of_lba0);
++			array_start = pba_of_lba0(map);
+ 			array_end = array_start +
+-				    __le32_to_cpu(map->blocks_per_member) - 1;
++				    blocks_per_member(map) - 1;
+ 
+ 			do {
+ 				/* check that we can start at pba_of_lba0 with
+@@ -7566,7 +7630,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
+ 		di->disk.minor = dl->minor;
+ 		di->disk.state = 0;
+ 		di->recovery_start = 0;
+-		di->data_offset = __le32_to_cpu(map->pba_of_lba0);
++		di->data_offset = pba_of_lba0(map);
+ 		di->component_size = a->info.component_size;
+ 		di->container_member = inst;
+ 		super->random = random32();
+@@ -8292,8 +8356,8 @@ static void imsm_process_update(struct supertype *st,
+ 		}
+ 
+ 		new_map = get_imsm_map(&u->dev, MAP_0);
+-		new_start = __le32_to_cpu(new_map->pba_of_lba0);
+-		new_end = new_start + __le32_to_cpu(new_map->blocks_per_member);
++		new_start = pba_of_lba0(new_map);
++		new_end = new_start + blocks_per_member(new_map);
+ 		inf = get_disk_info(u);
+ 
+ 		/* handle activate_spare versus create race:
+@@ -8303,8 +8367,8 @@ static void imsm_process_update(struct supertype *st,
+ 		for (i = 0; i < mpb->num_raid_devs; i++) {
+ 			dev = get_imsm_dev(super, i);
+ 			map = get_imsm_map(dev, MAP_0);
+-			start = __le32_to_cpu(map->pba_of_lba0);
+-			end = start + __le32_to_cpu(map->blocks_per_member);
++			start = pba_of_lba0(map);
++			end = start + blocks_per_member(map);
+ 			if ((new_start >= start && new_start <= end) ||
+ 			    (start >= new_start && start <= new_end))
+ 				/* overlap */;
+@@ -9165,7 +9229,7 @@ int recover_backup_imsm(struct supertype *st, struct mdinfo *info)
+ 
+ 	write_offset = ((unsigned long long)
+ 			__le32_to_cpu(migr_rec->dest_1st_member_lba) +
+-			__le32_to_cpu(map_dest->pba_of_lba0)) * 512;
++			pba_of_lba0(map_dest)) * 512;
+ 
+ 	unit_len = __le32_to_cpu(migr_rec->dest_depth_per_unit) * 512;
+ 	if (posix_memalign((void **)&buf, 512, unit_len) != 0)
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-display-maximum-volumes-per-controller-in-detai.patch b/mdadm-3.2.3-imsm-display-maximum-volumes-per-controller-in-detai.patch
new file mode 100644
index 0000000..1ca37ab
--- /dev/null
+++ b/mdadm-3.2.3-imsm-display-maximum-volumes-per-controller-in-detai.patch
@@ -0,0 +1,29 @@
+From 4ff46bbc34aca294afe2127536b620672486598e Mon Sep 17 00:00:00 2001
+From: Marcin Labun <Marcin.Labun at intel.com>
+Date: Wed, 14 Dec 2011 15:02:49 +0100
+Subject: [PATCH 1/6] imsm: display maximum volumes per controller in --detail-platform command
+
+Signed-off-by: Marcin Labun <marcin.labun at intel.com>
+---
+ super-intel.c |    5 +++--
+ 1 files changed, 3 insertions(+), 2 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index b64aa7a..1c22aff 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -1663,8 +1663,9 @@ static void print_imsm_capability(const struct imsm_orom *orom)
+ 	       imsm_orom_has_chunk(orom, 1024*16) ? " 16M" : "",
+ 	       imsm_orom_has_chunk(orom, 1024*32) ? " 32M" : "",
+ 	       imsm_orom_has_chunk(orom, 1024*64) ? " 64M" : "");
+-	printf("      Max Disks : %d\n", orom->tds);
+-	printf("    Max Volumes : %d\n", orom->vpa);
++	printf("    Max Disks                 : %d\n", orom->tds);
++	printf("    Max Volumes per array     : %d\n", orom->vpa);
++	printf("    Max Volumes per controller: %d\n", orom->vphba);
+ 	return;
+ }
+ 
+-- 
+1.7.1
+
diff --git a/mdadm-3.2.3-imsm-fix-rebuild-does-not-continue-after-reboot.patch b/mdadm-3.2.3-imsm-fix-rebuild-does-not-continue-after-reboot.patch
new file mode 100644
index 0000000..962f78b
--- /dev/null
+++ b/mdadm-3.2.3-imsm-fix-rebuild-does-not-continue-after-reboot.patch
@@ -0,0 +1,62 @@
+From 7ce05701813496571e1f7f79c726aa6e4868bd5f Mon Sep 17 00:00:00 2001
+From: Lukasz Dorau <lukasz.dorau at intel.com>
+Date: Fri, 20 Apr 2012 13:45:02 +0200
+Subject: [PATCH 2/3] imsm: fix: rebuild does not continue after reboot
+
+If system is rebooted during rebuild, md driver changes sync_action
+from 'recover' to 'idle' (during stopping all md devices).
+If mdmon is still running then, it detects the change of sync_action state,
+finishes rebuild and writes metadata to disks. After computer's restart
+the RAID volume is in Normal state in OROM and rebuild seems to be finished.
+After system's start-up RAID volume is in auto-read-only state
+and metadata is in Dirty state. Rebuild seems to be finished but it is not.
+Data is inconsistent (out-of-sync).
+
+When mdmon detects the change of sync_action from 'recover' to 'idle',
+it has to check if rebuild is really finished. Appropriate test was added.
+Now mdmon examines each volume's member if it is being rebuilt.
+
+Signed-off-by: Lukasz Dorau <lukasz.dorau at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |   17 +++++++++++++++++
+ 1 files changed, 17 insertions(+), 0 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index e405d97..1ad5e47 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -7273,6 +7273,8 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
+ 	struct imsm_dev *dev = get_imsm_dev(super, inst);
+ 	struct imsm_map *map = get_imsm_map(dev, MAP_0);
+ 	struct imsm_disk *disk;
++	struct mdinfo *mdi;
++	int recovery_not_finished = 0;
+ 	int failed;
+ 	__u32 ord;
+ 	__u8 map_state;
+@@ -7313,6 +7315,21 @@ static void imsm_set_disk(struct active_array *a, int n, int state)
+ 		dprintf("normal: ");
+ 		if (is_rebuilding(dev)) {
+ 			dprintf("while rebuilding");
++			/* check if recovery is really finished */
++			for (mdi = a->info.devs; mdi ; mdi = mdi->next)
++				if (mdi->recovery_start != MaxSector) {
++					recovery_not_finished = 1;
++					break;
++				}
++			if (recovery_not_finished) {
++				dprintf("\nimsm: Rebuild has not finished yet, "
++						"state not changed");
++				if (a->last_checkpoint < mdi->recovery_start) {
++					a->last_checkpoint = mdi->recovery_start;
++					super->updates_pending++;
++				}
++				break;
++			}
+ 			end_migration(dev, super, map_state);
+ 			map = get_imsm_map(dev, MAP_0);
+ 			map->failed_disk_num = ~0;
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-fix-the-second-array-need-to-have-the-whole-ava.patch b/mdadm-3.2.3-imsm-fix-the-second-array-need-to-have-the-whole-ava.patch
new file mode 100644
index 0000000..db17a01
--- /dev/null
+++ b/mdadm-3.2.3-imsm-fix-the-second-array-need-to-have-the-whole-ava.patch
@@ -0,0 +1,40 @@
+From f878b24226953f06912ebceb2c811edf36818d2f Mon Sep 17 00:00:00 2001
+From: "Labun, Marcin" <Marcin.Labun at intel.com>
+Date: Fri, 27 Jan 2012 15:28:36 +0000
+Subject: [PATCH] imsm: fix, the second array need to have the whole available
+ space on devices
+
+Fix the case with creating an array with given container in command line
+instead of real devices:
+mdadm -CR /dev/md/raid0 -l 0 -n 2 -z5G /dev/md/imsm
+
+Signed-off-by: Marcin Labun <marcin.labun at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |    9 ++++++++-
+ 1 files changed, 8 insertions(+), 1 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 8d67a14..eba11d6 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -6029,8 +6029,15 @@ static int reserve_space(struct supertype *st, int raiddisks,
+ 			size /= 2 * chunk;
+ 			size *= 2 * chunk;
+ 		}
++		maxsize = size;
++	}
++	if (!check_env("IMSM_NO_PLATFORM") &&
++	    mpb->num_raid_devs > 0 && size && size != maxsize) {
++		fprintf(stderr, Name ": attempting to create a second "
++			"volume with size less then remaining space. "
++			"Aborting...\n");
++		return 0;
+ 	}
+-
+ 	cnt = 0;
+ 	for (dl = super->disks; dl; dl = dl->next)
+ 		if (dl->e)
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-fix-thunderdome-may-drop-2tb-attribute.patch b/mdadm-3.2.3-imsm-fix-thunderdome-may-drop-2tb-attribute.patch
new file mode 100644
index 0000000..eb5d951
--- /dev/null
+++ b/mdadm-3.2.3-imsm-fix-thunderdome-may-drop-2tb-attribute.patch
@@ -0,0 +1,33 @@
+From 86130b7a213485f1aeb078c6f32c901648e2f679 Mon Sep 17 00:00:00 2001
+From: Anna Czarnowska <anna.czarnowska at intel.com>
+Date: Mon, 2 Apr 2012 22:42:51 +0200
+Subject: [PATCH] imsm: fix: thunderdome may drop 2tb attribute
+
+Spare superblock doesn't depend on other spares in container.
+When loading container metadata thunderdome
+may pick a small disk for the champion. This will result in incorrect
+interpretation of sizes of other disks in container when joint superblock
+is returned. If any disk in container has the 2TB attribute set, the result
+must have it set too.
+
+Signed-off-by: Anna Czarnowska <anna.czarnowska at intel.com>
+---
+ super-intel.c |    2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index ed13542..869a39c 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -4079,6 +4079,8 @@ imsm_thunderdome(struct intel_super **super_list, int len)
+ 		if (s == champion)
+ 			continue;
+ 
++		mpb->attributes |= s->anchor->attributes & MPB_ATTRIB_2TB_DISK;
++
+ 		for (i = 0; i < mpb->num_disks; i++) {
+ 			struct imsm_disk *disk;
+ 
+-- 
+1.6.4.2
+
diff --git a/mdadm-3.2.3-imsm-load_imsm_super_all-supports-loading-metadata-f.patch b/mdadm-3.2.3-imsm-load_imsm_super_all-supports-loading-metadata-f.patch
new file mode 100644
index 0000000..65090e0
--- /dev/null
+++ b/mdadm-3.2.3-imsm-load_imsm_super_all-supports-loading-metadata-f.patch
@@ -0,0 +1,157 @@
+From ec50f7b6bb3a5218b51e1a953d530ef6b446bcd4 Mon Sep 17 00:00:00 2001
+From: "Labun, Marcin" <Marcin.Labun at intel.com>
+Date: Mon, 30 Jan 2012 11:57:23 +1100
+Subject: [PATCH 2/3] imsm: load_imsm_super_all supports loading metadata from
+ the device list
+
+This option is going to be used to load and analyse the metadata from
+devices. This is needed to count the number of volumes on devcies attached
+to particular Intel controller (SATA or SAS). It shall be done without
+activation of container and volumes on the devices.
+
+Signed-off-by: Marcin Labun <marcin.labun at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |   79 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
+ 1 files changed, 73 insertions(+), 6 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 733d089..1cf8716 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -277,6 +277,22 @@ struct migr_record {
+ 				     * (for recovered migrations) */
+ } __attribute__ ((__packed__));
+ 
++struct md_list {
++	/* usage marker:
++	 *  1: load metadata
++	 *  2: metadata does not match
++	 *  4: already checked
++	 */
++	int   used;
++	char  *devname;
++	int   found;
++	int   container;
++	dev_t st_rdev;
++	struct md_list *next;
++};
++
++#define pr_vrb(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
++
+ static __u8 migr_type(struct imsm_dev *dev)
+ {
+ 	if (dev->vol.migr_type == MIGR_VERIFY &&
+@@ -4012,12 +4028,16 @@ imsm_thunderdome(struct intel_super **super_list, int len)
+ 
+ static int
+ get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd);
+-
+ static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
+ 			   int major, int minor, int keep_fd);
++static int
++get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list,
++			int *max, int keep_fd);
++
+ 
+ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
+-			       char *devname, int keep_fd)
++			       char *devname, struct md_list *devlist,
++			       int keep_fd)
+ {
+ 	struct intel_super *super_list = NULL;
+ 	struct intel_super *super = NULL;
+@@ -4028,7 +4048,8 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
+ 		/* 'fd' is an opened container */
+ 		err = get_sra_super_block(fd, &super_list, devname, &i, keep_fd);
+ 	else
+-		return 1;
++		/* get super block from devlist devices */
++		err = get_devlist_super_block(devlist, &super_list, &i, keep_fd);
+ 	if (err)
+ 		goto error;
+ 	/* all mpbs enter, maybe one leaves */
+@@ -4094,7 +4115,54 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
+ }
+ 
+ 
++static int
++get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list,
++			int *max, int keep_fd)
++{
++	struct md_list *tmpdev;
++	int err = 0;
++	int i = 0;
++	int lmax = 0;
+ 
++	for (i = 0, tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) {
++		if (tmpdev->used != 1)
++			continue;
++		if (tmpdev->container == 1) {
++			int fd = dev_open(tmpdev->devname, O_RDONLY|O_EXCL);
++			if (fd < 0) {
++				fprintf(stderr, Name ": cannot open device %s: %s\n",
++					tmpdev->devname, strerror(errno));
++				err = 8;
++				goto error;
++			}
++			err = get_sra_super_block(fd, super_list,
++						  tmpdev->devname, &lmax,
++						  keep_fd);
++			i += lmax;
++			close(fd);
++			if (err) {
++				err = 7;
++				goto error;
++			}
++		} else {
++			int major = major(tmpdev->st_rdev);
++			int minor = minor(tmpdev->st_rdev);
++			err = get_super_block(super_list,
++					      -1,
++					      tmpdev->devname,
++					      major, minor,
++					      keep_fd);
++			i++;
++			if (err) {
++				err = 6;
++				goto error;
++			}
++		}
++	}
++ error:
++	*max = i;
++	return err;
++}
+ 
+ static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
+ 			   int major, int minor, int keep_fd)
+@@ -4187,7 +4255,7 @@ get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int
+ 
+ static int load_container_imsm(struct supertype *st, int fd, char *devname)
+ {
+-	return load_super_imsm_all(st, fd, &st->sb, devname, 1);
++	return load_super_imsm_all(st, fd, &st->sb, devname, NULL, 1);
+ }
+ #endif
+ 
+@@ -5305,7 +5373,6 @@ static int imsm_default_chunk(const struct imsm_orom *orom)
+ 	return min(512, (1 << fs));
+ }
+ 
+-#define pr_vrb(fmt, arg...) (void) (verbose && fprintf(stderr, Name fmt, ##arg))
+ static int
+ validate_geometry_imsm_orom(struct intel_super *super, int level, int layout,
+ 			    int raiddisks, int *chunk, int verbose)
+@@ -5678,7 +5745,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+ 		 */
+ 		struct intel_super *super;
+ 
+-		if (load_super_imsm_all(st, cfd, (void **) &super, NULL, 1) == 0) {
++		if (load_super_imsm_all(st, cfd, (void **) &super, NULL, NULL, 1) == 0) {
+ 			st->sb = super;
+ 			st->container_dev = fd2devnum(cfd);
+ 			close(cfd);
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-load_super_imsm_all-function-refactoring.patch b/mdadm-3.2.3-imsm-load_super_imsm_all-function-refactoring.patch
new file mode 100644
index 0000000..0b93193
--- /dev/null
+++ b/mdadm-3.2.3-imsm-load_super_imsm_all-function-refactoring.patch
@@ -0,0 +1,261 @@
+From 9587c3739b6d6edc7abfa4a655b9ab46926abdbf Mon Sep 17 00:00:00 2001
+From: "Labun, Marcin" <Marcin.Labun at intel.com>
+Date: Mon, 30 Jan 2012 11:56:58 +1100
+Subject: [PATCH 1/3] imsm: load_super_imsm_all function refactoring
+
+Prepare function for subsequent changes related to
+loading metadata from devices list.
+
+Signed-off-by: Marcin Labun <marcin.labun at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |  176 +++++++++++++++++++++++++++++++++++++-------------------
+ 1 files changed, 116 insertions(+), 60 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 0e9269f..733d089 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -2985,7 +2985,7 @@ static void fd2devname(int fd, char *name)
+ 	rv = readlink(path, dname, sizeof(dname)-1);
+ 	if (rv <= 0)
+ 		return;
+-	
++
+ 	dname[rv] = '\0';
+ 	nm = strrchr(dname, '/');
+ 	if (nm) {
+@@ -4009,67 +4009,28 @@ imsm_thunderdome(struct intel_super **super_list, int len)
+ 	return champion;
+ }
+ 
++
++static int
++get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd);
++
++static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
++			   int major, int minor, int keep_fd);
++
+ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
+-			       char *devname)
++			       char *devname, int keep_fd)
+ {
+-	struct mdinfo *sra;
+ 	struct intel_super *super_list = NULL;
+ 	struct intel_super *super = NULL;
+-	int devnum = fd2devnum(fd);
+-	struct mdinfo *sd;
+-	int retry;
+ 	int err = 0;
+-	int i;
++	int i = 0;
+ 
+-	/* check if 'fd' an opened container */
+-	sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
+-	if (!sra)
++	if (fd >= 0)
++		/* 'fd' is an opened container */
++		err = get_sra_super_block(fd, &super_list, devname, &i, keep_fd);
++	else
+ 		return 1;
+-
+-	if (sra->array.major_version != -1 ||
+-	    sra->array.minor_version != -2 ||
+-	    strcmp(sra->text_version, "imsm") != 0) {
+-		err = 1;
++	if (err)
+ 		goto error;
+-	}
+-	/* load all mpbs */
+-	for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
+-		struct intel_super *s = alloc_super();
+-		char nm[32];
+-		int dfd;
+-		int rv;
+-
+-		err = 1;
+-		if (!s)
+-			goto error;
+-		s->next = super_list;
+-		super_list = s;
+-
+-		err = 2;
+-		sprintf(nm, "%d:%d", sd->disk.major, sd->disk.minor);
+-		dfd = dev_open(nm, O_RDWR);
+-		if (dfd < 0)
+-			goto error;
+-
+-		rv = find_intel_hba_capability(dfd, s, devname);
+-		/* no orom/efi or non-intel hba of the disk */
+-		if (rv != 0)
+-			goto error;
+-
+-		err = load_and_parse_mpb(dfd, s, NULL, 1);
+-
+-		/* retry the load if we might have raced against mdmon */
+-		if (err == 3 && mdmon_running(devnum))
+-			for (retry = 0; retry < 3; retry++) {
+-				usleep(3000);
+-				err = load_and_parse_mpb(dfd, s, NULL, 1);
+-				if (err != 3)
+-					break;
+-			}
+-		if (err)
+-			goto error;
+-	}
+-
+ 	/* all mpbs enter, maybe one leaves */
+ 	super = imsm_thunderdome(&super_list, i);
+ 	if (!super) {
+@@ -4114,13 +4075,16 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
+ 		super_list = super_list->next;
+ 		free_imsm(s);
+ 	}
+-	sysfs_free(sra);
++
+ 
+ 	if (err)
+ 		return err;
+ 
+ 	*sbp = super;
+-	st->container_dev = devnum;
++	if (fd >= 0)
++		st->container_dev = fd2devnum(fd);
++	else
++		st->container_dev = NoMdDev;
+ 	if (err == 0 && st->ss == NULL) {
+ 		st->ss = &super_imsm;
+ 		st->minor_version = 0;
+@@ -4129,9 +4093,101 @@ static int load_super_imsm_all(struct supertype *st, int fd, void **sbp,
+ 	return 0;
+ }
+ 
++
++
++
++static int get_super_block(struct intel_super **super_list, int devnum, char *devname,
++			   int major, int minor, int keep_fd)
++{
++	struct intel_super*s = NULL;
++	char nm[32];
++	int dfd = -1;
++	int rv;
++	int err = 0;
++	int retry;
++
++	s = alloc_super();
++	if (!s) {
++		err = 1;
++		goto error;
++	}
++
++	sprintf(nm, "%d:%d", major, minor);
++	dfd = dev_open(nm, O_RDWR);
++	if (dfd < 0) {
++		err = 2;
++		goto error;
++	}
++
++	rv = find_intel_hba_capability(dfd, s, devname);
++	/* no orom/efi or non-intel hba of the disk */
++	if (rv != 0) {
++		err = 4;
++		goto error;
++	}
++
++	err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
++
++	/* retry the load if we might have raced against mdmon */
++	if (err == 3 && (devnum != -1) && mdmon_running(devnum))
++		for (retry = 0; retry < 3; retry++) {
++			usleep(3000);
++			err = load_and_parse_mpb(dfd, s, NULL, keep_fd);
++			if (err != 3)
++				break;
++		}
++ error:
++	if (!err) {
++		s->next = *super_list;
++		*super_list = s;
++	} else {
++		if (s)
++			free(s);
++		if (dfd)
++			close(dfd);
++	}
++	if ((dfd >= 0) && (!keep_fd))
++		close(dfd);
++	return err;
++
++}
++
++static int
++get_sra_super_block(int fd, struct intel_super **super_list, char *devname, int *max, int keep_fd)
++{
++	struct mdinfo *sra;
++	int devnum;
++	struct mdinfo *sd;
++	int err = 0;
++	int i = 0;
++	sra = sysfs_read(fd, 0, GET_LEVEL|GET_VERSION|GET_DEVS|GET_STATE);
++	if (!sra)
++		return 1;
++
++	if (sra->array.major_version != -1 ||
++	    sra->array.minor_version != -2 ||
++	    strcmp(sra->text_version, "imsm") != 0) {
++		err = 1;
++		goto error;
++	}
++	/* load all mpbs */
++	devnum = fd2devnum(fd);
++	for (sd = sra->devs, i = 0; sd; sd = sd->next, i++) {
++		if (get_super_block(super_list, devnum, devname,
++				    sd->disk.major, sd->disk.minor, keep_fd) != 0) {
++			err = 7;
++			goto error;
++		}
++	}
++ error:
++	sysfs_free(sra);
++	*max = i;
++	return err;
++}
++
+ static int load_container_imsm(struct supertype *st, int fd, char *devname)
+ {
+-	return load_super_imsm_all(st, fd, &st->sb, devname);
++	return load_super_imsm_all(st, fd, &st->sb, devname, 1);
+ }
+ #endif
+ 
+@@ -5558,7 +5614,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+ 							dev, freesize,
+ 							verbose);
+ 	}
+-	
++
+ 	if (!dev) {
+ 		if (st->sb) {
+ 			if (!validate_geometry_imsm_orom(st->sb, level, layout,
+@@ -5622,7 +5678,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+ 		 */
+ 		struct intel_super *super;
+ 
+-		if (load_super_imsm_all(st, cfd, (void **) &super, NULL) == 0) {
++		if (load_super_imsm_all(st, cfd, (void **) &super, NULL, 1) == 0) {
+ 			st->sb = super;
+ 			st->container_dev = fd2devnum(cfd);
+ 			close(cfd);
+@@ -6198,7 +6254,7 @@ static int imsm_open_new(struct supertype *c, struct active_array *a,
+ {
+ 	struct intel_super *super = c->sb;
+ 	struct imsm_super *mpb = super->anchor;
+-	
++
+ 	if (atoi(inst) >= mpb->num_raid_devs) {
+ 		fprintf(stderr, "%s: subarry index %d, out of range\n",
+ 			__func__, atoi(inst));
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-set-2tb-disk-attribute-for-spare.patch b/mdadm-3.2.3-imsm-set-2tb-disk-attribute-for-spare.patch
new file mode 100644
index 0000000..1fc8ca1
--- /dev/null
+++ b/mdadm-3.2.3-imsm-set-2tb-disk-attribute-for-spare.patch
@@ -0,0 +1,30 @@
+From 027c374fd946824704291da933300da78c32a189 Mon Sep 17 00:00:00 2001
+From: "Czarnowska, Anna" <anna.czarnowska at intel.com>
+Date: Mon, 2 Apr 2012 10:19:04 +1000
+Subject: [PATCH 7/7] imsm: set 2tb disk attribute for spare
+
+This patch ensures metadata attribute is set correctly also for spares.
+
+Signed-off-by: Anna Czarnowska <anna.czarnowska at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 1bc9e9c..dad4c4d 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -5048,6 +5048,9 @@ static int write_super_imsm_spares(struct intel_super *super, int doclose)
+ 			continue;
+ 
+ 		spare->disk[0] = d->disk;
++		if (__le32_to_cpu(d->disk.total_blocks_hi) > 0)
++			spare->attributes |= MPB_ATTRIB_2TB_DISK;
++
+ 		sum = __gen_imsm_checksum(spare);
+ 		spare->family_num = __cpu_to_le32(sum);
+ 		spare->orig_family_num = 0;
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-imsm-validate-the-number-of-imsm-volumes-per-control.patch b/mdadm-3.2.3-imsm-validate-the-number-of-imsm-volumes-per-control.patch
new file mode 100644
index 0000000..9ba351f
--- /dev/null
+++ b/mdadm-3.2.3-imsm-validate-the-number-of-imsm-volumes-per-control.patch
@@ -0,0 +1,497 @@
+From ca9de185a3b96720adcc5120f6a34c5f9bb98b3f Mon Sep 17 00:00:00 2001
+From: "Labun, Marcin" <Marcin.Labun at intel.com>
+Date: Mon, 30 Jan 2012 12:00:10 +1100
+Subject: [PATCH 3/3] imsm: validate the number of imsm volumes per controller
+
+IMSM OROM limits number of volumes per controller. Volumes
+above the limit are blocked in OROM. mdadm should follow OROM limitations
+in this area. Therefore we need to count number of volumes on the devices
+attached to SATA (ahci driver) or SAS (isci) controller.  Adding a new volume
+must be blocked if the number of volumes on devices attached to the given
+controller is exceeded.
+
+Signed-off-by: Marcin Labun <marcin.labun at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |  404 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 files changed, 399 insertions(+), 5 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 1cf8716..7db5177 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -3285,7 +3285,7 @@ static int parse_raid_devices(struct intel_super *super)
+ 		len_migr = sizeof_imsm_dev(dev_iter, 1);
+ 		if (len_migr > len)
+ 			space_needed += len_migr - len;
+-		
++
+ 		dv = malloc(sizeof(*dv));
+ 		if (!dv)
+ 			return 1;
+@@ -3321,7 +3321,7 @@ static int parse_raid_devices(struct intel_super *super)
+ 		super->buf = buf;
+ 		super->len = len;
+ 	}
+-		
++
+ 	return 0;
+ }
+ 
+@@ -4122,12 +4122,12 @@ get_devlist_super_block(struct md_list *devlist, struct intel_super **super_list
+ 	struct md_list *tmpdev;
+ 	int err = 0;
+ 	int i = 0;
+-	int lmax = 0;
+ 
+ 	for (i = 0, tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) {
+ 		if (tmpdev->used != 1)
+ 			continue;
+ 		if (tmpdev->container == 1) {
++			int lmax = 0;
+ 			int fd = dev_open(tmpdev->devname, O_RDONLY|O_EXCL);
+ 			if (fd < 0) {
+ 				fprintf(stderr, Name ": cannot open device %s: %s\n",
+@@ -5363,6 +5363,377 @@ static int is_raid_level_supported(const struct imsm_orom *orom, int level, int
+ 	return 0;
+ }
+ 
++
++static int
++active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
++			int dpa, int verbose)
++{
++	struct mdstat_ent *mdstat = mdstat_read(0, 0);
++	struct mdstat_ent *memb = NULL;
++	int count = 0;
++	int num = 0;
++	struct md_list *dv = NULL;
++	int found;
++
++	for (memb = mdstat ; memb ; memb = memb->next) {
++		if (memb->metadata_version &&
++		    (strncmp(memb->metadata_version, "external:", 9) == 0)  &&
++		    (strcmp(&memb->metadata_version[9], name) == 0) &&
++		    !is_subarray(memb->metadata_version+9) &&
++		    memb->members) {
++			struct dev_member *dev = memb->members;
++			int fd = -1;
++			while(dev && (fd < 0)) {
++				char *path = malloc(strlen(dev->name) + strlen("/dev/") + 1);
++				if (path) {
++					num = sprintf(path, "%s%s", "/dev/", dev->name);
++					if (num > 0)
++						fd = open(path, O_RDONLY, 0);
++					if ((num <= 0) || (fd < 0)) {
++						pr_vrb(": Cannot open %s: %s\n",
++						       dev->name, strerror(errno));
++					}
++					free(path);
++				}
++				dev = dev->next;
++			}
++			found = 0;
++			if ((fd >= 0) && disk_attached_to_hba(fd, hba)) {
++				struct mdstat_ent *vol;
++				for (vol = mdstat ; vol ; vol = vol->next) {
++					if ((vol->active > 0) &&
++					    vol->metadata_version &&
++					    is_container_member(vol, memb->dev)) {
++						found++;
++						count++;
++					}
++				}
++				if (*devlist && (found < dpa)) {
++				  dv = calloc(1, sizeof(*dv));
++					if (dv == NULL)
++						fprintf(stderr, Name ": calloc failed\n");
++					else {
++						dv->devname = malloc(strlen(memb->dev) + strlen("/dev/") + 1);
++						if (dv->devname != NULL) {
++							sprintf(dv->devname, "%s%s", "/dev/", memb->dev);
++							dv->found = found;
++							dv->used = 0;
++							dv->next = *devlist;
++							*devlist = dv;
++						} else
++							free(dv);
++					}
++				}
++			}
++			if (fd >= 0)
++				close(fd);
++		}
++	}
++	free_mdstat(mdstat);
++	return count;
++}
++
++#ifdef DEBUG_LOOP
++static struct md_list*
++get_loop_devices(void)
++{
++	int i;
++	struct md_list *devlist = NULL;
++	struct md_list *dv = NULL;
++
++	for(i = 0; i < 12; i++) {
++		dv = calloc(1, sizeof(*dv));
++		if (dv == NULL) {
++			fprintf(stderr, Name ": calloc failed\n");
++			break;
++		}
++		dv->devname = malloc(40);
++		if (dv->devname == NULL) {
++			fprintf(stderr, Name ": malloc failed\n");
++			free(dv);
++			break;
++		}
++		sprintf(dv->devname, "/dev/loop%d", i);
++		dv->next = devlist;
++		devlist = dv;
++	}
++	return devlist;
++}
++#endif
++
++static struct md_list*
++get_devices(const char *hba_path)
++{
++	struct md_list *devlist = NULL;
++	struct md_list *dv = NULL;
++	struct dirent *ent;
++	DIR *dir;
++	int err = 0;
++
++#if DEBUG_LOOP
++	devlist = get_loop_devices();
++	return devlist;
++#endif
++	/* scroll through /sys/dev/block looking for devices attached to
++	 * this hba
++	 */
++	dir = opendir("/sys/dev/block");
++	for (ent = dir ? readdir(dir) : NULL; ent; ent = readdir(dir)) {
++		int fd;
++		char buf[1024];
++		int major, minor;
++		char *path = NULL;
++		if (sscanf(ent->d_name, "%d:%d", &major, &minor) != 2)
++			continue;
++		path = devt_to_devpath(makedev(major, minor));
++		if (!path)
++			continue;
++		if (!path_attached_to_hba(path, hba_path)) {
++			free(path);
++			path = NULL;
++			continue;
++		}
++		free(path);
++		path = NULL;
++		fd = dev_open(ent->d_name, O_RDONLY);
++		if (fd >= 0) {
++			fd2devname(fd, buf);
++			close(fd);
++		} else {
++			fprintf(stderr, Name ": cannot open device: %s\n",
++				ent->d_name);
++			continue;
++		}
++
++
++		dv = calloc(1, sizeof(*dv));
++		if (dv == NULL) {
++			fprintf(stderr, Name ": malloc failed\n");
++			err = 1;
++			break;
++		}
++		dv->devname = strdup(buf);
++		if (dv->devname == NULL) {
++			fprintf(stderr, Name ": malloc failed\n");
++			err = 1;
++			free(dv);
++			break;
++		}
++		dv->next = devlist;
++		devlist = dv;
++	}
++	if (err) {
++		while(devlist) {
++			dv = devlist;
++			devlist = devlist->next;
++			free(dv->devname);
++			free(dv);
++		}
++	}
++	return devlist;
++}
++
++static int
++count_volumes_list(struct md_list *devlist, char *homehost,
++		   int verbose, int *found)
++{
++	struct md_list *tmpdev;
++	int count = 0;
++	struct supertype *st = NULL;
++
++	/* first walk the list of devices to find a consistent set
++	 * that match the criterea, if that is possible.
++	 * We flag the ones we like with 'used'.
++	 */
++	*found = 0;
++	st = match_metadata_desc_imsm("imsm");
++	if (st == NULL) {
++		pr_vrb(": cannot allocate memory for imsm supertype\n");
++		return 0;
++	}
++
++	for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) {
++		char *devname = tmpdev->devname;
++		struct stat stb;
++		struct supertype *tst;
++		int dfd;
++		if (tmpdev->used > 1)
++			continue;
++		tst = dup_super(st);
++		if (tst == NULL) {
++			pr_vrb(": cannot allocate memory for imsm supertype\n");
++			goto err_1;
++		}
++		tmpdev->container = 0;
++		dfd = dev_open(devname, O_RDONLY|O_EXCL);
++		if (dfd < 0) {
++			dprintf(": cannot open device %s: %s\n",
++				devname, strerror(errno));
++			tmpdev->used = 2;
++		} else if (fstat(dfd, &stb)< 0) {
++			/* Impossible! */
++			dprintf(": fstat failed for %s: %s\n",
++				devname, strerror(errno));
++			tmpdev->used = 2;
++		} else if ((stb.st_mode & S_IFMT) != S_IFBLK) {
++			dprintf(": %s is not a block device.\n",
++				devname);
++			tmpdev->used = 2;
++		} else if (must_be_container(dfd)) {
++			struct supertype *cst;
++			cst = super_by_fd(dfd, NULL);
++			if (cst == NULL) {
++				dprintf(": cannot recognize container type %s\n",
++					devname);
++				tmpdev->used = 2;
++			} else if (tst->ss != st->ss) {
++				dprintf(": non-imsm container - ignore it: %s\n",
++					devname);
++				tmpdev->used = 2;
++			} else if (!tst->ss->load_container ||
++				   tst->ss->load_container(tst, dfd, NULL))
++				tmpdev->used = 2;
++			else {
++				tmpdev->container = 1;
++			}
++			if (cst)
++				cst->ss->free_super(cst);
++		} else {
++			tmpdev->st_rdev = stb.st_rdev;
++			if (tst->ss->load_super(tst,dfd, NULL)) {
++				dprintf(": no RAID superblock on %s\n",
++					devname);
++				tmpdev->used = 2;
++			} else if (tst->ss->compare_super == NULL) {
++				dprintf(": Cannot assemble %s metadata on %s\n",
++					tst->ss->name, devname);
++				tmpdev->used = 2;
++			}
++		}
++		if (dfd >= 0)
++			close(dfd);
++		if (tmpdev->used == 2 || tmpdev->used == 4) {
++			/* Ignore unrecognised devices during auto-assembly */
++			goto loop;
++		}
++		else {
++			struct mdinfo info;
++			tst->ss->getinfo_super(tst, &info, NULL);
++
++			if (st->minor_version == -1)
++				st->minor_version = tst->minor_version;
++
++			if (memcmp(info.uuid, uuid_zero,
++				   sizeof(int[4])) == 0) {
++				/* this is a floating spare.  It cannot define
++				 * an array unless there are no more arrays of
++				 * this type to be found.  It can be included
++				 * in an array of this type though.
++				 */
++				tmpdev->used = 3;
++				goto loop;
++			}
++
++			if (st->ss != tst->ss ||
++			    st->minor_version != tst->minor_version ||
++			    st->ss->compare_super(st, tst) != 0) {
++				/* Some mismatch. If exactly one array matches this host,
++				 * we can resolve on that one.
++				 * Or, if we are auto assembling, we just ignore the second
++				 * for now.
++				 */
++				dprintf(": superblock on %s doesn't match others - assembly aborted\n",
++					devname);
++				goto loop;
++			}
++			tmpdev->used = 1;
++			*found = 1;
++			dprintf("found: devname: %s\n", devname);
++		}
++	loop:
++		if (tst)
++			tst->ss->free_super(tst);
++	}
++	if (*found != 0) {
++		int err;
++		if ((err = load_super_imsm_all(st, -1, &st->sb, NULL, devlist, 0)) == 0) {
++			struct mdinfo *iter, *head = st->ss->container_content(st, NULL);
++			for (iter = head; iter; iter = iter->next) {
++				dprintf("content->text_version: %s vol\n",
++					iter->text_version);
++				if (iter->array.state & (1<<MD_SB_BLOCK_VOLUME)) {
++					/* do not assemble arrays with unsupported
++					   configurations */
++					dprintf(": Cannot activate member %s.\n",
++						iter->text_version);
++				} else
++					count++;
++			}
++			sysfs_free(head);
++
++		} else {
++			dprintf(" no valid super block on device list: err: %d %p\n",
++				err, st->sb);
++		}
++	} else {
++		dprintf(" no more devices to examin\n");
++	}
++
++	for (tmpdev = devlist; tmpdev; tmpdev = tmpdev->next) {
++		if ((tmpdev->used == 1) && (tmpdev->found)) {
++			if (count) {
++				if (count < tmpdev->found)
++					count = 0;
++				else
++					count -= tmpdev->found;
++			}
++		}
++		if (tmpdev->used == 1)
++			tmpdev->used = 4;
++	}
++	err_1:
++	if (st)
++		st->ss->free_super(st);
++	return count;
++}
++
++
++static int
++count_volumes(char *hba, int dpa, int verbose)
++{
++	struct md_list *devlist = NULL;
++	int count = 0;
++	int found = 0;;
++
++	devlist = get_devices(hba);
++	/* if no intel devices return zero volumes */
++	if (devlist == NULL)
++		return 0;
++
++	count = active_arrays_by_format("imsm", hba, &devlist, dpa, verbose);
++	dprintf(" path: %s active arrays: %d\n", hba, count);
++	if (devlist == NULL)
++		return 0;
++	do  {
++		found = 0;
++		count += count_volumes_list(devlist,
++					    NULL,
++					    verbose,
++					    &found);
++		dprintf("found %d count: %d\n", found, count);
++	} while (found);
++
++	dprintf("path: %s total number of volumes: %d\n", hba, count);
++
++	while(devlist) {
++		struct md_list *dv = devlist;
++		devlist = devlist->next;
++		free(dv->devname);
++		free(dv);
++	}
++	return count;
++}
++
+ static int imsm_default_chunk(const struct imsm_orom *orom)
+ {
+ 	/* up to 512 if the plaform supports it, otherwise the platform max.
+@@ -5583,6 +5954,15 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
+ 
+ 	*freesize = maxsize;
+ 
++	if (super->orom) {
++		int count = count_volumes(super->hba->path,
++				      super->orom->dpa, verbose);
++		if (super->orom->vphba <= count) {
++			pr_vrb(": platform does not support more then %d raid volumes.\n",
++			       super->orom->vphba);
++			return 0;
++		}
++	}
+ 	return 1;
+ }
+ 
+@@ -5684,6 +6064,7 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+ 
+ 	if (!dev) {
+ 		if (st->sb) {
++			struct intel_super *super = st->sb;
+ 			if (!validate_geometry_imsm_orom(st->sb, level, layout,
+ 							 raiddisks, chunk,
+ 							 verbose))
+@@ -5696,6 +6077,19 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
+ 			 * created.  add_to_super and getinfo_super
+ 			 * detect when autolayout is in progress.
+ 			 */
++			/* assuming that freesize is always given when array is
++			   created */
++			if (super->orom && freesize) {
++				int count;
++				count = count_volumes(super->hba->path,
++						      super->orom->dpa, verbose);
++				if (super->orom->vphba <= count) {
++					pr_vrb(": platform does not support more"
++					       "then %d raid volumes.\n",
++					       super->orom->vphba);
++					return 0;
++				}
++			}
+ 			if (freesize)
+ 				return reserve_space(st, raiddisks, size,
+ 						     chunk?*chunk:0, freesize);
+@@ -7176,7 +7570,7 @@ static struct mdinfo *imsm_activate_spare(struct active_array *a,
+ 		}
+ 		return NULL;
+ 	}
+-			
++
+ 	mu->space = NULL;
+ 	mu->space_list = NULL;
+ 	mu->len = sizeof(struct imsm_update_activate_spare) * num_spares;
+@@ -7420,7 +7814,7 @@ error_disk_add:
+ }
+ 
+ static int apply_update_activate_spare(struct imsm_update_activate_spare *u,
+-				       struct intel_super *super,	
++				       struct intel_super *super,
+ 				       struct active_array *active_array)
+ {
+ 	struct imsm_super *mpb = super->anchor;
+-- 
+1.7.7.6
+
diff --git a/mdadm-3.2.3-show-2TB-volumes-disks-support-in-detail-platform.patch b/mdadm-3.2.3-show-2TB-volumes-disks-support-in-detail-platform.patch
new file mode 100644
index 0000000..71deeee
--- /dev/null
+++ b/mdadm-3.2.3-show-2TB-volumes-disks-support-in-detail-platform.patch
@@ -0,0 +1,39 @@
+From 29cd0821bfe5acdeac0b8bb54b1de9e07a453323 Mon Sep 17 00:00:00 2001
+From: "Czarnowska, Anna" <anna.czarnowska at intel.com>
+Date: Mon, 2 Apr 2012 10:17:25 +1000
+Subject: [PATCH 4/7] show 2TB volumes/disks support in --detail-platform
+
+Signed-off-by: Anna Czarnowska <anna.czarnowska at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ platform-intel.h |    1 +
+ super-intel.c    |    4 ++++
+ 2 files changed, 5 insertions(+), 0 deletions(-)
+
+diff --git a/platform-intel.h b/platform-intel.h
+index c997f1b..94f2e81 100644
+--- a/platform-intel.h
++++ b/platform-intel.h
+@@ -76,6 +76,7 @@ struct imsm_orom {
+ 	#define IMSM_OROM_ATTR_RAID1E IMSM_OROM_RLC_RAID1E
+ 	#define IMSM_OROM_ATTR_RAID5 IMSM_OROM_RLC_RAID5
+ 	#define IMSM_OROM_ATTR_RAID_CNG IMSM_OROM_RLC_RAID_CNG
++	#define IMSM_OROM_ATTR_2TB_DISK (1 << 26)
+ 	#define IMSM_OROM_ATTR_2TB (1 << 29)
+ 	#define IMSM_OROM_ATTR_PM (1 << 30)
+ 	#define IMSM_OROM_ATTR_ChecksumVerify (1 << 31)
+diff --git a/super-intel.c b/super-intel.c
+index 642ca26..0c38b45 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -1786,6 +1786,10 @@
+ 	printf("    Max Disks                 : %d\n", orom->tds);
+ 	printf("    Max Volumes per array     : %d\n", orom->vpa);
+ 	printf("    Max Volumes per controller: %d\n", orom->vphba);
++	printf("    2TB Volumes:%s supported\n",
++	       (orom->attr & IMSM_OROM_ATTR_2TB) ? "" : " not");
++	printf("      2TB Disks:%s supported\n",
++	       (orom->attr & IMSM_OROM_ATTR_2TB_DISK) ? "" : " not");
+ 	return;
+ }
+ 
diff --git a/mdadm-3.2.3-simplify-calculating-array_blocks.patch b/mdadm-3.2.3-simplify-calculating-array_blocks.patch
new file mode 100644
index 0000000..d28def9
--- /dev/null
+++ b/mdadm-3.2.3-simplify-calculating-array_blocks.patch
@@ -0,0 +1,47 @@
+From e03640bda562df11b60ceaaa40a56425f358090e Mon Sep 17 00:00:00 2001
+From: "Czarnowska, Anna" <anna.czarnowska at intel.com>
+Date: Mon, 2 Apr 2012 10:16:04 +1000
+Subject: [PATCH 3/7] simplify calculating array_blocks
+
+no point calling info_to_blocks_per_member when it just returns size*2 for level==1
+calc_array_size can be used for all levels
+
+Signed-off-by: Anna Czarnowska <anna.czarnowska at intel.com>
+Signed-off-by: NeilBrown <neilb at suse.de>
+---
+ super-intel.c |    5 +----
+ util.c        |    2 ++
+ 2 files changed, 3 insertions(+), 4 deletions(-)
+
+diff --git a/super-intel.c b/super-intel.c
+index 480b379..642ca26 100644
+--- a/super-intel.c
++++ b/super-intel.c
+@@ -4623,10 +4623,7 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
+ 	}
+ 
+ 	strncpy((char *) dev->volume, name, MAX_RAID_SERIAL_LEN);
+-	if (info->level == 1)
+-		array_blocks = info_to_blocks_per_member(info, size);
+-	else
+-		array_blocks = calc_array_size(info->level, info->raid_disks,
++	array_blocks = calc_array_size(info->level, info->raid_disks,
+ 					       info->layout, info->chunk_size,
+ 					       size * 2);
+ 	/* round array size down to closest MB */
+diff --git a/util.c b/util.c
+index 7abbff7..d32e650 100644
+--- a/util.c
++++ b/util.c
+@@ -711,6 +711,8 @@ void print_r10_layout(int layout)
+ unsigned long long calc_array_size(int level, int raid_disks, int layout,
+ 				   int chunksize, unsigned long long devsize)
+ {
++	if (level == 1)
++		return devsize;
+ 	devsize &= ~(unsigned long long)((chunksize>>9)-1);
+ 	return get_data_disks(level, layout, raid_disks) * devsize;
+ }
+-- 
+1.7.7.6
+
diff --git a/mdadm.spec b/mdadm.spec
index 82ea4fe..a5a4792 100644
--- a/mdadm.spec
+++ b/mdadm.spec
@@ -1,7 +1,7 @@
 Summary:     The mdadm program controls Linux md devices (software RAID arrays)
 Name:        mdadm
 Version:     3.2.3
-Release:     8%{?dist}
+Release:     9%{?dist}
 Source:      http://www.kernel.org/pub/linux/utils/raid/mdadm/mdadm-%{version}.tar.bz2
 Source1:     mdmonitor.init
 Source2:     raid-check
@@ -38,6 +38,49 @@ Patch24:     mdadm-3.2.3-imsm-FIX-Clear-migration-record-when-migration-switc.pa
 Patch25:     mdadm-3.2.3-FIX-restart-reshape-when-reshape-process-is-stopped-.patch
 Patch26:     mdadm-3.2.3-FIX-Do-not-try-to-continue-reshape-using-inactive-ar.patch
 Patch27:     mdadm-3.2.3-FIX-Changes-in-0-case-for-reshape-position-verificat.patch
+Patch28:     mdadm-3.2.3-fix-Monitor-sometimes-crashes.patch
+Patch29:     mdadm-3.2.3-fix-container-creation-with-incremental-used.patch
+Patch30:     mdadm-3.2.3-imsm-fix-the-second-array-need-to-have-the-whole-ava.patch
+Patch31:     mdadm-3.2.3-imsm-load_super_imsm_all-function-refactoring.patch
+Patch32:     mdadm-3.2.3-imsm-load_imsm_super_all-supports-loading-metadata-f.patch
+Patch33:     mdadm-3.2.3-imsm-validate-the-number-of-imsm-volumes-per-control.patch
+Patch34:     mdadm-3.2.3-imsm-display-maximum-volumes-per-controller-in-detai.patch
+Patch35:     mdadm-3.2.3-imsm-avoid-overflows-for-disks-over-1TB.patch
+Patch36:     mdadm-3.2.3-clear-hi-bits-if-not-used-after-loading-metadata-fro.patch
+Patch37:     mdadm-3.2.3-simplify-calculating-array_blocks.patch
+Patch38:     mdadm-3.2.3-show-2TB-volumes-disks-support-in-detail-platform.patch
+Patch39:     mdadm-3.2.3-check-volume-size-in-validate_geometry_imsm_orom.patch
+Patch40:     mdadm-3.2.3-check-that-no-disk-over-2TB-is-used-to-create-contai.patch
+Patch41:     mdadm-3.2.3-imsm-set-2tb-disk-attribute-for-spare.patch
+Patch42:     mdadm-3.2.3-imsm-fix-thunderdome-may-drop-2tb-attribute.patch
+Patch43:     mdadm-3.2.3-imsm-FIX-Update-function-imsm_num_data_members-for-R.patch
+Patch44:     mdadm-3.2.3-imsm-FIX-Add-volume-size-expand-support-to-imsm_anal.patch
+Patch45:     mdadm-3.2.3-imsm-Add-new-metadata-update-for-volume-size-expansi.patch
+Patch46:     mdadm-3.2.3-imsm-Execute-size-change-for-external-metatdata.patch
+Patch47:     mdadm-3.2.3-FIX-Support-metadata-changes-rollback.patch
+Patch48:     mdadm-3.2.3-imsm-FIX-Support-metadata-changes-rollback.patch
+Patch49:     mdadm-3.2.3-FIX-Extend-size-of-raid0-array.patch
+Patch50:     mdadm-3.2.3-FIX-Respect-metadata-size-limitations.patch
+Patch51:     mdadm-3.2.3-FIX-Detect-error-and-rollback-metadata.patch
+Patch52:     mdadm-3.2.3-imsm-Add-function-imsm_get_free_size.patch
+Patch53:     mdadm-3.2.3-imsm-Support-setting-max-size-for-size-change-operat.patch
+Patch54:     mdadm-3.2.3-imsm-FIX-Component-size-alignment-check.patch
+Patch55:     mdadm-3.2.3-FIX-Size-change-is-possible-as-standalone-change-onl.patch
+Patch56:     mdadm-3.2.3-FIX-Assembled-second-array-is-in-read-only-state-dur.patch
+Patch57:     mdadm-3.2.3-fix-correct-extending-size-of-raid0-array.patch
+Patch58:     mdadm-3.2.3-imsm-fix-rebuild-does-not-continue-after-reboot.patch
+Patch59:     mdadm-3.2.3-Manage-allow-re-add-to-failed-array.patch
+Patch60:     mdadm-3.2.3-Manage-replace-return-1-with-goto-abort.patch
+Patch61:     mdadm-3.2.3-Manage-freeze-recovery-while-adding-multiple-devices.patch
+Patch62:     mdadm-3.2.3-Relax-restrictions-on-when-add-is-permitted.patch
+Patch63:     mdadm-3.2.3-Raid-limit-of-1024-when-scanning-for-devices.patch
+Patch64:     mdadm-3.2.3-Remove-avail_disks-arg-from-enough.patch
+Patch65:     mdadm-3.2.3-Reset-bad-flag-on-map-update.patch
+Patch66:     mdadm-3.2.3-Bitmap_offset-is-a-signed-number.patch
+Patch67:     mdadm-3.2.3-Fix-sign-extension-of-bitmap_offset-in-super1.c.patch
+Patch68:     mdadm-3.2.3-Introduce-sysfs_set_num_signed-and-use-it-to-set-bit.patch
+
+# Fedora customization patches
 Patch98:     mdadm-3.2.3-udev.patch
 Patch99:     mdadm-2.5.2-static.patch
 URL:         http://www.kernel.org/pub/linux/utils/raid/mdadm/
@@ -99,6 +142,47 @@ is not used as the system init process.
 %patch25 -p1 -b .restart
 %patch26 -p1 -b .nocontinue
 %patch27 -p1 -b .0case
+%patch28 -p1 -b .monitor3
+%patch29 -p1 -b .container
+%patch30 -p1 -b .available
+%patch31 -p1 -b .validate-1
+%patch32 -p1 -b .validate-2
+%patch33 -p1 -b .validate-3
+%patch34 -p1 -b .validate-4
+%patch35 -p1 -b .2tb-1
+%patch36 -p1 -b .2tb-2
+%patch37 -p1 -b .2tb-3
+%patch38 -p1 -b .2tb-4
+%patch39 -p1 -b .2tb-5
+%patch40 -p1 -b .2tb-6
+%patch41 -p1 -b .2tb-7
+%patch42 -p1 -b .2tb-8
+%patch43 -p1 -b .expand-01
+%patch44 -p1 -b .expand-02
+%patch45 -p1 -b .expand-03
+%patch46 -p1 -b .expand-04
+%patch47 -p1 -b .expand-05
+%patch48 -p1 -b .expand-06
+%patch49 -p1 -b .expand-07
+%patch50 -p1 -b .expand-08
+%patch51 -p1 -b .expand-09
+%patch52 -p1 -b .expand-10
+%patch53 -p1 -b .expand-11
+%patch54 -p1 -b .expand-12
+%patch55 -p1 -b .expand-13
+%patch56 -p1 -b .expand-14
+%patch57 -p1 -b .expand-15
+%patch58 -p1 -b .rebuild-continue
+%patch59 -p1 -b .allow-re-add
+%patch60 -p1 -b .replace-return-1
+%patch61 -p1 -b .freeze-recovery
+%patch62 -p1 -b .make-add-work
+%patch63 -p1 -b .max-devices
+%patch64 -p1 -b .enough
+%patch65 -p1 -b .bad-flag
+%patch66 -p1 -b .bitmap-offset
+%patch67 -p1 -b .bitmap-offset2
+%patch68 -p1 -b .bitmap-offset3
 
 # Fedora customization patches
 %patch98 -p1 -b .udev
@@ -175,6 +259,27 @@ fi
 %{_initrddir}/*
 
 %changelog
+* Mon Apr 30 2012 Jes Sorensen <Jes.Sorensen at redhat.com> - 3.2.3-9
+- Fix Monitor mode sometimes crashes when a resync completes
+- Fix missing symlink for mdadm container device when incremental creates
+  the array
+- Make sure when creating a second array in a container that the second
+  array uses all available space since leaving space for a third array
+  is invalid
+- Validate the number of imsm volumes per controller
+- Fix issues with imsm arrays and disks larger than 2TB
+- Add support for expanding imsm arrays/containers
+- The support for expanding imsm arrays/containers was accepted upstream,
+  update to the official patches from there
+- Fix for the issue of --add not being very smart
+- Fix an issue causing rebuilds to fail to restart on reboot (data
+  corrupter level problem)
+- Reset the bad flag on map file updates
+- Correctly fix failure when trying to add internal bitmap to 1.0 arrays
+- Resolves: bz817023 (f17) bz817024 (f17) bz817026 (f17) bz817028 (f17)
+- Resolves: bz817029 (f17) bz817032 (f17) bz817038 (f17) bz808774 (f17)
+- Resolves: bz817039 (f17) bz817042 (f17)
+
 * Mon Apr 30 2012 Jes Sorensen <Jes.Sorensen at redhat.com> - 3.2.3-8
 - Fix bug where IMSM arrays stay inactive in case a reboot is
 - performed during the reshape process.


More information about the scm-commits mailing list