215 lines
7.1 KiB
Diff
215 lines
7.1 KiB
Diff
From aa19fdd45b2ba474f6a51a6d4b8f3c44ef19dafd Mon Sep 17 00:00:00 2001
|
|
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
|
|
Date: Mon, 29 May 2023 15:52:37 +0200
|
|
Subject: [PATCH 131/165] imsm: return free space after volume for expand
|
|
|
|
merge_extends() routine searches for the biggest free space. For expand,
|
|
it works only in standard cases where the last volume is expanded and
|
|
the free space is determined after the last volume.
|
|
Add volume index to extent struct and use that do determine size after
|
|
super->current_vol during expand.
|
|
|
|
Limitation to last volume is no longer needed. It unblocks scenarios
|
|
where kill-subarray is used to remove first volume and later it is
|
|
recreated (now it is the second volume, even if it is placed before
|
|
existing one).
|
|
|
|
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
|
|
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
|
|
---
|
|
super-intel.c | 71 +++++++++++++++++++++++++++------------------------
|
|
1 file changed, 37 insertions(+), 34 deletions(-)
|
|
|
|
diff --git a/super-intel.c b/super-intel.c
|
|
index 5bd70356..e249d925 100644
|
|
--- a/super-intel.c
|
|
+++ b/super-intel.c
|
|
@@ -499,8 +499,15 @@ struct intel_disk {
|
|
struct intel_disk *next;
|
|
};
|
|
|
|
+/**
|
|
+ * struct extent - reserved space details.
|
|
+ * @start: start offset.
|
|
+ * @size: size of reservation, set to 0 for metadata reservation.
|
|
+ * @vol: index of the volume, meaningful if &size is set.
|
|
+ */
|
|
struct extent {
|
|
unsigned long long start, size;
|
|
+ int vol;
|
|
};
|
|
|
|
/* definitions of reshape process types */
|
|
@@ -1539,9 +1546,10 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl,
|
|
int get_minimal_reservation)
|
|
{
|
|
/* find a list of used extents on the given physical device */
|
|
- struct extent *rv, *e;
|
|
- int i;
|
|
int memberships = count_memberships(dl, super);
|
|
+ struct extent *rv = xcalloc(memberships + 1, sizeof(struct extent));
|
|
+ struct extent *e = rv;
|
|
+ int i;
|
|
__u32 reservation;
|
|
|
|
/* trim the reserved area for spares, so they can join any array
|
|
@@ -1553,9 +1561,6 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl,
|
|
else
|
|
reservation = MPB_SECTOR_CNT + IMSM_RESERVED_SECTORS;
|
|
|
|
- rv = xcalloc(sizeof(struct extent), (memberships + 1));
|
|
- e = rv;
|
|
-
|
|
for (i = 0; i < super->anchor->num_raid_devs; i++) {
|
|
struct imsm_dev *dev = get_imsm_dev(super, i);
|
|
struct imsm_map *map = get_imsm_map(dev, MAP_0);
|
|
@@ -1563,6 +1568,7 @@ static struct extent *get_extents(struct intel_super *super, struct dl *dl,
|
|
if (get_imsm_disk_slot(map, dl->index) >= 0) {
|
|
e->start = pba_of_lba0(map);
|
|
e->size = per_dev_array_size(map);
|
|
+ e->vol = i;
|
|
e++;
|
|
}
|
|
}
|
|
@@ -6894,24 +6900,26 @@ static unsigned long long find_size(struct extent *e, int *idx, int num_extents)
|
|
return end - base_start;
|
|
}
|
|
|
|
-/** merge_extents() - analyze extents and get max common free size.
|
|
+/** merge_extents() - analyze extents and get free size.
|
|
* @super: Intel metadata, not NULL.
|
|
+ * @expanding: if set, we are expanding &super->current_vol.
|
|
*
|
|
- * Build a composite disk with all known extents and generate a new maxsize
|
|
- * given the "all disks in an array must share a common start offset"
|
|
- * constraint.
|
|
+ * Build a composite disk with all known extents and generate a size given the
|
|
+ * "all disks in an array must share a common start offset" constraint.
|
|
+ * If a volume is expanded, then return free space after the volume.
|
|
*
|
|
- * Return: Max free space or 0 on failure.
|
|
+ * Return: Free space or 0 on failure.
|
|
*/
|
|
-static unsigned long long merge_extents(struct intel_super *super)
|
|
+static unsigned long long merge_extents(struct intel_super *super, const bool expanding)
|
|
{
|
|
struct extent *e;
|
|
struct dl *dl;
|
|
- int i, j;
|
|
- int start_extent, sum_extents = 0;
|
|
- unsigned long long pos;
|
|
+ int i, j, pos_vol_idx = -1;
|
|
+ int extent_idx = 0;
|
|
+ int sum_extents = 0;
|
|
+ unsigned long long pos = 0;
|
|
unsigned long long start = 0;
|
|
- unsigned long long maxsize;
|
|
+ unsigned long long maxsize = 0;
|
|
unsigned long reserve;
|
|
|
|
for (dl = super->disks; dl; dl = dl->next)
|
|
@@ -6936,26 +6944,26 @@ static unsigned long long merge_extents(struct intel_super *super)
|
|
j = 0;
|
|
while (i < sum_extents) {
|
|
e[j].start = e[i].start;
|
|
+ e[j].vol = e[i].vol;
|
|
e[j].size = find_size(e, &i, sum_extents);
|
|
j++;
|
|
if (e[j-1].size == 0)
|
|
break;
|
|
}
|
|
|
|
- pos = 0;
|
|
- maxsize = 0;
|
|
- start_extent = 0;
|
|
i = 0;
|
|
do {
|
|
- unsigned long long esize;
|
|
+ unsigned long long esize = e[i].start - pos;
|
|
|
|
- esize = e[i].start - pos;
|
|
- if (esize >= maxsize) {
|
|
+ if (expanding ? pos_vol_idx == super->current_vol : esize >= maxsize) {
|
|
maxsize = esize;
|
|
start = pos;
|
|
- start_extent = i;
|
|
+ extent_idx = i;
|
|
}
|
|
+
|
|
pos = e[i].start + e[i].size;
|
|
+ pos_vol_idx = e[i].vol;
|
|
+
|
|
i++;
|
|
} while (e[i-1].size);
|
|
free(e);
|
|
@@ -6966,7 +6974,7 @@ static unsigned long long merge_extents(struct intel_super *super)
|
|
/* FIXME assumes volume at offset 0 is the first volume in a
|
|
* container
|
|
*/
|
|
- if (start_extent > 0)
|
|
+ if (extent_idx > 0)
|
|
reserve = IMSM_RESERVED_SECTORS; /* gap between raid regions */
|
|
else
|
|
reserve = 0;
|
|
@@ -7577,7 +7585,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
|
|
return 0;
|
|
}
|
|
|
|
- maxsize = merge_extents(super);
|
|
+ maxsize = merge_extents(super, false);
|
|
|
|
if (mpb->num_raid_devs > 0 && size && size != maxsize)
|
|
pr_err("attempting to create a second volume with size less then remaining space.\n");
|
|
@@ -7626,7 +7634,8 @@ 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)
|
|
+ unsigned long long *freesize,
|
|
+ bool expanding)
|
|
{
|
|
struct imsm_super *mpb = super->anchor;
|
|
struct dl *dl;
|
|
@@ -7663,7 +7672,7 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super,
|
|
cnt++;
|
|
}
|
|
|
|
- maxsize = merge_extents(super);
|
|
+ maxsize = merge_extents(super, expanding);
|
|
if (maxsize < minsize) {
|
|
pr_err("imsm: Free space is %llu but must be equal or larger than %llu.\n",
|
|
maxsize, minsize);
|
|
@@ -7721,7 +7730,7 @@ static imsm_status_t autolayout_imsm(struct intel_super *super,
|
|
int vol_cnt = super->anchor->num_raid_devs;
|
|
imsm_status_t rv;
|
|
|
|
- rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize);
|
|
+ rv = imsm_get_free_size(super, raiddisks, size, chunk, freesize, false);
|
|
if (rv != IMSM_STATUS_OK)
|
|
return IMSM_STATUS_ERROR;
|
|
|
|
@@ -11685,19 +11694,13 @@ static imsm_status_t imsm_analyze_expand(struct supertype *st,
|
|
goto success;
|
|
}
|
|
|
|
- if (super->current_vol + 1 != super->anchor->num_raid_devs) {
|
|
- pr_err("imsm: The last volume in container can be expanded only (%i/%s).\n",
|
|
- super->current_vol, st->devnm);
|
|
- return IMSM_STATUS_ERROR;
|
|
- }
|
|
-
|
|
if (data_disks == 0) {
|
|
pr_err("imsm: Cannot retrieve data disks.\n");
|
|
return IMSM_STATUS_ERROR;
|
|
}
|
|
current_size = array->custom_array_size / data_disks;
|
|
|
|
- rv = imsm_get_free_size(super, dev->vol.map->num_members, 0, chunk_kib, &free_size);
|
|
+ rv = imsm_get_free_size(super, dev->vol.map->num_members, 0, chunk_kib, &free_size, true);
|
|
if (rv != IMSM_STATUS_OK) {
|
|
pr_err("imsm: Cannot find free space for expand.\n");
|
|
return IMSM_STATUS_ERROR;
|
|
--
|
|
2.40.1
|
|
|