You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
252 lines
7.8 KiB
252 lines
7.8 KiB
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/52] imsm: use same slot across container |
|
|
|
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 cd1f1e3d..deef7c87 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.31.1 |
|
|
|
|