Blame SOURCES/0071-libmultipath-fix-queue_mode-feature-handling.patch

e71b65
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
e71b65
From: Benjamin Marzinski <bmarzins@redhat.com>
e71b65
Date: Fri, 7 Oct 2022 12:35:40 -0500
e71b65
Subject: [PATCH] libmultipath: fix queue_mode feature handling
e71b65
e71b65
device-mapper is not able to change the queue_mode on a table reload.
e71b65
Make sure that when multipath sets up the map, both on regular reloads
e71b65
and reconfigures, it keeps the queue_mode the same.
e71b65
e71b65
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
e71b65
Reviewed-by: Martin Wilck <mwilck@suse.com>
e71b65
---
e71b65
 libmultipath/configure.c   |  4 +++
e71b65
 libmultipath/dmparser.c    |  2 ++
e71b65
 libmultipath/propsel.c     | 55 ++++++++++++++++++++++++++++++++++++++
e71b65
 libmultipath/structs.h     |  7 +++++
e71b65
 multipath/multipath.conf.5 |  7 +++--
e71b65
 5 files changed, 73 insertions(+), 2 deletions(-)
e71b65
e71b65
diff --git a/libmultipath/configure.c b/libmultipath/configure.c
e71b65
index 70049f47..cc778a22 100644
e71b65
--- a/libmultipath/configure.c
e71b65
+++ b/libmultipath/configure.c
e71b65
@@ -1118,6 +1118,7 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid,
e71b65
 	struct config *conf = NULL;
e71b65
 	int allow_queueing;
e71b65
 	struct bitfield *size_mismatch_seen;
e71b65
+	struct multipath * cmpp;
e71b65
 
e71b65
 	/* ignore refwwid if it's empty */
e71b65
 	if (refwwid && !strlen(refwwid))
e71b65
@@ -1227,6 +1228,9 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid,
e71b65
 		}
e71b65
 		verify_paths(mpp);
e71b65
 
e71b65
+		cmpp = find_mp_by_wwid(curmp, mpp->wwid);
e71b65
+		if (cmpp)
e71b65
+			mpp->queue_mode = cmpp->queue_mode;
e71b65
 		if (setup_map(mpp, &params, vecs)) {
e71b65
 			remove_map(mpp, vecs->pathvec, NULL);
e71b65
 			continue;
e71b65
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
e71b65
index bc311421..16377c54 100644
e71b65
--- a/libmultipath/dmparser.c
e71b65
+++ b/libmultipath/dmparser.c
e71b65
@@ -152,6 +152,8 @@ int disassemble_map(const struct _vector *pathvec,
e71b65
 
e71b65
 		FREE(word);
e71b65
 	}
e71b65
+	mpp->queue_mode = strstr(mpp->features, "queue_mode bio") ?
e71b65
+			  QUEUE_MODE_BIO : QUEUE_MODE_RQ;
e71b65
 
e71b65
 	/*
e71b65
 	 * hwhandler
e71b65
diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c
e71b65
index 2b47f5f8..9dea6f92 100644
e71b65
--- a/libmultipath/propsel.c
e71b65
+++ b/libmultipath/propsel.c
e71b65
@@ -27,6 +27,7 @@
e71b65
 #include "strbuf.h"
e71b65
 #include <inttypes.h>
e71b65
 #include <libudev.h>
e71b65
+#include <ctype.h>
e71b65
 
e71b65
 pgpolicyfn *pgpolicies[] = {
e71b65
 	NULL,
e71b65
@@ -414,6 +415,59 @@ void reconcile_features_with_options(const char *id, char **features, int* no_pa
e71b65
 	}
e71b65
 }
e71b65
 
e71b65
+static void reconcile_features_with_queue_mode(struct multipath *mp)
e71b65
+{
e71b65
+	char *space = NULL, *val = NULL, *mode_str = NULL, *feat;
e71b65
+	int features_mode = QUEUE_MODE_UNDEF;
e71b65
+
e71b65
+	if (!mp->features)
e71b65
+		return;
e71b65
+
e71b65
+	pthread_cleanup_push(cleanup_free_ptr, &space);
e71b65
+	pthread_cleanup_push(cleanup_free_ptr, &val;;
e71b65
+	pthread_cleanup_push(cleanup_free_ptr, &mode_str);
e71b65
+
e71b65
+	if (!(feat = strstr(mp->features, "queue_mode")) ||
e71b65
+	    feat == mp->features || !isspace(*(feat - 1)) ||
e71b65
+	    sscanf(feat, "queue_mode%m[ \f\n\r\t\v]%ms", &space, &val) != 2)
e71b65
+		goto sync_mode;
e71b65
+	if (asprintf(&mode_str, "queue_mode%s%s", space, val) < 0) {
e71b65
+		condlog(1, "failed to allocate space for queue_mode feature string");
e71b65
+		mode_str = NULL; /* value undefined on failure */
e71b65
+		goto exit;
e71b65
+	}
e71b65
+
e71b65
+	if (!strcmp(val, "rq") || !strcmp(val, "mq"))
e71b65
+		features_mode = QUEUE_MODE_RQ;
e71b65
+	else if (!strcmp(val, "bio"))
e71b65
+		features_mode = QUEUE_MODE_BIO;
e71b65
+	if (features_mode == QUEUE_MODE_UNDEF) {
e71b65
+		condlog(2, "%s: ignoring invalid feature '%s'",
e71b65
+			mp->alias, mode_str);
e71b65
+		goto sync_mode;
e71b65
+	}
e71b65
+
e71b65
+	if (mp->queue_mode == QUEUE_MODE_UNDEF)
e71b65
+		mp->queue_mode = features_mode;
e71b65
+	if (mp->queue_mode == features_mode)
e71b65
+		goto exit;
e71b65
+
e71b65
+	condlog(2,
e71b65
+		"%s: ignoring feature '%s' because queue_mode is set to '%s'",
e71b65
+		mp->alias, mode_str,
e71b65
+		(mp->queue_mode == QUEUE_MODE_RQ)? "rq" : "bio");
e71b65
+
e71b65
+sync_mode:
e71b65
+	if (mode_str)
e71b65
+		remove_feature(&mp->features, mode_str);
e71b65
+	if (mp->queue_mode == QUEUE_MODE_BIO)
e71b65
+		add_feature(&mp->features, "queue_mode bio");
e71b65
+exit:
e71b65
+	pthread_cleanup_pop(1);
e71b65
+	pthread_cleanup_pop(1);
e71b65
+	pthread_cleanup_pop(1);
e71b65
+}
e71b65
+
e71b65
 int select_features(struct config *conf, struct multipath *mp)
