From 9fbf711de4a80aa8dc009ca5b954e54ccb0dcbfd 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 flag for Create and Grow

This can be used to over-ride the automatic assignment of
data offset.
For --create, it is useful to re-create old arrays where different
   defaults applied.
For --grow it may be able to force a reshape in the reverse direction.

Signed-off-by: NeilBrown <neilb@suse.de>
---
 Create.c |   14 ++++++++------
 Grow.c   |    6 ++++++
 ReadMe.c |    4 ++++
 mdadm.c  |   20 +++++++++++++++++++-
 mdadm.h  |    5 ++++-
 super1.c |    6 +++---
 6 files changed, 44 insertions(+), 11 deletions(-)

--- mdadm-3.2.6.orig/Create.c
+++ mdadm-3.2.6/Create.c
@@ -72,7 +72,7 @@ int Create(struct supertype *st, char *m
 	   int subdevs, struct mddev_dev *devlist,
 	   int runstop, int verbose, int force, int assume_clean,
 	   char *bitmap_file, int bitmap_chunk, int write_behind,
-	   int delay, int autof)
+	   int delay, int autof, unsigned long long data_offset)
 {
 	/*
 	 * Create a new raid array.
@@ -263,7 +263,7 @@ int Create(struct supertype *st, char *m
 		size &= ~(unsigned long long)(chunk - 1);
 	newsize = size * 2;
 	if (st && ! st->ss->validate_geometry(st, level, layout, raiddisks,
-					      &chunk, size*2, -1LL, NULL,
+					      &chunk, size*2, data_offset, NULL,
 					      &newsize, verbose>=0))
 		return 1;
 
@@ -346,7 +346,7 @@ int Create(struct supertype *st, char *m
 					layout = default_layout(st, level, verbose);
 				switch (st->ss->validate_geometry(
 						st, level, layout, raiddisks,
-						&chunk, size*2, -1LL, dname,
+						&chunk, size*2, data_offset, dname,
 						&freesize, verbose > 0)) {
 				case -1: /* Not valid, message printed, and not
 					  * worth checking any further */
@@ -382,7 +382,7 @@ int Create(struct supertype *st, char *m
 				layout = default_layout(st, level, 0);
 			if (!st->ss->validate_geometry(st, level, layout,
 						       raiddisks,
-						       &chunk, size*2, -1LL,
+						       &chunk, size*2, data_offset,
 						       dname, &freesize,
 						       verbose >= 0)) {
 
@@ -489,7 +489,8 @@ int Create(struct supertype *st, char *m
 			/* size is meaningful */
 			if (!st->ss->validate_geometry(st, level, layout,
 						       raiddisks,
-						       &chunk, minsize*2, -1LL,
+						       &chunk, minsize*2,
+						       data_offset,
 						       NULL, NULL, 0)) {
 				fprintf(stderr, Name ": devices too large for RAID level %d\n", level);
 				return 1;
@@ -697,7 +698,8 @@ int Create(struct supertype *st, char *m
 				name += 2;
 		}
 	}
-	if (!st->ss->init_super(st, &info.array, size, name, homehost, uuid, -1LL))
+	if (!st->ss->init_super(st, &info.array, size, name, homehost,
+				uuid, data_offset))
 		goto abort_locked;
 
 	total_slots = info.array.nr_disks;
--- mdadm-3.2.6.orig/Grow.c
+++ mdadm-3.2.6/Grow.c
@@ -1438,6 +1438,7 @@ static int reshape_container(char *conta
 int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
 		 long long size,
 		 int level, char *layout_str, int chunksize, int raid_disks,
+		 long long data_offset,
 		 struct mddev_dev *devlist,
 		 int assume_clean, int force)
 {
@@ -1475,6 +1476,11 @@ int Grow_reshape(char *devname, int fd,
 	struct mdinfo info;
 	struct mdinfo *sra;
 
+	if (data_offset >= 0) {
+		fprintf(stderr, Name ": --grow --data-offset not yet supported\n");
+		return 1;
+	}
+
 	if (ioctl(fd, GET_ARRAY_INFO, &array) < 0) {
 		fprintf(stderr, Name ": %s is not an active md array - aborting\n",
 			devname);
--- mdadm-3.2.6.orig/ReadMe.c
+++ mdadm-3.2.6/ReadMe.c
@@ -147,6 +147,7 @@ struct option long_options[] = {
     {"re-add",    0, 0,  ReAdd},
     {"homehost",  1, 0,  HomeHost},
     {"symlinks",  1, 0,  Symlinks},
+    {"data-offset",1, 0, DataOffset},
 
     /* For assemble */
     {"uuid",      1, 0, 'u'},
@@ -364,6 +365,8 @@ char Help_create[] =
 "  --raid-devices= -n : number of active devices in array\n"
 "  --spare-devices= -x: number of spares (eXtras) devices in initial array\n"
 "  --size=       -z   : Size (in K) of each drive in RAID1/4/5/6/10 - optional\n"
+"  --data-offset=     : Space to leave between start of device and start\n"
+"                     : of array data.\n"
 "  --force       -f   : Honour devices as listed on command line.  Don't\n"
 "                     : insert a missing drive for RAID5.\n"
 "  --run         -R   : insist of running the array even if not all\n"
@@ -549,6 +552,7 @@ char Help_grow[] =
 "                      : RAID4/5/6 array. Not needed when a spare is present.\n"
 "  --array-size=  -Z   : Change visible size of array.  This does not change\n"
 "                      : any data on the device, and is not stable across restarts.\n"
+"  --data-offset=      : Location on device to move start of data to.\n"
 ;
 
 char Help_incr[] =
--- mdadm-3.2.6.orig/mdadm.c
+++ mdadm-3.2.6/mdadm.c
@@ -42,6 +42,7 @@ int main(int argc, char *argv[])
 	int chunk = 0;
 	long long size = -1;
 	long long array_size = -1;
+	long long data_offset = -1;
 	int level = UnSet;
 	int layout = UnSet;
 	char *layout_str = NULL;
@@ -476,6 +477,21 @@ int main(int argc, char *argv[])
 			}
 			continue;
 
+		case O(CREATE,DataOffset):
+		case O(GROW,DataOffset):
+			if (data_offset >= 0) {
+				fprintf(stderr, Name ": data-offset may only be specified one. "
+					"Second value is %s.\n", optarg);
+				exit(2);
+			}
+			data_offset = parse_size(optarg);
+			if (data_offset < 0) {
+				fprintf(stderr, Name ": invalid data-offset: %s\n",
+					optarg);
+				exit(2);
+			}
+			continue;
+
 		case O(GROW,'l'):
 		case O(CREATE,'l'):
 		case O(BUILD,'l'): /* set raid level*/
@@ -1459,7 +1475,8 @@ int main(int argc, char *argv[])
 			    raiddisks, sparedisks, ident.name, homehost,
 			    ident.uuid_set ? ident.uuid : NULL,
 			    devs_found-1, devlist->next, runstop, verbose-quiet, force, assume_clean,
-			    bitmap_file, bitmap_chunk, write_behind, delay, autof);
+			    bitmap_file, bitmap_chunk, write_behind, delay, autof,
+			    data_offset);
 		break;
 	case MISC:
 		if (devmode == 'E') {
@@ -1715,6 +1732,7 @@ int main(int argc, char *argv[])
 			   || chunk != 0 || level != UnSet) {
 			rv = Grow_reshape(devlist->devname, mdfd, quiet, backup_file,
 					  size, level, layout_str, chunk, raiddisks,
+					  data_offset,
 					  devlist->next,
 					  assume_clean, force);
 		} else if (array_size < 0)
--- mdadm-3.2.6.orig/mdadm.h
+++ mdadm-3.2.6/mdadm.h
@@ -325,6 +325,7 @@ enum special_options {
 	Continue,
 	OffRootOpt,
 	Prefer,
+	DataOffset,
 };
 
 /* structures read from config file */
@@ -1057,6 +1058,7 @@ extern int Grow_addbitmap(char *devname,
 extern int Grow_reshape(char *devname, int fd, int quiet, char *backup_file,
 			long long size,
 			int level, char *layout_str, int chunksize, int raid_disks,
+			long long data_offset,
 			struct mddev_dev *devlist,
 			int assume_clean, int force);
 extern int Grow_restart(struct supertype *st, struct mdinfo *info,
@@ -1093,7 +1095,8 @@ extern int Create(struct supertype *st,
 		  char *name, char *homehost, int *uuid,
 		  int subdevs, struct mddev_dev *devlist,
 		  int runstop, int verbose, int force, int assume_clean,
-		  char *bitmap_file, int bitmap_chunk, int write_behind, int delay, int autof);
+		  char *bitmap_file, int bitmap_chunk, int write_behind, int delay, int autof,
+		  unsigned long long data_offset);
 
 extern int Detail(char *dev, int brief, int export, int test, char *homehost, char *prefer);
 extern int Detail_Platform(struct superswitch *ss, int scan, int verbose);
--- mdadm-3.2.6.orig/super1.c
+++ mdadm-3.2.6/super1.c
@@ -1238,9 +1238,9 @@ static int write_init_super1(struct supe
 			sb->data_size = __cpu_to_le64(sb_offset - bm_space);
 			break;
 		case 1:
+			sb->super_offset = __cpu_to_le64(0);
 			data_offset = __le64_to_cpu(sb->data_offset);
 			if (data_offset < 0) {
-				sb->super_offset = __cpu_to_le64(0);
 				reserved = bm_space + 4*2;
 				if (reserved < headroom)
 					reserved = headroom;
@@ -1261,10 +1261,10 @@ static int write_init_super1(struct supe
 			sb->data_size = __cpu_to_le64(dsize - reserved);
 			break;
 		case 2:
+			sb_offset = 4*2;
+			sb->super_offset = __cpu_to_le64(4*2);
 			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 + array_size
 					> dsize)
 					bm_space = dsize - array_size
