255 lines
7.9 KiB
Diff
255 lines
7.9 KiB
Diff
|
From 6d4d9ab295de165e57b5c30e044028dbffb8f297 Mon Sep 17 00:00:00 2001
|
||
|
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
|
||
|
Date: Tue, 21 Jun 2022 00:10:42 +0800
|
||
|
Subject: [PATCH 24/61] imsm: use same slot across container
|
||
|
Patch-mainline: mdadm-4.2+
|
||
|
References: jsc#PED-1009
|
||
|
|
||
|
Autolayout relies on drives order on super->disks list, but
|
||
|
it is not quaranted by readdir() in sysfs_read(). As a result
|
||
|
drive could be put in different slot in second volume.
|
||
|
|
||
|
Make it consistent by reffering to first volume, if exists.
|
||
|
|
||
|
Use enum imsm_status to unify error handling.
|
||
|
|
||
|
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
|
||
|
Acked-by: Coly Li <colyli@suse.de>
|
||
|
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
|
||
|
---
|
||
|
super-intel.c | 169 ++++++++++++++++++++++++++++++++------------------
|
||
|
1 file changed, 108 insertions(+), 61 deletions(-)
|
||
|
|
||
|
diff --git a/super-intel.c b/super-intel.c
|
||
|
index cd1f1e3..deef7c8 100644
|
||
|
--- a/super-intel.c
|
||
|
+++ b/super-intel.c
|
||
|
@@ -7522,11 +7522,27 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
-static int imsm_get_free_size(struct supertype *st, int raiddisks,
|
||
|
- unsigned long long size, int chunk,
|
||
|
- unsigned long long *freesize)
|
||
|
+/**
|
||
|
+ * imsm_get_free_size() - get the biggest, common free space from members.
|
||
|
+ * @super: &intel_super pointer, not NULL.
|
||
|
+ * @raiddisks: number of raid disks.
|
||
|
+ * @size: requested size, could be 0 (means max size).
|
||
|
+ * @chunk: requested chunk.
|
||
|
+ * @freesize: pointer for returned size value.
|
||
|
+ *
|
||
|
+ * Return: &IMSM_STATUS_OK or &IMSM_STATUS_ERROR.
|
||
|
+ *
|
||
|
+ * @freesize is set to meaningful value, this can be @size, or calculated
|
||
|
+ * max free size.
|
||
|
+ * super->create_offset value is modified and set appropriately in
|
||
|
+ * merge_extends() for further creation.
|
||
|
+ */
|
||
|
+static imsm_status_t imsm_get_free_size(struct intel_super *super,
|
||
|
+ const int raiddisks,
|
||
|
+ unsigned long long size,
|
||
|
+ const int chunk,
|
||
|
+ unsigned long long *freesize)
|
||
|
{
|
||
|
- struct intel_super *super = st->sb;
|
||
|
struct imsm_super *mpb = super->anchor;
|
||
|
struct dl *dl;
|
||
|
int i;
|
||
|
@@ -7570,12 +7586,10 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks,
|
||
|
/* chunk is in K */
|
||
|
minsize = chunk * 2;
|
||
|
|
||
|
- if (cnt < raiddisks ||
|
||
|
- (super->orom && used && used != raiddisks) ||
|
||
|
- maxsize < minsize ||
|
||
|
- maxsize == 0) {
|
||
|
+ if (cnt < raiddisks || (super->orom && used && used != raiddisks) ||
|
||
|
+ maxsize < minsize || maxsize == 0) {
|
||
|
pr_err("not enough devices with space to create array.\n");
|
||
|
- return 0; /* No enough free spaces large enough */
|
||
|
+ return IMSM_STATUS_ERROR;
|
||
|
}
|
||
|
|
||
|
if (size == 0) {
|
||
|
@@ -7588,37 +7602,69 @@ static int imsm_get_free_size(struct supertype *st, int raiddisks,
|
||
|
}
|
||
|
if (mpb->num_raid_devs > 0 && size && size != maxsize)
|
||
|
pr_err("attempting to create a second volume with size less then remaining space.\n");
|
||
|
- cnt = 0;
|
||
|
- for (dl = super->disks; dl; dl = dl->next)
|
||
|
- if (dl->e)
|
||
|
- dl->raiddisk = cnt++;
|
||
|
-
|
||
|
*freesize = size;
|
||
|
|
||
|
dprintf("imsm: imsm_get_free_size() returns : %llu\n", size);
|
||
|
|
||
|
- return 1;
|
||
|
+ return IMSM_STATUS_OK;
|
||
|
}
|
||
|
|
||
|
-static int reserve_space(struct supertype *st, int raiddisks,
|
||
|
- unsigned long long size, int chunk,
|
||
|
- unsigned long long *freesize)
|
||
|
+/**
|
||
|
+ * autolayout_imsm() - automatically layout a new volume.
|
||
|
+ * @super: &intel_super pointer, not NULL.
|
||
|
+ * @raiddisks: number of raid disks.
|
||
|
+ * @size: requested size, could be 0 (means max size).
|
||
|
+ * @chunk: requested chunk.
|
||
|
+ * @freesize: pointer for returned size value.
|
||
|
+ *
|
||
|
+ * We are being asked to automatically layout a new volume based on the current
|
||
|
+ * contents of the container. If the parameters can be satisfied autolayout_imsm
|
||
|
+ * will record the disks, start offset, and will return size of the volume to
|
||
|
+ * be created. See imsm_get_free_size() for details.
|
||
|
+ * add_to_super() and getinfo_super() detect when autolayout is in progress.
|
||
|
+ * If first volume exists, slots are set consistently to it.
|
||
|
+ *
|
||
|
+ * Return: &IMSM_STATUS_OK on success, &IMSM_STATUS_ERROR otherwise.
|
||
|
+ *
|
||
|
+ * Disks are marked for creation via dl->raiddisk.
|
||
|
+ */
|
||
|
+static imsm_status_t autolayout_imsm(struct intel_super *super,
|
||
|
+ const int raiddisks,
|
||
|
+ unsigned long long size, const int chunk,
|
||
|
+ unsigned long long *freesize)
|
||
|
{
|
||
|
- struct intel_super *super = st->sb;
|
||
|
- struct dl *dl;
|
||
|
- int cnt;
|
||
|
- int rv = 0;
|
||
|
+ int curr_slot = 0;
|
||
|
+ struct dl *disk;
|
||
|
+ int vol_cnt = super->anchor->num_raid_devs;
|
||
|
+ imsm_status_t rv;
|
||
|
|
||
|
- rv = imsm_get_free_size(st, raiddisks, size, chunk, freesize);
|
||
|
- if (rv) {
|
||
|
- cnt = 0;
|
||
|
- for (dl = super->disks; dl; dl = dl->next)
|
||
|
- if (dl->e)
|
||
|
- dl->raiddisk = cnt++;
|
||
|
- rv = 1;
|
||
|
+ rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize);
|
||
|
+ if (rv != IMSM_STATUS_OK)
|
||
|
+ return IMSM_STATUS_ERROR;
|
||
|
+
|
||
|
+ for (disk = super->disks; disk; disk = disk->next) {
|
||
|
+ if (!disk->e)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (curr_slot == raiddisks)
|
||
|
+ break;
|
||
|
+
|
||
|
+ if (vol_cnt == 0) {
|
||
|
+ disk->raiddisk = curr_slot;
|
||
|
+ } else {
|
||
|
+ int _slot = get_disk_slot_in_dev(super, 0, disk->index);
|
||
|
+
|
||
|
+ if (_slot == -1) {
|
||
|
+ pr_err("Disk %s is not used in first volume, aborting\n",
|
||
|
+ disk->devname);
|
||
|
+ return IMSM_STATUS_ERROR;
|
||
|
+ }
|
||
|
+ disk->raiddisk = _slot;
|
||
|
+ }
|
||
|
+ curr_slot++;
|
||
|
}
|
||
|
|
||
|
- return rv;
|
||
|
+ return IMSM_STATUS_OK;
|
||
|
}
|
||
|
|
||
|
static int validate_geometry_imsm(struct supertype *st, int level, int layout,
|
||
|
@@ -7654,35 +7700,35 @@ static int validate_geometry_imsm(struct supertype *st, int level, int layout,
|
||
|
}
|
||
|
|
||
|
if (!dev) {
|
||
|
- if (st->sb) {
|
||
|
- struct intel_super *super = st->sb;
|
||
|
- if (!validate_geometry_imsm_orom(st->sb, level, layout,
|
||
|
- raiddisks, chunk, size,
|
||
|
- verbose))
|
||
|
+ struct intel_super *super = st->sb;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Autolayout mode, st->sb and freesize must be set.
|
||
|
+ */
|
||
|
+ if (!super || !freesize) {
|
||
|
+ pr_vrb("freesize and superblock must be set for autolayout, aborting\n");
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!validate_geometry_imsm_orom(st->sb, level, layout,
|
||
|
+ raiddisks, chunk, size,
|
||
|
+ verbose))
|
||
|
+ return 0;
|
||
|
+
|
||
|
+ if (super->orom) {
|
||
|
+ imsm_status_t rv;
|
||
|
+ int count = count_volumes(super->hba, super->orom->dpa,
|
||
|
+ verbose);
|
||
|
+ if (super->orom->vphba <= count) {
|
||
|
+ pr_vrb("platform does not support more than %d raid volumes.\n",
|
||
|
+ super->orom->vphba);
|
||
|
return 0;
|
||
|
- /* we are being asked to automatically layout a
|
||
|
- * new volume based on the current contents of
|
||
|
- * the container. If the the parameters can be
|
||
|
- * satisfied reserve_space will record the disks,
|
||
|
- * start offset, and size of the volume to be
|
||
|
- * created. add_to_super and getinfo_super
|
||
|
- * detect when autolayout is in progress.
|
||
|
- */
|
||
|
- /* assuming that freesize is always given when array is
|
||
|
- created */
|
||
|
- if (super->orom && freesize) {
|
||
|
- int count;
|
||
|
- count = count_volumes(super->hba,
|
||
|
- super->orom->dpa, verbose);
|
||
|
- if (super->orom->vphba <= count) {
|
||
|
- pr_vrb("platform does not support more than %d raid volumes.\n",
|
||
|
- super->orom->vphba);
|
||
|
- return 0;
|
||
|
- }
|
||
|
}
|
||
|
- if (freesize)
|
||
|
- return reserve_space(st, raiddisks, size,
|
||
|
- *chunk, freesize);
|
||
|
+
|
||
|
+ rv = autolayout_imsm(super, raiddisks, size, *chunk,
|
||
|
+ freesize);
|
||
|
+ if (rv != IMSM_STATUS_OK)
|
||
|
+ return 0;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
@@ -11538,7 +11584,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
|
||
|
unsigned long long current_size;
|
||
|
unsigned long long free_size;
|
||
|
unsigned long long max_size;
|
||
|
- int rv;
|
||
|
+ imsm_status_t rv;
|
||
|
|
||
|
getinfo_super_imsm_volume(st, &info, NULL);
|
||
|
if (geo->level != info.array.level && geo->level >= 0 &&
|
||
|
@@ -11657,9 +11703,10 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
|
||
|
}
|
||
|
/* check the maximum available size
|
||
|
*/
|
||
|
- rv = imsm_get_free_size(st, dev->vol.map->num_members,
|
||
|
- 0, chunk, &free_size);
|
||
|
- if (rv == 0)
|
||
|
+ rv = imsm_get_free_size(super, dev->vol.map->num_members,
|
||
|
+ 0, chunk, &free_size);
|
||
|
+
|
||
|
+ if (rv != IMSM_STATUS_OK)
|
||
|
/* Cannot find maximum available space
|
||
|
*/
|
||
|
max_size = 0;
|
||
|
--
|
||
|
2.35.3
|
||
|
|