e71b65
 {
e71b65
 	const char *origin;
e71b65
@@ -429,6 +483,7 @@ out:
e71b65
 	reconcile_features_with_options(mp->alias, &mp->features,
e71b65
 					&mp->no_path_retry,
e71b65
 					&mp->retain_hwhandler);
e71b65
+	reconcile_features_with_queue_mode(mp);
e71b65
 	condlog(3, "%s: features = \"%s\" %s", mp->alias, mp->features, origin);
e71b65
 	return 0;
e71b65
 }
e71b65
diff --git a/libmultipath/structs.h b/libmultipath/structs.h
e71b65
index 8a07d470..b4f75de0 100644
e71b65
--- a/libmultipath/structs.h
e71b65
+++ b/libmultipath/structs.h
e71b65
@@ -170,6 +170,12 @@ enum max_sectors_kb_states {
e71b65
 	MAX_SECTORS_KB_MIN = 4,  /* can't be smaller than page size */
e71b65
 };
e71b65
 
e71b65
+enum queue_mode_states {
e71b65
+	QUEUE_MODE_UNDEF = 0,
e71b65
+	QUEUE_MODE_BIO,
e71b65
+	QUEUE_MODE_RQ,
e71b65
+};
e71b65
+
e71b65
 enum scsi_protocol {
e71b65
 	SCSI_PROTOCOL_FCP = 0,	/* Fibre Channel */
e71b65
 	SCSI_PROTOCOL_SPI = 1,	/* parallel SCSI */
e71b65
@@ -387,6 +393,7 @@ struct multipath {
e71b65
 	int needs_paths_uevent;
e71b65
 	int ghost_delay;
e71b65
 	int ghost_delay_tick;
e71b65
+	int queue_mode;
e71b65
 	uid_t uid;
e71b65
 	gid_t gid;
e71b65
 	mode_t mode;
e71b65
diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5
e71b65
index f7de5140..e1a787d4 100644
e71b65
--- a/multipath/multipath.conf.5
e71b65
+++ b/multipath/multipath.conf.5
e71b65
@@ -468,8 +468,11 @@ precedence. See KNOWN ISSUES.
e71b65
 <mode> can be \fIbio\fR, \fIrq\fR or \fImq\fR, which corresponds to
e71b65
 bio-based, request-based, and block-multiqueue (blk-mq) request-based,
e71b65
 respectively.
e71b65
-The default depends on the kernel parameter \fBdm_mod.use_blk_mq\fR. It is
e71b65
-\fImq\fR if the latter is set, and \fIrq\fR otherwise.
e71b65
+Before kernel 4.20 The default depends on the kernel parameter
e71b65
+\fBdm_mod.use_blk_mq\fR. It is \fImq\fR if the latter is set, and \fIrq\fR
e71b65
+otherwise. Since kernel 4.20, \fIrq\fR and \fImq\fR both correspond to
e71b65
+block-multiqueue. Once a multipath device has been created, its queue_mode
e71b65
+cannot be changed.
e71b65
 .TP
e71b65
 The default is: \fB<unset>\fR
e71b65
 .RE