344 lines
11 KiB
Diff
344 lines
11 KiB
Diff
|
From fbfdcb06dc5b1dcb227b0394f174faa2df734700 Mon Sep 17 00:00:00 2001
|
||
|
From: Alexey Obitotskiy <aleksey.obitotskiy@intel.com>
|
||
|
Date: Tue, 9 May 2017 12:25:46 +0200
|
||
|
Subject: [PATCH] Allow more spare selection criteria
|
||
|
|
||
|
Disks can be moved across containers in order to be used as a spare
|
||
|
drive for reubild. At the moment the only requirement checked for such
|
||
|
disk is its size (if it matches donor expectations). In order to
|
||
|
introduce more criteria rename corresponding superswitch method to more
|
||
|
generic name and move function parameter to a structure. This change is
|
||
|
a big edit but it doesn't introduce any changes in code logic, it just
|
||
|
updates function naming and parameters.
|
||
|
|
||
|
Signed-off-by: Alexey Obitotskiy <aleksey.obitotskiy@intel.com>
|
||
|
Signed-off-by: Tomasz Majchrzak <tomasz.majchrzak@intel.com>
|
||
|
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
|
||
|
---
|
||
|
Incremental.c | 18 +++++++++++-------
|
||
|
Monitor.c | 30 ++++++++++++++++--------------
|
||
|
mdadm.h | 16 +++++++++++-----
|
||
|
super-intel.c | 33 +++++++++++++++++++++------------
|
||
|
util.c | 6 +++---
|
||
|
5 files changed, 62 insertions(+), 41 deletions(-)
|
||
|
|
||
|
Index: mdadm/Incremental.c
|
||
|
===================================================================
|
||
|
--- mdadm.orig/Incremental.c
|
||
|
+++ mdadm/Incremental.c
|
||
|
@@ -889,7 +889,7 @@ static int array_try_spare(char *devname
|
||
|
struct domainlist *dl = NULL;
|
||
|
struct mdinfo *sra;
|
||
|
unsigned long long devsize;
|
||
|
- unsigned long long component_size = 0;
|
||
|
+ struct spare_criteria sc = {0};
|
||
|
|
||
|
if (is_subarray(mp->metadata))
|
||
|
continue;
|
||
|
@@ -958,7 +958,8 @@ static int array_try_spare(char *devname
|
||
|
}
|
||
|
if (st3->ss->load_container &&
|
||
|
!st3->ss->load_container(st3, mdfd, mp->path)) {
|
||
|
- component_size = st3->ss->min_acceptable_spare_size(st3);
|
||
|
+ if (st3->ss->get_spare_criteria)
|
||
|
+ st3->ss->get_spare_criteria(st3, &sc);
|
||
|
st3->ss->free_super(st3);
|
||
|
}
|
||
|
free(st3);
|
||
|
@@ -969,9 +970,8 @@ static int array_try_spare(char *devname
|
||
|
sra->devs
|
||
|
? sra->devs->data_offset
|
||
|
: INVALID_SECTORS)
|
||
|
- < sra->component_size)
|
||
|
- ||
|
||
|
- (sra->component_size == 0 && devsize < component_size)) {
|
||
|
+ < sra->component_size) ||
|
||
|
+ (sra->component_size == 0 && devsize < sc.min_size)) {
|
||
|
if (verbose > 1)
|
||
|
pr_err("not adding %s to %s as it is too small\n",
|
||
|
devname, mp->path);
|
||
|
@@ -1655,12 +1655,15 @@ static int Incremental_container(struct
|
||
|
struct supertype *sst =
|
||
|
super_imsm.match_metadata_desc("imsm");
|
||
|
struct mdinfo *sinfo;
|
||
|
- unsigned long long min_size = 0;
|
||
|
- if (st->ss->min_acceptable_spare_size)
|
||
|
- min_size = st->ss->min_acceptable_spare_size(st);
|
||
|
+
|
||
|
if (!sst->ss->load_container(sst, sfd, NULL)) {
|
||
|
+ struct spare_criteria sc = {0};
|
||
|
+
|
||
|
+ if (st->ss->get_spare_criteria)
|
||
|
+ st->ss->get_spare_criteria(st, &sc);
|
||
|
+
|
||
|
close(sfd);
|
||
|
- sinfo = container_choose_spares(sst, min_size,
|
||
|
+ sinfo = container_choose_spares(sst, &sc,
|
||
|
domains, NULL,
|
||
|
st->ss->name, 0);
|
||
|
sst->ss->free_super(sst);
|
||
|
Index: mdadm/Monitor.c
|
||
|
===================================================================
|
||
|
--- mdadm.orig/Monitor.c
|
||
|
+++ mdadm/Monitor.c
|
||
|
@@ -746,13 +746,14 @@ static int add_new_arrays(struct mdstat_
|
||
|
return new_found;
|
||
|
}
|
||
|
|
||
|
-static int get_min_spare_size_required(struct state *st, unsigned long long *sizep)
|
||
|
+static int get_required_spare_criteria(struct state *st,
|
||
|
+ struct spare_criteria *sc)
|
||
|
{
|
||
|
int fd;
|
||
|
|
||
|
if (!st->metadata ||
|
||
|
- !st->metadata->ss->min_acceptable_spare_size) {
|
||
|
- *sizep = 0;
|
||
|
+ !st->metadata->ss->get_spare_criteria) {
|
||
|
+ sc->min_size = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -766,7 +767,8 @@ static int get_min_spare_size_required(s
|
||
|
close(fd);
|
||
|
if (!st->metadata->sb)
|
||
|
return 1;
|
||
|
- *sizep = st->metadata->ss->min_acceptable_spare_size(st->metadata);
|
||
|
+
|
||
|
+ st->metadata->ss->get_spare_criteria(st->metadata, sc);
|
||
|
st->metadata->ss->free_super(st->metadata);
|
||
|
|
||
|
return 0;
|
||
|
@@ -798,7 +800,7 @@ static int check_donor(struct state *fro
|
||
|
}
|
||
|
|
||
|
static dev_t choose_spare(struct state *from, struct state *to,
|
||
|
- struct domainlist *domlist, unsigned long long min_size)
|
||
|
+ struct domainlist *domlist, struct spare_criteria *sc)
|
||
|
{
|
||
|
int d;
|
||
|
dev_t dev = 0;
|
||
|
@@ -813,9 +815,9 @@ static dev_t choose_spare(struct state *
|
||
|
test_partition_from_id(from->devid[d]))
|
||
|
continue;
|
||
|
|
||
|
- if (min_size &&
|
||
|
+ if (sc->min_size &&
|
||
|
dev_size_from_id(from->devid[d], &dev_size) &&
|
||
|
- dev_size < min_size)
|
||
|
+ dev_size < sc->min_size)
|
||
|
continue;
|
||
|
|
||
|
pol = devid_policy(from->devid[d]);
|
||
|
@@ -832,7 +834,7 @@ static dev_t choose_spare(struct state *
|
||
|
|
||
|
static dev_t container_choose_spare(struct state *from, struct state *to,
|
||
|
struct domainlist *domlist,
|
||
|
- unsigned long long min_size, int active)
|
||
|
+ struct spare_criteria *sc, int active)
|
||
|
{
|
||
|
/* This is similar to choose_spare, but we cannot trust devstate,
|
||
|
* so we need to read the metadata instead
|
||
|
@@ -883,7 +885,7 @@ static dev_t container_choose_spare(stru
|
||
|
}
|
||
|
|
||
|
/* We only need one spare so full list not needed */
|
||
|
- list = container_choose_spares(st, min_size, domlist, from->spare_group,
|
||
|
+ list = container_choose_spares(st, sc, domlist, from->spare_group,
|
||
|
to->metadata->ss->name, 1);
|
||
|
if (list) {
|
||
|
struct mdinfo *disks = list->devs;
|
||
|
@@ -899,6 +901,7 @@ static void try_spare_migration(struct s
|
||
|
{
|
||
|
struct state *from;
|
||
|
struct state *st;
|
||
|
+ struct spare_criteria sc;
|
||
|
|
||
|
link_containers_with_subarrays(statelist);
|
||
|
for (st = statelist; st; st = st->next)
|
||
|
@@ -907,7 +910,6 @@ static void try_spare_migration(struct s
|
||
|
struct domainlist *domlist = NULL;
|
||
|
int d;
|
||
|
struct state *to = st;
|
||
|
- unsigned long long min_size;
|
||
|
|
||
|
if (to->parent_devnm[0] && !to->parent)
|
||
|
/* subarray monitored without parent container
|
||
|
@@ -918,14 +920,14 @@ static void try_spare_migration(struct s
|
||
|
/* member of a container */
|
||
|
to = to->parent;
|
||
|
|
||
|
- if (get_min_spare_size_required(to, &min_size))
|
||
|
+ if (get_required_spare_criteria(to, &sc))
|
||
|
continue;
|
||
|
if (to->metadata->ss->external) {
|
||
|
/* We must make sure there is
|
||
|
* no suitable spare in container already.
|
||
|
* If there is we don't add more */
|
||
|
dev_t devid = container_choose_spare(
|
||
|
- to, to, NULL, min_size, st->active);
|
||
|
+ to, to, NULL, &sc, st->active);
|
||
|
if (devid > 0)
|
||
|
continue;
|
||
|
}
|
||
|
@@ -948,10 +950,10 @@ static void try_spare_migration(struct s
|
||
|
continue;
|
||
|
if (from->metadata->ss->external)
|
||
|
devid = container_choose_spare(
|
||
|
- from, to, domlist, min_size, 0);
|
||
|
+ from, to, domlist, &sc, 0);
|
||
|
else
|
||
|
devid = choose_spare(from, to, domlist,
|
||
|
- min_size);
|
||
|
+ &sc);
|
||
|
if (devid > 0
|
||
|
&& move_spare(from->devname, to->devname, devid)) {
|
||
|
alert("MoveSpare", to->devname, from->devname, info);
|
||
|
Index: mdadm/mdadm.h
|
||
|
===================================================================
|
||
|
--- mdadm.orig/mdadm.h
|
||
|
+++ mdadm/mdadm.h
|
||
|
@@ -351,6 +351,10 @@ struct createinfo {
|
||
|
struct supertype *supertype;
|
||
|
};
|
||
|
|
||
|
+struct spare_criteria {
|
||
|
+ unsigned long long min_size;
|
||
|
+};
|
||
|
+
|
||
|
enum mode {
|
||
|
ASSEMBLE=1,
|
||
|
BUILD,
|
||
|
@@ -929,11 +933,13 @@ extern struct superswitch {
|
||
|
*/
|
||
|
__u64 (*avail_size)(struct supertype *st, __u64 size,
|
||
|
unsigned long long data_offset);
|
||
|
- /* This is similar to 'avail_size' in purpose, but is used for
|
||
|
- * containers for which there is no 'component size' to compare.
|
||
|
- * This reports that whole-device size which is a minimum
|
||
|
+ /*
|
||
|
+ * Return spare criteria for array:
|
||
|
+ * - minimum disk size can be used in array;
|
||
|
+ * Return values: 0 - for success and -EINVAL on error.
|
||
|
*/
|
||
|
- unsigned long long (*min_acceptable_spare_size)(struct supertype *st);
|
||
|
+ int (*get_spare_criteria)(struct supertype *st,
|
||
|
+ struct spare_criteria *sc);
|
||
|
/* Find somewhere to put a bitmap - possibly auto-size it - and
|
||
|
* update the metadata to record this. The array may be newly
|
||
|
* created, in which case data_size may be updated, or it might
|
||
|
@@ -1491,7 +1497,7 @@ extern int assemble_container_content(st
|
||
|
#define INCR_ALREADY 4
|
||
|
#define INCR_YES 8
|
||
|
extern struct mdinfo *container_choose_spares(struct supertype *st,
|
||
|
- unsigned long long min_size,
|
||
|
+ struct spare_criteria *criteria,
|
||
|
struct domainlist *domlist,
|
||
|
char *spare_group,
|
||
|
const char *metadata, int get_one);
|
||
|
Index: mdadm/super-intel.c
|
||
|
===================================================================
|
||
|
--- mdadm.orig/super-intel.c
|
||
|
+++ mdadm/super-intel.c
|
||
|
@@ -1386,37 +1386,44 @@ static __u32 imsm_min_reserved_sectors(s
|
||
|
return (remainder < rv) ? remainder : rv;
|
||
|
}
|
||
|
|
||
|
-/* Return minimum size of a spare that can be used in this array*/
|
||
|
-static unsigned long long min_acceptable_spare_size_imsm(struct supertype *st)
|
||
|
+/*
|
||
|
+ * Return minimum size of a spare and sector size
|
||
|
+ * that can be used in this array
|
||
|
+ */
|
||
|
+int get_spare_criteria_imsm(struct supertype *st, struct spare_criteria *c)
|
||
|
{
|
||
|
struct intel_super *super = st->sb;
|
||
|
struct dl *dl;
|
||
|
struct extent *e;
|
||
|
int i;
|
||
|
- unsigned long long rv = 0;
|
||
|
+ unsigned long long size = 0;
|
||
|
+
|
||
|
+ c->min_size = 0;
|
||
|
|
||
|
if (!super)
|
||
|
- return rv;
|
||
|
+ return -EINVAL;
|
||
|
/* find first active disk in array */
|
||
|
dl = super->disks;
|
||
|
while (dl && (is_failed(&dl->disk) || dl->index == -1))
|
||
|
dl = dl->next;
|
||
|
if (!dl)
|
||
|
- return rv;
|
||
|
+ return -EINVAL;
|
||
|
/* find last lba used by subarrays */
|
||
|
e = get_extents(super, dl);
|
||
|
if (!e)
|
||
|
- return rv;
|
||
|
+ return -EINVAL;
|
||
|
for (i = 0; e[i].size; i++)
|
||
|
continue;
|
||
|
if (i > 0)
|
||
|
- rv = e[i-1].start + e[i-1].size;
|
||
|
+ size = e[i-1].start + e[i-1].size;
|
||
|
free(e);
|
||
|
|
||
|
/* add the amount of space needed for metadata */
|
||
|
- rv = rv + imsm_min_reserved_sectors(super);
|
||
|
+ size += imsm_min_reserved_sectors(super);
|
||
|
+
|
||
|
+ c->min_size = size * 512;
|
||
|
|
||
|
- return rv * 512;
|
||
|
+ return 0;
|
||
|
}
|
||
|
|
||
|
static int is_gen_migration(struct imsm_dev *dev);
|
||
|
@@ -10868,8 +10875,10 @@ static int imsm_reshape_is_allowed_on_co
|
||
|
*/
|
||
|
static struct mdinfo *get_spares_for_grow(struct supertype *st)
|
||
|
{
|
||
|
- unsigned long long min_size = min_acceptable_spare_size_imsm(st);
|
||
|
- return container_choose_spares(st, min_size, NULL, NULL, NULL, 0);
|
||
|
+ struct spare_criteria sc;
|
||
|
+
|
||
|
+ get_spare_criteria_imsm(st, &sc);
|
||
|
+ return container_choose_spares(st, &sc, NULL, NULL, NULL, 0);
|
||
|
}
|
||
|
|
||
|
/******************************************************************************
|
||
|
@@ -11908,7 +11917,7 @@ struct superswitch super_imsm = {
|
||
|
.update_super = update_super_imsm,
|
||
|
|
||
|
.avail_size = avail_size_imsm,
|
||
|
- .min_acceptable_spare_size = min_acceptable_spare_size_imsm,
|
||
|
+ .get_spare_criteria = get_spare_criteria_imsm,
|
||
|
|
||
|
.compare_super = compare_super_imsm,
|
||
|
|
||
|
Index: mdadm/util.c
|
||
|
===================================================================
|
||
|
--- mdadm.orig/util.c
|
||
|
+++ mdadm/util.c
|
||
|
@@ -2083,7 +2083,7 @@ int experimental(void)
|
||
|
* if spare_group given add it to domains of each spare
|
||
|
* metadata allows to test domains using metadata of destination array */
|
||
|
struct mdinfo *container_choose_spares(struct supertype *st,
|
||
|
- unsigned long long min_size,
|
||
|
+ struct spare_criteria *criteria,
|
||
|
struct domainlist *domlist,
|
||
|
char *spare_group,
|
||
|
const char *metadata, int get_one)
|
||
|
@@ -2107,9 +2107,9 @@ struct mdinfo *container_choose_spares(s
|
||
|
unsigned long long dev_size;
|
||
|
dev_t dev = makedev(d->disk.major,d->disk.minor);
|
||
|
|
||
|
- if (!min_size ||
|
||
|
+ if (!criteria->min_size ||
|
||
|
(dev_size_from_id(dev, &dev_size) &&
|
||
|
- dev_size >= min_size))
|
||
|
+ dev_size >= criteria->min_size))
|
||
|
found = 1;
|
||
|
/* check if domain matches */
|
||
|
if (found && domlist) {
|