From 0d34aa5d0ca359774cbc4bf082506a35d3cfb605 Mon Sep 17 00:00:00 2001
From: NeilBrown <neilb@suse.de>
Date: Wed, 28 Mar 2012 17:29:55 +1100
Subject: [PATCH] Add data_offset arg to ->avail_size

This is currently only useful for 1.x metadata and will allow an
explicit --data-offset request on command line.

Signed-off-by: NeilBrown <neilb@suse.de>
---
 Incremental.c |    5 ++++-
 Manage.c      |    2 +-
 mdadm.h       |    3 ++-
 super-ddf.c   |    5 +++--
 super-intel.c |    5 +++--
 super0.c      |    5 ++++-
 super1.c      |   25 +++++++++++++++++++++----
 7 files changed, 38 insertions(+), 12 deletions(-)

--- mdadm-3.2.6.orig/Incremental.c
+++ mdadm-3.2.6/Incremental.c
@@ -912,7 +912,10 @@ static int array_try_spare(char *devname
 			close(mdfd);
 		}
 		if ((sra->component_size > 0 &&
-		     st2->ss->avail_size(st2, devsize) < sra->component_size)
+		     st2->ss->avail_size(st2, devsize,
+					 sra->devs
+					 ? (long long)sra->devs->data_offset : -1)
+		     < sra->component_size)
 		    ||
 		    (sra->component_size == 0 && devsize < component_size)) {
 			if (verbose > 1)
--- mdadm-3.2.6.orig/Manage.c
+++ mdadm-3.2.6/Manage.c
@@ -807,7 +807,7 @@ int Manage_subdevs(char *devname, int fd
 				}
 
 				/* Make sure device is large enough */
-				if (tst->ss->avail_size(tst, ldsize/512) <
+				if (tst->ss->avail_size(tst, ldsize/512, -1) <
 				    array_size) {
 					close(tfd);
 					tfd = -1;
--- mdadm-3.2.6.orig/mdadm.h
+++ mdadm-3.2.6/mdadm.h
@@ -710,7 +710,8 @@ extern struct superswitch {
 	int (*load_super)(struct supertype *st, int fd, char *devname);
 	int (*load_container)(struct supertype *st, int fd, char *devname);
 	struct supertype * (*match_metadata_desc)(char *arg);
-	__u64 (*avail_size)(struct supertype *st, __u64 size);
+	__u64 (*avail_size)(struct supertype *st, __u64 size,
+			    long long data_offset);
 	unsigned long long (*min_acceptable_spare_size)(struct supertype *st);
 	int (*add_internal_bitmap)(struct supertype *st, int *chunkp,
 				   int delay, int write_behind,
--- mdadm-3.2.6.orig/super-ddf.c
+++ mdadm-3.2.6/super-ddf.c
@@ -2497,7 +2497,8 @@ static int write_init_super_ddf(struct s
 
 #endif
 
-static __u64 avail_size_ddf(struct supertype *st, __u64 devsize)
+static __u64 avail_size_ddf(struct supertype *st, __u64 devsize,
+			    long long data_offset)
 {
 	/* We must reserve the last 32Meg */
 	if (devsize <= 32*1024*2)
@@ -2768,7 +2769,7 @@ validate_geometry_ddf_container(struct s
 	}
 	close(fd);
 
-	*freesize = avail_size_ddf(st, ldsize >> 9);
+	*freesize = avail_size_ddf(st, ldsize >> 9, -1);
 	if (*freesize == 0)
 		return 0;
 
--- mdadm-3.2.6.orig/super-intel.c
+++ mdadm-3.2.6/super-intel.c
@@ -2947,7 +2947,8 @@ static size_t disks_to_mpb_size(int disk
 	return size;
 }
 
-static __u64 avail_size_imsm(struct supertype *st, __u64 devsize)
+static __u64 avail_size_imsm(struct supertype *st, __u64 devsize,
+			     long long data_offset)
 {
 	if (devsize < (MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS))
 		return 0;
@@ -5352,7 +5353,7 @@ static int validate_geometry_imsm_contai
 		}
 	}
 
-	*freesize = avail_size_imsm(st, ldsize >> 9);
+	*freesize = avail_size_imsm(st, ldsize >> 9, -1);
 	free_imsm(super);
 
 	return 1;
--- mdadm-3.2.6.orig/super0.c
+++ mdadm-3.2.6/super0.c
@@ -982,8 +982,11 @@ static struct supertype *match_metadata_
 	return NULL;
 }
 
-static __u64 avail_size0(struct supertype *st, __u64 devsize)
+static __u64 avail_size0(struct supertype *st, __u64 devsize,
+			 long long data_offset)
 {
+	if (data_offset > 0)
+		return 0ULL;
 	if (devsize < MD_RESERVED_SECTORS)
 		return 0ULL;
 	return MD_NEW_SIZE_SECTORS(devsize);
--- mdadm-3.2.6.orig/super1.c
+++ mdadm-3.2.6/super1.c
@@ -1519,27 +1519,44 @@ static struct supertype *match_metadata_
  * superblock type st, and reserving 'reserve' sectors for
  * a possible bitmap
  */
-static __u64 avail_size1(struct supertype *st, __u64 devsize)
+static __u64 avail_size1(struct supertype *st, __u64 devsize,
+			 long long data_offset)
 {
 	struct mdp_superblock_1 *super = st->sb;
+	int bmspace = 0;
 	if (devsize < 24)
 		return 0;
 
 	if (super == NULL)
 		/* creating:  allow suitable space for bitmap */
-		devsize -= choose_bm_space(devsize);
+		bmspace = choose_bm_space(devsize);
 #ifndef MDASSEMBLE
 	else if (__le32_to_cpu(super->feature_map)&MD_FEATURE_BITMAP_OFFSET) {
 		/* hot-add. allow for actual size of bitmap */
 		struct bitmap_super_s *bsb;
 		bsb = (struct bitmap_super_s *)(((char*)super)+MAX_SB_SIZE);
-		devsize -= bitmap_sectors(bsb);
+		bmspace = bitmap_sectors(bsb);
 	}
 #endif
 
+
 	if (st->minor_version < 0)
 		/* not specified, so time to set default */
 		st->minor_version = 2;
+
+	if (data_offset > 0)
+		switch(st->minor_version) {
+		case 0:
+			return devsize - data_offset - 8*2;
+		case 1:
+		case 2:
+			return devsize - data_offset;
+		default:
+			return 0;
+		}
+
+	devsize -= bmspace;
+
 	if (super == NULL && st->minor_version > 0) {
 		/* haven't committed to a size yet, so allow some
 		 * slack for space for reshape.
@@ -1802,7 +1819,7 @@ static int validate_geometry1(struct sup
 	}
 	close(fd);
 
-	*freesize = avail_size1(st, ldsize >> 9);
+	*freesize = avail_size1(st, ldsize >> 9, -1);
 	return 1;
 }
 #endif /* MDASSEMBLE */
