Blame SOURCES/Allow-more-spare-selection-criteria.patch

2c1b57
commit fbfdcb06dc5b1dcb227b0394f174faa2df734700
2c1b57
Author: Alexey Obitotskiy <aleksey.obitotskiy@intel.com>
2c1b57
Date:   Tue May 9 12:25:46 2017 +0200
2c1b57
2c1b57
    Allow more spare selection criteria
2c1b57
    
2c1b57
    Disks can be moved across containers in order to be used as a spare
2c1b57
    drive for reubild. At the moment the only requirement checked for such
2c1b57
    disk is its size (if it matches donor expectations). In order to
2c1b57
    introduce more criteria rename corresponding superswitch method to more
2c1b57
    generic name and move function parameter to a structure. This change is
2c1b57
    a big edit but it doesn't introduce any changes in code logic, it just
2c1b57
    updates function naming and parameters.
2c1b57
    
2c1b57
    Signed-off-by: Alexey Obitotskiy <aleksey.obitotskiy@intel.com>
2c1b57
    Signed-off-by: Tomasz Majchrzak <tomasz.majchrzak@intel.com>
2c1b57
    Signed-off-by: Jes Sorensen <jsorensen@fb.com>
2c1b57
2c1b57
diff --git a/Incremental.c b/Incremental.c
2c1b57
index 680d318..fe9d644 100644
2c1b57
--- a/Incremental.c
2c1b57
+++ b/Incremental.c
2c1b57
@@ -867,7 +867,7 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
2c1b57
 		struct domainlist *dl = NULL;
2c1b57
 		struct mdinfo *sra;
2c1b57
 		unsigned long long devsize;
2c1b57
-		unsigned long long component_size = 0;
2c1b57
+		struct spare_criteria sc = {0};
2c1b57
 
2c1b57
 		if (is_subarray(mp->metadata))
2c1b57
 			continue;
2c1b57
@@ -936,7 +936,8 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
2c1b57
 			}
2c1b57
 			if (st3->ss->load_container &&
2c1b57
 			    !st3->ss->load_container(st3, mdfd, mp->path)) {
2c1b57
-				component_size = st3->ss->min_acceptable_spare_size(st3);
2c1b57
+				if (st3->ss->get_spare_criteria)
2c1b57
+					st3->ss->get_spare_criteria(st3, &sc);
2c1b57
 				st3->ss->free_super(st3);
2c1b57
 			}
2c1b57
 			free(st3);
2c1b57
@@ -947,7 +948,7 @@ static int array_try_spare(char *devname, int *dfdp, struct dev_policy *pol,
2c1b57
 					 sra->devs ? sra->devs->data_offset :
2c1b57
 					 INVALID_SECTORS) <
2c1b57
 		     sra->component_size) ||
