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 <bmarz...@redhat.com>
---
 libmultipath/configure.c   |  4 +++
 libmultipath/dmparser.c    |  2 ++
 libmultipath/propsel.c     | 55 ++++++++++++++++++++++++++++++++++++++
 libmultipath/structs.h     |  7 +++++
 multipath/multipath.conf.5 |  7 +++--
 5 files changed, 73 insertions(+), 2 deletions(-)

diff --git a/libmultipath/configure.c b/libmultipath/configure.c
index 8af7cd79..41641e30 100644
--- a/libmultipath/configure.c
+++ b/libmultipath/configure.c
@@ -1075,6 +1075,7 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, 
char *refwwid,
        struct config *conf = NULL;
        int allow_queueing;
        struct bitfield *size_mismatch_seen;
+       struct multipath * cmpp;
 
        /* ignore refwwid if it's empty */
        if (refwwid && !strlen(refwwid))
@@ -1184,6 +1185,9 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, 
char *refwwid,
                }
                verify_paths(mpp);
 
+               cmpp = find_mp_by_wwid(curmp, mpp->wwid);
+               if (cmpp)
+                       mpp->queue_mode = cmpp->queue_mode;
                if (setup_map(mpp, &params, vecs)) {
                        remove_map(mpp, vecs->pathvec, NULL);
                        continue;
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
index 50d13c08..3b37a926 100644
--- a/libmultipath/dmparser.c
+++ b/libmultipath/dmparser.c
@@ -151,6 +151,8 @@ int disassemble_map(const struct _vector *pathvec,
 
                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 98e3aad1..d4f19897 100644
--- a/libmultipath/propsel.c
+++ b/libmultipath/propsel.c
@@ -26,6 +26,7 @@
 #include "strbuf.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 5a713d46..129bdf0e 100644
--- a/libmultipath/structs.h
+++ b/libmultipath/structs.h
@@ -170,6 +170,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 */
@@ -396,6 +402,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/multipath/multipath.conf.5 b/multipath/multipath.conf.5
index e098d555..46a4126c 100644
--- a/multipath/multipath.conf.5
+++ b/multipath/multipath.conf.5
@@ -459,8 +459,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
-- 
2.17.2

--
dm-devel mailing list
dm-devel@redhat.com
https://listman.redhat.com/mailman/listinfo/dm-devel

Reply via email to