import device-mapper-multipath-0.8.4-32.el8
This commit is contained in:
parent
cbe66698dd
commit
cd67b834f7
@ -0,0 +1,47 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Wed, 19 Oct 2022 12:57:10 -0500
|
||||
Subject: [PATCH] kpartx: hold device open until partitions have been created
|
||||
|
||||
kpartx was closing the whole device after it read the partition
|
||||
information off it. This allowed a race, where the device could be
|
||||
removed and another one created with the same major:minor, after kpartx
|
||||
read the partition information but before it created the partition
|
||||
devices.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
kpartx/kpartx.c | 11 +++--------
|
||||
1 file changed, 3 insertions(+), 8 deletions(-)
|
||||
|
||||
diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c
|
||||
index a337a07b..e62b764f 100644
|
||||
--- a/kpartx/kpartx.c
|
||||
+++ b/kpartx/kpartx.c
|
||||
@@ -426,12 +426,7 @@ main(int argc, char **argv){
|
||||
if (n >= 0)
|
||||
printf("%s: %d slices\n", ptp->type, n);
|
||||
#endif
|
||||
-
|
||||
- if (n > 0) {
|
||||
- close(fd);
|
||||
- fd = -1;
|
||||
- }
|
||||
- else
|
||||
+ if (n <= 0)
|
||||
continue;
|
||||
|
||||
switch(what) {
|
||||
@@ -649,9 +644,9 @@ main(int argc, char **argv){
|
||||
if (n > 0)
|
||||
break;
|
||||
}
|
||||
+ if (fd != -1)
|
||||
+ close(fd);
|
||||
if (what == LIST && loopcreated) {
|
||||
- if (fd != -1)
|
||||
- close(fd);
|
||||
if (del_loop(device)) {
|
||||
if (verbose)
|
||||
fprintf(stderr, "can't del loop : %s\n",
|
153
SOURCES/0117-libmultipath-cleanup-remove_feature.patch
Normal file
153
SOURCES/0117-libmultipath-cleanup-remove_feature.patch
Normal file
@ -0,0 +1,153 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 7 Oct 2022 12:35:37 -0500
|
||||
Subject: [PATCH] libmultipath: cleanup remove_feature
|
||||
|
||||
remove_feature() didn't correctly handle feature strings that used
|
||||
whitespace other than spaces, which the kernel allows. It also didn't
|
||||
check if the feature string to be removed was part of a larger feature
|
||||
token. Finally, it did a lot of unnecessary work. By failing if the
|
||||
feature string to be removed contains leading or trailing whitespace,
|
||||
the function can be significanly simplified.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmultipath/structs.c | 82 +++++++++++++++---------------------------
|
||||
1 file changed, 29 insertions(+), 53 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
|
||||
index 9f86eb69..471087e2 100644
|
||||
--- a/libmultipath/structs.c
|
||||
+++ b/libmultipath/structs.c
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <unistd.h>
|
||||
#include <libdevmapper.h>
|
||||
#include <libudev.h>
|
||||
+#include <ctype.h>
|
||||
|
||||
#include "checkers.h"
|
||||
#include "memory.h"
|
||||
@@ -633,7 +634,7 @@ int add_feature(char **f, const char *n)
|
||||
|
||||
int remove_feature(char **f, const char *o)
|
||||
{
|
||||
- int c = 0, d, l;
|
||||
+ int c = 0, d;
|
||||
char *e, *p, *n;
|
||||
const char *q;
|
||||
|
||||
@@ -644,33 +645,35 @@ int remove_feature(char **f, const char *o)
|
||||
if (!o || *o == '\0')
|
||||
return 0;
|
||||
|
||||
- /* Check if not present */
|
||||
- if (!strstr(*f, o))
|
||||
+ d = strlen(o);
|
||||
+ if (isspace(*o) || isspace(*(o + d - 1))) {
|
||||
+ condlog(0, "internal error: feature \"%s\" has leading or trailing spaces", o);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ /* Check if present and not part of a larger feature token*/
|
||||
+ p = *f + 1; /* the size must be at the start of the features string */
|
||||
+ while ((p = strstr(p, o)) != NULL) {
|
||||
+ if (isspace(*(p - 1)) &&
|
||||
+ (isspace(*(p + d)) || *(p + d) == '\0'))
|
||||
+ break;
|
||||
+ p += d;
|
||||
+ }
|
||||
+ if (!p)
|
||||
return 0;
|
||||
|
||||
/* Get feature count */
|
||||
c = strtoul(*f, &e, 10);
|
||||
- if (*f == e)
|
||||
- /* parse error */
|
||||
+ if (*f == e || !isspace(*e)) {
|
||||
+ condlog(0, "parse error in feature string \"%s\"", *f);
|
||||
return 1;
|
||||
-
|
||||
- /* Normalize features */
|
||||
- while (*o == ' ') {
|
||||
- o++;
|
||||
}
|
||||
- /* Just spaces, return */
|
||||
- if (*o == '\0')
|
||||
- return 0;
|
||||
- q = o + strlen(o);
|
||||
- while (*q == ' ')
|
||||
- q--;
|
||||
- d = (int)(q - o);
|
||||
|
||||
/* Update feature count */
|
||||
c--;
|
||||
q = o;
|
||||
- while (q[0] != '\0') {
|
||||
- if (q[0] == ' ' && q[1] != ' ' && q[1] != '\0')
|
||||
+ while (*q != '\0') {
|
||||
+ if (isspace(*q) && !isspace(*(q + 1)) && *(q + 1) != '\0')
|
||||
c--;
|
||||
q++;
|
||||
}
|
||||
@@ -684,15 +687,8 @@ int remove_feature(char **f, const char *o)
|
||||
goto out;
|
||||
}
|
||||
|
||||
- /* Search feature to be removed */
|
||||
- e = strstr(*f, o);
|
||||
- if (!e)
|
||||
- /* Not found, return */
|
||||
- return 0;
|
||||
-
|
||||
/* Update feature count space */
|
||||
- l = strlen(*f) - d;
|
||||
- n = MALLOC(l + 1);
|
||||
+ n = MALLOC(strlen(*f) - d + 1);
|
||||
if (!n)
|
||||
return 1;
|
||||
|
||||
@@ -702,36 +698,16 @@ int remove_feature(char **f, const char *o)
|
||||
* Copy existing features up to the feature
|
||||
* about to be removed
|
||||
*/
|
||||
- p = strchr(*f, ' ');
|
||||
- if (!p) {
|
||||
- /* Internal error, feature string inconsistent */
|
||||
- FREE(n);
|
||||
- return 1;
|
||||
- }
|
||||
- while (*p == ' ')
|
||||
- p++;
|
||||
- p--;
|
||||
- if (e != p) {
|
||||
- do {
|
||||
- e--;
|
||||
- d++;
|
||||
- } while (*e == ' ');
|
||||
- e++; d--;
|
||||
- strncat(n, p, (size_t)(e - p));
|
||||
- p += (size_t)(e - p);
|
||||
- }
|
||||
+ strncat(n, e, (size_t)(p - e));
|
||||
/* Skip feature to be removed */
|
||||
p += d;
|
||||
-
|
||||
/* Copy remaining features */
|
||||
- if (strlen(p)) {
|
||||
- while (*p == ' ')
|
||||
- p++;
|
||||
- if (strlen(p)) {
|
||||
- p--;
|
||||
- strcat(n, p);
|
||||
- }
|
||||
- }
|
||||
+ while (isspace(*p))
|
||||
+ p++;
|
||||
+ if (*p != '\0')
|
||||
+ strcat(n, p);
|
||||
+ else
|
||||
+ strchop(n);
|
||||
|
||||
out:
|
||||
FREE(*f);
|
107
SOURCES/0118-libmultipath-cleanup-add_feature.patch
Normal file
107
SOURCES/0118-libmultipath-cleanup-add_feature.patch
Normal file
@ -0,0 +1,107 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 7 Oct 2022 12:35:38 -0500
|
||||
Subject: [PATCH] libmultipath: cleanup add_feature
|
||||
|
||||
add_feature() didn't correctly handle feature strings that used
|
||||
whitespace other than spaces, which the kernel allows. It also didn't
|
||||
allow adding features with multiple tokens. When it looked to see if the
|
||||
feature string to be added already existed, it didn't check if the match
|
||||
was part of a larger token. Finally, it did unnecessary work. By using
|
||||
asprintf() to create the string, the function can be signifcantly
|
||||
simplified.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmultipath/structs.c | 49 +++++++++++++++++++++---------------------
|
||||
1 file changed, 24 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
|
||||
index 471087e2..84f9c959 100644
|
||||
--- a/libmultipath/structs.c
|
||||
+++ b/libmultipath/structs.c
|
||||
@@ -572,23 +572,33 @@ int add_feature(char **f, const char *n)
|
||||
{
|
||||
int c = 0, d, l;
|
||||
char *e, *t;
|
||||
+ const char *p;
|
||||
|
||||
if (!f)
|
||||
return 1;
|
||||
|
||||
/* Nothing to do */
|
||||
- if (!n || *n == '0')
|
||||
+ if (!n || *n == '\0')
|
||||
return 0;
|
||||
|
||||
- if (strchr(n, ' ') != NULL) {
|
||||
- condlog(0, "internal error: feature \"%s\" contains spaces", n);
|
||||
+ l = strlen(n);
|
||||
+ if (isspace(*n) || isspace(*(n + l - 1))) {
|
||||
+ condlog(0, "internal error: feature \"%s\" has leading or trailing spaces", n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
+ p = n;
|
||||
+ d = 1;
|
||||
+ while (*p != '\0') {
|
||||
+ if (isspace(*p) && !isspace(*(p + 1)) && *(p + 1) != '\0')
|
||||
+ d++;
|
||||
+ p++;
|
||||
+ }
|
||||
+
|
||||
/* default feature is null */
|
||||
if(!*f)
|
||||
{
|
||||
- l = asprintf(&t, "1 %s", n);
|
||||
+ l = asprintf(&t, "%0d %s", d, n);
|
||||
if(l == -1)
|
||||
return 1;
|
||||
|
||||
@@ -597,35 +607,24 @@ int add_feature(char **f, const char *n)
|
||||
}
|
||||
|
||||
/* Check if feature is already present */
|
||||
- if (strstr(*f, n))
|
||||
- return 0;
|
||||
+ e = *f;
|
||||
+ while ((e = strstr(e, n)) != NULL) {
|
||||
+ if (isspace(*(e - 1)) &&
|
||||
+ (isspace(*(e + l)) || *(e + l) == '\0'))
|
||||
+ return 0;
|
||||
+ e += l;
|
||||
+ }
|
||||
|
||||
/* Get feature count */
|
||||
c = strtoul(*f, &e, 10);
|
||||
- if (*f == e || (*e != ' ' && *e != '\0')) {
|
||||
+ if (*f == e || (!isspace(*e) && *e != '\0')) {
|
||||
condlog(0, "parse error in feature string \"%s\"", *f);
|
||||
return 1;
|
||||
}
|
||||
-
|
||||
- /* Add 1 digit and 1 space */
|
||||
- l = strlen(e) + strlen(n) + 2;
|
||||
-
|
||||
- c++;
|
||||
- /* Check if we need more digits for feature count */
|
||||
- for (d = c; d >= 10; d /= 10)
|
||||
- l++;
|
||||
-
|
||||
- t = MALLOC(l + 1);
|
||||
- if (!t)
|
||||
+ c += d;
|
||||
+ if (asprintf(&t, "%0d%s %s", c, e, n) < 0)
|
||||
return 1;
|
||||
|
||||
- /* e: old feature string with leading space, or "" */
|
||||
- if (*e == ' ')
|
||||
- while (*(e + 1) == ' ')
|
||||
- e++;
|
||||
-
|
||||
- snprintf(t, l + 1, "%0d%s %s", c, e, n);
|
||||
-
|
||||
FREE(*f);
|
||||
*f = t;
|
||||
|
@ -0,0 +1,350 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 7 Oct 2022 12:35:39 -0500
|
||||
Subject: [PATCH] multipath tests: tests for adding and removing features
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
tests/Makefile | 2 +-
|
||||
tests/features.c | 318 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 319 insertions(+), 1 deletion(-)
|
||||
create mode 100644 tests/features.c
|
||||
|
||||
diff --git a/tests/Makefile b/tests/Makefile
|
||||
index 77ff3249..914413b8 100644
|
||||
--- a/tests/Makefile
|
||||
+++ b/tests/Makefile
|
||||
@@ -13,7 +13,7 @@ CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) \
|
||||
LIBDEPS += -L$(multipathdir) -lmultipath -lcmocka
|
||||
|
||||
TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \
|
||||
- alias directio
|
||||
+ alias directio features
|
||||
|
||||
.SILENT: $(TESTS:%=%.o)
|
||||
.PRECIOUS: $(TESTS:%=%-test)
|
||||
diff --git a/tests/features.c b/tests/features.c
|
||||
new file mode 100644
|
||||
index 00000000..1e2e6bff
|
||||
--- /dev/null
|
||||
+++ b/tests/features.c
|
||||
@@ -0,0 +1,318 @@
|
||||
+#include <stddef.h>
|
||||
+#include <stdarg.h>
|
||||
+#include <setjmp.h>
|
||||
+#include <cmocka.h>
|
||||
+
|
||||
+#include "structs.h"
|
||||
+#include "globals.c"
|
||||
+
|
||||
+static void test_af_null_features_ptr(void **state)
|
||||
+{
|
||||
+ assert_int_equal(add_feature(NULL, "test"), 1);
|
||||
+}
|
||||
+
|
||||
+static void af_helper(const char *features_start, const char *addition,
|
||||
+ const char *features_end, int result)
|
||||
+{
|
||||
+ char *f = NULL, *orig = NULL;
|
||||
+
|
||||
+ if (features_start) {
|
||||
+ f = strdup(features_start);
|
||||
+ assert_non_null(f);
|
||||
+ orig = f;
|
||||
+ }
|
||||
+ assert_int_equal(add_feature(&f, addition), result);
|
||||
+ if (result != 0 || features_end == NULL)
|
||||
+ assert_ptr_equal(orig, f);
|
||||
+ else
|
||||
+ assert_string_equal(f, features_end);
|
||||
+ free(f);
|
||||
+}
|
||||
+
|
||||
+static void test_af_null_addition1(void **state)
|
||||
+{
|
||||
+ af_helper("0", NULL, NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_null_addition2(void **state)
|
||||
+{
|
||||
+ af_helper("1 queue_if_no_path", NULL, NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_empty_addition(void **state)
|
||||
+{
|
||||
+ af_helper("2 pg_init_retries 5", "", NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_invalid_addition1(void **state)
|
||||
+{
|
||||
+ af_helper("2 pg_init_retries 5", " ", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_af_invalid_addition2(void **state)
|
||||
+{
|
||||
+ af_helper("2 pg_init_retries 5", "\tbad", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_af_invalid_addition3(void **state)
|
||||
+{
|
||||
+ af_helper("2 pg_init_retries 5", "bad ", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_af_invalid_addition4(void **state)
|
||||
+{
|
||||
+ af_helper("2 pg_init_retries 5", " bad ", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_af_null_features1(void **state)
|
||||
+{
|
||||
+ af_helper(NULL, "test", "1 test", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_null_features2(void **state)
|
||||
+{
|
||||
+ af_helper(NULL, "test\t more", "2 test\t more", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_null_features3(void **state)
|
||||
+{
|
||||
+ af_helper(NULL, "test\neven\tmore", "3 test\neven\tmore", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_already_exists1(void **state)
|
||||
+{
|
||||
+ af_helper("4 this is a test", "test", NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_already_exists2(void **state)
|
||||
+{
|
||||
+ af_helper("5 contest testy intestine test retest", "test", NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_almost_exists(void **state)
|
||||
+{
|
||||
+ af_helper("3 contest testy intestine", "test",
|
||||
+ "4 contest testy intestine test", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_bad_features1(void **state)
|
||||
+{
|
||||
+ af_helper("bad", "test", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_af_bad_features2(void **state)
|
||||
+{
|
||||
+ af_helper("1bad", "test", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_af_add1(void **state)
|
||||
+{
|
||||
+ af_helper("0", "test", "1 test", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_add2(void **state)
|
||||
+{
|
||||
+ af_helper("0", "this is a test", "4 this is a test", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_add3(void **state)
|
||||
+{
|
||||
+ af_helper("1 features", "more values", "3 features more values", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_af_add4(void **state)
|
||||
+{
|
||||
+ af_helper("2 one\ttwo", "three\t four", "4 one\ttwo three\t four", 0);
|
||||
+}
|
||||
+
|
||||
+static int test_add_features(void)
|
||||
+{
|
||||
+ const struct CMUnitTest tests[] = {
|
||||
+ cmocka_unit_test(test_af_null_features_ptr),
|
||||
+ cmocka_unit_test(test_af_null_addition1),
|
||||
+ cmocka_unit_test(test_af_null_addition2),
|
||||
+ cmocka_unit_test(test_af_empty_addition),
|
||||
+ cmocka_unit_test(test_af_invalid_addition1),
|
||||
+ cmocka_unit_test(test_af_invalid_addition2),
|
||||
+ cmocka_unit_test(test_af_invalid_addition3),
|
||||
+ cmocka_unit_test(test_af_invalid_addition4),
|
||||
+ cmocka_unit_test(test_af_null_features1),
|
||||
+ cmocka_unit_test(test_af_null_features2),
|
||||
+ cmocka_unit_test(test_af_null_features3),
|
||||
+ cmocka_unit_test(test_af_already_exists1),
|
||||
+ cmocka_unit_test(test_af_already_exists2),
|
||||
+ cmocka_unit_test(test_af_almost_exists),
|
||||
+ cmocka_unit_test(test_af_bad_features1),
|
||||
+ cmocka_unit_test(test_af_bad_features2),
|
||||
+ cmocka_unit_test(test_af_add1),
|
||||
+ cmocka_unit_test(test_af_add2),
|
||||
+ cmocka_unit_test(test_af_add3),
|
||||
+ cmocka_unit_test(test_af_add4),
|
||||
+ };
|
||||
+ return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_null_features_ptr(void **state)
|
||||
+{
|
||||
+ assert_int_equal(remove_feature(NULL, "test"), 1);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_null_features(void **state)
|
||||
+{
|
||||
+ char *f = NULL;
|
||||
+ assert_int_equal(remove_feature(&f, "test"), 1);
|
||||
+}
|
||||
+
|
||||
+static void rf_helper(const char *features_start, const char *removal,
|
||||
+ const char *features_end, int result)
|
||||
+{
|
||||
+ char *f = strdup(features_start);
|
||||
+ char *orig = f;
|
||||
+
|
||||
+ assert_non_null(f);
|
||||
+ assert_int_equal(remove_feature(&f, removal), result);
|
||||
+ if (result != 0 || features_end == NULL)
|
||||
+ assert_ptr_equal(orig, f);
|
||||
+ else
|
||||
+ assert_string_equal(f, features_end);
|
||||
+ free(f);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_null_removal(void **state)
|
||||
+{
|
||||
+ rf_helper("1 feature", NULL, NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_empty_removal(void **state)
|
||||
+{
|
||||
+ rf_helper("1 feature", "", NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_invalid_removal1(void **state)
|
||||
+{
|
||||
+ rf_helper("1 feature", " ", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_invalid_removal2(void **state)
|
||||
+{
|
||||
+ rf_helper("1 feature", " bad", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_invalid_removal3(void **state)
|
||||
+{
|
||||
+ rf_helper("1 feature", "bad\n", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_invalid_removal4(void **state)
|
||||
+{
|
||||
+ rf_helper("1 feature", "\tbad \n", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_bad_features1(void **state)
|
||||
+{
|
||||
+ rf_helper("invalid feature test string", "test", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_bad_features2(void **state)
|
||||
+{
|
||||
+ rf_helper("2no space test", "test", NULL, 1);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_missing_removal1(void **state)
|
||||
+{
|
||||
+ rf_helper("0", "test", NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_missing_removal2(void **state)
|
||||
+{
|
||||
+ rf_helper("1 detest", "test", NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_missing_removal3(void **state)
|
||||
+{
|
||||
+ rf_helper("4 testing one two three", "test", NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_missing_removal4(void **state)
|
||||
+{
|
||||
+ rf_helper("1 contestant", "test", NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_missing_removal5(void **state)
|
||||
+{
|
||||
+ rf_helper("3 testament protest detestable", "test", NULL, 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_remove_all_features1(void **state)
|
||||
+{
|
||||
+ rf_helper("1 test", "test", "0", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_remove_all_features2(void **state)
|
||||
+{
|
||||
+ rf_helper("2 another\t test", "another\t test", "0", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_remove1(void **state)
|
||||
+{
|
||||
+ rf_helper("2 feature1 feature2", "feature2", "1 feature1", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_remove2(void **state)
|
||||
+{
|
||||
+ rf_helper("2 feature1 feature2", "feature1", "1 feature2", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_remove3(void **state)
|
||||
+{
|
||||
+ rf_helper("3 test1 test\ttest2", "test", "2 test1 test2", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_remove4(void **state)
|
||||
+{
|
||||
+ rf_helper("4 this\t is a test", "is a", "2 this\t test", 0);
|
||||
+}
|
||||
+
|
||||
+static void test_rf_remove5(void **state)
|
||||
+{
|
||||
+ rf_helper("3 one more test", "more test", "1 one", 0);
|
||||
+}
|
||||
+
|
||||
+static int test_remove_features(void)
|
||||
+{
|
||||
+ const struct CMUnitTest tests[] = {
|
||||
+ cmocka_unit_test(test_rf_null_features_ptr),
|
||||
+ cmocka_unit_test(test_rf_null_features),
|
||||
+ cmocka_unit_test(test_rf_null_removal),
|
||||
+ cmocka_unit_test(test_rf_empty_removal),
|
||||
+ cmocka_unit_test(test_rf_invalid_removal1),
|
||||
+ cmocka_unit_test(test_rf_invalid_removal2),
|
||||
+ cmocka_unit_test(test_rf_invalid_removal3),
|
||||
+ cmocka_unit_test(test_rf_invalid_removal4),
|
||||
+ cmocka_unit_test(test_rf_bad_features1),
|
||||
+ cmocka_unit_test(test_rf_bad_features2),
|
||||
+ cmocka_unit_test(test_rf_missing_removal1),
|
||||
+ cmocka_unit_test(test_rf_missing_removal2),
|
||||
+ cmocka_unit_test(test_rf_missing_removal3),
|
||||
+ cmocka_unit_test(test_rf_missing_removal4),
|
||||
+ cmocka_unit_test(test_rf_missing_removal5),
|
||||
+ cmocka_unit_test(test_rf_remove_all_features1),
|
||||
+ cmocka_unit_test(test_rf_remove_all_features2),
|
||||
+ cmocka_unit_test(test_rf_remove1),
|
||||
+ cmocka_unit_test(test_rf_remove2),
|
||||
+ cmocka_unit_test(test_rf_remove3),
|
||||
+ cmocka_unit_test(test_rf_remove4),
|
||||
+ cmocka_unit_test(test_rf_remove5),
|
||||
+ };
|
||||
+ return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
+}
|
||||
+
|
||||
+int main(void)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ ret += test_add_features();
|
||||
+ ret += test_remove_features();
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
212
SOURCES/0120-libmultipath-fix-queue_mode-feature-handling.patch
Normal file
212
SOURCES/0120-libmultipath-fix-queue_mode-feature-handling.patch
Normal file
@ -0,0 +1,212 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 7 Oct 2022 12:35:40 -0500
|
||||
Subject: [PATCH] libmultipath: fix queue_mode feature handling
|
||||
|
||||
device-mapper is not able to change the queue_mode on a table reload.
|
||||
Make sure that when multipath sets up the map, both on regular reloads
|
||||
and reconfigures, it keeps the queue_mode the same.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmultipath/configure.c | 4 +++
|
||||
libmultipath/dmparser.c | 2 ++
|
||||
libmultipath/propsel.c | 55 ++++++++++++++++++++++++++++++++++++++
|
||||
libmultipath/structs.h | 7 +++++
|
||||
libmultipath/util.c | 10 +++++++
|
||||
libmultipath/util.h | 1 +
|
||||
multipath/multipath.conf.5 | 7 +++--
|
||||
7 files changed, 84 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||||
index 6cad0468..287289f7 100644
|
||||
--- a/libmultipath/configure.c
|
||||
+++ b/libmultipath/configure.c
|
||||
@@ -1102,6 +1102,7 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
|
||||
uint64_t *size_mismatch_seen;
|
||||
bool map_processed = false;
|
||||
bool no_daemon = false;
|
||||
+ struct multipath * cmpp;
|
||||
|
||||
/* ignore refwwid if it's empty */
|
||||
if (refwwid && !strlen(refwwid))
|
||||
@@ -1197,6 +1198,9 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
|
||||
}
|
||||
verify_paths(mpp, vecs);
|
||||
|
||||
+ cmpp = find_mp_by_wwid(curmp, mpp->wwid);
|
||||
+ if (cmpp)
|
||||
+ mpp->queue_mode = cmpp->queue_mode;
|
||||
params[0] = '\0';
|
||||
if (setup_map(mpp, params, PARAMS_SIZE, vecs)) {
|
||||
remove_map(mpp, vecs, 0);
|
||||
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
|
||||
index b856a07f..b9c4dabc 100644
|
||||
--- a/libmultipath/dmparser.c
|
||||
+++ b/libmultipath/dmparser.c
|
||||
@@ -164,6 +164,8 @@ int disassemble_map(vector pathvec, char *params, struct multipath *mpp,
|
||||
|
||||
FREE(word);
|
||||
}
|
||||
+ mpp->queue_mode = strstr(mpp->features, "queue_mode bio") ?
|
||||
+ QUEUE_MODE_BIO : QUEUE_MODE_RQ;
|
||||
|
||||
/*
|
||||
* hwhandler
|
||||
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
|
||||
index be79902f..3f119dd9 100644
|
||||
--- a/libmultipath/propsel.c
|
||||
+++ b/libmultipath/propsel.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "propsel.h"
|
||||
#include <inttypes.h>
|
||||
#include <libudev.h>
|
||||
+#include <ctype.h>
|
||||
|
||||
pgpolicyfn *pgpolicies[] = {
|
||||
NULL,
|
||||
@@ -413,6 +414,59 @@ void reconcile_features_with_options(const char *id, char **features, int* no_pa
|
||||
}
|
||||
}
|
||||
|
||||
+static void reconcile_features_with_queue_mode(struct multipath *mp)
|
||||
+{
|
||||
+ char *space = NULL, *val = NULL, *mode_str = NULL, *feat;
|
||||
+ int features_mode = QUEUE_MODE_UNDEF;
|
||||
+
|
||||
+ if (!mp->features)
|
||||
+ return;
|
||||
+
|
||||
+ pthread_cleanup_push(cleanup_free_ptr, &space);
|
||||
+ pthread_cleanup_push(cleanup_free_ptr, &val);
|
||||
+ pthread_cleanup_push(cleanup_free_ptr, &mode_str);
|
||||
+
|
||||
+ if (!(feat = strstr(mp->features, "queue_mode")) ||
|
||||
+ feat == mp->features || !isspace(*(feat - 1)) ||
|
||||
+ sscanf(feat, "queue_mode%m[ \f\n\r\t\v]%ms", &space, &val) != 2)
|
||||
+ goto sync_mode;
|
||||
+ if (asprintf(&mode_str, "queue_mode%s%s", space, val) < 0) {
|
||||
+ condlog(1, "failed to allocate space for queue_mode feature string");
|
||||
+ mode_str = NULL; /* value undefined on failure */
|
||||
+ goto exit;
|
||||
+ }
|
||||
+
|
||||
+ if (!strcmp(val, "rq") || !strcmp(val, "mq"))
|
||||
+ features_mode = QUEUE_MODE_RQ;
|
||||
+ else if (!strcmp(val, "bio"))
|
||||
+ features_mode = QUEUE_MODE_BIO;
|
||||
+ if (features_mode == QUEUE_MODE_UNDEF) {
|
||||
+ condlog(2, "%s: ignoring invalid feature '%s'",
|
||||
+ mp->alias, mode_str);
|
||||
+ goto sync_mode;
|
||||
+ }
|
||||
+
|
||||
+ if (mp->queue_mode == QUEUE_MODE_UNDEF)
|
||||
+ mp->queue_mode = features_mode;
|
||||
+ if (mp->queue_mode == features_mode)
|
||||
+ goto exit;
|
||||
+
|
||||
+ condlog(2,
|
||||
+ "%s: ignoring feature '%s' because queue_mode is set to '%s'",
|
||||
+ mp->alias, mode_str,
|
||||
+ (mp->queue_mode == QUEUE_MODE_RQ)? "rq" : "bio");
|
||||
+
|
||||
+sync_mode:
|
||||
+ if (mode_str)
|
||||
+ remove_feature(&mp->features, mode_str);
|
||||
+ if (mp->queue_mode == QUEUE_MODE_BIO)
|
||||
+ add_feature(&mp->features, "queue_mode bio");
|
||||
+exit:
|
||||
+ pthread_cleanup_pop(1);
|
||||
+ pthread_cleanup_pop(1);
|
||||
+ pthread_cleanup_pop(1);
|
||||
+}
|
||||
+
|
||||
int select_features(struct config *conf, struct multipath *mp)
|
||||
{
|
||||
const char *origin;
|
||||
@@ -428,6 +482,7 @@ out:
|
||||
reconcile_features_with_options(mp->alias, &mp->features,
|
||||
&mp->no_path_retry,
|
||||
&mp->retain_hwhandler);
|
||||
+ reconcile_features_with_queue_mode(mp);
|
||||
condlog(3, "%s: features = \"%s\" %s", mp->alias, mp->features, origin);
|
||||
return 0;
|
||||
}
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index 3ed5cfc1..9a404da7 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -187,6 +187,12 @@ enum max_sectors_kb_states {
|
||||
MAX_SECTORS_KB_MIN = 4, /* can't be smaller than page size */
|
||||
};
|
||||
|
||||
+enum queue_mode_states {
|
||||
+ QUEUE_MODE_UNDEF = 0,
|
||||
+ QUEUE_MODE_BIO,
|
||||
+ QUEUE_MODE_RQ,
|
||||
+};
|
||||
+
|
||||
enum scsi_protocol {
|
||||
SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */
|
||||
SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */
|
||||
@@ -397,6 +403,7 @@ struct multipath {
|
||||
int needs_paths_uevent;
|
||||
int ghost_delay;
|
||||
int ghost_delay_tick;
|
||||
+ int queue_mode;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
mode_t mode;
|
||||
diff --git a/libmultipath/util.c b/libmultipath/util.c
|
||||
index dd30a46e..e04d20ab 100644
|
||||
--- a/libmultipath/util.c
|
||||
+++ b/libmultipath/util.c
|
||||
@@ -465,6 +465,16 @@ void free_scandir_result(struct scandir_result *res)
|
||||
FREE(res->di);
|
||||
}
|
||||
|
||||
+void cleanup_free_ptr(void *arg)
|
||||
+{
|
||||
+ void **p = arg;
|
||||
+
|
||||
+ if (p && *p) {
|
||||
+ free(*p);
|
||||
+ *p = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void close_fd(void *arg)
|
||||
{
|
||||
close((long)arg);
|
||||
diff --git a/libmultipath/util.h b/libmultipath/util.h
|
||||
index ce277680..f898c829 100644
|
||||
--- a/libmultipath/util.h
|
||||
+++ b/libmultipath/util.h
|
||||
@@ -44,6 +44,7 @@ void set_max_fds(rlim_t max_fds);
|
||||
pthread_cleanup_push(((void (*)(void *))&f), (arg))
|
||||
|
||||
void close_fd(void *arg);
|
||||
+void cleanup_free_ptr(void *arg);
|
||||
void cleanup_mutex(void *arg);
|
||||
|
||||
struct scandir_result {
|
||||
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
||||
index 8e418372..61d2712b 100644
|
||||
--- a/multipath/multipath.conf.5
|
||||
+++ b/multipath/multipath.conf.5
|
||||
@@ -458,8 +458,11 @@ precedence. See KNOWN ISSUES.
|
||||
<mode> can be \fIbio\fR, \fIrq\fR or \fImq\fR, which corresponds to
|
||||
bio-based, request-based, and block-multiqueue (blk-mq) request-based,
|
||||
respectively.
|
||||
-The default depends on the kernel parameter \fBdm_mod.use_blk_mq\fR. It is
|
||||
-\fImq\fR if the latter is set, and \fIrq\fR otherwise.
|
||||
+Before kernel 4.20 The default depends on the kernel parameter
|
||||
+\fBdm_mod.use_blk_mq\fR. It is \fImq\fR if the latter is set, and \fIrq\fR
|
||||
+otherwise. Since kernel 4.20, \fIrq\fR and \fImq\fR both correspond to
|
||||
+block-multiqueue. Once a multipath device has been created, its queue_mode
|
||||
+cannot be changed.
|
||||
.TP
|
||||
The default is: \fB<unset>\fR
|
||||
.RE
|
@ -0,0 +1,290 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 7 Oct 2022 12:35:41 -0500
|
||||
Subject: [PATCH] multipath tests: tests for reconcile_features_with_queue_mode
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
tests/Makefile | 2 +
|
||||
tests/features.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 233 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/tests/Makefile b/tests/Makefile
|
||||
index 914413b8..f3e49487 100644
|
||||
--- a/tests/Makefile
|
||||
+++ b/tests/Makefile
|
||||
@@ -29,6 +29,7 @@ endif
|
||||
ifneq ($(DIO_TEST_DEV),)
|
||||
directio-test_FLAGS := -DDIO_TEST_DEV=\"$(DIO_TEST_DEV)\"
|
||||
endif
|
||||
+features-test_FLAGS := -I$(multipathdir)/nvme
|
||||
|
||||
# test-specific linker flags
|
||||
# XYZ-test_TESTDEPS: test libraries containing __wrap_xyz functions
|
||||
@@ -53,6 +54,7 @@ alias-test_LIBDEPS := -lpthread -ldl
|
||||
ifneq ($(DIO_TEST_DEV),)
|
||||
directio-test_LIBDEPS := -laio
|
||||
endif
|
||||
+features-test_LIBDEPS := -ludev -lpthread
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) $($*-test_FLAGS) -c -o $@ $<
|
||||
diff --git a/tests/features.c b/tests/features.c
|
||||
index 1e2e6bff..01fbccb7 100644
|
||||
--- a/tests/features.c
|
||||
+++ b/tests/features.c
|
||||
@@ -1,9 +1,10 @@
|
||||
+#define _GNU_SOURCE
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
#include <cmocka.h>
|
||||
|
||||
-#include "structs.h"
|
||||
+#include "../libmultipath/propsel.c"
|
||||
#include "globals.c"
|
||||
|
||||
static void test_af_null_features_ptr(void **state)
|
||||
@@ -307,12 +308,241 @@ static int test_remove_features(void)
|
||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
}
|
||||
|
||||
+static void test_cf_null_features(void **state)
|
||||
+{
|
||||
+ struct multipath mp = {
|
||||
+ .alias = "test",
|
||||
+ };
|
||||
+ reconcile_features_with_queue_mode(&mp);
|
||||
+ assert_null(mp.features);
|
||||
+}
|
||||
+
|
||||
+static void cf_helper(const char *features_start, const char *features_end,
|
||||
+ int queue_mode_start, int queue_mode_end)
|
||||
+{
|
||||
+ struct multipath mp = {
|
||||
+ .alias = "test",
|
||||
+ .features = strdup(features_start),
|
||||
+ .queue_mode = queue_mode_start,
|
||||
+ };
|
||||
+ char *orig = mp.features;
|
||||
+
|
||||
+ assert_non_null(orig);
|
||||
+ reconcile_features_with_queue_mode(&mp);
|
||||
+ if (!features_end)
|
||||
+ assert_ptr_equal(orig, mp.features);
|
||||
+ else
|
||||
+ assert_string_equal(mp.features, features_end);
|
||||
+ free(mp.features);
|
||||
+ assert_int_equal(mp.queue_mode, queue_mode_end);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_unset_unset1(void **state)
|
||||
+{
|
||||
+ cf_helper("0", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_UNDEF);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_unset_unset2(void **state)
|
||||
+{
|
||||
+ cf_helper("1 queue_mode", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_UNDEF);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_unset_unset3(void **state)
|
||||
+{
|
||||
+ cf_helper("queue_mode", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_UNDEF);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_unset_unset4(void **state)
|
||||
+{
|
||||
+ cf_helper("2 queue_model bio", NULL, QUEUE_MODE_UNDEF,
|
||||
+ QUEUE_MODE_UNDEF);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_unset_unset5(void **state)
|
||||
+{
|
||||
+ cf_helper("1 queue_if_no_path", NULL, QUEUE_MODE_UNDEF,
|
||||
+ QUEUE_MODE_UNDEF);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_invalid_unset1(void **state)
|
||||
+{
|
||||
+ cf_helper("2 queue_mode biop", "0", QUEUE_MODE_UNDEF, QUEUE_MODE_UNDEF);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_invalid_unset2(void **state)
|
||||
+{
|
||||
+ cf_helper("3 queue_mode rqs queue_if_no_path", "1 queue_if_no_path",
|
||||
+ QUEUE_MODE_UNDEF, QUEUE_MODE_UNDEF);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_rq_unset1(void **state)
|
||||
+{
|
||||
+ cf_helper("2 queue_mode rq", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_rq_unset2(void **state)
|
||||
+{
|
||||
+ cf_helper("2 queue_mode mq", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_bio_unset(void **state)
|
||||
+{
|
||||
+ cf_helper("2 queue_mode bio", NULL, QUEUE_MODE_UNDEF, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_unset_bio1(void **state)
|
||||
+{
|
||||
+ cf_helper("1 queue_if_no_path", "3 queue_if_no_path queue_mode bio",
|
||||
+ QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_unset_bio2(void **state)
|
||||
+{
|
||||
+ cf_helper("0", "2 queue_mode bio", QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_unset_bio3(void **state)
|
||||
+{
|
||||
+ cf_helper("2 pg_init_retries 50", "4 pg_init_retries 50 queue_mode bio",
|
||||
+ QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_invalid_bio1(void **state)
|
||||
+{
|
||||
+ cf_helper("2 queue_mode bad", "2 queue_mode bio",
|
||||
+ QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_invalid_bio2(void **state)
|
||||
+{
|
||||
+ cf_helper("3 queue_if_no_path queue_mode\tbad", "3 queue_if_no_path queue_mode bio",
|
||||
+ QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_bio_bio1(void **state)
|
||||
+{
|
||||
+ cf_helper("2 queue_mode bio", NULL, QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_bio_bio2(void **state)
|
||||
+{
|
||||
+ cf_helper("3 queue_if_no_path queue_mode bio", NULL, QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_bio_bio3(void **state)
|
||||
+{
|
||||
+ cf_helper("3 queue_mode\nbio queue_if_no_path", NULL, QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_bio_rq1(void **state)
|
||||
+{
|
||||
+ cf_helper("2\nqueue_mode\tbio", "0", QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_bio_rq2(void **state)
|
||||
+{
|
||||
+ cf_helper("3 queue_if_no_path\nqueue_mode bio", "1 queue_if_no_path",
|
||||
+ QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_bio_rq3(void **state)
|
||||
+{
|
||||
+ cf_helper("4 queue_mode bio pg_init_retries 20", "2 pg_init_retries 20",
|
||||
+ QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_unset_rq1(void **state)
|
||||
+{
|
||||
+ cf_helper("0", NULL, QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_unset_rq2(void **state)
|
||||
+{
|
||||
+ cf_helper("2 pg_init_retries 15", NULL, QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_invalid_rq1(void **state)
|
||||
+{
|
||||
+ cf_helper("2 queue_mode bionic", "0", QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_invalid_rq2(void **state)
|
||||
+{
|
||||
+ cf_helper("3 queue_mode b\nqueue_if_no_path", "1 queue_if_no_path",
|
||||
+ QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_rq_rq1(void **state)
|
||||
+{
|
||||
+ cf_helper("2 queue_mode rq", NULL, QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_rq_rq2(void **state)
|
||||
+{
|
||||
+ cf_helper("3 queue_mode\t \trq\nqueue_if_no_path", NULL, QUEUE_MODE_RQ, QUEUE_MODE_RQ);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_rq_bio1(void **state)
|
||||
+{
|
||||
+ cf_helper("2 queue_mode rq", "2 queue_mode bio", QUEUE_MODE_BIO,
|
||||
+ QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_rq_bio2(void **state)
|
||||
+{
|
||||
+ cf_helper("3 queue_if_no_path\nqueue_mode rq", "3 queue_if_no_path queue_mode bio", QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static void test_cf_rq_bio3(void **state)
|
||||
+{
|
||||
+ cf_helper("3 queue_mode rq\nqueue_if_no_path", "3 queue_if_no_path queue_mode bio", QUEUE_MODE_BIO, QUEUE_MODE_BIO);
|
||||
+}
|
||||
+
|
||||
+static int test_reconcile_features(void)
|
||||
+{
|
||||
+ const struct CMUnitTest tests[] = {
|
||||
+ cmocka_unit_test(test_cf_null_features),
|
||||
+ cmocka_unit_test(test_cf_unset_unset1),
|
||||
+ cmocka_unit_test(test_cf_unset_unset2),
|
||||
+ cmocka_unit_test(test_cf_unset_unset3),
|
||||
+ cmocka_unit_test(test_cf_unset_unset4),
|
||||
+ cmocka_unit_test(test_cf_unset_unset5),
|
||||
+ cmocka_unit_test(test_cf_invalid_unset1),
|
||||
+ cmocka_unit_test(test_cf_invalid_unset2),
|
||||
+ cmocka_unit_test(test_cf_rq_unset1),
|
||||
+ cmocka_unit_test(test_cf_rq_unset2),
|
||||
+ cmocka_unit_test(test_cf_bio_unset),
|
||||
+ cmocka_unit_test(test_cf_unset_bio1),
|
||||
+ cmocka_unit_test(test_cf_unset_bio2),
|
||||
+ cmocka_unit_test(test_cf_unset_bio3),
|
||||
+ cmocka_unit_test(test_cf_invalid_bio1),
|
||||
+ cmocka_unit_test(test_cf_invalid_bio2),
|
||||
+ cmocka_unit_test(test_cf_bio_bio1),
|
||||
+ cmocka_unit_test(test_cf_bio_bio2),
|
||||
+ cmocka_unit_test(test_cf_bio_bio3),
|
||||
+ cmocka_unit_test(test_cf_bio_rq1),
|
||||
+ cmocka_unit_test(test_cf_bio_rq2),
|
||||
+ cmocka_unit_test(test_cf_bio_rq3),
|
||||
+ cmocka_unit_test(test_cf_unset_rq1),
|
||||
+ cmocka_unit_test(test_cf_unset_rq2),
|
||||
+ cmocka_unit_test(test_cf_invalid_rq1),
|
||||
+ cmocka_unit_test(test_cf_invalid_rq2),
|
||||
+ cmocka_unit_test(test_cf_rq_rq1),
|
||||
+ cmocka_unit_test(test_cf_rq_rq2),
|
||||
+ cmocka_unit_test(test_cf_rq_bio1),
|
||||
+ cmocka_unit_test(test_cf_rq_bio2),
|
||||
+ cmocka_unit_test(test_cf_rq_bio3),
|
||||
+ };
|
||||
+ return cmocka_run_group_tests(tests, NULL, NULL);
|
||||
+}
|
||||
+
|
||||
int main(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret += test_add_features();
|
||||
ret += test_remove_features();
|
||||
+ ret += test_reconcile_features();
|
||||
|
||||
return ret;
|
||||
}
|
@ -0,0 +1,143 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 7 Oct 2022 12:35:42 -0500
|
||||
Subject: [PATCH] libmultipath: prepare proto_id for use by non-scsi devivces
|
||||
|
||||
Make sure that when we are checking for a scsi protocol, we are first
|
||||
checking that we are working with a scsi path.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmultipath/configure.c | 9 +++++----
|
||||
libmultipath/discovery.c | 13 ++++++++-----
|
||||
libmultipath/print.c | 6 ++++--
|
||||
libmultipath/structs.c | 2 +-
|
||||
libmultipath/structs.h | 4 +++-
|
||||
multipathd/fpin_handlers.c | 2 +-
|
||||
6 files changed, 22 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||||
index 287289f7..8e1bc488 100644
|
||||
--- a/libmultipath/configure.c
|
||||
+++ b/libmultipath/configure.c
|
||||
@@ -223,10 +223,11 @@ int rr_optimize_path_order(struct pathgroup *pgp)
|
||||
|
||||
total_paths = VECTOR_SIZE(pgp->paths);
|
||||
vector_foreach_slot(pgp->paths, pp, i) {
|
||||
- if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP &&
|
||||
- pp->sg_id.proto_id != SCSI_PROTOCOL_SAS &&
|
||||
- pp->sg_id.proto_id != SCSI_PROTOCOL_ISCSI &&
|
||||
- pp->sg_id.proto_id != SCSI_PROTOCOL_SRP) {
|
||||
+ if (pp->bus != SYSFS_BUS_SCSI ||
|
||||
+ (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP &&
|
||||
+ pp->sg_id.proto_id != SCSI_PROTOCOL_SAS &&
|
||||
+ pp->sg_id.proto_id != SCSI_PROTOCOL_ISCSI &&
|
||||
+ pp->sg_id.proto_id != SCSI_PROTOCOL_SRP)) {
|
||||
/* return success as default path order
|
||||
* is maintained in path group
|
||||
*/
|
||||
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
||||
index 36cc389e..5f4e0794 100644
|
||||
--- a/libmultipath/discovery.c
|
||||
+++ b/libmultipath/discovery.c
|
||||
@@ -468,10 +468,11 @@ int sysfs_get_host_adapter_name(const struct path *pp, char *adapter_name)
|
||||
|
||||
proto_id = pp->sg_id.proto_id;
|
||||
|
||||
- if (proto_id != SCSI_PROTOCOL_FCP &&
|
||||
- proto_id != SCSI_PROTOCOL_SAS &&
|
||||
- proto_id != SCSI_PROTOCOL_ISCSI &&
|
||||
- proto_id != SCSI_PROTOCOL_SRP) {
|
||||
+ if (pp->bus != SYSFS_BUS_SCSI ||
|
||||
+ (proto_id != SCSI_PROTOCOL_FCP &&
|
||||
+ proto_id != SCSI_PROTOCOL_SAS &&
|
||||
+ proto_id != SCSI_PROTOCOL_ISCSI &&
|
||||
+ proto_id != SCSI_PROTOCOL_SRP)) {
|
||||
return 1;
|
||||
}
|
||||
/* iscsi doesn't have adapter info in sysfs
|
||||
@@ -1722,8 +1723,10 @@ sysfs_pathinfo(struct path * pp, vector hwtable)
|
||||
pp->bus = SYSFS_BUS_CCISS;
|
||||
if (!strncmp(pp->dev,"dasd", 4))
|
||||
pp->bus = SYSFS_BUS_CCW;
|
||||
- if (!strncmp(pp->dev,"sd", 2))
|
||||
+ if (!strncmp(pp->dev,"sd", 2)) {
|
||||
pp->bus = SYSFS_BUS_SCSI;
|
||||
+ pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
|
||||
+ }
|
||||
if (!strncmp(pp->dev,"nvme", 4))
|
||||
pp->bus = SYSFS_BUS_NVME;
|
||||
|
||||
diff --git a/libmultipath/print.c b/libmultipath/print.c
|
||||
index 8a6fbe83..8a85df66 100644
|
||||
--- a/libmultipath/print.c
|
||||
+++ b/libmultipath/print.c
|
||||
@@ -558,7 +558,8 @@ snprint_host_attr (char * buff, size_t len, const struct path * pp, char *attr)
|
||||
const char *value = NULL;
|
||||
int ret;
|
||||
|
||||
- if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
|
||||
+ if (pp->bus != SYSFS_BUS_SCSI ||
|
||||
+ pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
|
||||
return snprintf(buff, len, "[undef]");
|
||||
sprintf(host_id, "host%d", pp->sg_id.host_no);
|
||||
host_dev = udev_device_new_from_subsystem_sysname(udev, "fc_host",
|
||||
@@ -597,7 +598,8 @@ snprint_tgt_wwpn (char * buff, size_t len, const struct path * pp)
|
||||
const char *value = NULL;
|
||||
int ret;
|
||||
|
||||
- if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
|
||||
+ if (pp->bus != SYSFS_BUS_SCSI ||
|
||||
+ pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
|
||||
return snprintf(buff, len, "[undef]");
|
||||
sprintf(rport_id, "rport-%d:%d-%d",
|
||||
pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
|
||||
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
|
||||
index 84f9c959..1122cfae 100644
|
||||
--- a/libmultipath/structs.c
|
||||
+++ b/libmultipath/structs.c
|
||||
@@ -115,7 +115,7 @@ alloc_path (void)
|
||||
pp->sg_id.channel = -1;
|
||||
pp->sg_id.scsi_id = -1;
|
||||
pp->sg_id.lun = -1;
|
||||
- pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
|
||||
+ pp->sg_id.proto_id = PROTOCOL_UNSET;
|
||||
pp->fd = -1;
|
||||
pp->tpgs = TPGS_UNDEF;
|
||||
pp->priority = PRIO_UNDEF;
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index 9a404da7..960ea024 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -193,6 +193,8 @@ enum queue_mode_states {
|
||||
QUEUE_MODE_RQ,
|
||||
};
|
||||
|
||||
+#define PROTOCOL_UNSET -1
|
||||
+
|
||||
enum scsi_protocol {
|
||||
SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */
|
||||
SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */
|
||||
@@ -294,7 +296,7 @@ struct sg_id {
|
||||
int lun;
|
||||
short h_cmd_per_lun;
|
||||
short d_queue_depth;
|
||||
- enum scsi_protocol proto_id;
|
||||
+ int proto_id;
|
||||
int transport_id;
|
||||
};
|
||||
|
||||
diff --git a/multipathd/fpin_handlers.c b/multipathd/fpin_handlers.c
|
||||
index b14366d7..599f2893 100644
|
||||
--- a/multipathd/fpin_handlers.c
|
||||
+++ b/multipathd/fpin_handlers.c
|
||||
@@ -220,7 +220,7 @@ static int fpin_chk_wwn_setpath_marginal(uint16_t host_num, struct vectors *ve
|
||||
|
||||
vector_foreach_slot(vecs->pathvec, pp, k) {
|
||||
/* Checks the host number and also for the SCSI FCP */
|
||||
- if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP || host_num != pp->sg_id.host_no)
|
||||
+ if (pp->bus != SYSFS_BUS_SCSI || pp->sg_id.proto_id != SCSI_PROTOCOL_FCP || host_num != pp->sg_id.host_no)
|
||||
continue;
|
||||
sprintf(rport_id, "rport-%d:%d-%d",
|
||||
pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
|
194
SOURCES/0123-libmultipath-get-nvme-path-transport-protocol.patch
Normal file
194
SOURCES/0123-libmultipath-get-nvme-path-transport-protocol.patch
Normal file
@ -0,0 +1,194 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 7 Oct 2022 12:35:43 -0500
|
||||
Subject: [PATCH] libmultipath: get nvme path transport protocol
|
||||
|
||||
Read the transport protocol from /sys/block/nvmeXnY/device/transport.
|
||||
Update protocol_name[] and bus_protocol_id() to store the nvme protocol
|
||||
names after the scsi protocol names.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmultipath/discovery.c | 18 ++++++++++++++++--
|
||||
libmultipath/structs.c | 22 +++++++++++++++++-----
|
||||
libmultipath/structs.h | 33 +++++++++++++++++++++------------
|
||||
multipath/multipath.conf.5 | 10 +++++++---
|
||||
4 files changed, 61 insertions(+), 22 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c
|
||||
index 5f4e0794..eb7a634b 100644
|
||||
--- a/libmultipath/discovery.c
|
||||
+++ b/libmultipath/discovery.c
|
||||
@@ -1455,6 +1455,7 @@ nvme_sysfs_pathinfo (struct path * pp, vector hwtable)
|
||||
struct udev_device *parent;
|
||||
const char *attr_path = NULL;
|
||||
const char *attr;
|
||||
+ int i;
|
||||
|
||||
attr_path = udev_device_get_sysname(pp->udev);
|
||||
if (!attr_path)
|
||||
@@ -1476,6 +1477,18 @@ nvme_sysfs_pathinfo (struct path * pp, vector hwtable)
|
||||
attr = udev_device_get_sysattr_value(parent, "cntlid");
|
||||
pp->sg_id.channel = attr ? atoi(attr) : 0;
|
||||
|
||||
+ attr = udev_device_get_sysattr_value(parent, "transport");
|
||||
+ if (attr) {
|
||||
+ for (i = 0; i < NVME_PROTOCOL_UNSPEC; i++){
|
||||
+ if (protocol_name[SYSFS_BUS_NVME + i] &&
|
||||
+ !strcmp(attr,
|
||||
+ protocol_name[SYSFS_BUS_NVME + i] + 5)) {
|
||||
+ pp->sg_id.proto_id = i;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
snprintf(pp->vendor_id, SCSI_VENDOR_SIZE, "NVME");
|
||||
snprintf(pp->product_id, PATH_PRODUCT_SIZE, "%s",
|
||||
udev_device_get_sysattr_value(parent, "model"));
|
||||
@@ -1727,9 +1740,10 @@ sysfs_pathinfo(struct path * pp, vector hwtable)
|
||||
pp->bus = SYSFS_BUS_SCSI;
|
||||
pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
|
||||
}
|
||||
- if (!strncmp(pp->dev,"nvme", 4))
|
||||
+ if (!strncmp(pp->dev,"nvme", 4)) {
|
||||
pp->bus = SYSFS_BUS_NVME;
|
||||
-
|
||||
+ pp->sg_id.proto_id = NVME_PROTOCOL_UNSPEC;
|
||||
+ }
|
||||
switch (pp->bus) {
|
||||
case SYSFS_BUS_SCSI:
|
||||
return scsi_sysfs_pathinfo(pp, hwtable);
|
||||
diff --git a/libmultipath/structs.c b/libmultipath/structs.c
|
||||
index 1122cfae..7bdf9152 100644
|
||||
--- a/libmultipath/structs.c
|
||||
+++ b/libmultipath/structs.c
|
||||
@@ -25,7 +25,6 @@ const char * const protocol_name[LAST_BUS_PROTOCOL_ID + 1] = {
|
||||
[SYSFS_BUS_UNDEF] = "undef",
|
||||
[SYSFS_BUS_CCW] = "ccw",
|
||||
[SYSFS_BUS_CCISS] = "cciss",
|
||||
- [SYSFS_BUS_NVME] = "nvme",
|
||||
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_FCP] = "scsi:fcp",
|
||||
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_SPI] = "scsi:spi",
|
||||
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_SSA] = "scsi:ssa",
|
||||
@@ -37,6 +36,13 @@ const char * const protocol_name[LAST_BUS_PROTOCOL_ID + 1] = {
|
||||
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_ATA] = "scsi:ata",
|
||||
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_USB] = "scsi:usb",
|
||||
[SYSFS_BUS_SCSI + SCSI_PROTOCOL_UNSPEC] = "scsi:unspec",
|
||||
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_PCIE] = "nvme:pcie",
|
||||
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_RDMA] = "nvme:rdma",
|
||||
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_FC] = "nvme:fc",
|
||||
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_TCP] = "nvme:tcp",
|
||||
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_LOOP] = "nvme:loop",
|
||||
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_APPLE_NVME] = "nvme:apple-nvme",
|
||||
+ [SYSFS_BUS_NVME + NVME_PROTOCOL_UNSPEC] = "nvme:unspec",
|
||||
};
|
||||
|
||||
struct adapter_group *
|
||||
@@ -716,11 +722,17 @@ out:
|
||||
}
|
||||
|
||||
unsigned int bus_protocol_id(const struct path *pp) {
|
||||
- if (!pp || pp->bus < 0 || pp->bus > SYSFS_BUS_SCSI)
|
||||
+ if (!pp || pp->bus < 0 || pp->bus > SYSFS_BUS_NVME)
|
||||
return SYSFS_BUS_UNDEF;
|
||||
- if (pp->bus != SYSFS_BUS_SCSI)
|
||||
+ if (pp->bus != SYSFS_BUS_SCSI && pp->bus != SYSFS_BUS_NVME)
|
||||
return pp->bus;
|
||||
- if ((int)pp->sg_id.proto_id < 0 || pp->sg_id.proto_id > SCSI_PROTOCOL_UNSPEC)
|
||||
+ if (pp->sg_id.proto_id < 0)
|
||||
return SYSFS_BUS_UNDEF;
|
||||
- return SYSFS_BUS_SCSI + pp->sg_id.proto_id;
|
||||
+ if (pp->bus == SYSFS_BUS_SCSI &&
|
||||
+ pp->sg_id.proto_id > SCSI_PROTOCOL_UNSPEC)
|
||||
+ return SYSFS_BUS_UNDEF;
|
||||
+ if (pp->bus == SYSFS_BUS_NVME &&
|
||||
+ pp->sg_id.proto_id > NVME_PROTOCOL_UNSPEC)
|
||||
+ return SYSFS_BUS_UNDEF;
|
||||
+ return pp->bus + pp->sg_id.proto_id;
|
||||
}
|
||||
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
|
||||
index 960ea024..9130efb5 100644
|
||||
--- a/libmultipath/structs.h
|
||||
+++ b/libmultipath/structs.h
|
||||
@@ -57,15 +57,6 @@ enum failback_mode {
|
||||
FAILBACK_FOLLOWOVER
|
||||
};
|
||||
|
||||
-/* SYSFS_BUS_SCSI should be last, see bus_protocol_id() */
|
||||
-enum sysfs_buses {
|
||||
- SYSFS_BUS_UNDEF,
|
||||
- SYSFS_BUS_CCW,
|
||||
- SYSFS_BUS_CCISS,
|
||||
- SYSFS_BUS_NVME,
|
||||
- SYSFS_BUS_SCSI,
|
||||
-};
|
||||
-
|
||||
enum pathstates {
|
||||
PSTATE_UNDEF,
|
||||
PSTATE_FAILED,
|
||||
@@ -207,14 +198,32 @@ enum scsi_protocol {
|
||||
SCSI_PROTOCOL_ATA = 8,
|
||||
SCSI_PROTOCOL_USB = 9, /* USB Attached SCSI (UAS), and others */
|
||||
SCSI_PROTOCOL_UNSPEC = 0xa, /* No specific protocol */
|
||||
+ SCSI_PROTOCOL_END = 0xb, /* offset of the next sysfs_buses entry */
|
||||
+};
|
||||
+
|
||||
+/* values from /sys/class/nvme/nvmeX */
|
||||
+enum nvme_protocol {
|
||||
+ NVME_PROTOCOL_PCIE = 0,
|
||||
+ NVME_PROTOCOL_RDMA = 1,
|
||||
+ NVME_PROTOCOL_FC = 2,
|
||||
+ NVME_PROTOCOL_TCP = 3,
|
||||
+ NVME_PROTOCOL_LOOP = 4,
|
||||
+ NVME_PROTOCOL_APPLE_NVME = 5,
|
||||
+ NVME_PROTOCOL_UNSPEC = 6, /* unknown protocol */
|
||||
+};
|
||||
+
|
||||
+enum sysfs_buses {
|
||||
+ SYSFS_BUS_UNDEF,
|
||||
+ SYSFS_BUS_CCW,
|
||||
+ SYSFS_BUS_CCISS,
|
||||
+ SYSFS_BUS_SCSI,
|
||||
+ SYSFS_BUS_NVME = SYSFS_BUS_SCSI + SCSI_PROTOCOL_END,
|
||||
};
|
||||
|
||||
/*
|
||||
* Linear ordering of bus/protocol
|
||||
- * This assumes that SYSFS_BUS_SCSI is last in enum sysfs_buses
|
||||
- * SCSI is the only bus type for which we distinguish protocols.
|
||||
*/
|
||||
-#define LAST_BUS_PROTOCOL_ID (SYSFS_BUS_SCSI + SCSI_PROTOCOL_UNSPEC)
|
||||
+#define LAST_BUS_PROTOCOL_ID (SYSFS_BUS_NVME + NVME_PROTOCOL_UNSPEC)
|
||||
unsigned int bus_protocol_id(const struct path *pp);
|
||||
extern const char * const protocol_name[];
|
||||
|
||||
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
||||
index 61d2712b..1f5a40b6 100644
|
||||
--- a/multipath/multipath.conf.5
|
||||
+++ b/multipath/multipath.conf.5
|
||||
@@ -1369,7 +1369,9 @@ Regular expression for the protocol of a device to be excluded/included.
|
||||
The protocol strings that multipath recognizes are \fIscsi:fcp\fR,
|
||||
\fIscsi:spi\fR, \fIscsi:ssa\fR, \fIscsi:sbp\fR, \fIscsi:srp\fR,
|
||||
\fIscsi:iscsi\fR, \fIscsi:sas\fR, \fIscsi:adt\fR, \fIscsi:ata\fR,
|
||||
-\fIscsi:unspec\fR, \fIccw\fR, \fIcciss\fR, \fInvme\fR, and \fIundef\fR.
|
||||
+\fIscsi:unspec\fR, \fInvme:pcie\fR, \fInvme:rdma\fR, \fInvme:fc\fR,
|
||||
+\fInvme:tcp\fR, \fInvme:loop\fR, \fInvme:apple-nvme\fR, \fInvme:unspec\fR,
|
||||
+\fIccw\fR, \fIcciss\fR, and \fIundef\fR.
|
||||
The protocol that a path is using can be viewed by running
|
||||
\fBmultipathd show paths format "%d %P"\fR
|
||||
.RE
|
||||
@@ -1757,8 +1759,10 @@ The protocol subsection recognizes the following mandatory attribute:
|
||||
The protocol string of the path device. The possible values are \fIscsi:fcp\fR,
|
||||
\fIscsi:spi\fR, \fIscsi:ssa\fR, \fIscsi:sbp\fR, \fIscsi:srp\fR,
|
||||
\fIscsi:iscsi\fR, \fIscsi:sas\fR, \fIscsi:adt\fR, \fIscsi:ata\fR,
|
||||
-\fIscsi:unspec\fR, \fIccw\fR, \fIcciss\fR, \fInvme\fR, and \fIundef\fR. This is
|
||||
-\fBnot\fR a regular expression. the path device protcol string must match
|
||||
+\fIscsi:unspec\fR, \fInvme:pcie\fR, \fInvme:rdma\fR, \fInvme:fc\fR,
|
||||
+\fInvme:tcp\fR, \fInvme:loop\fR, \fInvme:apple-nvme\fR, \fInvme:unspec\fR,
|
||||
+\fIccw\fR, \fIcciss\fR, and \fIundef\fR. This is
|
||||
+\fBnot\fR a regular expression. the path device protocol string must match
|
||||
exactly. The protocol that a path is using can be viewed by running
|
||||
\fBmultipathd show paths format "%d %P"\fR
|
||||
.LP
|
@ -0,0 +1,111 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Date: Fri, 7 Oct 2022 12:35:44 -0500
|
||||
Subject: [PATCH] libmultipath: enforce queue_mode bio for nmve:tcp paths
|
||||
|
||||
nvme:tcp devices set BLK_MQ_F_BLOCKING (they are the only block devices
|
||||
which multipath supports that do so), meaning that block_mq expects that
|
||||
they can block at certain points while servicing a request. However,
|
||||
due to the way device-mapper sets up its queue, it is not able to set
|
||||
BLK_MQ_F_BLOCKING when it includes paths that set this flag. Patches
|
||||
were written to address this issue but they were rejected upstream
|
||||
|
||||
https://lore.kernel.org/linux-block/YcH%2FE4JNag0QYYAa@infradead.org/T/#t
|
||||
|
||||
The proposed solution was to have multipath use the bio queue_mode for
|
||||
multipath devices that include nvme:tcp paths.
|
||||
|
||||
Multipath devices now automatically add the "queue_mode bio" feature if
|
||||
they include nvme:tcp paths. If a multipath devices was created with
|
||||
"queue_mode rq", it will disallow the addition of nvme:tcp paths.
|
||||
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
Reviewed-by: Martin Wilck <mwilck@suse.com>
|
||||
---
|
||||
libmultipath/configure.c | 17 ++++++++++++++++-
|
||||
libmultipath/structs_vec.c | 7 +++++++
|
||||
multipath/multipath.conf.5 | 4 +++-
|
||||
3 files changed, 26 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
|
||||
index 8e1bc488..c341793c 100644
|
||||
--- a/libmultipath/configure.c
|
||||
+++ b/libmultipath/configure.c
|
||||
@@ -297,6 +297,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size,
|
||||
struct vectors *vecs)
|
||||
{
|
||||
struct pathgroup * pgp;
|
||||
+ struct path *pp;
|
||||
struct config *conf;
|
||||
int i, n_paths, marginal_pathgroups;
|
||||
|
||||
@@ -308,6 +309,14 @@ int setup_map(struct multipath *mpp, char *params, int params_size,
|
||||
return 1;
|
||||
}
|
||||
|
||||
+ /* Force QUEUE_MODE_BIO for maps with nvme:tcp paths */
|
||||
+ vector_foreach_slot(mpp->paths, pp, i) {
|
||||
+ if (pp->bus == SYSFS_BUS_NVME &&
|
||||
+ pp->sg_id.proto_id == NVME_PROTOCOL_TCP) {
|
||||
+ mpp->queue_mode = QUEUE_MODE_BIO;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
/*
|
||||
* free features, selector, and hwhandler properties if they are being reused
|
||||
*/
|
||||
@@ -1161,6 +1170,13 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
|
||||
continue;
|
||||
}
|
||||
|
||||
+ cmpp = find_mp_by_wwid(curmp, pp1->wwid);
|
||||
+ if (cmpp && cmpp->queue_mode == QUEUE_MODE_RQ &&
|
||||
+ pp1->bus == SYSFS_BUS_NVME && pp1->sg_id.proto_id ==
|
||||
+ NVME_PROTOCOL_TCP) {
|
||||
+ orphan_path(pp1, "nvme:tcp path not allowed with request queue_mode multipath device");
|
||||
+ continue;
|
||||
+ }
|
||||
/*
|
||||
* at this point, we know we really got a new mp
|
||||
*/
|
||||
@@ -1199,7 +1215,6 @@ int coalesce_paths (struct vectors * vecs, vector newmp, char * refwwid,
|
||||
}
|
||||
verify_paths(mpp, vecs);
|
||||
|
||||
- cmpp = find_mp_by_wwid(curmp, mpp->wwid);
|
||||
if (cmpp)
|
||||
mpp->queue_mode = cmpp->queue_mode;
|
||||
params[0] = '\0';
|
||||
diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
|
||||
index 8137ea21..24ac022e 100644
|
||||
--- a/libmultipath/structs_vec.c
|
||||
+++ b/libmultipath/structs_vec.c
|
||||
@@ -68,6 +68,13 @@ int adopt_paths(vector pathvec, struct multipath *mpp)
|
||||
pp->dev, mpp->alias);
|
||||
continue;
|
||||
}
|
||||
+ if (mpp->queue_mode == QUEUE_MODE_RQ &&
|
||||
+ pp->bus == SYSFS_BUS_NVME &&
|
||||
+ pp->sg_id.proto_id == NVME_PROTOCOL_TCP) {
|
||||
+ condlog(2, "%s: mulitpath device %s created with request queue_mode. Unable to add nvme:tcp paths",
|
||||
+ pp->dev, mpp->alias);
|
||||
+ continue;
|
||||
+ }
|
||||
condlog(3, "%s: ownership set to %s",
|
||||
pp->dev, mpp->alias);
|
||||
pp->mpp = mpp;
|
||||
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
|
||||
index 1f5a40b6..cb07a62c 100644
|
||||
--- a/multipath/multipath.conf.5
|
||||
+++ b/multipath/multipath.conf.5
|
||||
@@ -462,7 +462,9 @@ Before kernel 4.20 The default depends on the kernel parameter
|
||||
\fBdm_mod.use_blk_mq\fR. It is \fImq\fR if the latter is set, and \fIrq\fR
|
||||
otherwise. Since kernel 4.20, \fIrq\fR and \fImq\fR both correspond to
|
||||
block-multiqueue. Once a multipath device has been created, its queue_mode
|
||||
-cannot be changed.
|
||||
+cannot be changed. \fInvme:tcp\fR paths are only supported in multipath
|
||||
+devices with queue_mode set to \fIbio\fR. multipath will automatically
|
||||
+set this when creating a device with \fInvme:tcp\fR paths.
|
||||
.TP
|
||||
The default is: \fB<unset>\fR
|
||||
.RE
|
@ -1,7 +1,7 @@
|
||||
Summary: Tools to manage multipath devices using device-mapper
|
||||
Name: device-mapper-multipath
|
||||
Version: 0.8.4
|
||||
Release: 31%{?dist}
|
||||
Release: 32%{?dist}
|
||||
License: GPLv2
|
||||
Group: System Environment/Base
|
||||
URL: http://christophe.varoqui.free.fr/
|
||||
@ -126,6 +126,15 @@ Patch00112: 0112-libmultipath-return-success-if-we-raced-to-remove-a-.patch
|
||||
Patch00113: 0113-multipathd-Handle-losing-all-path-in-update_map.patch
|
||||
Patch00114: 0114-multipathd-ignore-duplicated-multipathd-command-keys.patch
|
||||
Patch00115: 0115-multipath-tools-use-run-instead-of-dev-shm.patch
|
||||
Patch00116: 0116-kpartx-hold-device-open-until-partitions-have-been-c.patch
|
||||
Patch00117: 0117-libmultipath-cleanup-remove_feature.patch
|
||||
Patch00118: 0118-libmultipath-cleanup-add_feature.patch
|
||||
Patch00119: 0119-multipath-tests-tests-for-adding-and-removing-featur.patch
|
||||
Patch00120: 0120-libmultipath-fix-queue_mode-feature-handling.patch
|
||||
Patch00121: 0121-multipath-tests-tests-for-reconcile_features_with_qu.patch
|
||||
Patch00122: 0122-libmultipath-prepare-proto_id-for-use-by-non-scsi-de.patch
|
||||
Patch00123: 0123-libmultipath-get-nvme-path-transport-protocol.patch
|
||||
Patch00124: 0124-libmultipath-enforce-queue_mode-bio-for-nmve-tcp-pat.patch
|
||||
|
||||
# runtime
|
||||
Requires: %{name}-libs = %{version}-%{release}
|
||||
@ -330,6 +339,20 @@ fi
|
||||
%{_pkgconfdir}/libdmmp.pc
|
||||
|
||||
%changelog
|
||||
* Thu Nov 10 2022 Benjamin Marzinski <bmarzins@redhat.com> 0.8.4-32
|
||||
- Add 0116-kpartx-hold-device-open-until-partitions-have-been-c.patch
|
||||
* Fixes bz #2128885
|
||||
- Add 0117-libmultipath-cleanup-remove_feature.patch
|
||||
- Add 0118-libmultipath-cleanup-add_feature.patch
|
||||
- Add 0119-multipath-tests-tests-for-adding-and-removing-featur.patch
|
||||
- Add 0120-libmultipath-fix-queue_mode-feature-handling.patch
|
||||
- Add 0121-multipath-tests-tests-for-reconcile_features_with_qu.patch
|
||||
- Add 0122-libmultipath-prepare-proto_id-for-use-by-non-scsi-de.patch
|
||||
- Add 0123-libmultipath-get-nvme-path-transport-protocol.patch
|
||||
- Add 0124-libmultipath-enforce-queue_mode-bio-for-nmve-tcp-pat.patch
|
||||
* Fixes bz #2022359
|
||||
- Resolves: bz #2022359, #2128885
|
||||
|
||||
* Thu Oct 13 2022 Benjamin Marzinski <bmarzins@redhat.com> 0.8.4-31
|
||||
- Add 0114-multipathd-ignore-duplicated-multipathd-command-keys.patch
|
||||
* Fixes bz #2133996
|
||||
|
Loading…
Reference in New Issue
Block a user