2c1b57
-		    (sra->component_size == 0 && devsize < component_size)) {
2c1b57
+		    (sra->component_size == 0 && devsize < sc.min_size)) {
2c1b57
 			if (verbose > 1)
2c1b57
 				pr_err("not adding %s to %s as it is too small\n",
2c1b57
 					devname, mp->path);
2c1b57
@@ -1624,12 +1625,15 @@ static int Incremental_container(struct supertype *st, char *devname,
2c1b57
 		struct supertype *sst =
2c1b57
 			super_imsm.match_metadata_desc("imsm");
2c1b57
 		struct mdinfo *sinfo;
2c1b57
-		unsigned long long min_size = 0;
2c1b57
-		if (st->ss->min_acceptable_spare_size)
2c1b57
-			min_size = st->ss->min_acceptable_spare_size(st);
2c1b57
+
2c1b57
 		if (!sst->ss->load_container(sst, sfd, NULL)) {
2c1b57
+			struct spare_criteria sc = {0};
2c1b57
+
2c1b57
+			if (st->ss->get_spare_criteria)
2c1b57
+				st->ss->get_spare_criteria(st, &sc);
2c1b57
+
2c1b57
 			close(sfd);
2c1b57
-			sinfo = container_choose_spares(sst, min_size,
2c1b57
+			sinfo = container_choose_spares(sst, &sc,
2c1b57
 							domains, NULL,
2c1b57
 							st->ss->name, 0);
2c1b57
 			sst->ss->free_super(sst);
2c1b57
diff --git a/Monitor.c b/Monitor.c
2c1b57
index ec643d4..9a2baad 100644
2c1b57
--- a/Monitor.c
2c1b57
+++ b/Monitor.c
2c1b57
@@ -723,13 +723,14 @@ static int add_new_arrays(struct mdstat_ent *mdstat, struct state **statelist,
2c1b57
 	return new_found;
2c1b57
 }
2c1b57
 
2c1b57
-static int get_min_spare_size_required(struct state *st, unsigned long long *sizep)
2c1b57
+static int get_required_spare_criteria(struct state *st,
2c1b57
+				       struct spare_criteria *sc)
2c1b57
 {
2c1b57
 	int fd;
2c1b57
 
2c1b57
 	if (!st->metadata ||
2c1b57
-	    !st->metadata->ss->min_acceptable_spare_size) {
2c1b57
-		*sizep = 0;
2c1b57
+	    !st->metadata->ss->get_spare_criteria) {
2c1b57
+		sc->min_size = 0;
2c1b57
 		return 0;
2c1b57
 	}
2c1b57
 
2c1b57
@@ -743,7 +744,8 @@ static int get_min_spare_size_required(struct state *st, unsigned long long *siz
2c1b57
 	close(fd);
2c1b57
 	if (!st->metadata->sb)
2c1b57
 		return 1;
2c1b57
-	*sizep = st->metadata->ss->min_acceptable_spare_size(st->metadata);
2c1b57
+
2c1b57
+	st->metadata->ss->get_spare_criteria(st->metadata, sc);
2c1b57
 	st->metadata->ss->free_super(st->metadata);
2c1b57
 
2c1b57
 	return 0;
2c1b57
@@ -775,7 +777,7 @@ static int check_donor(struct state *from, struct state *to)
2c1b57
 }
2c1b57
 
2c1b57
 static dev_t choose_spare(struct state *from, struct state *to,
2c1b57
-			struct domainlist *domlist, unsigned long long min_size)
2c1b57
+			struct domainlist *domlist, struct spare_criteria *sc)
2c1b57
 {
2c1b57
 	int d;
2c1b57
 	dev_t dev = 0;
2c1b57
@@ -790,9 +792,9 @@ static dev_t choose_spare(struct state *from, struct state *to,
2c1b57
 			    test_partition_from_id(from->devid[d]))
2c1b57
 				continue;
2c1b57
 
2c1b57
-			if (min_size &&
2c1b57
+			if (sc->min_size &&
2c1b57
 			    dev_size_from_id(from->devid[d], &dev_size) &&
2c1b57
-			    dev_size < min_size)
2c1b57
+			    dev_size < sc->min_size)
2c1b57
 				continue;
2c1b57
 
2c1b57
 			pol = devid_policy(from->devid[d]);
2c1b57
@@ -809,7 +811,7 @@ static dev_t choose_spare(struct state *from, struct state *to,
2c1b57
 
2c1b57
 static dev_t container_choose_spare(struct state *from, struct state *to,
2c1b57
 				    struct domainlist *domlist,
2c1b57
-				    unsigned long long min_size, int active)
2c1b57
+				    struct spare_criteria *sc, int active)
2c1b57
 {
2c1b57
 	/* This is similar to choose_spare, but we cannot trust devstate,
2c1b57
 	 * so we need to read the metadata instead
2c1b57
@@ -860,7 +862,7 @@ static dev_t container_choose_spare(struct state *from, struct state *to,
2c1b57
 	}
2c1b57
 
2c1b57
 	/* We only need one spare so full list not needed */
2c1b57
-	list = container_choose_spares(st, min_size, domlist, from->spare_group,
2c1b57
+	list = container_choose_spares(st, sc, domlist, from->spare_group,
2c1b57
 				       to->metadata->ss->name, 1);
2c1b57
 	if (list) {
2c1b57
 		struct mdinfo *disks = list->devs;
2c1b57
@@ -876,6 +878,7 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info
2c1b57
 {
2c1b57
 	struct state *from;
2c1b57
 	struct state *st;
2c1b57
+	struct spare_criteria sc;
2c1b57
 
2c1b57
 	link_containers_with_subarrays(statelist);
2c1b57
 	for (st = statelist; st; st = st->next)
2c1b57
@@ -884,7 +887,6 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info
2c1b57
 			struct domainlist *domlist = NULL;
2c1b57
 			int d;
2c1b57
 			struct state *to = st;
2c1b57
-			unsigned long long min_size;
2c1b57
 
2c1b57
 			if (to->parent_devnm[0] && !to->parent)
2c1b57
 				/* subarray monitored without parent container
2c1b57
@@ -895,14 +897,14 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info
2c1b57
 				/* member of a container */
2c1b57
 				to = to->parent;
2c1b57
 
2c1b57
-			if (get_min_spare_size_required(to, &min_size))
2c1b57
+			if (get_required_spare_criteria(to, &sc))
2c1b57
 				continue;
2c1b57
 			if (to->metadata->ss->external) {
2c1b57
 				/* We must make sure there is
2c1b57
 				 * no suitable spare in container already.
2c1b57
 				 * If there is we don't add more */
2c1b57
 				dev_t devid = container_choose_spare(
2c1b57
-					to, to, NULL, min_size, st->active);
2c1b57
+					to, to, NULL, &sc, st->active);
2c1b57
 				if (devid > 0)
2c1b57
 					continue;
2c1b57
 			}
2c1b57
@@ -925,10 +927,10 @@ static void try_spare_migration(struct state *statelist, struct alert_info *info
2c1b57
 					continue;
2c1b57
 				if (from->metadata->ss->external)
2c1b57
 					devid = container_choose_spare(
2c1b57
-						from, to, domlist, min_size, 0);
2c1b57
+						from, to, domlist, &sc, 0);
2c1b57
 				else
2c1b57
 					devid = choose_spare(from, to, domlist,
2c1b57
-							     min_size);
2c1b57
+							     &sc);
2c1b57
 				if (devid > 0
2c1b57
 				    && move_spare(from->devname, to->devname, devid)) {
2c1b57
 					alert("MoveSpare", to->devname, from->devname, info);
2c1b57
diff --git a/mdadm.h b/mdadm.h
2c1b57
index a92feb2..8da7fd3 100644
2c1b57
--- a/mdadm.h
2c1b57
+++ b/mdadm.h
2c1b57
@@ -361,6 +361,10 @@ struct createinfo {
2c1b57
 	struct supertype *supertype;
2c1b57
 };
2c1b57
 
2c1b57
+struct spare_criteria {
2c1b57
+	unsigned long long min_size;
2c1b57
+};
2c1b57
+
2c1b57
 enum mode {
2c1b57
 	ASSEMBLE=1,
2c1b57
 	BUILD,
2c1b57
@@ -940,11 +944,13 @@ extern struct superswitch {
2c1b57
 	 */
2c1b57
 	__u64 (*avail_size)(struct supertype *st, __u64 size,
2c1b57
 			    unsigned long long data_offset);
2c1b57
-	/* This is similar to 'avail_size' in purpose, but is used for
2c1b57
-	 * containers for which there is no 'component size' to compare.
2c1b57
-	 * This reports that whole-device size which is a minimum
2c1b57
+	/*
2c1b57
+	 * Return spare criteria for array:
2c1b57
+	 * - minimum disk size can be used in array;
2c1b57
+	 * Return values: 0 - for success and -EINVAL on error.
2c1b57
 	 */
2c1b57
-	unsigned long long (*min_acceptable_spare_size)(struct supertype *st);
2c1b57
+	int (*get_spare_criteria)(struct supertype *st,
2c1b57
+				  struct spare_criteria *sc);
2c1b57
 	/* Find somewhere to put a bitmap - possibly auto-size it - and
2c1b57
 	 * update the metadata to record this.  The array may be newly
2c1b57
 	 * created, in which case data_size may be updated, or it might
2c1b57
@@ -1507,7 +1513,7 @@ extern int assemble_container_content(struct supertype *st, int mdfd,
2c1b57
 #define	INCR_ALREADY	4
2c1b57
 #define	INCR_YES	8
2c1b57
 extern struct mdinfo *container_choose_spares(struct supertype *st,
2c1b57
-					      unsigned long long min_size,
2c1b57
+					      struct spare_criteria *criteria,
2c1b57
 					      struct domainlist *domlist,
2c1b57
 					      char *spare_group,
2c1b57
 					      const char *metadata, int get_one);
2c1b57
diff --git a/super-intel.c b/super-intel.c
2c1b57
index e88fe82..be973f8 100644
2c1b57
--- a/super-intel.c
2c1b57
+++ b/super-intel.c
2c1b57
@@ -1383,37 +1383,44 @@ static __u32 imsm_min_reserved_sectors(struct intel_super *super)
2c1b57
 	return  (remainder < rv) ? remainder : rv;
2c1b57
 }
2c1b57
 
2c1b57
-/* Return minimum size of a spare that can be used in this array*/
2c1b57
-static unsigned long long min_acceptable_spare_size_imsm(struct supertype *st)
2c1b57
+/*
2c1b57
+ * Return minimum size of a spare and sector size
2c1b57
+ * that can be used in this array
2c1b57
+ */
2c1b57
+int get_spare_criteria_imsm(struct supertype *st, struct spare_criteria *c)
2c1b57
 {
2c1b57
 	struct intel_super *super = st->sb;
2c1b57
 	struct dl *dl;
2c1b57
 	struct extent *e;
2c1b57
 	int i;
2c1b57
-	unsigned long long rv = 0;
2c1b57
+	unsigned long long size = 0;
2c1b57
+
2c1b57
+	c->min_size = 0;
2c1b57
 
2c1b57
 	if (!super)
2c1b57
-		return rv;
2c1b57
+		return -EINVAL;
2c1b57
 	/* find first active disk in array */
2c1b57
 	dl = super->disks;
2c1b57
 	while (dl && (is_failed(&dl->disk) || dl->index == -1))
2c1b57
 		dl = dl->next;
2c1b57
 	if (!dl)
2c1b57
-		return rv;
2c1b57
+		return -EINVAL;
2c1b57
 	/* find last lba used by subarrays */
2c1b57
 	e = get_extents(super, dl);
2c1b57
 	if (!e)
2c1b57
-		return rv;
2c1b57
+		return -EINVAL;
2c1b57
 	for (i = 0; e[i].size; i++)
2c1b57
 		continue;
2c1b57
 	if (i > 0)
2c1b57
-		rv = e[i-1].start + e[i-1].size;
2c1b57
+		size = e[i-1].start + e[i-1].size;
2c1b57
 	free(e);
2c1b57
 
2c1b57
 	/* add the amount of space needed for metadata */
2c1b57
-	rv = rv + imsm_min_reserved_sectors(super);
2c1b57
+	size += imsm_min_reserved_sectors(super);
2c1b57
+
2c1b57
+	c->min_size = size * 512;
2c1b57
 
2c1b57
-	return rv * 512;
2c1b57
+	return 0;
2c1b57
 }
2c1b57
 
2c1b57
 static int is_gen_migration(struct imsm_dev *dev);
2c1b57
@@ -10817,8 +10824,10 @@ static int imsm_reshape_is_allowed_on_container(struct supertype *st,
2c1b57
  */
2c1b57
 static struct mdinfo *get_spares_for_grow(struct supertype *st)
2c1b57
 {
2c1b57
-	unsigned long long min_size = min_acceptable_spare_size_imsm(st);
2c1b57
-	return container_choose_spares(st, min_size, NULL, NULL, NULL, 0);
2c1b57
+	struct spare_criteria sc;
2c1b57
+
2c1b57
+	get_spare_criteria_imsm(st, &sc);
2c1b57
+	return container_choose_spares(st, &sc, NULL, NULL, NULL, 0);
2c1b57
 }
2c1b57
 
2c1b57
 /******************************************************************************
2c1b57
@@ -11853,7 +11862,7 @@ struct superswitch super_imsm = {
2c1b57
 	.update_super	= update_super_imsm,
2c1b57
 
2c1b57
 	.avail_size	= avail_size_imsm,
2c1b57
-	.min_acceptable_spare_size = min_acceptable_spare_size_imsm,
2c1b57
+	.get_spare_criteria = get_spare_criteria_imsm,
2c1b57
 
2c1b57
 	.compare_super	= compare_super_imsm,
2c1b57
 
2c1b57
diff --git a/util.c b/util.c
2c1b57
index 11ff2cc..8b3c67d 100644
2c1b57
--- a/util.c
2c1b57
+++ b/util.c
2c1b57
@@ -2107,7 +2107,7 @@ int experimental(void)
2c1b57
  * if spare_group given add it to domains of each spare
2c1b57
  * metadata allows to test domains using metadata of destination array */
2c1b57
 struct mdinfo *container_choose_spares(struct supertype *st,
2c1b57
-				       unsigned long long min_size,
2c1b57
+				       struct spare_criteria *criteria,
2c1b57
 				       struct domainlist *domlist,
2c1b57
 				       char *spare_group,
2c1b57
 				       const char *metadata, int get_one)
2c1b57
@@ -2131,9 +2131,9 @@ struct mdinfo *container_choose_spares(struct supertype *st,
2c1b57
 			unsigned long long dev_size;
2c1b57
 			dev_t dev = makedev(d->disk.major,d->disk.minor);
2c1b57
 
2c1b57
-			if (!min_size ||
2c1b57
+			if (!criteria->min_size ||
2c1b57
 			   (dev_size_from_id(dev,  &dev_size) &&
2c1b57
-			    dev_size >= min_size))
2c1b57
+			    dev_size >= criteria->min_size))
2c1b57
 				found = 1;
2c1b57
 			/* check if domain matches */
2c1b57
 			if (found && domlist) {