import mdadm-4.2-12.el9_4

c9 imports/c9/mdadm-4.2-12.el9_4
MSVSphere Packaging Team 8 months ago
parent 8cb1d79ccd
commit d621d90f47

@ -0,0 +1,33 @@
From cf1577bf54afe76b77ecaa62df25901739ca8ae9 Mon Sep 17 00:00:00 2001
From: Mateusz Grzonka <mateusz.grzonka@intel.com>
Date: Wed, 5 Jul 2023 16:34:56 +0200
Subject: [PATCH 126/165] imsm: Fix possible segfault in check_no_platform()
conf_line() may return NULL, which is not handled and might cause
segfault.
Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
super-intel.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/super-intel.c b/super-intel.c
index ae0f4a8c..4ef33d31 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -650,6 +650,11 @@ static int check_no_platform(void)
char *l = conf_line(fp);
char *w = l;
+ if (l == NULL) {
+ fclose(fp);
+ return 0;
+ }
+
do {
if (strcmp(w, search) == 0)
no_platform = 1;
--
2.40.1

@ -0,0 +1,105 @@
From 9bc426fa1f236b8cad518431574a54fc60718739 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Mon, 29 May 2023 15:52:33 +0200
Subject: [PATCH 127/165] imsm: move sum_extents calculations to
merge_extents()
This logic is only used by merge_extents() code, there is no need to pass
it as parameter. Move it up. Add proper description.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
super-intel.c | 37 +++++++++++++++++++------------------
1 file changed, 19 insertions(+), 18 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index 4ef33d31..26b20313 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -6882,21 +6882,31 @@ static unsigned long long find_size(struct extent *e, int *idx, int num_extents)
return end - base_start;
}
-static unsigned long long merge_extents(struct intel_super *super, int sum_extents)
+/** merge_extents() - analyze extents and get max common free size.
+ * @super: Intel metadata, not NULL.
+ *
+ * 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.
+ *
+ * Return: Max free space or 0 on failure.
+ */
+static unsigned long long merge_extents(struct intel_super *super)
{
- /* 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
- */
- struct extent *e = xcalloc(sum_extents, sizeof(*e));
+ struct extent *e;
struct dl *dl;
int i, j;
- int start_extent;
+ int start_extent, sum_extents = 0;
unsigned long long pos;
unsigned long long start = 0;
unsigned long long maxsize;
unsigned long reserve;
+ for (dl = super->disks; dl; dl = dl->next)
+ if (dl->e)
+ sum_extents += dl->extent_cnt;
+ e = xcalloc(sum_extents, sizeof(struct extent));
+
/* coalesce and sort all extents. also, check to see if we need to
* reserve space between member arrays
*/
@@ -7555,13 +7565,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
return 0;
}
- /* count total number of extents for merge */
- i = 0;
- for (dl = super->disks; dl; dl = dl->next)
- if (dl->e)
- i += dl->extent_cnt;
-
- maxsize = merge_extents(super, i);
+ maxsize = merge_extents(super);
if (mpb->num_raid_devs > 0 && size && size != maxsize)
pr_err("attempting to create a second volume with size less then remaining space.\n");
@@ -7615,7 +7619,6 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super,
struct imsm_super *mpb = super->anchor;
struct dl *dl;
int i;
- int extent_cnt;
struct extent *e;
unsigned long long maxsize;
unsigned long long minsize;
@@ -7624,7 +7627,6 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super,
/* find the largest common start free region of the possible disks */
used = 0;
- extent_cnt = 0;
cnt = 0;
for (dl = super->disks; dl; dl = dl->next) {
dl->raiddisk = -1;
@@ -7645,11 +7647,10 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super,
;
dl->e = e;
dl->extent_cnt = i;
- extent_cnt += i;
cnt++;
}
- maxsize = merge_extents(super, extent_cnt);
+ maxsize = merge_extents(super);
minsize = size;
if (size == 0)
/* chunk is in K */
--
2.40.1

