From 042e05814a1f16eee8f782d1c3b19793f2106af3 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 ->init_super and use it in super1.c

So if ->data_offset is already set, use that rather than
computing one.

Signed-off-by: NeilBrown <neilb@suse.de>
---
 Create.c      |    2 -
 Kill.c        |    2 -
 mdadm.h       |    2 -
 super-ddf.c   |   14 +++++++---
 super-intel.c |   13 +++++++--
 super0.c      |    7 ++++-
 super1.c      |   76 ++++++++++++++++++++++++++++++++--------------------------
 7 files changed, 72 insertions(+), 44 deletions(-)

--- mdadm-3.2.2.orig/Create.c
+++ mdadm-3.2.2/Create.c
@@ -679,7 +679,7 @@ int Create(struct supertype *st, char *m
 				name += 2;
 		}
 	}
-	if (!st->ss->init_super(st, &info.array, size, name, homehost, uuid))
+	if (!st->ss->init_super(st, &info.array, size, name, homehost, uuid, -1LL))
 		goto abort_locked;
 
 	total_slots = info.array.nr_disks;
--- mdadm-3.2.2.orig/Kill.c
+++ mdadm-3.2.2/Kill.c
@@ -65,7 +65,7 @@ int Kill(char *dev, struct supertype *st
 		rv = 0; /* ignore bad data in superblock */
 	if (rv== 0 || (force && rv >= 2)) {
 		st->ss->free_super(st);
-		st->ss->init_super(st, NULL, 0, "", NULL, NULL);
+		st->ss->init_super(st, NULL, 0, "", NULL, NULL, -1LL);
 		if (st->ss->store_super(st, fd)) {
 			if (!quiet)
 				fprintf(stderr, Name ": Could not zero superblock on %s\n",
--- mdadm-3.2.2.orig/mdadm.h
+++ mdadm-3.2.2/mdadm.h
@@ -677,7 +677,7 @@ extern struct superswitch {
 	 */
 	int (*init_super)(struct supertype *st, mdu_array_info_t *info,
 			  unsigned long long size, char *name,
-			  char *homehost, int *uuid);
+			  char *homehost, int *uuid, long long data_offset);
 
 	/* update the metadata to include new device, either at create or
 	 * when hot-adding a spare.
--- mdadm-3.2.2.orig/super-ddf.c
+++ mdadm-3.2.2/super-ddf.c
@@ -1581,12 +1581,12 @@ static int init_super_ddf_bvd(struct sup
 			      mdu_array_info_t *info,
 			      unsigned long long size,
 			      char *name, char *homehost,
-			      int *uuid);
+			      int *uuid, long long data_offset);
 
 static int init_super_ddf(struct supertype *st,
 			  mdu_array_info_t *info,
 			  unsigned long long size, char *name, char *homehost,
-			  int *uuid)
+			  int *uuid, long long data_offset)
 {
 	/* This is primarily called by Create when creating a new array.
 	 * We will then get add_to_super called for each component, and then
@@ -1622,8 +1622,14 @@ static int init_super_ddf(struct superty
 	struct phys_disk *pd;
 	struct virtual_disk *vd;
 
+	if (data_offset >= 0) {
+		fprintf(stderr, Name ": data-offset not supported by DDF\n");
+		return 0;
+	}
+
 	if (st->sb)
-		return init_super_ddf_bvd(st, info, size, name, homehost, uuid);
+		return init_super_ddf_bvd(st, info, size, name, homehost, uuid,
+					  data_offset);
 
 	if (posix_memalign((void**)&ddf, 512, sizeof(*ddf)) != 0) {
 		fprintf(stderr, Name ": %s could not allocate superblock\n", __func__);
@@ -1953,7 +1959,7 @@ static int init_super_ddf_bvd(struct sup
 			      mdu_array_info_t *info,
 			      unsigned long long size,
 			      char *name, char *homehost,
-			      int *uuid)
+			      int *uuid, long long data_offset)
 {
 	/* We are creating a BVD inside a pre-existing container.
 	 * so st->sb is already set.
--- mdadm-3.2.2.orig/super-intel.c
+++ mdadm-3.2.2/super-intel.c
@@ -4300,7 +4300,8 @@ static int check_name(struct intel_super
 
 static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
 				  unsigned long long size, char *name,
-				  char *homehost, int *uuid)
+				  char *homehost, int *uuid,
+				  long long data_offset)
 {
 	/* We are creating a volume inside a pre-existing container.
 	 * so st->sb is already set.
@@ -4469,7 +4470,7 @@ static int init_super_imsm_volume(struct
 
 static int init_super_imsm(struct supertype *st, mdu_array_info_t *info,
 			   unsigned long long size, char *name,
-			   char *homehost, int *uuid)
+			   char *homehost, int *uuid, long long data_offset)
 {
 	/* This is primarily called by Create when creating a new array.
 	 * We will then get add_to_super called for each component, and then
@@ -4484,8 +4485,14 @@ static int init_super_imsm(struct supert
 	size_t mpb_size;
 	char *version;
 
+	if (data_offset >= 0) {
+		fprintf(stderr, Name ": data-offset not supported by imsm\n");
+		return 0;
+	}
+
 	if (st->sb)
-		return init_super_imsm_volume(st, info, size, name, homehost, uuid);
+		return init_super_imsm_volume(st, info, size, name, homehost, uuid,
+					      data_offset);
 
 	if (info)
 		mpb_size = disks_to_mpb_size(info->nr_disks);
--- mdadm-3.2.2.orig/super0.c
+++ mdadm-3.2.2/super0.c
@@ -604,11 +604,16 @@ static int update_super0(struct supertyp
 
 static int init_super0(struct supertype *st, mdu_array_info_t *info,
 		       unsigned long long size, char *ignored_name, char *homehost,
-		       int *uuid)
+		       int *uuid, long long data_offset)
 {
 	mdp_super_t *sb;
 	int spares;
 
+	if (data_offset >= 0) {
+		fprintf(stderr, Name ": data-offset not support for 0.90\n");
+		return 0;
+	}
+
 	if (posix_memalign((void**)&sb, 4096,
 			   MD_SB_BYTES + ROUND_UP(sizeof(bitmap_super_t), 4096)) != 0) {
 		fprintf(stderr, Name ": %s could not allocate superblock\n", __func__);
--- mdadm-3.2.2.orig/super1.c
+++ mdadm-3.2.2/super1.c
@@ -837,7 +837,8 @@ static int update_super1(struct supertyp
 }
 
 static int init_super1(struct supertype *st, mdu_array_info_t *info,
-		       unsigned long long size, char *name, char *homehost, int *uuid)
+		       unsigned long long size, char *name, char *homehost,
+		       int *uuid, long long data_offset)
 {
 	struct mdp_superblock_1 *sb;
 	int spares;
@@ -903,7 +904,7 @@ static int init_super1(struct supertype
 	sb->chunksize = __cpu_to_le32(info->chunk_size>>9);
 	sb->raid_disks = __cpu_to_le32(info->raid_disks);
 
-	sb->data_offset = __cpu_to_le64(0);
+	sb->data_offset = __cpu_to_le64(data_offset);
 	sb->data_size = __cpu_to_le64(0);
 	sb->super_offset = __cpu_to_le64(0);
 	sb->recovery_offset = __cpu_to_le64(0);
@@ -1071,6 +1072,7 @@ static int write_init_super1(struct supe
 	struct devinfo *di;
 	unsigned long long dsize, array_size;
 	unsigned long long sb_offset, headroom;
+	long long data_offset;
 
 	for (di = st->info; di && ! rv ; di = di->next) {
 		if (di->disk.state == 1)
@@ -1158,47 +1160,58 @@ static int write_init_super1(struct supe
 			sb_offset -= 8*2;
 			sb_offset &= ~(4*2-1);
 			sb->super_offset = __cpu_to_le64(sb_offset);
+			data_offset = (long long)(int64_t)__le64_to_cpu(sb->data_offset);
+			if (data_offset < 0)
+				sb->data_offset = 0;
-			sb->data_offset = __cpu_to_le64(0);
+			/* data_offset already set */
 			if (sb_offset < array_size + bm_space)
 				bm_space = sb_offset - array_size;
 			sb->data_size = __cpu_to_le64(sb_offset - bm_space);
 			break;
 		case 1:
-			sb->super_offset = __cpu_to_le64(0);
-			reserved = bm_space + 4*2;
-			/* Try for multiple of 1Meg so it is nicely aligned */
-			#define ONE_MEG (2*1024)
-			reserved = ((reserved + ONE_MEG-1)/ONE_MEG) * ONE_MEG;
-			if (reserved + __le64_to_cpu(sb->size) > dsize)
-				reserved = dsize - __le64_to_cpu(sb->size);
-			/* force 4K alignment */
-			reserved &= ~7ULL;
-
-			if (reserved < headroom)
-				reserved = headroom;
+			data_offset = __le64_to_cpu(sb->data_offset);
+			if (data_offset < 0) {
+				sb->super_offset = __cpu_to_le64(0);
+				reserved = bm_space + 4*2;
+				/* Try for multiple of 1Meg so it is nicely aligned */
+				#define ONE_MEG (2*1024)
+				reserved = ((reserved + ONE_MEG-1)/ONE_MEG) * ONE_MEG;
+				if (reserved + __le64_to_cpu(sb->size) > dsize)
+					reserved = dsize - __le64_to_cpu(sb->size);
+				/* force 4K alignment */
+				reserved &= ~7ULL;
+
+				if (reserved < headroom)
+					reserved = headroom;
+			} else
+				reserved = data_offset;
 
 			sb->data_offset = __cpu_to_le64(reserved);
 			sb->data_size = __cpu_to_le64(dsize - reserved);
 			break;
 		case 2:
-			sb_offset = 4*2;
-			sb->super_offset = __cpu_to_le64(4*2);
-			if (4*2 + 4*2 + bm_space + __le64_to_cpu(sb->size)
-			    > dsize)
-				bm_space = dsize - __le64_to_cpu(sb->size)
-					- 4*2 - 4*2;
-
-			reserved = bm_space + 4*2 + 4*2;
-			/* Try for multiple of 1Meg so it is nicely aligned */
-			#define ONE_MEG (2*1024)
-			reserved = ((reserved + ONE_MEG-1)/ONE_MEG) * ONE_MEG;
-			if (reserved + __le64_to_cpu(sb->size) > dsize)
-				reserved = dsize - __le64_to_cpu(sb->size);
-			/* force 4K alignment */
-			reserved &= ~7ULL;
-
-			if (reserved < headroom)
-				reserved = headroom;
+			data_offset = __le64_to_cpu(sb->data_offset);
+			if (data_offset < 0) {
+				sb_offset = 4*2;
+				sb->super_offset = __cpu_to_le64(4*2);
+				if (4*2 + 4*2 + bm_space + __le64_to_cpu(sb->size)
+				    > dsize)
+					bm_space = dsize - __le64_to_cpu(sb->size)
+						- 4*2 - 4*2;
+
+				reserved = bm_space + 4*2 + 4*2;
+				/* Try for multiple of 1Meg so it is nicely aligned */
+				#define ONE_MEG (2*1024)
+				reserved = ((reserved + ONE_MEG-1)/ONE_MEG) * ONE_MEG;
+				if (reserved + __le64_to_cpu(sb->size) > dsize)
+					reserved = dsize - __le64_to_cpu(sb->size);
+				/* force 4K alignment */
+				reserved &= ~7ULL;
+
+				if (reserved < headroom)
+					reserved = headroom;
+			} else
+				reserved = data_offset;
 
 			sb->data_offset = __cpu_to_le64(reserved);
 			sb->data_size = __cpu_to_le64(dsize - reserved);