@ -0,0 +1,72 @@
From 5f027b9357c011ca0421400e258a777d97f18d17 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Mon, 29 May 2023 15:52:34 +0200
Subject: [PATCH 128/165] imsm: imsm_get_free_size() refactor.
Move minsize calculations up. Add error message if free size is too small.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
super-intel.c | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index 26b20313..16a30ba7 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -7600,7 +7600,7 @@ static int validate_geometry_imsm_volume(struct supertype *st, int level,
* @super: &intel_super pointer, not NULL.
* @raiddisks: number of raid disks.
* @size: requested size, could be 0 (means max size).
- * @chunk: requested chunk.
+ * @chunk: requested chunk size in KiB.
* @freesize: pointer for returned size value.
*
* Return: &IMSM_STATUS_OK or &IMSM_STATUS_ERROR.
@@ -7620,14 +7620,15 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super,
struct dl *dl;
int i;
struct extent *e;
+ int cnt = 0;
+ int used = 0;
unsigned long long maxsize;
- unsigned long long minsize;
- int cnt;
- int used;
+ unsigned long long minsize = size;
+
+ if (minsize == 0)
+ minsize = chunk * 2;
/* find the largest common start free region of the possible disks */
- used = 0;
- cnt = 0;
for (dl = super->disks; dl; dl = dl->next) {
dl->raiddisk = -1;
@@ -7651,14 +7652,14 @@ static imsm_status_t imsm_get_free_size(struct intel_super *super,
}
maxsize = merge_extents(super);
- minsize = size;
- if (size == 0)
- /* chunk is in K */
- minsize = chunk * 2;
+ if (maxsize < minsize) {
+ pr_err("imsm: Free space is %llu but must be equal or larger than %llu.\n",
+ maxsize, minsize);
+ return IMSM_STATUS_ERROR;
+ }
- if (cnt < raiddisks || (super->orom && used && used != raiddisks) ||
- maxsize < minsize || maxsize == 0) {
- pr_err("not enough devices with space to create array.\n");
+ if (cnt < raiddisks || (super->orom && used && used != raiddisks)) {
+ pr_err("imsm: Not enough devices with space to create array.\n");
return IMSM_STATUS_ERROR;
}
--
2.40.1

@ -0,0 +1,68 @@
From 78c8028b331c8e281554d43fde4d46e9cb4a227e Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Mon, 29 May 2023 15:52:35 +0200
Subject: [PATCH 129/165] imsm: introduce round_member_size_to_mb()
Extract rounding logic to separate function.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
super-intel.c | 31 +++++++++++++++++++++----------
1 file changed, 21 insertions(+), 10 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index 16a30ba7..36171107 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -1644,17 +1644,29 @@ static int is_journal(struct imsm_disk *disk)
return (disk->status & JOURNAL_DISK) == JOURNAL_DISK;
}
-/* round array size down to closest MB and ensure it splits evenly
- * between members
+/**
+ * round_member_size_to_mb()- Round given size to closest MiB.
+ * @size: size to round in sectors.
*/
-static unsigned long long round_size_to_mb(unsigned long long size, unsigned int
- disk_count)
+static inline unsigned long long round_member_size_to_mb(unsigned long long size)
{
- size /= disk_count;
- size = (size >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT;
- size *= disk_count;
+ return (size >> SECT_PER_MB_SHIFT) << SECT_PER_MB_SHIFT;
+}
- return size;
+/**
+ * round_size_to_mb()- Round given size.
+ * @array_size: size to round in sectors.
+ * @disk_count: count of data members.
+ *
+ * Get size per each data member and round it to closest MiB to ensure that data
+ * splits evenly between members.
+ *
+ * Return: Array size, rounded down.
+ */
+static inline unsigned long long round_size_to_mb(unsigned long long array_size,
+ unsigned int disk_count)
+{
+ return round_member_size_to_mb(array_size / disk_count) * disk_count;
}
static int able_to_resync(int raid_level, int missing_disks)
@@ -11810,8 +11822,7 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
} else {
/* round size due to metadata compatibility
*/
- geo->size = (geo->size >> SECT_PER_MB_SHIFT)
- << SECT_PER_MB_SHIFT;
+ geo->size = round_member_size_to_mb(geo->size);
dprintf("Prepare update for size change to %llu\n",
geo->size );
if (current_size >= geo->size) {
--
2.40.1

@ -0,0 +1,238 @@
From cbaa7904a175628a294ed54b4de6c52afa4f830d Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Mon, 29 May 2023 15:52:36 +0200
Subject: [PATCH 130/165] imsm: move expand verification code into new function
The code here is too complex. Move it to separate function and
simplify it. Add more error messages.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
super-intel.c | 187 +++++++++++++++++++++++++++-----------------------
1 file changed, 101 insertions(+), 86 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index 36171107..5bd70356 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -11643,6 +11643,102 @@ static void imsm_update_metadata_locally(struct supertype *st,
}
}
+/**
+ * imsm_analyze_expand() - check expand properties and calculate new size.
+ * @st: imsm supertype.
+ * @geo: new geometry params.
+ * @array: array info.
+ * @direction: reshape direction.
+ *
+ * Obtain free space after the &array and verify if expand to requested size is
+ * possible. If geo->size is set to %MAX_SIZE, assume that max free size is
+ * requested.
+ *
+ * Return:
+ * On success %IMSM_STATUS_OK is returned, geo->size and geo->raid_disks are
+ * updated.
+ * On error, %IMSM_STATUS_ERROR is returned.
+ */
+static imsm_status_t imsm_analyze_expand(struct supertype *st,
+ struct geo_params *geo,
+ struct mdinfo *array,
+ int direction)
+{
+ struct intel_super *super = st->sb;
+ struct imsm_dev *dev = get_imsm_dev(super, super->current_vol);
+ struct imsm_map *map = get_imsm_map(dev, MAP_0);
+ int data_disks = imsm_num_data_members(map);
+
+ unsigned long long current_size;
+ unsigned long long free_size;
+ unsigned long long new_size;
+ unsigned long long max_size;
+
+ const int chunk_kib = geo->chunksize / 1024;
+ imsm_status_t rv;
+
+ if (direction == ROLLBACK_METADATA_CHANGES) {
+ /**
+ * Accept size for rollback only.
+ */
+ new_size = geo->size * 2;
+ 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);
+ if (rv != IMSM_STATUS_OK) {
+ pr_err("imsm: Cannot find free space for expand.\n");
+ return IMSM_STATUS_ERROR;
+ }
+ max_size = round_member_size_to_mb(free_size + current_size);
+
+ if (geo->size == MAX_SIZE)
+ new_size = max_size;
+ else
+ new_size = round_member_size_to_mb(geo->size * 2);
+
+ if (new_size == 0) {
+ pr_err("imsm: Rounded requested size is 0.\n");
+ return IMSM_STATUS_ERROR;
+ }
+
+ if (new_size > max_size) {
+ pr_err("imsm: Rounded requested size (%llu) is larger than free space available (%llu).\n",
+ new_size, max_size);
+ return IMSM_STATUS_ERROR;
+ }
+
+ if (new_size == current_size) {
+ pr_err("imsm: Rounded requested size (%llu) is same as current size (%llu).\n",
+ new_size, current_size);
+ return IMSM_STATUS_ERROR;
+ }
+
+ if (new_size < current_size) {
+ pr_err("imsm: Size reduction is not supported, rounded requested size (%llu) is smaller than current (%llu).\n",
+ new_size, current_size);
+ return IMSM_STATUS_ERROR;
+ }
+
+success:
+ dprintf("imsm: New size per member is %llu.\n", new_size);
+ geo->size = data_disks * new_size;
+ geo->raid_disks = dev->vol.map->num_members;
+ return IMSM_STATUS_OK;
+}
+
/***************************************************************************
* Function: imsm_analyze_change
* Description: Function analyze change for single volume
@@ -11663,13 +11759,6 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
int devNumChange = 0;
/* imsm compatible layout value for array geometry verification */
int imsm_layout = -1;
- int data_disks;
- struct imsm_dev *dev;
- struct imsm_map *map;
- struct intel_super *super;
- unsigned long long current_size;
- unsigned long long free_size;
- unsigned long long max_size;
imsm_status_t rv;
getinfo_super_imsm_volume(st, &info, NULL);
@@ -11752,94 +11841,20 @@ enum imsm_reshape_type imsm_analyze_change(struct supertype *st,
geo->chunksize = info.array.chunk_size;
}
- chunk = geo->chunksize / 1024;
-
- super = st->sb;
- dev = get_imsm_dev(super, super->current_vol);
- map = get_imsm_map(dev, MAP_0);
- data_disks = imsm_num_data_members(map);
- /* compute current size per disk member
- */
- current_size = info.custom_array_size / data_disks;
-
- if (geo->size > 0 && geo->size != MAX_SIZE) {
- /* align component size
- */
- geo->size = imsm_component_size_alignment_check(
- get_imsm_raid_level(dev->vol.map),
- chunk * 1024, super->sector_size,
- geo->size * 2);
- if (geo->size == 0) {
- pr_err("Error. Size expansion is supported only (current size is %llu, requested size /rounded/ is 0).\n",
- current_size);
- goto analyse_change_exit;
- }
- }
-
- if (current_size != geo->size && geo->size > 0) {
+ if (geo->size > 0) {
if (change != -1) {
pr_err("Error. Size change should be the only one at a time.\n");
change = -1;
goto analyse_change_exit;
}
- if ((super->current_vol + 1) != super->anchor->num_raid_devs) {
- pr_err("Error. The last volume in container can be expanded only (%i/%s).\n",
- super->current_vol, st->devnm);
- goto analyse_change_exit;
- }
- /* check the maximum available size
- */
- rv = imsm_get_free_size(super, dev->vol.map->num_members,
- 0, chunk, &free_size);
+ rv = imsm_analyze_expand(st, geo, &info, direction);
if (rv != IMSM_STATUS_OK)
- /* Cannot find maximum available space
- */
- max_size = 0;
- else {
- max_size = free_size + current_size;
- /* align component size
- */
- max_size = imsm_component_size_alignment_check(
- get_imsm_raid_level(dev->vol.map),
- chunk * 1024, super->sector_size,
- max_size);
- }
- if (geo->size == MAX_SIZE) {
- /* requested size change to the maximum available size
- */
- if (max_size == 0) {
- pr_err("Error. Cannot find maximum available space.\n");
- change = -1;
- goto analyse_change_exit;
- } else
- geo->size = max_size;
- }
-
- if (direction == ROLLBACK_METADATA_CHANGES) {
- /* accept size for rollback only
- */
- } else {
- /* round size due to metadata compatibility
- */
- geo->size = round_member_size_to_mb(geo->size);
- dprintf("Prepare update for size change to %llu\n",
- geo->size );
- if (current_size >= geo->size) {
- pr_err("Error. Size expansion is supported only (current size is %llu, requested size /rounded/ is %llu).\n",
- current_size, geo->size);
- goto analyse_change_exit;
- }
- if (max_size && geo->size > max_size) {
- pr_err("Error. Requested size is larger than maximum available size (maximum available size is %llu, requested size /rounded/ is %llu).\n",
- max_size, geo->size);
- goto analyse_change_exit;
- }
- }
- geo->size *= data_disks;
- geo->raid_disks = dev->vol.map->num_members;
+ goto analyse_change_exit;
change = CH_ARRAY_SIZE;
}
+
+ chunk = geo->chunksize / 1024;
if (!validate_geometry_imsm(st,
geo->level,
imsm_layout,
--
2.40.1

@ -0,0 +1,214 @@
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

@ -0,0 +1,113 @@
From 1dea84ae38288fbefa04d9fda2b3f36c21a9e1bd Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Mon, 29 May 2023 15:52:38 +0200
Subject: [PATCH 132/165] imsm: fix free space calculations
Between two volumes or between last volume and metadata at least
IMSM_RESERVED_SECTORS gap must exist. Currently the gap can be doubled
because metadata reservation contains IMSM_RESERVED_SECTORS too.
Divide reserve variable into pre_reservation and post_reservation to be
more flexible and decide separately if each reservation is needed.
Pre_reservation is needed only when a volume is created and it is not a
real first volume in a container (we can check that by extent_idx).
This type of reservation is not needed for expand.
Post_reservation is not needed only if real last volume is created or
expanded because reservation is done with the metadata.
The volume index in metadata cannot be trusted, because the real volume
order can be reversed. It is safer to use extent table, it is sorted by
start position.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
super-intel.c | 50 ++++++++++++++++++++++++++++++--------------------
1 file changed, 30 insertions(+), 20 deletions(-)
diff --git a/super-intel.c b/super-intel.c
index e249d925..824c1356 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -6919,8 +6919,11 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex
int sum_extents = 0;
unsigned long long pos = 0;
unsigned long long start = 0;
- unsigned long long maxsize = 0;
- unsigned long reserve;
+ unsigned long long free_size = 0;
+
+ unsigned long pre_reservation = 0;
+ unsigned long post_reservation = IMSM_RESERVED_SECTORS;
+ unsigned long reservation_size;
for (dl = super->disks; dl; dl = dl->next)
if (dl->e)
@@ -6955,8 +6958,8 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex
do {
unsigned long long esize = e[i].start - pos;
- if (expanding ? pos_vol_idx == super->current_vol : esize >= maxsize) {
- maxsize = esize;
+ if (expanding ? pos_vol_idx == super->current_vol : esize >= free_size) {
+ free_size = esize;
start = pos;
extent_idx = i;
}
@@ -6966,28 +6969,35 @@ static unsigned long long merge_extents(struct intel_super *super, const bool ex
i++;
} while (e[i-1].size);
- free(e);
- if (maxsize == 0)
+ if (free_size == 0) {
+ dprintf("imsm: Cannot find free size.\n");
+ free(e);
return 0;
+ }
- /* FIXME assumes volume at offset 0 is the first volume in a
- * container
- */
- if (extent_idx > 0)
- reserve = IMSM_RESERVED_SECTORS; /* gap between raid regions */
- else
- reserve = 0;
+ if (!expanding && extent_idx != 0)
+ /*
+ * Not a real first volume in a container is created, pre_reservation is needed.
+ */
+ pre_reservation = IMSM_RESERVED_SECTORS;
- if (maxsize < reserve)
- return 0;
+ if (e[extent_idx].size == 0)
+ /*
+ * extent_idx points to the metadata, post_reservation is allready done.
+ */
+ post_reservation = 0;
+ free(e);
- super->create_offset = ~((unsigned long long) 0);
- if (start + reserve > super->create_offset)
- return 0; /* start overflows create_offset */
- super->create_offset = start + reserve;
+ reservation_size = pre_reservation + post_reservation;
+
+ if (free_size < reservation_size) {
+ dprintf("imsm: Reservation size is greater than free space.\n");
+ return 0;
+ }
- return maxsize - reserve;
+ super->create_offset = start + pre_reservation;
+ return free_size - reservation_size;
}
static int is_raid_level_supported(const struct imsm_orom *orom, int level, int raiddisks)
--
2.40.1

@ -0,0 +1,124 @@
From 21e622f214a38c048c5689158bc6314a91a46e40 Mon Sep 17 00:00:00 2001
From: Blazej Kucman <blazej.kucman@intel.com>
Date: Fri, 16 Jun 2023 21:45:55 +0200
Subject: [PATCH 133/165] Add secure gethostname() wrapper
gethostname() func does not ensure null-terminated string
if hostname is longer than buffer length.
For security, a function s_gethostname() has been added
to ensure that "\0" is added to the end of the buffer.
Previously this had to be handled in each place
of the gethostname() call.
Signed-off-by: Blazej Kucman <blazej.kucman@intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Monitor.c | 3 +--
lib.c | 19 +++++++++++++++++++
mapfile.c | 3 +--
mdadm.c | 3 +--
mdadm.h | 1 +
super-ddf.c | 3 +--
6 files changed, 24 insertions(+), 8 deletions(-)
diff --git a/Monitor.c b/Monitor.c
index 66175968..e74a0558 100644
--- a/Monitor.c
+++ b/Monitor.c
@@ -222,11 +222,10 @@ int Monitor(struct mddev_dev *devlist,
info.dosyslog = dosyslog;
info.test = c->test;
- if (gethostname(info.hostname, sizeof(info.hostname)) != 0) {
+ if (s_gethostname(info.hostname, sizeof(info.hostname)) != 0) {
pr_err("Cannot get hostname.\n");
return 1;
}
- info.hostname[sizeof(info.hostname) - 1] = '\0';
if (share){
if (check_one_sharer(c->scan) == 2)
diff --git a/lib.c b/lib.c
index fe5c8d2c..8a4b48e0 100644
--- a/lib.c
+++ b/lib.c
@@ -585,3 +585,22 @@ int parse_num(int *dest, const char *num)
*dest = temp;
return 0;
}
+
+/**
+ * s_gethostname() - secure get hostname. Assure null-terminated string.
+ *
+ * @buf: buffer for hostname.
+ * @buf_len: buffer length.
+ *
+ * Return: gethostname() result.
+ */
+int s_gethostname(char *buf, int buf_len)
+{
+ assert(buf);
+
+ int ret = gethostname(buf, buf_len);
+
+ buf[buf_len - 1] = 0;
+
+ return ret;
+}
diff --git a/mapfile.c b/mapfile.c
index 34fea179..f1f3ee2c 100644
--- a/mapfile.c
+++ b/mapfile.c
@@ -363,8 +363,7 @@ void RebuildMap(void)
char *homehost = conf_get_homehost(&require_homehost);
if (homehost == NULL || strcmp(homehost, "<system>")==0) {
- if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) {
- sys_hostname[sizeof(sys_hostname)-1] = 0;
+ if (s_gethostname(sys_hostname, sizeof(sys_hostname)) == 0) {
homehost = sys_hostname;
}
}
diff --git a/mdadm.c b/mdadm.c
index 076b45e0..e32598cb 100644
--- a/mdadm.c
+++ b/mdadm.c
@@ -1340,8 +1340,7 @@ int main(int argc, char *argv[])
if (c.homehost == NULL && c.require_homehost)
c.homehost = conf_get_homehost(&c.require_homehost);
if (c.homehost == NULL || strcasecmp(c.homehost, "<system>") == 0) {
- if (gethostname(sys_hostname, sizeof(sys_hostname)) == 0) {
- sys_hostname[sizeof(sys_hostname)-1] = 0;
+ if (s_gethostname(sys_hostname, sizeof(sys_hostname)) == 0) {
c.homehost = sys_hostname;
}
}
diff --git a/mdadm.h b/mdadm.h
index 83f2cf7f..f0ceeb78 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -1805,6 +1805,7 @@ extern void set_dlm_hooks(void);
extern void sleep_for(unsigned int sec, long nsec, bool wake_after_interrupt);
extern bool is_directory(const char *path);
extern bool is_file(const char *path);
+extern int s_gethostname(char *buf, int buf_len);
#define _ROUND_UP(val, base) (((val) + (base) - 1) & ~(base - 1))
#define ROUND_UP(val, base) _ROUND_UP(val, (typeof(val))(base))
diff --git a/super-ddf.c b/super-ddf.c
index 7213284e..c5242654 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -2364,8 +2364,7 @@ static int init_super_ddf(struct supertype *st,
* Remaining 16 are serial number.... maybe a hostname would do?
*/
memcpy(ddf->controller.guid, T10, sizeof(T10));
- gethostname(hostname, sizeof(hostname));
- hostname[sizeof(hostname) - 1] = 0;
+ s_gethostname(hostname, sizeof(hostname));
hostlen = strlen(hostname);
memcpy(ddf->controller.guid + 24 - hostlen, hostname, hostlen);
for (i = strlen(T10) ; i+hostlen < 24; i++)
--
2.40.1

@ -0,0 +1,41 @@
From 1ab341e5ce0cb01a1533a2c36e5b69eabf12bf95 Mon Sep 17 00:00:00 2001
From: Xiao Ni <xni@redhat.com>
Date: Fri, 25 Aug 2023 20:55:41 +0800
Subject: [PATCH 134/165] mdadm: Stop mdcheck_continue timer when mdcheck_start
service can finish check
mdcheck_continue is triggered by mdcheck_start timer. It's used to
continue check action if the raid is too big and mdcheck_start
service can't finish check action. If mdcheck start can finish check
action, it doesn't need to mdcheck continue service anymore. So stop
it when mdcheck start service can finish check action.
Signed-off-by: Xiao Ni <xni@redhat.com>
Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
misc/mdcheck | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/misc/mdcheck b/misc/mdcheck
index 700c3e25..f87999d3 100644
--- a/misc/mdcheck
+++ b/misc/mdcheck
@@ -140,7 +140,13 @@ do
echo $a > $fl
any=yes
done
- if [ -z "$any" ]; then exit 0; fi
+ # mdcheck_continue.timer is started by mdcheck_start.timer.
+ # When the check action can be finished in mdcheck_start.service,
+ # it doesn't need mdcheck_continue anymore.
+ if [ -z "$any" ]; then
+ systemctl stop mdcheck_continue.timer
+ exit 0;
+ fi
sleep 120
done
--
2.40.1

@ -0,0 +1,90 @@
From e9fb93af0f769d147a13e86ab4e5d0aeb935e9fc Mon Sep 17 00:00:00 2001
From: Guanqin Miao <miaoguanqin@huawei.com>
Date: Mon, 24 Apr 2023 16:06:34 +0800
Subject: [PATCH 135/165] Fix memory leak in file Assemble
When we test mdadm with asan, we found some memory leaks in Assemble.c
We fix these memory leaks based on code logic.
v2: Set st = NULL before jumping to loop
Signed-off-by: Guanqin Miao <miaoguanqin@huawei.com>
Signed-off-by: Li Xiao Keng <lixiaokeng@huawei.com>
Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Assemble.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/Assemble.c b/Assemble.c
index 49804941..61e8cd17 100644
--- a/Assemble.c
+++ b/Assemble.c
@@ -341,8 +341,10 @@ static int select_devices(struct mddev_dev *devlist,
st->ss->free_super(st);
dev_policy_free(pol);
domain_free(domains);
- if (tst)
+ if (tst) {
tst->ss->free_super(tst);
+ free(tst);
+ }
return -1;
}
@@ -417,6 +419,7 @@ static int select_devices(struct mddev_dev *devlist,
st->ss->free_super(st);
dev_policy_free(pol);
domain_free(domains);
+ free(st);
return -1;
}
if (c->verbose > 0)
@@ -425,6 +428,8 @@ static int select_devices(struct mddev_dev *devlist,
/* make sure we finished the loop */
tmpdev = NULL;
+ free(st);
+ st = NULL;
goto loop;
} else {
content = *contentp;
@@ -533,6 +538,7 @@ static int select_devices(struct mddev_dev *devlist,
st->ss->free_super(st);
dev_policy_free(pol);
domain_free(domains);
+ free(tst);
return -1;
}
tmpdev->used = 1;
@@ -546,8 +552,10 @@ static int select_devices(struct mddev_dev *devlist,
}
dev_policy_free(pol);
pol = NULL;
- if (tst)
+ if (tst) {
tst->ss->free_super(tst);
+ free(tst);
+ }
}
/* Check if we found some imsm spares but no members */
@@ -839,6 +847,7 @@ static int load_devices(struct devs *devices, char *devmap,
close(mdfd);
free(devices);
free(devmap);
+ free(best);
*stp = st;
return -1;
}
@@ -1950,6 +1959,7 @@ out:
} else if (mdfd >= 0)
close(mdfd);
+ free(best);
/* '2' means 'OK, but not started yet' */
if (rv == -1) {
free(devices);
--
2.40.1

@ -0,0 +1,54 @@
From 8fd0c565b09ba449418d7d604ceba66313246152 Mon Sep 17 00:00:00 2001
From: Guanqin Miao <miaoguanqin@huawei.com>
Date: Mon, 24 Apr 2023 16:06:35 +0800
Subject: [PATCH 136/165] Fix memory leak in file Kill
When we test mdadm with asan, we found some memory leaks in Kill.c
We fix these memory leaks based on code logic.
Signed-off-by: Guanqin Miao <miaoguanqin@huawei.com>
Signed-off-by: Li Xiao Keng <lixiaokeng@huawei.com>
Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Kill.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/Kill.c b/Kill.c
index bfd0efdc..43c9abed 100644
--- a/Kill.c
+++ b/Kill.c
@@ -41,6 +41,7 @@ int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl)
* 4 - failed to find a superblock.
*/
+ bool free_super = false;
int fd, rv = 0;
if (force)
@@ -52,8 +53,10 @@ int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl)
dev);
return 2;
}
- if (st == NULL)
+ if (st == NULL) {
st = guess_super(fd);
+ free_super = true;
+ }
if (st == NULL || st->ss->init_super == NULL) {
if (verbose >= 0)
pr_err("Unrecognised md component device - %s\n", dev);
@@ -77,6 +80,10 @@ int Kill(char *dev, struct supertype *st, int force, int verbose, int noexcl)
rv = 0;
}
}
+ if (free_super && st) {
+ st->ss->free_super(st);
+ free(st);
+ }
close(fd);
return rv;
}
--
2.40.1

@ -0,0 +1,74 @@
From f6feb3fbb50f48c193e9e4d775a20aa20f7b47b3 Mon Sep 17 00:00:00 2001
From: Guanqin Miao <miaoguanqin@huawei.com>
Date: Mon, 24 Apr 2023 16:06:36 +0800
Subject: [PATCH 137/165] Fix memory leak in file Manage
When we test mdadm with asan, we found some memory leaks in Manage.c
We fix these memory leaks based on code logic.
v2: Fix free() of uninitialized 'tst' in abort path.
Signed-off-by: Guanqin Miao <miaoguanqin@huawei.com>
Signed-off-by: Li Xiao Keng <lixiaokeng@huawei.com>
Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Manage.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/Manage.c b/Manage.c
index f54de7c6..f997b163 100644
--- a/Manage.c
+++ b/Manage.c
@@ -222,6 +222,7 @@ int Manage_stop(char *devname, int fd, int verbose, int will_retry)
if (verbose >= 0)
pr_err("Cannot get exclusive access to %s:Perhaps a running process, mounted filesystem or active volume group?\n",
devname);
+ sysfs_free(mdi);
return 1;
}
/* If this is an mdmon managed array, just write 'inactive'
@@ -801,8 +802,14 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
rdev, update, devname,
verbose, array);
dev_st->ss->free_super(dev_st);
- if (rv)
+ if (rv) {
+ free(dev_st);
return rv;
+ }
+ }
+ if (dev_st) {
+ dev_st->ss->free_super(dev_st);
+ free(dev_st);
}
}
if (dv->disposition == 'M') {
@@ -1362,7 +1369,7 @@ int Manage_subdevs(char *devname, int fd,
unsigned long long array_size;
struct mddev_dev *dv;
int tfd = -1;
- struct supertype *tst;
+ struct supertype *tst = NULL;
char *subarray = NULL;
int sysfd = -1;
int count = 0; /* number of actions taken */
@@ -1699,6 +1706,7 @@ int Manage_subdevs(char *devname, int fd,
break;
}
}
+ free(tst);
if (frozen > 0)
sysfs_set_str(&info, NULL, "sync_action","idle");
if (test && count == 0)
@@ -1706,6 +1714,7 @@ int Manage_subdevs(char *devname, int fd,
return 0;
abort:
+ free(tst);
if (frozen > 0)
sysfs_set_str(&info, NULL, "sync_action","idle");
return !test && busy ? 2 : 1;
--
2.40.1

@ -0,0 +1,34 @@
From e62a561ee8b7157a2390eab215dcef6240bd7b03 Mon Sep 17 00:00:00 2001
From: Guanqin Miao <miaoguanqin@huawei.com>
Date: Mon, 24 Apr 2023 16:06:37 +0800
Subject: [PATCH 138/165] Fix memory leak in file mdadm
When we test mdadm with asan, we found some memory leaks in mdadm.c
We fix these memory leaks based on code logic.
Signed-off-by: Guanqin Miao <miaoguanqin@huawei.com>
Signed-off-by: Li Xiao Keng <lixiaokeng@huawei.com>
Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
mdadm.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/mdadm.c b/mdadm.c
index e32598cb..22d1c53b 100644
--- a/mdadm.c
+++ b/mdadm.c
@@ -1708,6 +1708,10 @@ int main(int argc, char *argv[])
autodetect();
break;
}
+ if (ss) {
+ ss->ss->free_super(ss);
+ free(ss);
+ }
if (locked)
cluster_release_dlmlock();
close_fd(&mdfd);
--
2.40.1

@ -0,0 +1,116 @@
From dd5ab40204b1d78ec3bdbcfd5a38a8ffb72bdb50 Mon Sep 17 00:00:00 2001
From: Kinga Tanska <kinga.tanska@intel.com>
Date: Thu, 11 May 2023 04:55:12 +0200
Subject: [PATCH 139/165] Fix unsafe string functions
Add string length limitations where necessary to
avoid buffer overflows.
Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
mdmon.c | 6 +++---
mdopen.c | 4 ++--
platform-intel.c | 2 +-
super-intel.c | 6 +++---
4 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/mdmon.c b/mdmon.c
index cef5bbc8..a2038fe6 100644
--- a/mdmon.c
+++ b/mdmon.c
@@ -240,7 +240,7 @@ static int make_control_sock(char *devname)
return -1;
addr.sun_family = PF_LOCAL;
- strcpy(addr.sun_path, path);
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
umask(077); /* ensure no world write access */
if (bind(sfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
close(sfd);
@@ -389,7 +389,7 @@ int main(int argc, char *argv[])
if (all) {
struct mdstat_ent *mdstat, *e;
- int container_len = strlen(container_name);
+ int container_len = strnlen(container_name, MD_NAME_MAX);
/* launch an mdmon instance for each container found */
mdstat = mdstat_read(0, 0);
@@ -472,7 +472,7 @@ static int mdmon(char *devnm, int must_fork, int takeover)
pfd[0] = pfd[1] = -1;
container = xcalloc(1, sizeof(*container));
- strcpy(container->devnm, devnm);
+ snprintf(container->devnm, MD_NAME_MAX, "%s", devnm);
container->arrays = NULL;
container->sock = -1;
diff --git a/mdopen.c b/mdopen.c
index d3022a54..3daa71f9 100644
--- a/mdopen.c
+++ b/mdopen.c
@@ -193,14 +193,14 @@ int create_mddev(char *dev, char *name, int autof, int trustworthy,
if (dev) {
if (strncmp(dev, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) {
- strcpy(cname, dev + DEV_MD_DIR_LEN);
+ snprintf(cname, MD_NAME_MAX, "%s", dev + DEV_MD_DIR_LEN);
} else if (strncmp(dev, "/dev/", 5) == 0) {
char *e = dev + strlen(dev);
while (e > dev && isdigit(e[-1]))
e--;
if (e[0])
num = strtoul(e, NULL, 10);
- strcpy(cname, dev+5);
+ snprintf(cname, MD_NAME_MAX, "%s", dev + 5);
cname[e-(dev+5)] = 0;
/* name *must* be mdXX or md_dXX in this context */
if (num < 0 ||
diff --git a/platform-intel.c b/platform-intel.c
index 914164c0..eb6e1b7e 100644
--- a/platform-intel.c
+++ b/platform-intel.c
@@ -214,7 +214,7 @@ struct sys_dev *device_by_id_and_path(__u16 device_id, const char *path)
static int devpath_to_ll(const char *dev_path, const char *entry, unsigned long long *val)
{
- char path[strlen(dev_path) + strlen(entry) + 2];
+ char path[strnlen(dev_path, PATH_MAX) + strnlen(entry, PATH_MAX) + 2];
int fd;
int n;
diff --git a/super-intel.c b/super-intel.c
index 824c1356..ce813172 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -7043,7 +7043,7 @@ active_arrays_by_format(char *name, char* hba, struct md_list **devlist,
int fd = -1;
while (dev && !is_fd_valid(fd)) {
char *path = xmalloc(strlen(dev->name) + strlen("/dev/") + 1);
- num = sprintf(path, "%s%s", "/dev/", dev->name);
+ num = snprintf(path, PATH_MAX, "%s%s", "/dev/", dev->name);
if (num > 0)
fd = open(path, O_RDONLY, 0);
if (num <= 0 || !is_fd_valid(fd)) {
@@ -7935,7 +7935,7 @@ static int kill_subarray_imsm(struct supertype *st, char *subarray_id)
if (i < current_vol)
continue;
- sprintf(subarray, "%u", i);
+ snprintf(subarray, sizeof(subarray), "%u", i);
if (is_subarray_active(subarray, st->devnm)) {
pr_err("deleting subarray-%d would change the UUID of active subarray-%d, aborting\n",
current_vol, i);
@@ -11308,7 +11308,7 @@ static const char *imsm_get_disk_controller_domain(const char *path)
char *drv=NULL;
struct stat st;
- strcpy(disk_path, disk_by_path);
+ strncpy(disk_path, disk_by_path, PATH_MAX);
strncat(disk_path, path, PATH_MAX - strlen(disk_path) - 1);
if (stat(disk_path, &st) == 0) {
struct sys_dev* hba;
--
2.40.1

@ -0,0 +1,55 @@
From 5ccd457b29809bee442749b5f66ac27ebba4a72d Mon Sep 17 00:00:00 2001
From: Kinga Tanska <kinga.tanska@intel.com>
Date: Thu, 11 May 2023 04:55:13 +0200
Subject: [PATCH 140/165] platform-intel: limit guid length
Moving GUID_STR_MAX to header to use it as
a length limitation for snprintf function.
Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
platform-intel.c | 3 ---
platform-intel.h | 5 ++++-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/platform-intel.c b/platform-intel.c
index eb6e1b7e..ef90c3fd 100644
--- a/platform-intel.c
+++ b/platform-intel.c
@@ -510,9 +510,6 @@ static const struct imsm_orom *find_imsm_hba_orom(struct sys_dev *hba)
return get_orom_by_device_id(hba->dev_id);
}
-#define GUID_STR_MAX 37 /* according to GUID format:
- * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */
-
#define EFI_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
((struct efi_guid) \
{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \
diff --git a/platform-intel.h b/platform-intel.h
index 2c0f4e39..ba97fb04 100644
--- a/platform-intel.h
+++ b/platform-intel.h
@@ -19,6 +19,9 @@
#include <asm/types.h>
#include <strings.h>
+/* according to GUID format: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" */
+#define GUID_STR_MAX 37
+
/* The IMSM Capability (IMSM AHCI and ISCU OROM/EFI variable) Version Table definition */
struct imsm_orom {
__u8 signature[4];
@@ -229,7 +232,7 @@ extern struct orom_entry *orom_entries;
static inline char *guid_str(char *buf, struct efi_guid guid)
{
- sprintf(buf, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+ snprintf(buf, GUID_STR_MAX, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
guid.b[3], guid.b[2], guid.b[1], guid.b[0],
guid.b[5], guid.b[4], guid.b[7], guid.b[6],
guid.b[8], guid.b[9], guid.b[10], guid.b[11],
--
2.40.1

@ -0,0 +1,220 @@
From 8d1114be8c0a307d251c24078833b029efabc448 Mon Sep 17 00:00:00 2001
From: Mateusz Grzonka <mateusz.grzonka@intel.com>
Date: Wed, 5 Jul 2023 16:23:17 +0200
Subject: [PATCH 141/165] imsm: Add reading vmd register for finding imsm
capability
Currently mdadm does not find imsm capability when running inside VM.
This patch adds the possibility to read from vmd register and check for
capability, effectively allowing to use mdadm with imsm inside virtual machines.
Additionally refactor find_imsm_capability() to make assignments in new
lines.
Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
platform-intel.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++-
platform-intel.h | 11 ++++-
super-intel.c | 11 +++--
3 files changed, 130 insertions(+), 6 deletions(-)
diff --git a/platform-intel.c b/platform-intel.c
index ef90c3fd..ac282bc5 100644
--- a/platform-intel.c
+++ b/platform-intel.c
@@ -700,6 +700,106 @@ const struct imsm_orom *find_imsm_nvme(struct sys_dev *hba)
return &nvme_orom->orom;
}
+#define VMD_REGISTER_OFFSET 0x3FC
+#define VMD_REGISTER_SKU_SHIFT 1
+#define VMD_REGISTER_SKU_MASK (0x00000007)
+#define VMD_REGISTER_SKU_PREMIUM 2
+#define MD_REGISTER_VER_MAJOR_SHIFT 4
+#define MD_REGISTER_VER_MAJOR_MASK (0x0000000F)
+#define MD_REGISTER_VER_MINOR_SHIFT 8
+#define MD_REGISTER_VER_MINOR_MASK (0x0000000F)
+
+/*
+ * read_vmd_register() - Reads VMD register and writes contents to buff ptr
+ * @buff: buffer for vmd register data, should be the size of uint32_t
+ *
+ * Return: 0 on success, 1 on error
+ */
+int read_vmd_register(uint32_t *buff, struct sys_dev *hba)
+{
+ int fd;
+ char vmd_pci_config_path[PATH_MAX];
+
+ if (!vmd_domain_to_controller(hba, vmd_pci_config_path))
+ return 1;
+
+ strncat(vmd_pci_config_path, "/config", PATH_MAX - strnlen(vmd_pci_config_path, PATH_MAX));
+
+ fd = open(vmd_pci_config_path, O_RDONLY);
+ if (fd < 0)
+ return 1;
+
+ if (pread(fd, buff, sizeof(uint32_t), VMD_REGISTER_OFFSET) != sizeof(uint32_t)) {
+ close(fd);
+ return 1;
+ }
+ close(fd);
+ return 0;
+}
+
+/*
+ * add_vmd_orom() - Adds VMD orom cap to orom list, writes orom_entry ptr into vmd_orom
+ * @vmd_orom: pointer to orom entry pointer
+ *
+ * Return: 0 on success, 1 on error
+ */
+int add_vmd_orom(struct orom_entry **vmd_orom, struct sys_dev *hba)
+{
+ uint8_t sku;
+ uint32_t vmd_register_data;
+ struct imsm_orom vmd_orom_cap = {
+ .signature = IMSM_VMD_OROM_COMPAT_SIGNATURE,
+ .sss = IMSM_OROM_SSS_4kB | IMSM_OROM_SSS_8kB |
+ IMSM_OROM_SSS_16kB | IMSM_OROM_SSS_32kB |
+ IMSM_OROM_SSS_64kB | IMSM_OROM_SSS_128kB,
+ .dpa = IMSM_OROM_DISKS_PER_ARRAY_NVME,
+ .tds = IMSM_OROM_TOTAL_DISKS_VMD,
+ .vpa = IMSM_OROM_VOLUMES_PER_ARRAY,
+ .vphba = IMSM_OROM_VOLUMES_PER_HBA_VMD,
+ .attr = IMSM_OROM_ATTR_2TB | IMSM_OROM_ATTR_2TB_DISK,
+ .driver_features = IMSM_OROM_CAPABILITIES_EnterpriseSystem |
+ IMSM_OROM_CAPABILITIES_TPV
+ };
+
+ if (read_vmd_register(&vmd_register_data, hba) != 0)
+ return 1;
+
+ sku = (uint8_t)((vmd_register_data >> VMD_REGISTER_SKU_SHIFT) &
+ VMD_REGISTER_SKU_MASK);
+
+ if (sku == VMD_REGISTER_SKU_PREMIUM)
+ vmd_orom_cap.rlc = IMSM_OROM_RLC_RAID0 | IMSM_OROM_RLC_RAID1 |
+ IMSM_OROM_RLC_RAID10 | IMSM_OROM_RLC_RAID5;
+ else
+ vmd_orom_cap.rlc = IMSM_OROM_RLC_RAID_CNG;
+
+ vmd_orom_cap.major_ver = (uint8_t)
+ ((vmd_register_data >> MD_REGISTER_VER_MAJOR_SHIFT) &
+ MD_REGISTER_VER_MAJOR_MASK);
+ vmd_orom_cap.minor_ver = (uint8_t)
+ ((vmd_register_data >> MD_REGISTER_VER_MINOR_SHIFT) &
+ MD_REGISTER_VER_MINOR_MASK);
+
+ *vmd_orom = add_orom(&vmd_orom_cap);
+
+ return 0;
+}
+
+const struct imsm_orom *find_imsm_vmd(struct sys_dev *hba)
+{
+ static struct orom_entry *vmd_orom;
+
+ if (hba->type != SYS_DEV_VMD)
+ return NULL;
+
+ if (!vmd_orom && add_vmd_orom(&vmd_orom, hba) != 0)
+ return NULL;
+
+ add_orom_device_id(vmd_orom, hba->dev_id);
+ vmd_orom->type = SYS_DEV_VMD;
+ return &vmd_orom->orom;
+}
+
const struct imsm_orom *find_imsm_capability(struct sys_dev *hba)
{
const struct imsm_orom *cap = get_orom_by_device_id(hba->dev_id);
@@ -709,9 +809,19 @@ const struct imsm_orom *find_imsm_capability(struct sys_dev *hba)
if (hba->type == SYS_DEV_NVME)
return find_imsm_nvme(hba);
- if ((cap = find_imsm_efi(hba)) != NULL)
+
+ cap = find_imsm_efi(hba);
+ if (cap)
return cap;
- if ((cap = find_imsm_hba_orom(hba)) != NULL)
+
+ if (hba->type == SYS_DEV_VMD) {
+ cap = find_imsm_vmd(hba);
+ if (cap)
+ return cap;
+ }
+
+ cap = find_imsm_hba_orom(hba);
+ if (cap)
return cap;
return NULL;
diff --git a/platform-intel.h b/platform-intel.h
index ba97fb04..ce29d3da 100644
--- a/platform-intel.h
+++ b/platform-intel.h
@@ -27,6 +27,7 @@ struct imsm_orom {
__u8 signature[4];
#define IMSM_OROM_SIGNATURE "$VER"
#define IMSM_NVME_OROM_COMPAT_SIGNATURE "$NVM"
+ #define IMSM_VMD_OROM_COMPAT_SIGNATURE "$VMD"
__u8 table_ver_major; /* Currently 2 (can change with future revs) */
__u8 table_ver_minor; /* Currently 2 (can change with future revs) */
__u16 major_ver; /* Example: 8 as in 8.6.0.1020 */
@@ -68,11 +69,13 @@ struct imsm_orom {
__u16 tds; /* Total Disks Supported */
#define IMSM_OROM_TOTAL_DISKS 6
#define IMSM_OROM_TOTAL_DISKS_NVME 12
+ #define IMSM_OROM_TOTAL_DISKS_VMD 48
__u8 vpa; /* # Volumes Per Array supported */
#define IMSM_OROM_VOLUMES_PER_ARRAY 2
__u8 vphba; /* # Volumes Per Host Bus Adapter supported */
#define IMSM_OROM_VOLUMES_PER_HBA 4
#define IMSM_OROM_VOLUMES_PER_HBA_NVME 4
+ #define IMSM_OROM_VOLUMES_PER_HBA_VMD 24
/* Attributes supported. This should map to the
* attributes in the MPB. Also, lower 16 bits
* should match/duplicate RLC bits above.
@@ -185,7 +188,13 @@ static inline int imsm_orom_is_enterprise(const struct imsm_orom *orom)
static inline int imsm_orom_is_nvme(const struct imsm_orom *orom)
{
return memcmp(orom->signature, IMSM_NVME_OROM_COMPAT_SIGNATURE,
- sizeof(orom->signature)) == 0;
+ sizeof(orom->signature)) == 0;
+}
+
+static inline int imsm_orom_is_vmd_without_efi(const struct imsm_orom *orom)
+{
+ return memcmp(orom->signature, IMSM_VMD_OROM_COMPAT_SIGNATURE,
+ sizeof(orom->signature)) == 0;
}
static inline int imsm_orom_has_tpv_support(const struct imsm_orom *orom)
diff --git a/super-intel.c b/super-intel.c
index ce813172..77b0066f 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -2672,9 +2672,14 @@ static void print_imsm_capability(const struct imsm_orom *orom)
else
printf("Rapid Storage Technology%s\n",
imsm_orom_is_enterprise(orom) ? " enterprise" : "");
- if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build)
- printf(" Version : %d.%d.%d.%d\n", orom->major_ver,
- orom->minor_ver, orom->hotfix_ver, orom->build);
+ if (orom->major_ver || orom->minor_ver || orom->hotfix_ver || orom->build) {
+ if (imsm_orom_is_vmd_without_efi(orom))
+ printf(" Version : %d.%d\n", orom->major_ver,
+ orom->minor_ver);
+ else
+ printf(" Version : %d.%d.%d.%d\n", orom->major_ver,
+ orom->minor_ver, orom->hotfix_ver, orom->build);
+ }
printf(" RAID Levels :%s%s%s%s%s\n",
imsm_orom_has_raid0(orom) ? " raid0" : "",
imsm_orom_has_raid1(orom) ? " raid1" : "",
--
2.40.1

@ -0,0 +1,109 @@
From 55a1150c7438afcb7756fccd49713ede20a58e4a Mon Sep 17 00:00:00 2001
From: Mateusz Grzonka <mateusz.grzonka@intel.com>
Date: Mon, 17 Jul 2023 15:19:10 +0200
Subject: [PATCH 142/165] Add compiler defenses flags
It is essential to avoid buffer overflows and similar bugs as much as
possible.
According to Intel rules we are obligated to verify certain
compiler flags, so it will be much easier if they are added to the
Makefile.
Add gcc flags for prevention of buffer overflows, format string vulnerabilities,
stack protection to prevent stack overwrites and aslr enablement through -fPIE.
Also make the flags configurable.
The changes were verified on gcc versions 7.5, 8.3, 9.2, 10 and 12.2.
Signed-off-by: Mateusz Grzonka <mateusz.grzonka@intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Makefile | 41 +++++++++++++++++++++++++++++------------
1 file changed, 29 insertions(+), 12 deletions(-)
diff --git a/Makefile b/Makefile
index 5eac1a4e..b3aa36f6 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,7 @@
# define "CXFLAGS" to give extra flags to CC.
# e.g. make CXFLAGS=-O to optimise
-CXFLAGS ?=-O2
+CXFLAGS ?=-O2 -D_FORTIFY_SOURCE=2
TCC = tcc
UCLIBC_GCC = $(shell for nm in i386-uclibc-linux-gcc i386-uclibc-gcc; do which $$nm > /dev/null && { echo $$nm ; exit; } ; done; echo false No uclibc found )
#DIET_GCC = diet gcc
@@ -50,14 +50,30 @@ ifeq ($(origin CC),default)
CC := $(CROSS_COMPILE)gcc
endif
CXFLAGS ?= -ggdb
-CWFLAGS = -Wall -Werror -Wstrict-prototypes -Wextra -Wno-unused-parameter
+CWFLAGS ?= -Wall -Werror -Wstrict-prototypes -Wextra -Wno-unused-parameter -Wformat -Wformat-security -Werror=format-security -fstack-protector-strong -fPIE -Warray-bounds
ifdef WARN_UNUSED
-CWFLAGS += -Wp,-D_FORTIFY_SOURCE=2 -O3
+CWFLAGS += -Wp -O3
endif
-FALLTHROUGH := $(shell gcc -v --help 2>&1 | grep "implicit-fallthrough" | wc -l)
-ifneq "$(FALLTHROUGH)" "0"
-CWFLAGS += -Wimplicit-fallthrough=0
+ifeq ($(origin FALLTHROUGH), undefined)
+ FALLTHROUGH := $(shell gcc -Q --help=warnings 2>&1 | grep "implicit-fallthrough" | wc -l)
+ ifneq "$(FALLTHROUGH)" "0"
+ CWFLAGS += -Wimplicit-fallthrough=0
+ endif
+endif
+
+ifeq ($(origin FORMATOVERFLOW), undefined)
+ FORMATOVERFLOW := $(shell gcc -Q --help=warnings 2>&1 | grep "format-overflow" | wc -l)
+ ifneq "$(FORMATOVERFLOW)" "0"
+ CWFLAGS += -Wformat-overflow
+ endif
+endif
+
+ifeq ($(origin STRINGOPOVERFLOW), undefined)
+ STRINGOPOVERFLOW := $(shell gcc -Q --help=warnings 2>&1 | grep "stringop-overflow" | wc -l)
+ ifneq "$(STRINGOPOVERFLOW)" "0"
+ CWFLAGS += -Wstringop-overflow
+ endif
endif
ifdef DEBIAN
@@ -116,10 +132,12 @@ CFLAGS += -DUSE_PTHREADS
MON_LDFLAGS += -pthread
endif
+LDFLAGS = -Wl,-z,now,-z,noexecstack
+
# If you want a static binary, you might uncomment these
-# LDFLAGS = -static
+# LDFLAGS += -static
# STRIP = -s
-LDLIBS = -ldl
+LDLIBS = -ldl -pie
# To explicitly disable libudev, set -DNO_LIBUDEV in CXFLAGS
ifeq (, $(findstring -DNO_LIBUDEV, $(CXFLAGS)))
@@ -209,14 +227,13 @@ mdadm.Os : $(SRCS) $(INCL)
$(CC) -o mdadm.Os $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DHAVE_STDINT_H -Os $(SRCS) $(LDLIBS)
mdadm.O2 : $(SRCS) $(INCL) mdmon.O2
- $(CC) -o mdadm.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DHAVE_STDINT_H -O2 -D_FORTIFY_SOURCE=2 $(SRCS) $(LDLIBS)
+ $(CC) -o mdadm.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -DHAVE_STDINT_H -O2 $(SRCS) $(LDLIBS)
mdmon.O2 : $(MON_SRCS) $(INCL) mdmon.h
- $(CC) -o mdmon.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -DHAVE_STDINT_H -O2 -D_FORTIFY_SOURCE=2 $(MON_SRCS) $(LDLIBS)
+ $(CC) -o mdmon.O2 $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -DHAVE_STDINT_H -O2 $(MON_SRCS) $(LDLIBS)
-# use '-z now' to guarantee no dynamic linker interactions with the monitor thread
mdmon : $(MON_OBJS) | check_rundir
- $(CC) $(CFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -Wl,-z,now -o mdmon $(MON_OBJS) $(LDLIBS)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(MON_LDFLAGS) -o mdmon $(MON_OBJS) $(LDLIBS)
msg.o: msg.c msg.h
test_stripe : restripe.c xmalloc.o mdadm.h
--
2.40.1

@ -0,0 +1,34 @@
From 024d652e16dd9e3bd1ecdfce4d6f7a8cb498ba42 Mon Sep 17 00:00:00 2001
From: Kinga Tanska <kinga.tanska@intel.com>
Date: Tue, 12 Sep 2023 04:27:01 +0200
Subject: [PATCH 143/165] Assemble: fix redundant memory free
Commit e9fb93af0f76 ("Fix memory leak in file Assemble")
fixes few memory leaks in Assemble, but it introduces
problem with assembling RAID volume. It was caused by
clearing metadata too fast, not only on fail in
select_devices() function.
This commit removes redundant memory free.
Signed-off-by: Kinga Tanska <kinga.tanska@intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Assemble.c | 2 --
1 file changed, 2 deletions(-)
diff --git a/Assemble.c b/Assemble.c
index 61e8cd17..5be58e40 100644
--- a/Assemble.c
+++ b/Assemble.c
@@ -428,8 +428,6 @@ static int select_devices(struct mddev_dev *devlist,
/* make sure we finished the loop */
tmpdev = NULL;
- free(st);
- st = NULL;
goto loop;
} else {
content = *contentp;
--
2.40.1

@ -0,0 +1,92 @@
From 7fe21767d3ab65a686518d2e36d18a07f535972e Mon Sep 17 00:00:00 2001
From: Yu Kuai <yukuai3@huawei.com>
Date: Mon, 29 May 2023 21:28:19 +0800
Subject: [PATCH 144/165] tests: add a new test for rdev lifetime
This test add and remove a underlying disk to raid concurretly, verify
that the following problem is fixed:
run mdadm test 23rdev-lifetime at Fri Apr 28 03:25:30 UTC 2023
md: could not open device unknown-block(1,0).
sysfs: cannot create duplicate filename '/devices/virtual/block/md0/md/dev-ram0'
CPU: 26 PID: 10521 Comm: test Not tainted 6.3.0-rc2-00134-g7b3a8828043c #115
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.1-2.fc37 04/014
Call Trace:
<TASK>
dump_stack_lvl+0xe7/0x180
dump_stack+0x18/0x30
sysfs_warn_dup+0xa2/0xd0
sysfs_create_dir_ns+0x119/0x140
kobject_add_internal+0x143/0x4d0
kobject_add_varg+0x35/0x70
kobject_add+0x64/0xd0
bind_rdev_to_array+0x254/0x840 [md_mod]
new_dev_store+0x14d/0x350 [md_mod]
md_attr_store+0xc1/0x1a0 [md_mod]
sysfs_kf_write+0x51/0x70
kernfs_fop_write_iter+0x188/0x270
vfs_write+0x27e/0x460
ksys_write+0x85/0x180
__x64_sys_write+0x21/0x30
do_syscall_64+0x6c/0xe0
entry_SYSCALL_64_after_hwframe+0x63/0xcd
RIP: 0033:0x7f26bacf5387
Code: 0d 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 f3 0f 1e fa 64 84
RSP: 002b:00007ffe98d79e68 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
RAX: ffffffffffffffda RBX: 0000000000000004 RCX: 00007f26bacf5387
RDX: 0000000000000004 RSI: 000055bd10282bf0 RDI: 0000000000000001
RBP: 000055bd10282bf0 R08: 000000000000000a R09: 00007f26bad8b4e0
R10: 00007f26bad8b3e0 R11: 0000000000000246 R12: 0000000000000004
R13: 00007f26badc8520 R14: 0000000000000004 R15: 00007f26badc8700
</TASK>
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/23rdev-lifetime | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 tests/23rdev-lifetime
diff --git a/tests/23rdev-lifetime b/tests/23rdev-lifetime
new file mode 100644
index 00000000..1750b0db
--- /dev/null
+++ b/tests/23rdev-lifetime
@@ -0,0 +1,34 @@
+devname=${dev0##*/}
+devt=`cat /sys/block/$devname/dev`
+pid=""
+runtime=2
+
+clean_up_test() {
+ pill -9 $pid
+ echo clear > /sys/block/md0/md/array_state
+}
+
+trap 'clean_up_test' EXIT
+
+add_by_sysfs() {
+ while true; do
+ echo $devt > /sys/block/md0/md/new_dev
+ done
+}
+
+remove_by_sysfs(){
+ while true; do
+ echo remove > /sys/block/md0/md/dev-${devname}/state
+ done
+}
+
+echo md0 > /sys/module/md_mod/parameters/new_array || die "create md0 failed"
+
+add_by_sysfs &
+pid="$pid $!"
+
+remove_by_sysfs &
+pid="$pid $!"
+
+sleep $runtime
+exit 0
--
2.40.1

@ -0,0 +1,38 @@
From 0ef9465f6355db612e53afc32e3084721c3dd7c7 Mon Sep 17 00:00:00 2001
From: Yu Kuai <yukuai3@huawei.com>
Date: Mon, 29 May 2023 21:28:20 +0800
Subject: [PATCH 145/165] tests: support to skip checking dmesg
Prepare to add a regression test for raid10 that require error injection
to trigger error path, and kernel will complain about io error, checking
dmesg for error log will make it impossible to pass this test.
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
test | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/test b/test
index 61d9ee83..b244453b 100755
--- a/test
+++ b/test
@@ -107,8 +107,12 @@ do_test() {
echo -ne "$_script... "
if ( set -ex ; . $_script ) &> $targetdir/log
then
- dmesg | grep -iq "error\|call trace\|segfault" &&
- die "dmesg prints errors when testing $_basename!"
+ if [ -f "${_script}.inject_error" ]; then
+ echo "dmesg checking is skipped because test inject error"
+ else
+ dmesg | grep -iq "error\|call trace\|segfault" &&
+ die "dmesg prints errors when testing $_basename!"
+ fi
echo "succeeded"
_fail=0
else
--
2.40.1

@ -0,0 +1,122 @@
From 3973f65293ce69ddd7c19be9a7a796abfe80e370 Mon Sep 17 00:00:00 2001
From: Yu Kuai <yukuai3@huawei.com>
Date: Mon, 29 May 2023 21:28:21 +0800
Subject: [PATCH 146/165] tests: add a regression test for raid10 deadlock
The deadlock is described in [1], it's fixed first by [2], however,
it turns out this commit will trigger other problems[3], hence this
commit will be reverted and the deadlock is supposed to be fixed by [1].
[1] https://lore.kernel.org/linux-raid/20230322064122.2384589-5-yukuai1@huaweicloud.com/
[2] https://lore.kernel.org/linux-raid/20220621031129.24778-1-guoqing.jiang@linux.dev/
[3] https://lore.kernel.org/linux-raid/20230322064122.2384589-2-yukuai1@huaweicloud.com/
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/24raid10deadlock | 88 +++++++++++++++++++++++++++++
tests/24raid10deadlock.inject_error | 0
2 files changed, 88 insertions(+)
create mode 100644 tests/24raid10deadlock
create mode 100644 tests/24raid10deadlock.inject_error
diff --git a/tests/24raid10deadlock b/tests/24raid10deadlock
new file mode 100644
index 00000000..ee330aa9
--- /dev/null
+++ b/tests/24raid10deadlock
@@ -0,0 +1,88 @@
+devs="$dev0 $dev1 $dev2 $dev3"
+runtime=120
+pid=""
+action_pid=""
+
+set_up_injection()
+{
+ echo -1 > /sys/kernel/debug/fail_make_request/times
+ echo 1 > /sys/kernel/debug/fail_make_request/probability
+ echo 0 > /sys/kernel/debug/fail_make_request/verbose
+ echo 1 > /sys/block/${1##*/}/make-it-fail
+}
+
+clean_up_injection()
+{
+ echo 0 > /sys/block/${1##*/}/make-it-fail
+ echo 0 > /sys/kernel/debug/fail_make_request/times
+ echo 0 > /sys/kernel/debug/fail_make_request/probability
+ echo 2 > /sys/kernel/debug/fail_make_request/verbose
+}
+
+test_rdev()
+{
+ while true; do
+ mdadm -f $md0 $1 &> /dev/null
+ mdadm -r $md0 $1 &> /dev/null
+ mdadm --zero-superblock $1 &> /dev/null
+ mdadm -a $md0 $1 &> /dev/null
+ sleep $2
+ done
+}
+
+test_write_action()
+{
+ while true; do
+ echo frozen > /sys/block/md0/md/sync_action
+ echo idle > /sys/block/md0/md/sync_action
+ sleep 0.1
+ done
+}
+
+set_up_test()
+{
+ fio -h &> /dev/null || die "fio not found"
+
+ # create a simple raid10
+ mdadm -Cv -R -n 4 -l10 $md0 $devs || die "create raid10 failed"
+}
+
+clean_up_test()
+{
+ clean_up_injection $dev0
+ pkill -9 fio
+ kill -9 $pid
+ kill -9 $action_pid
+
+ sleep 1
+
+ if ps $action_pid | tail -1 | awk '{print $3}' | grep D; then
+ die "thread that is writing sysfs is stuck in D state, deadlock is triggered"
+ fi
+ mdadm -S $md0
+}
+
+cat /sys/kernel/debug/fail_make_request/times || die "fault injection is not enabled"
+
+trap 'clean_up_test' EXIT
+
+set_up_test || die "set up test failed"
+
+# backgroup io pressure
+fio -filename=$md0 -rw=randwrite -direct=1 -name=test -bs=4k -numjobs=16 -iodepth=16 &
+
+# trigger add/remove device by io failure
+set_up_injection $dev0
+test_rdev $dev0 2 &
+pid="$pid $!"
+
+# add/remove device directly
+test_rdev $dev3 10 &
+pid="$pid $!"
+
+test_write_action &
+action_pid="$!"
+
+sleep $runtime
+
+exit 0
diff --git a/tests/24raid10deadlock.inject_error b/tests/24raid10deadlock.inject_error
new file mode 100644
index 00000000..e69de29b
--
2.40.1

@ -0,0 +1,87 @@
From 9d0fb58f3b1314678564b4ac7bfb19942acc8926 Mon Sep 17 00:00:00 2001
From: Yu Kuai <yukuai3@huawei.com>
Date: Mon, 29 May 2023 21:28:22 +0800
Subject: [PATCH 147/165] tests: add a regression test for raid456 deadlock
The deadlock is described in [1], as the last patch described, it's
fixed first by [2], however this fix will be reverted and the deadlock
is supposed to be fixed by [3].
[1] https://lore.kernel.org/linux-raid/5ed54ffc-ce82-bf66-4eff-390cb23bc1ac@molgen.mpg.de/T/#t
[2] https://lore.kernel.org/linux-raid/20220621031129.24778-1-guoqing.jiang@linux.dev/
[3] https://lore.kernel.org/linux-raid/20230322064122.2384589-5-yukuai1@huaweicloud.com/
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/24raid456deadlock | 58 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 58 insertions(+)
create mode 100644 tests/24raid456deadlock
diff --git a/tests/24raid456deadlock b/tests/24raid456deadlock
new file mode 100644
index 00000000..80e6e97e
--- /dev/null
+++ b/tests/24raid456deadlock
@@ -0,0 +1,58 @@
+devs="$dev0 $dev1 $dev2 $dev3 $dev4 $dev5"
+runtime=120
+pid=""
+old=`cat /proc/sys/vm/dirty_background_ratio`
+
+test_write_action()
+{
+ while true; do
+ echo check > /sys/block/md0/md/sync_action &> /dev/null
+ sleep 0.1
+ echo idle > /sys/block/md0/md/sync_action &> /dev/null
+ done
+}
+
+test_write_back()
+{
+ fio -filename=$md0 -bs=4k -rw=write -numjobs=1 -name=test \
+ -time_based -runtime=$runtime &> /dev/null
+}
+
+set_up_test()
+{
+ fio -h &> /dev/null || die "fio not found"
+
+ # create a simple raid6
+ mdadm -Cv -R -n 6 -l6 $md0 $devs --assume-clean || die "create raid6 failed"
+
+ # trigger dirty pages write back
+ echo 0 > /proc/sys/vm/dirty_background_ratio
+}
+
+clean_up_test()
+{
+ echo $old > /proc/sys/vm/dirty_background_ratio
+
+ pkill -9 fio
+ kill -9 $pid
+
+ sleep 1
+
+ if ps $pid | tail -1 | awk '{print $3}' | grep D; then
+ die "thread that is writing sysfs is stuck in D state, deadlock is triggered"
+ fi
+ mdadm -S $md0
+}
+
+trap 'clean_up_test' EXIT
+
+set_up_test || die "set up test failed"
+
+test_write_back &
+
+test_write_action &
+pid="$!"
+
+sleep $runtime
+
+exit 0
--
2.40.1

@ -0,0 +1,59 @@
From 4db8a3d452daaf2def41ca45c36e36c5781627ac Mon Sep 17 00:00:00 2001
From: Yu Kuai <yukuai3@huawei.com>
Date: Mon, 29 May 2023 21:28:23 +0800
Subject: [PATCH 148/165] tests: add a regression test that raid456 can't
assemble
If recovery is interrupted and reshape is started, then this array can't
assemble anymore. The problem is supposed to be fixed by [1].
[1] https://lore.kernel.org/linux-raid/20230529031045.1760883-1-yukuai1@huaweicloud.com/
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/25raid456-reshape-while-recovery | 32 ++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 tests/25raid456-reshape-while-recovery
diff --git a/tests/25raid456-reshape-while-recovery b/tests/25raid456-reshape-while-recovery
new file mode 100644
index 00000000..b9f871f2
--- /dev/null
+++ b/tests/25raid456-reshape-while-recovery
@@ -0,0 +1,32 @@
+devs="$dev0 $dev1 $dev2"
+
+set_up_test()
+{
+ mdadm -Cv -R -n 3 -l5 $md0 $devs --assume-clean --size=50M || die "create array failed"
+ mdadm -a $md0 $dev3 $dev4 || die "failed to bind new disk to array"
+ echo 1000 > /sys/block/md0/md/sync_speed_max
+}
+
+clean_up_test()
+{
+ mdadm -S $md0
+}
+
+trap 'clean_up_test' EXIT
+
+set_up_test || die "set up test failed"
+
+# set up replacement
+echo want_replacement > /sys/block/md0/md/rd0/state
+sleep 1
+
+# trigger reshape
+echo frozen > /sys/block/md0/md/sync_action
+mdadm --grow -l 6 $md0
+sleep 1
+
+# reassemeble array
+mdadm -S $md0 || die "can't stop array"
+mdadm --assemble $md0 $devs $dev3 $dev4 || die "can't assemble array"
+
+exit 0
--
2.40.1

@ -0,0 +1,58 @@
From 8d45abd0c317d3f4971b779b4f8d1e33b5490dac Mon Sep 17 00:00:00 2001
From: Yu Kuai <yukuai3@huawei.com>
Date: Mon, 29 May 2023 21:28:24 +0800
Subject: [PATCH 149/165] tests: add a regression test that raid456 can't
assemble again
This is a regression test for commit 0aecb06e2249 ("md/raid5: don't allow
replacement while reshape is in progress").
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/25raid456-recovery-while-reshape | 33 ++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
create mode 100644 tests/25raid456-recovery-while-reshape
diff --git a/tests/25raid456-recovery-while-reshape b/tests/25raid456-recovery-while-reshape
new file mode 100644
index 00000000..3f6251bf
--- /dev/null
+++ b/tests/25raid456-recovery-while-reshape
@@ -0,0 +1,33 @@
+devs="$dev0 $dev1 $dev2"
+
+set_up_test()
+{
+ mdadm -Cv -R -n 3 -l5 $md0 $devs --assume-clean --size=50M || die "create array failed"
+ mdadm -a $md0 $dev3 $dev4 || die "failed to bind new disk to array"
+ echo 1000 > /sys/block/md0/md/sync_speed_max
+}
+
+clean_up_test()
+{
+ mdadm -S $md0
+}
+
+trap 'clean_up_test' EXIT
+
+set_up_test || die "set up test failed"
+
+# trigger reshape
+mdadm --grow -l 6 $md0
+sleep 1
+
+# set up replacement
+echo frozen > /sys/block/md0/md/sync_action
+echo want_replacement > /sys/block/md0/md/rd0/state
+echo reshape > /sys/block/md0/md/sync_action
+sleep 1
+
+# reassemeble array
+mdadm -S $md0 || die "can't stop array"
+mdadm --assemble $md0 $devs $dev3 $dev4 || die "can't assemble array"
+
+exit 0
--
2.40.1

@ -0,0 +1,60 @@
From 481433482942c2ee2990965af394eff059990901 Mon Sep 17 00:00:00 2001
From: Yu Kuai <yukuai3@huawei.com>
Date: Mon, 29 May 2023 21:28:25 +0800
Subject: [PATCH 150/165] tests: add a regression test that reshape can corrupt
data
This is a regression test for commit 1544e95c6dd8 ("md: fix data
corruption for raid456 when reshape restart while grow up").
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/25raid456-reshape-corrupt-data | 35 ++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
create mode 100644 tests/25raid456-reshape-corrupt-data
diff --git a/tests/25raid456-reshape-corrupt-data b/tests/25raid456-reshape-corrupt-data
new file mode 100644
index 00000000..fdb875fb
--- /dev/null
+++ b/tests/25raid456-reshape-corrupt-data
@@ -0,0 +1,35 @@
+devs="$dev0 $dev1 $dev2"
+
+set_up_test()
+{
+ mdadm -Cv -R -n 3 -l5 $md0 $devs --size=50M || die "create array failed"
+ mdadm -a $md0 $dev3 || die "failed to bind new disk to array"
+ mkfs.xfs -f $md0 || die "mkfs failed"
+ xfs_ncheck $md0 || die "check fs failed"
+}
+
+clean_up_test()
+{
+ mdadm -S $md0
+}
+
+trap 'clean_up_test' EXIT
+
+set_up_test || die "set up test failed"
+
+# trigger reshape
+echo 1000 > /sys/block/md0/md/sync_speed_max
+mdadm --grow -l 6 $md0
+sleep 1
+
+# stop and start reshape
+echo frozen > /sys/block/md0/md/sync_action
+echo system > /sys/block/md0/md/sync_speed_max
+echo reshape > /sys/block/md0/md/sync_action
+
+mdadm -W $md0
+
+# check if data is corrupted
+xfs_ncheck $md0 || die "data is corrupted after reshape"
+
+exit 0
--
2.40.1

@ -0,0 +1,59 @@
From c6c7bce5a3064ac9d2956ae42ecab27f2e33dc2b Mon Sep 17 00:00:00 2001
From: Yu Kuai <yukuai3@huawei.com>
Date: Mon, 29 May 2023 21:28:26 +0800
Subject: [PATCH 151/165] tests: add a regression test for raid456 deadlock
again
This is a regression test for commit ("md/raid5: fix a deadlock in the
case that reshape is interrupted").
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/25raid456-reshape-deadlock | 34 ++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
create mode 100644 tests/25raid456-reshape-deadlock
diff --git a/tests/25raid456-reshape-deadlock b/tests/25raid456-reshape-deadlock
new file mode 100644
index 00000000..bfa0cc56
--- /dev/null
+++ b/tests/25raid456-reshape-deadlock
@@ -0,0 +1,34 @@
+devs="$dev0 $dev1 $dev2"
+
+set_up_test()
+{
+ mdadm -Cv -R -n 3 -l5 $md0 $devs --size=50M || die "create array failed"
+ mdadm -a $md0 $dev3 || die "failed to bind new disk to array"
+ echo 1000 > /sys/block/md0/md/sync_speed_max
+}
+
+clean_up_test()
+{
+ echo idle > /sys/block/md0/md/sync_action
+ mdadm -S $md0
+}
+
+trap 'clean_up_test' EXIT
+
+set_up_test || die "set up test failed"
+
+# trigger reshape
+mdadm --grow -l 6 $md0
+sleep 1
+
+# stop reshape
+echo frozen > /sys/block/md0/md/sync_action
+
+# read accross reshape
+dd if=$md0 of=/dev/NULL bs=1m count=100 iflag=direct &> /dev/null &
+sleep 2
+
+# suspend array
+echo 1 > /sys/block/md0/md/suspend_lo
+
+exit 0
--
2.40.1

@ -0,0 +1,193 @@
From d5fee8654e41dc4067dfdc3312542f1f43ebe884 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Thu, 1 Jun 2023 09:27:45 +0200
Subject: [PATCH 152/165] tests: create names_template
Create templates directory and names_template. Move code from
00createnames. This code will be reused for 00confnames in next patch.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/00createnames | 86 +++++++---------------------------
tests/templates/names_template | 53 +++++++++++++++++++++
2 files changed, 70 insertions(+), 69 deletions(-)
create mode 100644 tests/templates/names_template
diff --git a/tests/00createnames b/tests/00createnames
index 64b81b92..064eeef2 100644
--- a/tests/00createnames
+++ b/tests/00createnames
@@ -1,93 +1,41 @@
set -x -e
+. tests/templates/names_template
# Test how <devname> and --name= are handled for create mode.
-# We need to check three properties, generated from those parameters:
-# - devnode name
-# - link in /dev/md/ (MD_DEVNAME property from --detail --export)
-# - name in metadata (MD_NAME property from --examine --export)
-
-function _verify() {
- local DEVNODE_NAME="$1"
- local WANTED_LINK="$2"
- local WANTED_NAME="$3"
-
- local RES="$(mdadm -D --export $DEVNODE_NAME | grep MD_DEVNAME)"
- if [[ "$?" != "0" ]]; then
- echo "Cannot get details for $DEVNODE_NAME - unexpected devnode."
- exit 1
- fi
-
- if [[ "$WANTED_LINK" != "empty" ]]; then
- local EXPECTED="MD_DEVNAME=$WANTED_LINK"
- if [[ "$RES" != "$EXPECTED" ]]; then
- echo "$RES doesn't match $EXPECTED."
- exit 1
- fi
- fi
-
-
- local RES="$(mdadm -E --export $dev0 | grep MD_NAME)"
- if [[ "$?" != "0" ]]; then
- echo "Cannot get metadata from $dev0."
- exit 1
- fi
-
- local EXPECTED="MD_NAME=$(hostname):$WANTED_NAME"
- if [[ "$RES" != "$EXPECTED" ]]; then
- echo "$RES doesn't match $EXPECTED."
- exit 1
- fi
-}
-
-function _create() {
- local DEVNAME=$1
- local NAME=$2
-
- if [[ -z "$NAME" ]]; then
- mdadm -CR "$DEVNAME" -l0 -n 1 $dev0 --force
- else
- mdadm -CR "$DEVNAME" --name="$NAME" -l0 -n 1 $dev0 --force
- fi
-
- if [[ "$?" != "0" ]]; then
- echo "Cannot create device."
- exit 1
- fi
-}
# The most trivial case.
-_create "/dev/md/name"
-_verify "/dev/md127" "name" "name"
+names_create "/dev/md/name"
+names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
-_create "name"
-_verify "/dev/md127" "name" "name"
+names_create "name"
+names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# Use 'mdX' as name.
-_create "/dev/md/md0"
-_verify "/dev/md127" "md0" "md0"
+names_create "/dev/md/md0"
+names_verify "/dev/md127" "md0" "md0"
mdadm -S "/dev/md127"
-_create "md0"
-_verify "/dev/md127" "md0" "md0"
+names_create "md0"
+names_verify "/dev/md127" "md0" "md0"
mdadm -S "/dev/md127"
# <devnode> is used to create MD_DEVNAME but, name is used to create MD_NAME.
-_create "/dev/md/devnode" "name"
-_verify "/dev/md127" "devnode" "name"
+names_create "/dev/md/devnode" "name"
+names_verify "/dev/md127" "devnode" "name"
mdadm -S "/dev/md127"
-_create "devnode" "name"
-_verify "/dev/md127" "devnode" "name"
+names_create "devnode" "name"
+names_verify "/dev/md127" "devnode" "name"
mdadm -S "/dev/md127"
# Devnode points to /dev/ directory. MD_DEVNAME doesn't exist.
-_create "/dev/md0"
-_verify "/dev/md0" "empty" "0"
+names_create "/dev/md0"
+names_verify "/dev/md0" "empty" "0"
mdadm -S "/dev/md0"
# Devnode points to /dev/ directory and name is set.
-_create "/dev/md0" "name"
-_verify "/dev/md0" "empty" "name"
+names_create "/dev/md0" "name"
+names_verify "/dev/md0" "empty" "name"
mdadm -S "/dev/md0"
diff --git a/tests/templates/names_template b/tests/templates/names_template
new file mode 100644
index 00000000..9f09be9e
--- /dev/null
+++ b/tests/templates/names_template
@@ -0,0 +1,53 @@
+# NAME is optional. Testing with native 1.2 superblock.
+function names_create() {
+ local DEVNAME=$1
+ local NAME=$2
+
+ if [[ -z "$NAME" ]]; then
+ mdadm -CR "$DEVNAME" -l0 -n 1 $dev0 --force
+ else
+ mdadm -CR "$DEVNAME" --name="$NAME" --metadata=1.2 -l0 -n 1 $dev0 --force
+ fi
+
+ if [[ "$?" != "0" ]]; then
+ echo "Cannot create device."
+ exit 1
+ fi
+}
+
+# Three properties to check:
+# - devnode name
+# - link in /dev/md/ (MD_DEVNAME property from --detail --export)
+# - name in metadata (MD_NAME property from --detail --export)- that works only with 1.2 sb.
+function names_verify() {
+ local DEVNODE_NAME="$1"
+ local WANTED_LINK="$2"
+ local WANTED_NAME="$3"
+
+ local RES="$(mdadm -D --export $DEVNODE_NAME | grep MD_DEVNAME)"
+ if [[ "$?" != "0" ]]; then
+ echo "Cannot get details for $DEVNODE_NAME - unexpected devnode."
+ exit 1
+ fi
+
+ if [[ "$WANTED_LINK" != "empty" ]]; then
+ local EXPECTED="MD_DEVNAME=$WANTED_LINK"
+ fi
+
+ if [[ "$RES" != "$EXPECTED" ]]; then
+ echo "$RES doesn't match $EXPECTED."
+ exit 1
+ fi
+
+ local RES="$(mdadm -D --export $DEVNODE_NAME | grep MD_NAME)"
+ if [[ "$?" != "0" ]]; then
+ echo "Cannot get metadata from $dev0."
+ exit 1
+ fi
+
+ local EXPECTED="MD_NAME=$(hostname):$WANTED_NAME"
+ if [[ "$RES" != "$EXPECTED" ]]; then
+ echo "$RES doesn't match $EXPECTED."
+ exit 1
+ fi
+}
--
2.40.1

@ -0,0 +1,164 @@
From 569a23425939e4bfc7b4d7f871d8510bb968f892 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Thu, 1 Jun 2023 09:27:46 +0200
Subject: [PATCH 153/165] tests: create 00confnames
The test is an attempt to document current implementation of devnode
and name handling for config entries. It is focused on incremental-
default way of array assembling on boot.
The expectations are aligned to current implementation for native
metadata because it is the most complicated scenario- both variables
can be set.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/00confnames | 107 +++++++++++++++++++++++++++++++++
tests/templates/names_template | 20 ++++++
2 files changed, 127 insertions(+)
create mode 100644 tests/00confnames
diff --git a/tests/00confnames b/tests/00confnames
new file mode 100644
index 00000000..25a7127b
--- /dev/null
+++ b/tests/00confnames
@@ -0,0 +1,107 @@
+set -x -e
+. tests/templates/names_template
+
+# Test how <devname> and <name> from config are handled during Incremental assemblation.
+# 1-6 <devnode> only tests (no <name> in config).
+# 6-10 <devname> and <name> combinations are tested.
+# 11-13 corner cases.
+
+names_create "/dev/md/name"
+local _UUID="$(mdadm -D --export /dev/md127 | grep MD_UUID | cut -d'=' -f2)"
+[[ "$_UUID" == "" ]] && echo "Cannot obtain UUID for $DEVNODE_NAME" && exit 1
+
+
+# 1. <devname> definition consistent with metadata name.
+names_make_conf $_UUID "/dev/md/name" "empty" $config
+mdadm -S "/dev/md127"
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+# 2. Same as 1, but use short name form of <devname>.
+names_make_conf $_UUID "name" "empty" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+# 3. Same as 1, but use different <devname> than metadata provides.
+names_make_conf $_UUID "/dev/md/other" "empty" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "other" "name"
+mdadm -S "/dev/md127"
+
+# 4. Same as 3, but use short name form of <devname>.
+names_make_conf $_UUID "other" "empty" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "other" "name"
+mdadm -S "/dev/md127"
+
+# 5. Force particular node creation by setting <devname> to /dev/mdX. Link is not created in this
+# case.
+names_make_conf $_UUID "/dev/md4" "empty" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md4" "empty" "name"
+mdadm -S "/dev/md4"
+
+# 6. <devname> set to /dev/mdX, <name> same as in metadata.
+# Metadata name and default node used - controversial. Current behavior documented.
+names_make_conf $_UUID "/dev/md22" "name" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+# 7. <devname> set to /dev/mdX, <name> different than in metadata.
+# Metadata name and default node used - controversial. Current behavior documented.
+names_make_conf $_UUID "/dev/md8" "other" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+# 8. Both <devname> and <name> different than in metadata.
+# Metadata name and default node used - controversial. Current behavior documented.
+names_make_conf $_UUID "devnode" "other_name" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+# 9. <devname> set to metadata name, <name> different than in metadata.
+# Metadata name and default node used - controversial. Current behavior documented.
+names_make_conf $_UUID "name" "other_name" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+# 10. Bad <devname> set, no <name>.
+# Metadata name and default node used - expected.
+names_make_conf $_UUID "/im/bad/devname" "empty" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+# 11. <devname> with some special symbols and locales, no <name>.
+# It needs to wait a while for timeout because udev cannot create a link - known issue.
+names_make_conf $_UUID "tźż-\.,<>st+-" "empty" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "tźż-\.,<>st+-" "name"
+mdadm -S "/dev/md127"
+
+# 12. No <devname> and <name> set.
+# Metadata name and default node used - expected.
+names_make_conf $_UUID "empty" "empty" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+# 13. No <devname>, <name> set to /dev/mdX.
+# Entry should be ignored, it is not ignored but result is good anyway.
+names_make_conf $_UUID "empty" "/dev/md12" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
+
+# 13. No <devname>, <name> with special symbols and locales.
+# Entry should be ignored, it is not ignored but result is good anyway.
+names_make_conf $_UUID "empty" "./\śćń#&" $config
+mdadm -I $dev0 --config=$config
+names_verify "/dev/md127" "name" "name"
+mdadm -S "/dev/md127"
diff --git a/tests/templates/names_template b/tests/templates/names_template
index 9f09be9e..8d2b5c81 100644
--- a/tests/templates/names_template
+++ b/tests/templates/names_template
@@ -51,3 +51,23 @@ function names_verify() {
exit 1
fi
}
+
+# Generate ARRAYLINE for tested array.
+names_make_conf() {
+ local UUID="$1"
+ local WANTED_DEVNAME="$2"
+ local WANTED_NAME="$3"
+ local CONF="$4"
+
+ local LINE="ARRAY metadata=1.2 UUID=$UUID"
+
+ if [[ "$WANTED_DEVNAME" != "empty" ]]; then
+ LINE="$LINE $WANTED_DEVNAME"
+ fi
+
+ if [[ "$WANTED_NAME" != "empty" ]]; then
+ LINE="$LINE name=$WANTED_NAME"
+ fi
+
+ echo $LINE > $CONF
+}
--
2.40.1

@ -0,0 +1,399 @@
From 330c07f8e4d26f4f2d068e11f09c9df8a3380087 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Thu, 1 Jun 2023 09:27:47 +0200
Subject: [PATCH 154/165] mdadm: set ident.devname if applicable
This patch tries to propagate the usage of struct mddev_ident for cmdline
where it is applicable. To avoid regression, this value is derived
from devlist->devname for applicable modes only.
As a result, the whole structure is passed to some functions. It produces
some changes for Build, Create and Assemble.
No functional changes intended.
The goal of the change is to unify devname validation which is done in
next patches.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Build.c | 21 +++++++++------------
Create.c | 35 ++++++++++++++++------------------
mdadm.c | 57 +++++++++++++++++++++++++-------------------------------
mdadm.h | 13 +++++--------
4 files changed, 55 insertions(+), 71 deletions(-)
diff --git a/Build.c b/Build.c
index 8d6f6f58..657ab315 100644
--- a/Build.c
+++ b/Build.c
@@ -24,8 +24,8 @@
#include "mdadm.h"
-int Build(char *mddev, struct mddev_dev *devlist,
- struct shape *s, struct context *c)
+int Build(struct mddev_ident *ident, struct mddev_dev *devlist, struct shape *s,
+ struct context *c)
{
/* Build a linear or raid0 arrays without superblocks
* We cannot really do any checks, we just do it.
@@ -75,13 +75,12 @@ int Build(char *mddev, struct mddev_dev *devlist,
/* We need to create the device. It can have no name. */
map_lock(&map);
- mdfd = create_mddev(mddev, NULL, c->autof, LOCAL,
+ mdfd = create_mddev(ident->devname, NULL, c->autof, LOCAL,
chosen_name, 0);
if (mdfd < 0) {
map_unlock(&map);
return 1;
}
- mddev = chosen_name;
map_update(&map, fd2devnm(mdfd), "none", uuid, chosen_name);
map_unlock(&map);
@@ -93,7 +92,7 @@ int Build(char *mddev, struct mddev_dev *devlist,
array.nr_disks = s->raiddisks;
array.raid_disks = s->raiddisks;
array.md_minor = 0;
- if (fstat_is_blkdev(mdfd, mddev, &rdev))
+ if (fstat_is_blkdev(mdfd, chosen_name, &rdev))
array.md_minor = minor(rdev);
array.not_persistent = 1;
array.state = 0; /* not clean, but no errors */
@@ -108,8 +107,7 @@ int Build(char *mddev, struct mddev_dev *devlist,
array.chunk_size = s->chunk*1024;
array.layout = s->layout;
if (md_set_array_info(mdfd, &array)) {
- pr_err("md_set_array_info() failed for %s: %s\n",
- mddev, strerror(errno));
+ pr_err("md_set_array_info() failed for %s: %s\n", chosen_name, strerror(errno));
goto abort;
}
@@ -178,8 +176,8 @@ int Build(char *mddev, struct mddev_dev *devlist,
}
if (bitmap_fd >= 0) {
if (ioctl(mdfd, SET_BITMAP_FILE, bitmap_fd) < 0) {
- pr_err("Cannot set bitmap file for %s: %s\n",
- mddev, strerror(errno));
+ pr_err("Cannot set bitmap file for %s: %s\n", chosen_name,
+ strerror(errno));
goto abort;
}
}
@@ -193,9 +191,8 @@ int Build(char *mddev, struct mddev_dev *devlist,
}
if (c->verbose >= 0)
- pr_err("array %s built and started.\n",
- mddev);
- wait_for(mddev, mdfd);
+ pr_err("array %s built and started.\n", chosen_name);
+ wait_for(chosen_name, mdfd);
close(mdfd);
return 0;
diff --git a/Create.c b/Create.c
index ea6a4745..a280c7bc 100644
--- a/Create.c
+++ b/Create.c
@@ -471,11 +471,8 @@ out:
return ret;
}
-int Create(struct supertype *st, char *mddev,
- char *name, int *uuid,
- int subdevs, struct mddev_dev *devlist,
- struct shape *s,
- struct context *c)
+int Create(struct supertype *st, struct mddev_ident *ident, int subdevs,
+ struct mddev_dev *devlist, struct shape *s, struct context *c)
{
/*
* Create a new raid array.
@@ -497,6 +494,8 @@ int Create(struct supertype *st, char *mddev,
unsigned long long minsize = 0, maxsize = 0;
char *mindisc = NULL;
char *maxdisc = NULL;
+ char *name = ident->name;
+ int *uuid = ident->uuid_set == 1 ? ident->uuid : NULL;
int dnum;
struct mddev_dev *dv;
dev_t rdev;
@@ -1015,7 +1014,7 @@ int Create(struct supertype *st, char *mddev,
/* We need to create the device */
map_lock(&map);
- mdfd = create_mddev(mddev, name, c->autof, LOCAL, chosen_name, 1);
+ mdfd = create_mddev(ident->devname, ident->name, c->autof, LOCAL, chosen_name, 1);
if (mdfd < 0) {
map_unlock(&map);
return 1;
@@ -1032,7 +1031,6 @@ int Create(struct supertype *st, char *mddev,
udev_unblock();
return 1;
}
- mddev = chosen_name;
memset(&inf, 0, sizeof(inf));
md_get_array_info(mdfd, &inf);
@@ -1050,7 +1048,7 @@ int Create(struct supertype *st, char *mddev,
* with, but it chooses to trust me instead. Sigh
*/
info.array.md_minor = 0;
- if (fstat_is_blkdev(mdfd, mddev, &rdev))
+ if (fstat_is_blkdev(mdfd, chosen_name, &rdev))
info.array.md_minor = minor(rdev);
info.array.not_persistent = 0;
@@ -1102,8 +1100,8 @@ int Create(struct supertype *st, char *mddev,
info.array.layout = s->layout;
info.array.chunk_size = s->chunk*1024;
- if (name == NULL || *name == 0) {
- /* base name on mddev */
+ if (*name == 0) {
+ /* base name on devname */
/* /dev/md0 -> 0
* /dev/md_d0 -> d0
* /dev/md_foo -> foo
@@ -1113,15 +1111,16 @@ int Create(struct supertype *st, char *mddev,
* /dev/mdhome -> home
*/
/* FIXME compare this with rules in create_mddev */
- name = strrchr(mddev, '/');
+ name = strrchr(chosen_name, '/');
+
if (name) {
name++;
if (strncmp(name, "md_", 3) == 0 &&
- strlen(name) > 3 && (name-mddev) == 5 /* /dev/ */)
+ strlen(name) > 3 && (name - chosen_name) == 5 /* /dev/ */)
name += 3;
else if (strncmp(name, "md", 2) == 0 &&
strlen(name) > 2 && isdigit(name[2]) &&
- (name-mddev) == 5 /* /dev/ */)
+ (name - chosen_name) == 5 /* /dev/ */)
name += 2;
}
}
@@ -1215,8 +1214,7 @@ int Create(struct supertype *st, char *mddev,
}
rv = set_array_info(mdfd, st, &info);
if (rv) {
- pr_err("failed to set array info for %s: %s\n",
- mddev, strerror(errno));
+ pr_err("failed to set array info for %s: %s\n", chosen_name, strerror(errno));
goto abort_locked;
}
@@ -1237,8 +1235,7 @@ int Create(struct supertype *st, char *mddev,
goto abort_locked;
}
if (ioctl(mdfd, SET_BITMAP_FILE, bitmap_fd) < 0) {
- pr_err("Cannot set bitmap file for %s: %s\n",
- mddev, strerror(errno));
+ pr_err("Cannot set bitmap file for %s: %s\n", chosen_name, strerror(errno));
goto abort_locked;
}
}
@@ -1254,7 +1251,7 @@ int Create(struct supertype *st, char *mddev,
* create links */
sysfs_uevent(&info, "change");
if (c->verbose >= 0)
- pr_err("container %s prepared.\n", mddev);
+ pr_err("container %s prepared.\n", chosen_name);
wait_for(chosen_name, mdfd);
} else if (c->runstop == 1 || subdevs >= s->raiddisks) {
if (st->ss->external) {
@@ -1312,7 +1309,7 @@ int Create(struct supertype *st, char *mddev,
ioctl(mdfd, RESTART_ARRAY_RW, NULL);
}
if (c->verbose >= 0)
- pr_info("array %s started.\n", mddev);
+ pr_info("array %s started.\n", chosen_name);
if (st->ss->external && st->container_devnm[0]) {
if (need_mdmon)
start_mdmon(st->container_devnm);
diff --git a/mdadm.c b/mdadm.c
index 22d1c53b..0a56ed26 100644
--- a/mdadm.c
+++ b/mdadm.c
@@ -1290,37 +1290,39 @@ int main(int argc, char *argv[])
pr_err("an md device must be given in this mode\n");
exit(2);
}
+ ident.devname = devlist->devname;
+
if ((int)ident.super_minor == -2 && c.autof) {
pr_err("--super-minor=dev is incompatible with --auto\n");
exit(2);
}
if (mode == MANAGE || mode == GROW) {
- mdfd = open_mddev(devlist->devname, 1);
+ mdfd = open_mddev(ident.devname, 1);
if (mdfd < 0)
exit(1);
ret = fstat(mdfd, &stb);
if (ret) {
- pr_err("fstat failed on %s.\n", devlist->devname);
+ pr_err("fstat failed on %s.\n", ident.devname);
exit(1);
}
} else {
- char *bname = basename(devlist->devname);
+ char *bname = basename(ident.devname);
if (strlen(bname) > MD_NAME_MAX) {
- pr_err("Name %s is too long.\n", devlist->devname);
+ pr_err("Name %s is too long.\n", ident.devname);
exit(1);
}
- ret = stat(devlist->devname, &stb);
+ ret = stat(ident.devname, &stb);
if (ident.super_minor == -2 && ret != 0) {
pr_err("--super-minor=dev given, and listed device %s doesn't exist.\n",
- devlist->devname);
+ ident.devname);
exit(1);
}
if (!ret && !stat_is_md_dev(&stb)) {
- pr_err("device %s exists but is not an md array.\n", devlist->devname);
+ pr_err("device %s exists but is not an md array.\n", ident.devname);
exit(1);
}
}
@@ -1408,17 +1410,17 @@ int main(int argc, char *argv[])
case MANAGE:
/* readonly, add/remove, readwrite, runstop */
if (c.readonly > 0)
- rv = Manage_ro(devlist->devname, mdfd, c.readonly);
+ rv = Manage_ro(ident.devname, mdfd, c.readonly);
if (!rv && devs_found > 1)
- rv = Manage_subdevs(devlist->devname, mdfd,
+ rv = Manage_subdevs(ident.devname, mdfd,
devlist->next, c.verbose,
c.test, c.update, c.force);
if (!rv && c.readonly < 0)
- rv = Manage_ro(devlist->devname, mdfd, c.readonly);
+ rv = Manage_ro(ident.devname, mdfd, c.readonly);
if (!rv && c.runstop > 0)
- rv = Manage_run(devlist->devname, mdfd, &c);
+ rv = Manage_run(ident.devname, mdfd, &c);
if (!rv && c.runstop < 0)
- rv = Manage_stop(devlist->devname, mdfd, c.verbose, 0);
+ rv = Manage_stop(ident.devname, mdfd, c.verbose, 0);
break;
case ASSEMBLE:
if (!c.scan && c.runstop == -1) {
@@ -1428,22 +1430,19 @@ int main(int argc, char *argv[])
ident.super_minor == UnSet && ident.name[0] == 0 &&
!c.scan) {
/* Only a device has been given, so get details from config file */
- struct mddev_ident *array_ident = conf_get_ident(devlist->devname);
+ struct mddev_ident *array_ident = conf_get_ident(ident.devname);
if (array_ident == NULL) {
- pr_err("%s not identified in config file.\n",
- devlist->devname);
+ pr_err("%s not identified in config file.\n", ident.devname);
rv |= 1;
if (mdfd >= 0)
close(mdfd);
} else {
if (array_ident->autof == 0)
array_ident->autof = c.autof;
- rv |= Assemble(ss, devlist->devname, array_ident,
- NULL, &c);
+ rv |= Assemble(ss, ident.devname, array_ident, NULL, &c);
}
} else if (!c.scan)
- rv = Assemble(ss, devlist->devname, &ident,
- devlist->next, &c);
+ rv = Assemble(ss, ident.devname, &ident, devlist->next, &c);
else if (devs_found > 0) {
if (c.update && devs_found > 1) {
pr_err("can only update a single array at a time\n");
@@ -1501,7 +1500,7 @@ int main(int argc, char *argv[])
break;
}
}
- rv = Build(devlist->devname, devlist->next, &s, &c);
+ rv = Build(&ident, devlist->next, &s, &c);
break;
case CREATE:
if (c.delay == 0)
@@ -1538,9 +1537,7 @@ int main(int argc, char *argv[])
break;
}
- rv = Create(ss, devlist->devname,
- ident.name, ident.uuid_set ? ident.uuid : NULL,
- devs_found - 1, devlist->next, &s, &c);
+ rv = Create(ss, &ident, devs_found - 1, devlist->next, &s, &c);
break;
case MISC:
if (devmode == 'E') {
@@ -1637,8 +1634,7 @@ int main(int argc, char *argv[])
break;
}
for (dv = devlist->next; dv; dv = dv->next) {
- rv = Grow_Add_device(devlist->devname, mdfd,
- dv->devname);
+ rv = Grow_Add_device(ident.devname, mdfd, dv->devname);
if (rv)
break;
}
@@ -1651,18 +1647,15 @@ int main(int argc, char *argv[])
}
if (c.delay == 0)
c.delay = DEFAULT_BITMAP_DELAY;
- rv = Grow_addbitmap(devlist->devname, mdfd, &c, &s);
+ rv = Grow_addbitmap(ident.devname, mdfd, &c, &s);
} else if (grow_continue)
- rv = Grow_continue_command(devlist->devname,
- mdfd, c.backup_file,
- c.verbose);
+ rv = Grow_continue_command(ident.devname, mdfd, c.backup_file, c.verbose);
else if (s.size > 0 || s.raiddisks || s.layout_str ||
s.chunk != 0 || s.level != UnSet ||
s.data_offset != INVALID_SECTORS) {
- rv = Grow_reshape(devlist->devname, mdfd,
- devlist->next, &c, &s);
+ rv = Grow_reshape(ident.devname, mdfd, devlist->next, &c, &s);
} else if (s.consistency_policy != CONSISTENCY_POLICY_UNKNOWN) {
- rv = Grow_consistency_policy(devlist->devname, mdfd, &c, &s);
+ rv = Grow_consistency_policy(ident.devname, mdfd, &c, &s);
} else if (array_size == 0)
pr_err("no changes to --grow\n");
break;
diff --git a/mdadm.h b/mdadm.h
index f0ceeb78..5678eb11 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -1531,14 +1531,11 @@ extern int Assemble(struct supertype *st, char *mddev,
struct mddev_dev *devlist,
struct context *c);
-extern int Build(char *mddev, struct mddev_dev *devlist,
- struct shape *s, struct context *c);
-
-extern int Create(struct supertype *st, char *mddev,
- char *name, int *uuid,
- int subdevs, struct mddev_dev *devlist,
- struct shape *s,
- struct context *c);
+extern int Build(struct mddev_ident *ident, struct mddev_dev *devlist, struct shape *s,
+ struct context *c);
+
+extern int Create(struct supertype *st, struct mddev_ident *ident, int subdevs,
+ struct mddev_dev *devlist, struct shape *s, struct context *c);
extern int Detail(char *dev, struct context *c);
extern int Detail_Platform(struct superswitch *ss, int scan, int verbose, int export, char *controller_path);
--
2.40.1

@ -0,0 +1,253 @@
From 67417d9222c505103357191bb0e0ae300892e8a9 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Thu, 1 Jun 2023 09:27:48 +0200
Subject: [PATCH 155/165] mdadm: refactor ident->name handling
Create dedicated setter for name in mddev_ident and propagate it.
Following changes are made:
- move duplicated code from config.c and mdadm.c into new function.
- Add error enum in mdadm.h.
- Use MD_NAME_MAX instead of hardcoded value in mddev_ident.
- Use secure functions.
- Add more detailed verification of the name.
- make error messages reusable for cmdline and config:
- for cmdline, these are errors so use pr_err().
- for config, these are just warnings, so use pr_info().
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
config.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++++------
lib.c | 18 +++++++++++++
mdadm.c | 12 +++------
mdadm.h | 20 ++++++++++-----
4 files changed, 104 insertions(+), 23 deletions(-)
diff --git a/config.c b/config.c
index 450880e3..a9a0b4f7 100644
--- a/config.c
+++ b/config.c
@@ -131,6 +131,34 @@ bool is_devname_ignore(char *devname)
return false;
}
+/**
+ * ident_log() - generate and write message to the user.
+ * @param_name: name of the property.
+ * @value: value of the property.
+ * @reason: meaningful description.
+ * @cmdline: context dependent actions, see below.
+ *
+ * The function is made to provide similar error handling for both config and cmdline. The behavior
+ * is configurable via @cmdline. Message has following format:
+ * "Value "@value" cannot be set for @param_name. Reason: @reason."
+ *
+ * If cmdline is on:
+ * - message is written to stderr.
+ * otherwise:
+ * - message is written to stdout.
+ * - "Value ignored" is added at the end of the message.
+ */
+static void ident_log(const char *param_name, const char *value, const char *reason,
+ const bool cmdline)
+{
+ if (cmdline == true)
+ pr_err("Value \"%s\" cannot be set as %s. Reason: %s.\n", value, param_name,
+ reason);
+ else
+ pr_info("Value \"%s\" cannot be set as %s. Reason: %s. Value ignored.\n", value,
+ param_name, reason);
+}
+
/**
* ident_init() - Set defaults.
* @ident: ident pointer, not NULL.
@@ -159,6 +187,46 @@ inline void ident_init(struct mddev_ident *ident)
ident->uuid_set = 0;
}
+/**
+ * _ident_set_name()- set name in &mddev_ident.
+ * @ident: pointer to &mddev_ident.
+ * @name: name to be set.
+ * @cmdline: context dependent actions.
+ *
+ * If criteria passed, set name in @ident.
+ *
+ * Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR.
+ */
+static mdadm_status_t _ident_set_name(struct mddev_ident *ident, const char *name,
+ const bool cmdline)
+{
+ assert(name);
+ assert(ident);
+
+ const char *prop_name = "name";
+
+ if (ident->name[0]) {
+ ident_log(prop_name, name, "Already defined", cmdline);
+ return MDADM_STATUS_ERROR;
+ }
+
+ if (is_string_lq(name, MD_NAME_MAX + 1) == false) {
+ ident_log(prop_name, name, "Too long or empty", cmdline);
+ return MDADM_STATUS_ERROR;
+ }
+
+ snprintf(ident->name, MD_NAME_MAX + 1, "%s", name);
+ return MDADM_STATUS_SUCCESS;
+}
+
+/**
+ * ident_set_name()- exported, for cmdline.
+ */
+mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name)
+{
+ return _ident_set_name(ident, name, true);
+}
+
struct conf_dev {
struct conf_dev *next;
char *name;
@@ -444,14 +512,7 @@ void arrayline(char *line)
mis.super_minor = minor;
}
} else if (strncasecmp(w, "name=", 5) == 0) {
- if (mis.name[0])
- pr_err("only specify name once, %s ignored.\n",
- w);
- else if (strlen(w + 5) > 32)
- pr_err("name too long, ignoring %s\n", w);
- else
- strcpy(mis.name, w + 5);
-
+ _ident_set_name(&mis, w + 5, false);
} else if (strncasecmp(w, "bitmap=", 7) == 0) {
if (mis.bitmap_file)
pr_err("only specify bitmap file once. %s ignored\n",
diff --git a/lib.c b/lib.c
index 8a4b48e0..03198e2d 100644
--- a/lib.c
+++ b/lib.c
@@ -27,6 +27,24 @@
#include <ctype.h>
#include <limits.h>
+/**
+ * is_string_lq() - Check if string length with NULL byte is lower or equal to requested.
+ * @str: string to check.
+ * @max_len: max length.
+ *
+ * @str length must be bigger than 0 and be lower or equal @max_len, including termination byte.
+ */
+bool is_string_lq(const char * const str, size_t max_len)
+{
+ assert(str);
+
+ size_t _len = strnlen(str, max_len);
+
+ if (_len > 0 && _len < max_len)
+ return true;
+ return false;
+}
+
bool is_dev_alive(char *path)
{
if (!path)
diff --git a/mdadm.c b/mdadm.c
index 0a56ed26..8bc9304e 100644
--- a/mdadm.c
+++ b/mdadm.c
@@ -690,20 +690,14 @@ int main(int argc, char *argv[])
case O(CREATE,'N'):
case O(ASSEMBLE,'N'):
case O(MISC,'N'):
- if (ident.name[0]) {
- pr_err("name cannot be set twice. Second value %s.\n", optarg);
- exit(2);
- }
if (mode == MISC && !c.subarray) {
pr_err("-N/--name only valid with --update-subarray in misc mode\n");
exit(2);
}
- if (strlen(optarg) > 32) {
- pr_err("name '%s' is too long, 32 chars max.\n",
- optarg);
+
+ if (ident_set_name(&ident, optarg) != MDADM_STATUS_SUCCESS)
exit(2);
- }
- strcpy(ident.name, optarg);
+
continue;
case O(ASSEMBLE,'m'): /* super-minor for array */
diff --git a/mdadm.h b/mdadm.h
index 5678eb11..bbf386d6 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -294,6 +294,11 @@ static inline void __put_unaligned32(__u32 val, void *p)
#define KIB_TO_BYTES(x) ((x) << 10)
#define SEC_TO_BYTES(x) ((x) << 9)
+/**
+ * This is true for native and DDF, IMSM allows 16.
+ */
+#define MD_NAME_MAX 32
+
extern const char Name[];
struct md_bb_entry {
@@ -425,6 +430,12 @@ struct spare_criteria {
unsigned int sector_size;
};
+typedef enum mdadm_status {
+ MDADM_STATUS_SUCCESS = 0,
+ MDADM_STATUS_ERROR,
+ MDADM_STATUS_UNDEF,
+} mdadm_status_t;
+
enum mode {
ASSEMBLE=1,
BUILD,
@@ -593,7 +604,7 @@ struct mddev_ident {
int uuid_set;
int uuid[4];
- char name[33];
+ char name[MD_NAME_MAX + 1];
int super_minor;
@@ -1609,6 +1620,7 @@ extern int check_partitions(int fd, char *dname,
extern int fstat_is_blkdev(int fd, char *devname, dev_t *rdev);
extern int stat_is_blkdev(char *devname, dev_t *rdev);
+extern bool is_string_lq(const char * const str, size_t max_len);
extern bool is_dev_alive(char *path);
extern int get_mdp_major(void);
extern int get_maj_min(char *dev, int *major, int *minor);
@@ -1626,6 +1638,7 @@ extern void manage_fork_fds(int close_all);
extern int continue_via_systemd(char *devnm, char *service_name, char *prefix);
extern void ident_init(struct mddev_ident *ident);
+extern mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name);
extern int parse_auto(char *str, char *msg, int config);
extern struct mddev_ident *conf_get_ident(char *dev);
@@ -2002,11 +2015,6 @@ enum r0layout {
/* And another special number needed for --data_offset=variable */
#define VARIABLE_OFFSET 3
-/**
- * This is true for native and DDF, IMSM allows 16.
- */
-#define MD_NAME_MAX 32
-
/**
* is_container() - check if @level is &LEVEL_CONTAINER
* @level: level value
--
2.40.1

@ -0,0 +1,249 @@
From ae5f13a971bc309e0e25087421119b86daf2e510 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Thu, 1 Jun 2023 09:27:49 +0200
Subject: [PATCH 156/165] mdadm: define ident_set_devname()
Use dedicated set method for ident->devname. Now, devname validation
is done early for modes where device is created (Build, Create and
Assemble). The rules, used for devname validation are derived from
config file.
It could cause regression with execeptional cases where existing device
has name which doesn't match criteria for Manage and Grow modes. It is
low risk and those modes are not omitted from early devname validation.
Use can used main numbered devnode to avoid this problem.
Messages exposed to user are changed so it might cause a regression
in negative scenarios. Error codes are not changed.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
config.c | 102 +++++++++++++++++++++++++--------
mdadm.c | 10 +---
mdadm.h | 3 +-
tests/00createnames | 3 +
tests/templates/names_template | 7 +++
5 files changed, 92 insertions(+), 33 deletions(-)
diff --git a/config.c b/config.c
index a9a0b4f7..a0424845 100644
--- a/config.c
+++ b/config.c
@@ -122,7 +122,7 @@ int match_keyword(char *word)
/**
* is_devname_ignore() - check if &devname is a special "<ignore>" keyword.
*/
-bool is_devname_ignore(char *devname)
+bool is_devname_ignore(const char *devname)
{
static const char keyword[] = "<ignore>";
@@ -187,6 +187,74 @@ inline void ident_init(struct mddev_ident *ident)
ident->uuid_set = 0;
}
+/**
+ * _ident_set_devname()- verify devname and set it in &mddev_ident.
+ * @ident: pointer to &mddev_ident.
+ * @devname: devname to be set.
+ * @cmdline: context dependent actions. If set, ignore keyword is not allowed.
+ *
+ * @devname can have following forms:
+ * '<ignore>' keyword (if allowed)
+ * /dev/md{number}
+ * /dev/md_d{number} (legacy)
+ * /dev/md_{name}
+ * /dev/md/{name}
+ * {name} - anything that doesn't start from '/' or '<'.
+ *
+ * {name} must follow name's criteria.
+ * If criteria passed, duplicate memory and set devname in @ident.
+ *
+ * Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR.
+ */
+mdadm_status_t _ident_set_devname(struct mddev_ident *ident, const char *devname,
+ const bool cmdline)
+{
+ assert(ident);
+ assert(devname);
+
+ static const char named_dev_pref[] = DEV_NUM_PREF "_";
+ static const int named_dev_pref_size = sizeof(named_dev_pref) - 1;
+ const char *prop_name = "devname";
+ const char *name;
+
+ if (ident->devname) {
+ ident_log(prop_name, devname, "Already defined", cmdline);
+ return MDADM_STATUS_ERROR;
+ }
+
+ if (is_devname_ignore(devname) == true) {
+ if (!cmdline)
+ goto pass;
+
+ ident_log(prop_name, devname, "Special keyword is invalid in this context",
+ cmdline);
+ return MDADM_STATUS_ERROR;
+ }
+
+ if (is_devname_md_numbered(devname) == true || is_devname_md_d_numbered(devname) == true)
+ goto pass;
+
+ if (strncmp(devname, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0)
+ name = devname + DEV_MD_DIR_LEN;
+ else if (strncmp(devname, named_dev_pref, named_dev_pref_size) == 0)
+ name = devname + named_dev_pref_size;
+ else
+ name = devname;
+
+ if (*name == '/' || *name == '<') {
+ ident_log(prop_name, devname, "Cannot be started from \'/\' or \'<\'", cmdline);
+ return MDADM_STATUS_ERROR;
+ }
+
+ if (is_string_lq(name, MD_NAME_MAX + 1) == false) {
+ ident_log(prop_name, devname, "Invalid length", cmdline);
+ return MDADM_STATUS_ERROR;
+ }
+pass:
+ ident->devname = xstrdup(devname);
+ return MDADM_STATUS_SUCCESS;
+}
+
/**
* _ident_set_name()- set name in &mddev_ident.
* @ident: pointer to &mddev_ident.
@@ -219,6 +287,14 @@ static mdadm_status_t _ident_set_name(struct mddev_ident *ident, const char *nam
return MDADM_STATUS_SUCCESS;
}
+/**
+ * ident_set_devname()- exported, for cmdline.
+ */
+mdadm_status_t ident_set_devname(struct mddev_ident *ident, const char *name)
+{
+ return _ident_set_devname(ident, name, true);
+}
+
/**
* ident_set_name()- exported, for cmdline.
*/
@@ -464,29 +540,7 @@ void arrayline(char *line)
for (w = dl_next(line); w != line; w = dl_next(w)) {
if (w[0] == '/' || strchr(w, '=') == NULL) {
- /* This names the device, or is '<ignore>'.
- * The rules match those in create_mddev.
- * 'w' must be:
- * /dev/md/{anything}
- * /dev/mdNN
- * /dev/md_dNN
- * <ignore>
- * or anything that doesn't start '/' or '<'
- */
- if (is_devname_ignore(w) == true ||
- strncmp(w, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0 ||
- (w[0] != '/' && w[0] != '<') ||
- is_devname_md_numbered(w) == true ||
- is_devname_md_d_numbered(w) == true) {
- /* This is acceptable */;
- if (mis.devname)
- pr_err("only give one device per ARRAY line: %s and %s\n",
- mis.devname, w);
- else
- mis.devname = w;
- }else {
- pr_err("%s is an invalid name for an md device - ignored.\n", w);
- }
+ _ident_set_devname(&mis, w, false);
} else if (strncasecmp(w, "uuid=", 5) == 0) {
if (mis.uuid_set)
pr_err("only specify uuid once, %s ignored.\n",
diff --git a/mdadm.c b/mdadm.c
index 8bc9304e..62f981df 100644
--- a/mdadm.c
+++ b/mdadm.c
@@ -1284,7 +1284,8 @@ int main(int argc, char *argv[])
pr_err("an md device must be given in this mode\n");
exit(2);
}
- ident.devname = devlist->devname;
+ if (ident_set_devname(&ident, devlist->devname) != MDADM_STATUS_SUCCESS)
+ exit(1);
if ((int)ident.super_minor == -2 && c.autof) {
pr_err("--super-minor=dev is incompatible with --auto\n");
@@ -1301,13 +1302,6 @@ int main(int argc, char *argv[])
exit(1);
}
} else {
- char *bname = basename(ident.devname);
-
- if (strlen(bname) > MD_NAME_MAX) {
- pr_err("Name %s is too long.\n", ident.devname);
- exit(1);
- }
-
ret = stat(ident.devname, &stb);
if (ident.super_minor == -2 && ret != 0) {
pr_err("--super-minor=dev given, and listed device %s doesn't exist.\n",
diff --git a/mdadm.h b/mdadm.h
index bbf386d6..49422e24 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -1638,6 +1638,7 @@ extern void manage_fork_fds(int close_all);
extern int continue_via_systemd(char *devnm, char *service_name, char *prefix);
extern void ident_init(struct mddev_ident *ident);
+extern mdadm_status_t ident_set_devname(struct mddev_ident *ident, const char *devname);
extern mdadm_status_t ident_set_name(struct mddev_ident *ident, const char *name);
extern int parse_auto(char *str, char *msg, int config);
@@ -1660,7 +1661,7 @@ extern void print_escape(char *str);
extern int use_udev(void);
extern unsigned long GCD(unsigned long a, unsigned long b);
extern int conf_name_is_free(char *name);
-extern bool is_devname_ignore(char *devname);
+extern bool is_devname_ignore(const char *devname);
extern bool is_devname_md_numbered(const char *devname);
extern bool is_devname_md_d_numbered(const char *devname);
extern int conf_verify_devnames(struct mddev_ident *array_list);
diff --git a/tests/00createnames b/tests/00createnames
index 064eeef2..a95e7d2b 100644
--- a/tests/00createnames
+++ b/tests/00createnames
@@ -39,3 +39,6 @@ mdadm -S "/dev/md0"
names_create "/dev/md0" "name"
names_verify "/dev/md0" "empty" "name"
mdadm -S "/dev/md0"
+
+# Devnode is a special ignore keyword. Should be rejected.
+names_create "<ignore>" "name", "true"
diff --git a/tests/templates/names_template b/tests/templates/names_template
index 8d2b5c81..6181bfaa 100644
--- a/tests/templates/names_template
+++ b/tests/templates/names_template
@@ -2,6 +2,7 @@
function names_create() {
local DEVNAME=$1
local NAME=$2
+ local NEG_TEST=$3
if [[ -z "$NAME" ]]; then
mdadm -CR "$DEVNAME" -l0 -n 1 $dev0 --force
@@ -9,6 +10,12 @@ function names_create() {
mdadm -CR "$DEVNAME" --name="$NAME" --metadata=1.2 -l0 -n 1 $dev0 --force
fi
+ if [[ "$NEG_TEST" == "true" ]]; then
+ [[ "$?" == "0" ]] && return 0
+ echo "Negative verification failed"
+ exit 1
+ fi
+
if [[ "$?" != "0" ]]; then
echo "Cannot create device."
exit 1
--
2.40.1

@ -0,0 +1,471 @@
From e2eb503bd797908f515b58428b274f1ba6a05349 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Thu, 1 Jun 2023 09:27:50 +0200
Subject: [PATCH 157/165] mdadm: Follow POSIX Portable Character Set
When the user creates a device with a name that contains whitespace,
mdadm timeouts and throws an error. This issue is caused by udev, which
truncates /dev/md link until the first whitespace.
This patch introduces prohibition of characters other than A-Za-z0-9.-_
in the device name. Also, it prohibits using leading "-" in device name,
so name won't be confused with cli parameter.
Set of allowed characters is taken from POSIX 3.280 Portable Character
Set. Also, device name length now is limited to NAME_MAX.
In some places, there are other requirements for string length (e.g. size
up to MD_NAME_MAX for device name). This routine is made to follow POSIX
and other, more strict limitations should be checked separately.
We are aware of the risk of regression in exceptional cases (as
escape_devname function is removed) that should be fixed by updating
the array name.
The POSIX validation is added for:
- 'name' parameter in every mode.
- first devlist entry, for Build, Create, Assemble, Manage, Grow.
- config entries, both devname and "name=".
Additionally, some manual cleanups are made.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Detail.c | 17 ++++--------
config.c | 13 ++++++---
lib.c | 58 ++++++++++++++++++++++++++++-----------
mdadm.8.in | 70 ++++++++++++++++++++---------------------------
mdadm.conf.5.in | 4 ---
mdadm.h | 2 +-
super-intel.c | 47 ++++++++++++++++---------------
tests/00confnames | 4 +--
8 files changed, 113 insertions(+), 102 deletions(-)
diff --git a/Detail.c b/Detail.c
index 206d88e3..57ac336f 100644
--- a/Detail.c
+++ b/Detail.c
@@ -254,11 +254,9 @@ int Detail(char *dev, struct context *c)
fname_from_uuid(st, info, nbuf, ':');
printf("MD_UUID=%s\n", nbuf + 5);
mp = map_by_uuid(&map, info->uuid);
- if (mp && mp->path && strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) {
- printf("MD_DEVNAME=");
- print_escape(mp->path + DEV_MD_DIR_LEN);
- putchar('\n');
- }
+
+ if (mp && mp->path && strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0)
+ printf("MD_DEVNAME=%s\n", mp->path + DEV_MD_DIR_LEN);
if (st->ss->export_detail_super)
st->ss->export_detail_super(st);
@@ -271,12 +269,9 @@ int Detail(char *dev, struct context *c)
__fname_from_uuid(mp->uuid, 0, nbuf, ':');
printf("MD_UUID=%s\n", nbuf+5);
}
- if (mp && mp->path &&
- strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0) {
- printf("MD_DEVNAME=");
- print_escape(mp->path + DEV_MD_DIR_LEN);
- putchar('\n');
- }
+ if (mp && mp->path && strncmp(mp->path, DEV_MD_DIR, DEV_MD_DIR_LEN) == 0)
+ printf("MD_DEVNAME=%s\n", mp->path + DEV_MD_DIR_LEN);
+
map_free(map);
}
if (!c->no_devices && sra) {
diff --git a/config.c b/config.c
index a0424845..5f12a1f8 100644
--- a/config.c
+++ b/config.c
@@ -199,9 +199,9 @@ inline void ident_init(struct mddev_ident *ident)
* /dev/md_d{number} (legacy)
* /dev/md_{name}
* /dev/md/{name}
- * {name} - anything that doesn't start from '/' or '<'.
+ * {name}
*
- * {name} must follow name's criteria.
+ * {name} must follow name's criteria and be POSIX compatible.
* If criteria passed, duplicate memory and set devname in @ident.
*
* Return: %MDADM_STATUS_SUCCESS or %MDADM_STATUS_ERROR.
@@ -241,8 +241,8 @@ mdadm_status_t _ident_set_devname(struct mddev_ident *ident, const char *devname
else
name = devname;
- if (*name == '/' || *name == '<') {
- ident_log(prop_name, devname, "Cannot be started from \'/\' or \'<\'", cmdline);
+ if (is_name_posix_compatible(name) == false) {
+ ident_log(prop_name, name, "Not POSIX compatible", cmdline);
return MDADM_STATUS_ERROR;
}
@@ -283,6 +283,11 @@ static mdadm_status_t _ident_set_name(struct mddev_ident *ident, const char *nam
return MDADM_STATUS_ERROR;
}
+ if (is_name_posix_compatible(name) == false) {
+ ident_log(prop_name, name, "Not POSIX compatible", cmdline);
+ return MDADM_STATUS_ERROR;
+ }
+
snprintf(ident->name, MD_NAME_MAX + 1, "%s", name);
return MDADM_STATUS_SUCCESS;
}
diff --git a/lib.c b/lib.c
index 03198e2d..7ab59988 100644
--- a/lib.c
+++ b/lib.c
@@ -483,24 +483,50 @@ void print_quoted(char *str)
putchar(q);
}
-void print_escape(char *str)
+/**
+ * is_alphanum() - Check if sign is letter or digit.
+ * @c: char to analyze.
+ *
+ * Similar to isalnum() but additional locales are excluded.
+ *
+ * Return: %true on success, %false otherwise.
+ */
+bool is_alphanum(const char c)
{
- /* print str, but change space and tab to '_'
- * as is suitable for device names
- */
- for (; *str; str++) {
- switch (*str) {
- case ' ':
- case '\t':
- putchar('_');
- break;
- case '/':
- putchar('-');
- break;
- default:
- putchar(*str);
- }
+ if (isupper(c) || islower(c) || isdigit(c) != 0)
+ return true;
+ return false;
+}
+
+/**
+ * is_name_posix_compatible() - Check if name is POSIX compatible.
+ * @name: name to check.
+ *
+ * POSIX portable file name character set contains ASCII letters,
+ * digits, '_', '.', and '-'. Also forbid leading '-'.
+ * The length of the name cannot exceed NAME_MAX - 1 (ensure NULL ending).
+ *
+ * Return: %true on success, %false otherwise.
+ */
+bool is_name_posix_compatible(const char * const name)
+{
+ assert(name);
+
+ char allowed_symbols[] = "-_.";
+ const char *n = name;
+
+ if (!is_string_lq(name, NAME_MAX))
+ return false;
+
+ if (*n == '-')
+ return false;
+
+ while (*n != '\0') {
+ if (!is_alphanum(*n) && !strchr(allowed_symbols, *n))
+ return false;
+ n++;
}
+ return true;
}
int check_env(char *name)
diff --git a/mdadm.8.in b/mdadm.8.in
index b7159509..3142436f 100644
--- a/mdadm.8.in
+++ b/mdadm.8.in
@@ -364,7 +364,7 @@ Use the Intel(R) Matrix Storage Manager metadata format. This creates a
which is managed in a similar manner to DDF, and is supported by an
option-rom on some platforms:
.IP
-.B https://www.intel.com/content/www/us/en/support/products/122484/memory-and-storage/ssd-software/intel-virtual-raid-on-cpu-intel-vroc.html
+.B https://www.intel.com/content/www/us/en/support/products/122484
.PP
.RE
@@ -932,17 +932,14 @@ option will be ignored.
.BR \-N ", " \-\-name=
Set a
.B name
-for the array. This is currently only effective when creating an
-array with a version-1 superblock, or an array in a DDF container.
-The name is a simple textual string that can be used to identify array
-components when assembling. If name is needed but not specified, it
-is taken from the basename of the device that is being created.
-e.g. when creating
-.I /dev/md/home
-the
-.B name
-will default to
-.IR home .
+for the array. It must be
+.BR "POSIX PORTABLE NAME"
+compatible and cannot be longer than 32 chars. This is effective when creating an array
+with a v1 metadata, or an external array.
+
+If name is needed but not specified, it is taken from the basename of the device
+that is being created. See
+.BR "DEVICE NAMES"
.TP
.BR \-R ", " \-\-run
@@ -1132,8 +1129,10 @@ is much safer.
.TP
.BR \-N ", " \-\-name=
-Specify the name of the array to assemble. This must be the name
-that was specified when creating the array. It must either match
+Specify the name of the array to assemble. It must be
+.BR "POSIX PORTABLE NAME"
+compatible and cannot be longer than 32 chars. This must be the name
+that was specified when creating the array. It must either match
the name stored in the superblock exactly, or it must match
with the current
.I homehost
@@ -2179,14 +2178,17 @@ Usage:
.I md-device
.BI \-\-chunk= X
.BI \-\-level= Y
-.br
.BI \-\-raid\-devices= Z
.I devices
.PP
-This usage will initialise a new md array, associate some devices with
+This usage will initialize a new md array, associate some devices with
it, and activate the array.
+.I md-device
+is a new device. This could be standard name or chosen name. For details see:
+.BR "DEVICE NAMES"
+
The named device will normally not exist when
.I "mdadm \-\-create"
is run, but will be created by
@@ -2227,24 +2229,6 @@ array. This feature can be overridden with the
.B \-\-force
option.
-When creating an array with version-1 metadata a name for the array is
-required.
-If this is not given with the
-.B \-\-name
-option,
-.I mdadm
-will choose a name based on the last component of the name of the
-device being created. So if
-.B /dev/md3
-is being created, then the name
-.B 3
-will be chosen.
-If
-.B /dev/md/home
-is being created, then the name
-.B home
-will be used.
-
When creating a partition based array, using
.I mdadm
with version-1.x metadata, the partition type should be set to
@@ -2429,12 +2413,10 @@ and
The
.B name
-option updates the subarray name in the metadata, it may not affect the
-device node name or the device node symlink until the subarray is
-re\-assembled. If updating
-.B name
-would change the UUID of an active subarray this operation is blocked,
-and the command will end in an error.
+option updates the subarray name in the metadata. It must be
+.BR "POSIX PORTABLE NAME"
+compatible and cannot be longer than 32 chars. If successes, new value will be respected after
+next assembly.
The
.B ppl
@@ -3395,6 +3377,10 @@ When
.B \-\-incremental
mode is used, this file gets a list of arrays currently being created.
+.SH POSIX PORTABLE NAME
+A valid name can only consist of characters "A-Za-z0-9.-_".
+The name cannot start with a leading "-" and cannot exceed 255 chars.
+
.SH DEVICE NAMES
.I mdadm
@@ -3416,6 +3402,10 @@ can be given, or just the suffix of the second sort of name, such as
.I home
can be given.
+In every style, raw name must be compatible with
+.BR "POSIX PORTABLE NAME"
+and has to be no longer than 32 chars.
+
When
.I mdadm
chooses device names during auto-assembly or incremental assembly, it
diff --git a/mdadm.conf.5.in b/mdadm.conf.5.in
index bc2295c2..94e23dd0 100644
--- a/mdadm.conf.5.in
+++ b/mdadm.conf.5.in
@@ -717,10 +717,6 @@ ARRAY /dev/md/home UUID=9187a482:5dde19d9:eea3cc4a:d646ab8b
.br
auto=part
.br
-# The name of this array contains a space.
-.br
-ARRAY /dev/md9 name='Data Storage'
-.sp
POLICY domain=domain1 metadata=imsm path=pci-0000:00:1f.2-scsi-*
.br
action=spare
diff --git a/mdadm.h b/mdadm.h
index 49422e24..9effb941 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -1617,6 +1617,7 @@ extern int check_raid(int fd, char *name);
extern int check_partitions(int fd, char *dname,
unsigned long long freesize,
unsigned long long size);
+extern bool is_name_posix_compatible(const char *path);
extern int fstat_is_blkdev(int fd, char *devname, dev_t *rdev);
extern int stat_is_blkdev(char *devname, dev_t *rdev);
@@ -1657,7 +1658,6 @@ extern int conf_get_monitor_delay(void);
extern char *conf_line(FILE *file);
extern char *conf_word(FILE *file, int allow_key);
extern void print_quoted(char *str);
-extern void print_escape(char *str);
extern int use_udev(void);
extern unsigned long GCD(unsigned long a, unsigned long b);
extern int conf_name_is_free(char *name);
diff --git a/super-intel.c b/super-intel.c
index 77b0066f..05d3b056 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -5561,40 +5561,37 @@ static void imsm_update_version_info(struct intel_super *super)
}
}
-static int check_name(struct intel_super *super, char *name, int quiet)
+/**
+ * imsm_check_name() - check imsm naming criteria.
+ * @super: &intel_super pointer, not NULL.
+ * @name: name to check.
+ * @verbose: verbose level.
+ *
+ * Name must be no longer than &MAX_RAID_SERIAL_LEN and must be unique across volumes.
+ *
+ * Returns: &true if @name matches, &false otherwise.
+ */
+static bool imsm_is_name_allowed(struct intel_super *super, const char * const name,
+ const int verbose)
{
struct imsm_super *mpb = super->anchor;
- char *reason = NULL;
- char *start = name;
- size_t len = strlen(name);
int i;
- if (len > 0) {
- while (isspace(start[len - 1]))
- start[--len] = 0;
- while (*start && isspace(*start))
- ++start, --len;
- memmove(name, start, len + 1);
+ if (is_string_lq(name, MAX_RAID_SERIAL_LEN + 1) == false) {
+ pr_vrb("imsm: Name \"%s\" is too long\n", name);
+ return false;
}
- if (len > MAX_RAID_SERIAL_LEN)
- reason = "must be 16 characters or less";
- else if (len == 0)
- reason = "must be a non-empty string";
-
for (i = 0; i < mpb->num_raid_devs; i++) {
struct imsm_dev *dev = get_imsm_dev(super, i);
if (strncmp((char *) dev->volume, name, MAX_RAID_SERIAL_LEN) == 0) {
- reason = "already exists";
- break;
+ pr_vrb("imsm: Name \"%s\" already exists\n", name);
+ return false;
}
}
- if (reason && !quiet)
- pr_err("imsm volume name %s\n", reason);
-
- return !reason;
+ return true;
}
static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
@@ -5689,8 +5686,9 @@ static int init_super_imsm_volume(struct supertype *st, mdu_array_info_t *info,
}
}
- if (!check_name(super, name, 0))
+ if (imsm_is_name_allowed(super, name, 1) == false)
return 0;
+
dv = xmalloc(sizeof(*dv));
dev = xcalloc(1, sizeof(*dev) + sizeof(__u32) * (info->raid_disks - 1));
/*
@@ -8018,7 +8016,7 @@ static int update_subarray_imsm(struct supertype *st, char *subarray,
char *ep;
int vol;
- if (!check_name(super, name, 0))
+ if (imsm_is_name_allowed(super, name, 1) == false)
return 2;
vol = strtoul(subarray, &ep, 10);
@@ -10345,7 +10343,8 @@ static void imsm_process_update(struct supertype *st,
if (a->info.container_member == target)
break;
dev = get_imsm_dev(super, u->dev_idx);
- if (a || !check_name(super, name, 1)) {
+
+ if (a || !dev || imsm_is_name_allowed(super, name, 0) == false) {
dprintf("failed to rename subarray-%d\n", target);
break;
}
diff --git a/tests/00confnames b/tests/00confnames
index 25a7127b..10823f01 100644
--- a/tests/00confnames
+++ b/tests/00confnames
@@ -79,10 +79,10 @@ names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 11. <devname> with some special symbols and locales, no <name>.
-# It needs to wait a while for timeout because udev cannot create a link - known issue.
+# <devname> should be ignored.
names_make_conf $_UUID "tźż-\.,<>st+-" "empty" $config
mdadm -I $dev0 --config=$config
-names_verify "/dev/md127" "tźż-\.,<>st+-" "name"
+names_verify "/dev/md127" "name" "name"
mdadm -S "/dev/md127"
# 12. No <devname> and <name> set.
--
2.40.1

@ -0,0 +1,128 @@
From ba489abd688bf70c83e70700aaaec5f5e90889c5 Mon Sep 17 00:00:00 2001
From: Coly Li <colyli@suse.de>
Date: Mon, 14 Aug 2023 00:46:13 +0800
Subject: [PATCH 158/165] Incremental: remove obsoleted calls to udisks
Utility udisks is removed from udev upstream, calling this obsoleted
command in run_udisks() doesn't make any sense now.
This patch removes the calls chain of udisks, which includes routines
run_udisk(), force_remove(), and 2 locations where force_remove() are
called. Considering force_remove() is removed with udisks util, it is
fair to remove Manage_stop() inside force_remove() as well.
In the two modifications where calling force_remove() are removed,
the failure from Manage_subdevs() can be safely ignored, because,
1) udisks doesn't exist, no need to check the return value to umount
the file system by udisks and remove the component disk again.
2) After the 'I' inremental remove, there is another 'r' hot remove
following up. The first incremental remove is a best-try effort.
Therefore in this patch, where force_remove() is removed, the return
value of calling Manage_subdevs() is not checked too.
Signed-off-by: Coly Li <colyli@suse.de>
Reviewed-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Cc: Jes Sorensen <jes@trained-monkey.org>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Incremental.c | 64 +++++++++++----------------------------------------
1 file changed, 13 insertions(+), 51 deletions(-)
diff --git a/Incremental.c b/Incremental.c
index f13ce027..05b33c45 100644
--- a/Incremental.c
+++ b/Incremental.c
@@ -1628,54 +1628,18 @@ release:
return rv;
}
-static void run_udisks(char *arg1, char *arg2)
-{
- int pid = fork();
- int status;
- if (pid == 0) {
- manage_fork_fds(1);
- execl("/usr/bin/udisks", "udisks", arg1, arg2, NULL);
- execl("/bin/udisks", "udisks", arg1, arg2, NULL);
- exit(1);
- }
- while (pid > 0 && wait(&status) != pid)
- ;
-}
-
-static int force_remove(char *devnm, int fd, struct mdinfo *mdi, int verbose)
-{
- int rv;
- int devid = devnm2devid(devnm);
-
- run_udisks("--unmount", map_dev(major(devid), minor(devid), 0));
- rv = Manage_stop(devnm, fd, verbose, 1);
- if (rv) {
- /* At least we can try to trigger a 'remove' */
- sysfs_uevent(mdi, "remove");
- if (verbose)
- pr_err("Fail to stop %s too.\n", devnm);
- }
- return rv;
-}
-
static void remove_from_member_array(struct mdstat_ent *memb,
struct mddev_dev *devlist, int verbose)
{
- int rv;
- struct mdinfo mmdi;
int subfd = open_dev(memb->devnm);
if (subfd >= 0) {
- rv = Manage_subdevs(memb->devnm, subfd, devlist, verbose,
- 0, UOPT_UNDEFINED, 0);
- if (rv & 2) {
- if (sysfs_init(&mmdi, -1, memb->devnm))
- pr_err("unable to initialize sysfs for: %s\n",
- memb->devnm);
- else
- force_remove(memb->devnm, subfd, &mmdi,
- verbose);
- }
+ /*
+ * Ignore the return value because it's necessary
+ * to handle failure condition here.
+ */
+ Manage_subdevs(memb->devnm, subfd, devlist, verbose,
+ 0, UOPT_UNDEFINED, 0);
close(subfd);
}
}
@@ -1758,21 +1722,19 @@ int IncrementalRemove(char *devname, char *id_path, int verbose)
}
free_mdstat(mdstat);
} else {
- rv |= Manage_subdevs(ent->devnm, mdfd, &devlist,
- verbose, 0, UOPT_UNDEFINED, 0);
- if (rv & 2) {
- /* Failed due to EBUSY, try to stop the array.
- * Give udisks a chance to unmount it first.
+ /*
+ * This 'I' incremental remove is a try-best effort,
+ * the failure condition can be safely ignored
+ * because of the following up 'r' remove.
*/
- rv = force_remove(ent->devnm, mdfd, &mdi, verbose);
- goto end;
- }
+ Manage_subdevs(ent->devnm, mdfd, &devlist,
+ verbose, 0, UOPT_UNDEFINED, 0);
}
devlist.disposition = 'r';
rv = Manage_subdevs(ent->devnm, mdfd, &devlist,
verbose, 0, UOPT_UNDEFINED, 0);
-end:
+
close(mdfd);
free_mdstat(ent);
return rv;
--
2.40.1

@ -0,0 +1,31 @@
From 28fc84168646910a9271ebe1a12b1571e14f5900 Mon Sep 17 00:00:00 2001
From: Xiao Ni <xni@redhat.com>
Date: Thu, 7 Sep 2023 16:57:44 +0800
Subject: [PATCH 159/165] mdadm/tests: Fix regular expression failure
The test fails because of the regular expression.
Signed-off-by: Xiao Ni <xni@redhat.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/06name | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/tests/06name b/tests/06name
index 4d5e824d..86eaab69 100644
--- a/tests/06name
+++ b/tests/06name
@@ -3,8 +3,8 @@ set -x
# create an array with a name
mdadm -CR $md0 -l0 -n2 --metadata=1 --name="Fred" $dev0 $dev1
-mdadm -E $dev0 | grep 'Name : [^:]*:Fred ' > /dev/null || exit 1
-mdadm -D $md0 | grep 'Name : [^:]*:Fred ' > /dev/null || exit 1
+mdadm -E $dev0 | grep 'Name : Fred' > /dev/null || exit 1
+mdadm -D $md0 | grep 'Name : Fred' > /dev/null || exit 1
mdadm -S $md0
mdadm -A $md0 --name="Fred" $devlist
--
2.40.1

@ -0,0 +1,141 @@
From ed2c2cb3d440f3bd2692f1896446c4bcc703f05c Mon Sep 17 00:00:00 2001
From: Li Xiao Keng <lixiaokeng@huawei.com>
Date: Thu, 7 Sep 2023 19:37:44 +0800
Subject: [PATCH 160/165] Fix race of "mdadm --add" and "mdadm --incremental"
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
There is a raid1 with sda and sdb. And we add sdc to this raid,
it may return -EBUSY.
The main process of --add:
1. dev_opensdc) in Manage_add
2. store_super1(st, di->fd) in write_init_super1
3. fsync(fd) in store_super1
4. close(di->fd) in write_init_super1
5. ioctl(ADD_NEW_DISK)
Step 2 and 3 will add sdc to metadata of raid1. There will be
udev(change of sdc) event after step4. Then "/usr/sbin/mdadm
--incremental --export $devnode --offroot $env{DEVLINKS}"
will be run, and the sdc will be added to the raid1. Then
step 5 will return -EBUSY because it checks if device isn't
claimed in md_import_device()->lock_rdev()->blkdev_get_by_dev()
->blkdev_get().
It will be confusing for users because sdc is added first time.
The "incremental" will get map_lock before add sdc to raid1.
So we add map_lock before write_init_super in "mdadm --add"
to fix the race of "add" and "incremental".
Signed-off-by: Li Xiao Keng <lixiaokeng@huawei.com>
Signed-off-by: Guanqin Miao <miaoguanqin@huawei.com>
Reviewed-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Manage.c | 24 ++++++++++++++++--------
1 file changed, 16 insertions(+), 8 deletions(-)
diff --git a/Manage.c b/Manage.c
index f997b163..075dd720 100644
--- a/Manage.c
+++ b/Manage.c
@@ -704,6 +704,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
struct supertype *dev_st;
int j;
mdu_disk_info_t disc;
+ struct map_ent *map = NULL;
if (!get_dev_size(tfd, dv->devname, &ldsize)) {
if (dv->disposition == 'M')
@@ -907,6 +908,9 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
disc.raid_disk = 0;
}
+ if (map_lock(&map))
+ pr_err("failed to get exclusive lock on mapfile when add disk\n");
+
if (array->not_persistent==0) {
int dfd;
if (dv->disposition == 'j')
@@ -918,9 +922,9 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
dfd = dev_open(dv->devname, O_RDWR | O_EXCL|O_DIRECT);
if (tst->ss->add_to_super(tst, &disc, dfd,
dv->devname, INVALID_SECTORS))
- return -1;
+ goto unlock;
if (tst->ss->write_init_super(tst))
- return -1;
+ goto unlock;
} else if (dv->disposition == 'A') {
/* this had better be raid1.
* As we are "--re-add"ing we must find a spare slot
@@ -978,14 +982,14 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
pr_err("add failed for %s: could not get exclusive access to container\n",
dv->devname);
tst->ss->free_super(tst);
- return -1;
+ goto unlock;
}
/* Check if metadata handler is able to accept the drive */
if (!tst->ss->validate_geometry(tst, LEVEL_CONTAINER, 0, 1, NULL,
0, 0, dv->devname, NULL, 0, 1)) {
close(container_fd);
- return -1;
+ goto unlock;
}
Kill(dv->devname, NULL, 0, -1, 0);
@@ -994,7 +998,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
dv->devname, INVALID_SECTORS)) {
close(dfd);
close(container_fd);
- return -1;
+ goto unlock;
}
if (!mdmon_running(tst->container_devnm))
tst->ss->sync_metadata(tst);
@@ -1005,7 +1009,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
dv->devname);
close(container_fd);
tst->ss->free_super(tst);
- return -1;
+ goto unlock;
}
sra->array.level = LEVEL_CONTAINER;
/* Need to set data_offset and component_size */
@@ -1020,7 +1024,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
pr_err("add new device to external metadata failed for %s\n", dv->devname);
close(container_fd);
sysfs_free(sra);
- return -1;
+ goto unlock;
}
ping_monitor(devnm);
sysfs_free(sra);
@@ -1034,7 +1038,7 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
else
pr_err("add new device failed for %s as %d: %s\n",
dv->devname, j, strerror(errno));
- return -1;
+ goto unlock;
}
if (dv->disposition == 'j') {
pr_err("Journal added successfully, making %s read-write\n", devname);
@@ -1045,7 +1049,11 @@ int Manage_add(int fd, int tfd, struct mddev_dev *dv,
}
if (verbose >= 0)
pr_err("added %s\n", dv->devname);
+ map_unlock(&map);
return 1;
+unlock:
+ map_unlock(&map);
+ return -1;
}
int Manage_remove(struct supertype *tst, int fd, struct mddev_dev *dv,
--
2.40.1

@ -0,0 +1,32 @@
From c32b4754014c1eec8cc0c025fad2e9b621486164 Mon Sep 17 00:00:00 2001
From: Xiao Ni <xni@redhat.com>
Date: Fri, 8 Sep 2023 16:44:35 +0800
Subject: [PATCH 161/165] mdadm/tests: Don't run mknod before losetup
Sometimes it can fail:
losetup: /var/tmp/mdtest0: failed to set up loop device: No such device or address
/dev/loop0 and /var/tmp/mdtest0 are already created before losetup.
Because losetup can create device node by itself. So remove mknod.
Signed-off-by: Xiao Ni <xni@redhat.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
tests/func.sh | 1 -
1 file changed, 1 deletion(-)
diff --git a/tests/func.sh b/tests/func.sh
index 9710a53b..5053b012 100644
--- a/tests/func.sh
+++ b/tests/func.sh
@@ -170,7 +170,6 @@ do_setup() {
dd if=/dev/zero of=$targetdir/mdtest$d count=$sz bs=1K > /dev/null 2>&1
# make sure udev doesn't touch
mdadm --zero $targetdir/mdtest$d 2> /dev/null
- [ -b /dev/loop$d ] || mknod /dev/loop$d b 7 $d
if [ $d -eq 7 ]
then
losetup /dev/loop$d $targetdir/mdtest6 # for multipath use
--
2.40.1

@ -0,0 +1,45 @@
From 246b4b40558f6f7f84882e9c34659f1b582944e2 Mon Sep 17 00:00:00 2001
From: Xiao Ni <xni@redhat.com>
Date: Wed, 11 Oct 2023 21:03:32 +0800
Subject: [PATCH 162/165] mdadm/ddf: Abort when raid disk is smaller in
getinfo_super_ddf
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The metadata is corrupted when the raid_disk<0. So abort directly.
This also can avoid a building error:
super-ddf.c:1988:58: error: array subscript -1 is below array bounds of struct phys_disk_entry[0]
Suggested-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Ackedy-by: Xiao Ni <xni@redhat.com>
Acked-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
super-ddf.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/super-ddf.c b/super-ddf.c
index c5242654..7571e3b7 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -1984,12 +1984,14 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
info->disk.number = be32_to_cpu(ddf->dlist->disk.refnum);
info->disk.raid_disk = find_phys(ddf, ddf->dlist->disk.refnum);
+ if (info->disk.raid_disk < 0)
+ return;
+
info->data_offset = be64_to_cpu(ddf->phys->
entries[info->disk.raid_disk].
config_size);
info->component_size = ddf->dlist->size - info->data_offset;
- if (info->disk.raid_disk >= 0)
- pde = ddf->phys->entries + info->disk.raid_disk;
+ pde = ddf->phys->entries + info->disk.raid_disk;
if (pde &&
!(be16_to_cpu(pde->state) & DDF_Failed) &&
!(be16_to_cpu(pde->state) & DDF_Missing))
--
2.40.1

@ -0,0 +1,75 @@
From 6af520a5b4d91cd0fd32ab6361ff4519505c7f47 Mon Sep 17 00:00:00 2001
From: Xiao Ni <xni@redhat.com>
Date: Tue, 17 Oct 2023 20:35:46 +0800
Subject: [PATCH 163/165] mdadm/super1: Add MD_FEATURE_RAID0_LAYOUT if
kernel>=5.4
After and include kernel v5.4, it adds one feature bit MD_FEATURE_RAID0_LAYOUT.
It must need to specify a layout for raid0 with more than one zone. But for
raid0 with one zone, in fact it also has a defalut layout.
Now for raid0 with one zone, *unknown* layout can be seen when running mdadm -D
command. It's the reason that mdadm doesn't set MD_FEATURE_RAID0_LAYOUT for
raid0 with one zone. Then in kernel space, super_1_validate sets mddev->layout
to -1 because of no MD_FEATURE_RAID0_LAYOUT. In fact, in raid0 io path, it
uses the default layout. Set raid0_need_layout to true if kernel_version<=v5.4.
Fixes: 329dfc28debb ('Create: add support for RAID0 layouts.')
Signed-off-by: Xiao Ni <xni@redhat.com>
Reviewed-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
super1.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/super1.c b/super1.c
index 856b0208..1da71b98 100644
--- a/super1.c
+++ b/super1.c
@@ -1967,6 +1967,14 @@ fail_to_write:
return 1;
}
+static bool has_raid0_layout(struct mdp_superblock_1 *sb)
+{
+ if (sb->level == 0 && sb->layout != 0)
+ return true;
+ else
+ return false;
+}
+
static int write_init_super1(struct supertype *st)
{
struct mdp_superblock_1 *sb = st->sb;
@@ -1978,12 +1986,17 @@ static int write_init_super1(struct supertype *st)
unsigned long long sb_offset;
unsigned long long data_offset;
long bm_offset;
- int raid0_need_layout = 0;
+ bool raid0_need_layout = false;
+
+ /* Since linux kernel v5.4, raid0 always has a layout */
+ if (has_raid0_layout(sb) && get_linux_version() >= 5004000)
+ raid0_need_layout = true;
for (di = st->info; di; di = di->next) {
if (di->disk.state & (1 << MD_DISK_JOURNAL))
sb->feature_map |= __cpu_to_le32(MD_FEATURE_JOURNAL);
- if (sb->level == 0 && sb->layout != 0) {
+ if (has_raid0_layout(sb) && !raid0_need_layout) {
+
struct devinfo *di2 = st->info;
unsigned long long s1, s2;
s1 = di->dev_size;
@@ -1995,7 +2008,7 @@ static int write_init_super1(struct supertype *st)
s2 -= di2->data_offset;
s2 /= __le32_to_cpu(sb->chunksize);
if (s1 != s2)
- raid0_need_layout = 1;
+ raid0_need_layout = true;
}
}
--
2.40.1

@ -0,0 +1,139 @@
From 4dde420fc3e24077ab926f79674eaae1b71de10b Mon Sep 17 00:00:00 2001
From: Pawel Piatkowski <pawel.piatkowski@intel.com>
Date: Thu, 19 Oct 2023 16:35:24 +0200
Subject: [PATCH 164/165] mdadm: remove container_enough logic
Arrays without enough disk count will be assembled but not
started.
Now RAIDs will be assembled always (even if they are failed).
RAID devices in all states will be assembled and exposed
to mdstat.
This change affects only IMSM (for ddf it wasn't used,
container_enough was set to true always).
Removed this logic from incremental_container as well with
runstop checking because runstop condition is being verified
in assemble_container_content function.
Signed-off-by: Pawel Piatkowski <pawel.piatkowski@intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Incremental.c | 11 -----------
mdadm.h | 3 ---
super-ddf.c | 1 -
super-intel.c | 32 +-------------------------------
4 files changed, 1 insertion(+), 46 deletions(-)
diff --git a/Incremental.c b/Incremental.c
index 05b33c45..3551c65b 100644
--- a/Incremental.c
+++ b/Incremental.c
@@ -1467,17 +1467,6 @@ static int Incremental_container(struct supertype *st, char *devname,
st->ss->getinfo_super(st, &info, NULL);
- if ((c->runstop > 0 && info.container_enough >= 0) ||
- info.container_enough > 0)
- /* pass */;
- else {
- if (c->export) {
- printf("MD_STARTED=no\n");
- } else if (c->verbose)
- pr_err("not enough devices to start the container\n");
- return 0;
- }
-
match = conf_match(st, &info, devname, c->verbose, &rv);
if (match == NULL && rv == 2)
return rv;
diff --git a/mdadm.h b/mdadm.h
index 9effb941..b48e6f86 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -377,9 +377,6 @@ struct mdinfo {
int container_member; /* for assembling external-metatdata arrays
* This is to be used internally by metadata
* handler only */
- int container_enough; /* flag external handlers can set to
- * indicate that subarrays have not enough (-1),
- * enough to start (0), or all expected disks (1) */
char sys_name[32];
struct mdinfo *devs;
struct mdinfo *next;
diff --git a/super-ddf.c b/super-ddf.c
index 7571e3b7..a87e3169 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -1975,7 +1975,6 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
info->array.ctime = DECADE + __be32_to_cpu(*cptr);
info->array.chunk_size = 0;
- info->container_enough = 1;
info->disk.major = 0;
info->disk.minor = 0;
diff --git a/super-intel.c b/super-intel.c
index 05d3b056..6bdd5c4c 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -3806,7 +3806,6 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
struct intel_super *super = st->sb;
struct imsm_disk *disk;
int map_disks = info->array.raid_disks;
- int max_enough = -1;
int i;
struct imsm_super *mpb;
@@ -3848,12 +3847,9 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
for (i = 0; i < mpb->num_raid_devs; i++) {
struct imsm_dev *dev = get_imsm_dev(super, i);
- int failed, enough, j, missing = 0;
+ int j = 0;
struct imsm_map *map;
- __u8 state;
- failed = imsm_count_failed(super, dev, MAP_0);
- state = imsm_check_degraded(super, dev, failed, MAP_0);
map = get_imsm_map(dev, MAP_0);
/* any newly missing disks?
@@ -3868,36 +3864,10 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
if (!(ord & IMSM_ORD_REBUILD) &&
get_imsm_missing(super, idx)) {
- missing = 1;
break;
}
}
-
- if (state == IMSM_T_STATE_FAILED)
- enough = -1;
- else if (state == IMSM_T_STATE_DEGRADED &&
- (state != map->map_state || missing))
- enough = 0;
- else /* we're normal, or already degraded */
- enough = 1;
- if (is_gen_migration(dev) && missing) {
- /* during general migration we need all disks
- * that process is running on.
- * No new missing disk is allowed.
- */
- max_enough = -1;
- enough = -1;
- /* no more checks necessary
- */
- break;
- }
- /* in the missing/failed disk case check to see
- * if at least one array is runnable
- */
- max_enough = max(max_enough, enough);
}
- dprintf("enough: %d\n", max_enough);
- info->container_enough = max_enough;
if (super->disks) {
__u32 reserved = imsm_reserved_sectors(super, super->disks);
--
2.40.1

@ -0,0 +1,49 @@
From d8d09c1633b2f06f88633ab960aa02b41a6bdfb6 Mon Sep 17 00:00:00 2001
From: Pawel Piatkowski <pawel.piatkowski@intel.com>
Date: Thu, 19 Oct 2023 16:35:25 +0200
Subject: [PATCH 165/165] Fix assembling RAID volume by using incremental
After change "mdadm: remove container_enough logic"
IMSM volumes are started immediately. If volume is during
reshape, then it will be blocked by block_subarray() during
first mdadm -I <devname>. Assemble_container_content() for
next disk will see the change because metadata version from
sysfs and metadata doesn't match and will execute
sysfs_set_array again. Then it fails to set same
component_size, it is prohibited by kernel.
If array is frozen then first sign from metadata version
is different ("/" vs "-"), so exclude it from comparison.
All we want is to double check that base properties are set
and we don't need to call sysfs_set_array again.
Signed-off-by: Pawel Piatkowski <pawel.piatkowski@intel.com>
Signed-off-by: Jes Sorensen <jes@trained-monkey.org>
---
Assemble.c | 10 ++++------
1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/Assemble.c b/Assemble.c
index 5be58e40..0557a007 100644
--- a/Assemble.c
+++ b/Assemble.c
@@ -1990,12 +1990,10 @@ int assemble_container_content(struct supertype *st, int mdfd,
return 1;
}
- if (strcmp(sra->text_version, content->text_version) != 0) {
- if (content->array.major_version == -1 &&
- content->array.minor_version == -2 &&
- c->readonly &&
- content->text_version[0] == '/')
- content->text_version[0] = '-';
+ /* Fill sysfs properties only if they are not set. Determine it by checking text_version
+ * and ignoring special character on the first place.
+ */
+ if (strcmp(sra->text_version + 1, content->text_version + 1) != 0) {
if (sysfs_set_array(content, 9003) != 0) {
sysfs_free(sra);
return 1;
--
2.40.1

@ -0,0 +1,151 @@
From 476b00bdeeb6c004b3a758bd842b0fa9e4164508 Mon Sep 17 00:00:00 2001
From: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
Date: Mon, 5 Feb 2024 15:50:29 +0100
Subject: [PATCH 1/1] Revert "mdadm: remove container_enough logic"
Mentioned patch changes way of IMSM member arrays assembling, they are
updated by every new drive incremental processes. Previously, member
arrays were created and filled once, by last drive incremental process.
We determined regressions with various impact. Unfortunately, initial
testing didn't show them.
Regressions are connected to drive appearance order and may not be
reproducible on every configuration, there are at least two know
issues for now:
- sysfs attributes are filled using old metadata if there is
outdated drive and it is enumerated first.
- rebuild may be aborted and started from beginning after reboot,
if drive under rebuild is enumerated as the last one.
This reverts commit 4dde420fc3e24077ab926f79674eaae1b71de10b. It fixes
checkpatch issues and reworks logic to remove empty "if" branch in
Incremental.
Signed-off-by: Mariusz Tkaczyk <mariusz.tkaczyk@linux.intel.com>
---
Incremental.c | 9 +++++++++
mdadm.h | 7 +++++++
super-ddf.c | 1 +
super-intel.c | 32 +++++++++++++++++++++++++++++++-
4 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/Incremental.c b/Incremental.c
index 6cbc164a27b9..30c07c037028 100644
--- a/Incremental.c
+++ b/Incremental.c
@@ -1467,6 +1467,15 @@ static int Incremental_container(struct supertype *st, char *devname,
st->ss->getinfo_super(st, &info, NULL);
+ if (info.container_enough < 0 || (info.container_enough == 0 && c->runstop < 1)) {
+ if (c->export)
+ printf("MD_STARTED=no\n");
+ else if (c->verbose)
+ pr_err("Not enough devices to start the container.\n");
+
+ return 0;
+ }
+
match = conf_match(st, &info, devname, c->verbose, &rv);
if (match == NULL && rv == 2)
return rv;
diff --git a/mdadm.h b/mdadm.h
index 709b6104c401..1f28b3e754be 100644
--- a/mdadm.h
+++ b/mdadm.h
@@ -377,6 +377,13 @@ struct mdinfo {
int container_member; /* for assembling external-metatdata arrays
* This is to be used internally by metadata
* handler only */
+ /**
+ * flag external handlers can set to indicate that subarrays have:
+ * - not enough disks to start (-1),
+ * - enough disks to start (0),
+ * - all expected disks (1).
+ */
+ int container_enough;
char sys_name[32];
struct mdinfo *devs;
struct mdinfo *next;
diff --git a/super-ddf.c b/super-ddf.c
index a87e3169d325..7571e3b740c6 100644
--- a/super-ddf.c
+++ b/super-ddf.c
@@ -1975,6 +1975,7 @@ static void getinfo_super_ddf(struct supertype *st, struct mdinfo *info, char *m
info->array.ctime = DECADE + __be32_to_cpu(*cptr);
info->array.chunk_size = 0;
+ info->container_enough = 1;
info->disk.major = 0;
info->disk.minor = 0;
diff --git a/super-intel.c b/super-intel.c
index 6a664a2e58d3..dbea235dd4bd 100644
--- a/super-intel.c
+++ b/super-intel.c
@@ -3778,6 +3778,7 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
struct intel_super *super = st->sb;
struct imsm_disk *disk;
int map_disks = info->array.raid_disks;
+ int max_enough = -1;
int i;
struct imsm_super *mpb;
@@ -3819,9 +3820,12 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
for (i = 0; i < mpb->num_raid_devs; i++) {
struct imsm_dev *dev = get_imsm_dev(super, i);
- int j = 0;
+ int failed, enough, j, missing = 0;
struct imsm_map *map;
+ __u8 state;
+ failed = imsm_count_failed(super, dev, MAP_0);
+ state = imsm_check_degraded(super, dev, failed, MAP_0);
map = get_imsm_map(dev, MAP_0);
/* any newly missing disks?
@@ -3836,11 +3840,37 @@ static void getinfo_super_imsm(struct supertype *st, struct mdinfo *info, char *
if (!(ord & IMSM_ORD_REBUILD) &&
get_imsm_missing(super, idx)) {
+ missing = 1;
break;
}
}
+
+ if (state == IMSM_T_STATE_FAILED)
+ enough = -1;
+ else if (state == IMSM_T_STATE_DEGRADED &&
+ (state != map->map_state || missing))
+ enough = 0;
+ else /* we're normal, or already degraded */
+ enough = 1;
+ if (is_gen_migration(dev) && missing) {
+ /* during general migration we need all disks
+ * that process is running on.
+ * No new missing disk is allowed.
+ */
+ max_enough = -1;
+ enough = -1;
+ /* no more checks necessary
+ */
+ break;
+ }
+ /* in the missing/failed disk case check to see
+ * if at least one array is runnable
+ */
+ max_enough = max(max_enough, enough);
}
+ info->container_enough = max_enough;
+
if (super->disks) {
__u32 reserved = imsm_reserved_sectors(super, super->disks);
--
2.32.0 (Apple Git-132)

@ -1,11 +0,0 @@
--- mdadm/Makefile.orig 2021-07-28 21:39:23.887433859 +0800
+++ mdadm/Makefile 2021-07-28 21:39:37.989432841 +0800
@@ -50,7 +50,7 @@
CC := $(CROSS_COMPILE)gcc
endif
CXFLAGS ?= -ggdb
-CWFLAGS = -Wall -Werror -Wstrict-prototypes -Wextra -Wno-unused-parameter
+CWFLAGS = -Wall -Wstrict-prototypes -Wextra -Wno-unused-parameter
ifdef WARN_UNUSED
CWFLAGS += -Wp,-D_FORTIFY_SOURCE=2 -O3
endif

@ -1,7 +1,7 @@
Name: mdadm
Version: 4.2
# extraversion is used to define rhel internal version
%define extraversion 9
%define extraversion 12
Release: %{extraversion}%{?dist}
Summary: The mdadm program controls Linux md devices (software RAID arrays)
URL: http://www.kernel.org/pub/linux/utils/raid/mdadm/
@ -144,13 +144,52 @@ Patch121: 0122-mdadm-define-DEV_NUM_PREF.patch
Patch122: 0123-mdadm-define-is_devname_ignore.patch
Patch123: 0124-mdadm-numbered-names-verification.patch
Patch124: 0125-enable-RAID-for-SATA-under-VMD.patch
Patch125: 0126-imsm-Fix-possible-segfault-in-check_no_platform.patch
Patch126: 0127-imsm-move-sum_extents-calculations-to-merge_extents.patch
Patch127: 0128-imsm-imsm_get_free_size-refactor.patch
Patch128: 0129-imsm-introduce-round_member_size_to_mb.patch
Patch129: 0130-imsm-move-expand-verification-code-into-new-function.patch
Patch130: 0131-imsm-return-free-space-after-volume-for-expand.patch
Patch131: 0132-imsm-fix-free-space-calculations.patch
Patch132: 0133-Add-secure-gethostname-wrapper.patch
Patch133: 0134-mdadm-Stop-mdcheck_continue-timer-when-mdcheck_start.patch
Patch134: 0135-Fix-memory-leak-in-file-Assemble.patch
Patch135: 0136-Fix-memory-leak-in-file-Kill.patch
Patch136: 0137-Fix-memory-leak-in-file-Manage.patch
Patch137: 0138-Fix-memory-leak-in-file-mdadm.patch
Patch138: 0139-Fix-unsafe-string-functions.patch
Patch139: 0140-platform-intel-limit-guid-length.patch
Patch140: 0141-imsm-Add-reading-vmd-register-for-finding-imsm-capab.patch
Patch141: 0142-Add-compiler-defenses-flags.patch
Patch142: 0143-Assemble-fix-redundant-memory-free.patch
Patch143: 0144-tests-add-a-new-test-for-rdev-lifetime.patch
Patch144: 0145-tests-support-to-skip-checking-dmesg.patch
Patch145: 0146-tests-add-a-regression-test-for-raid10-deadlock.patch
Patch146: 0147-tests-add-a-regression-test-for-raid456-deadlock.patch
Patch147: 0148-tests-add-a-regression-test-that-raid456-can-t-assem.patch
Patch148: 0149-tests-add-a-regression-test-that-raid456-can-t-assem.patch
Patch149: 0150-tests-add-a-regression-test-that-reshape-can-corrupt.patch
Patch150: 0151-tests-add-a-regression-test-for-raid456-deadlock-aga.patch
Patch151: 0152-tests-create-names_template.patch
Patch152: 0153-tests-create-00confnames.patch
Patch153: 0154-mdadm-set-ident.devname-if-applicable.patch
Patch154: 0155-mdadm-refactor-ident-name-handling.patch
Patch155: 0156-mdadm-define-ident_set_devname.patch
Patch156: 0157-mdadm-Follow-POSIX-Portable-Character-Set.patch
Patch157: 0158-Incremental-remove-obsoleted-calls-to-udisks.patch
Patch158: 0159-mdadm-tests-Fix-regular-expression-failure.patch
Patch159: 0160-Fix-race-of-mdadm-add-and-mdadm-incremental.patch
Patch160: 0161-mdadm-tests-Don-t-run-mknod-before-losetup.patch
Patch161: 0162-mdadm-ddf-Abort-when-raid-disk-is-smaller-in-getinfo.patch
Patch162: 0163-mdadm-super1-Add-MD_FEATURE_RAID0_LAYOUT-if-kernel-5.patch
Patch163: 0164-mdadm-remove-container_enough-logic.patch
Patch164: 0165-Fix-assembling-RAID-volume-by-using-incremental.patch
Patch165: 0166-Revert-mdadm-remove-container_enough-logic.patch
# Fedora customization patches
Patch200: mdadm-udev.patch
Patch201: mdadm-2.5.2-static.patch
# Build without -Werror.
Patch202: disable-Werror.patch
BuildRequires: make
BuildRequires: systemd-rpm-macros binutils-devel gcc systemd-devel
@ -224,6 +263,18 @@ install -m644 %{SOURCE5} %{buildroot}/etc/libreport/events.d
/usr/share/mdadm/mdcheck
%changelog
* Wed Mar 20 2024 Xiao Ni <xni@redhat.com> 4.2-12
- To fix errata/osci problems
- Resolves RHEL-26272
* Fri Mar 15 2024 Xiao Ni <xni@redhat.com> 4.2-11
- revert "mdadm: remove container_enough logic"
- Resolves RHEL-26272
* Fri Nov 3 2023 Xiao Ni <xni@redhat.com> - 4.2-10
- Update to latest upstream
- Resolves RHEL-15386
* Tue May 16 2023 Xiao Ni <xni@redhat.com> - 4.2-9
- Update to latest upstream and fix mdcheck service bug
- Resolves rhbz#2159923, rhbz#2150865, rhbz#2124071, rhbz#2203859

Loading…
Cancel
Save