From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski 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 Reviewed-by: Martin Wilck --- 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 70049f47..cc778a22 100644 --- a/libmultipath/configure.c +++ b/libmultipath/configure.c @@ -1118,6 +1118,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)) @@ -1227,6 +1228,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, ¶ms, vecs)) { remove_map(mpp, vecs->pathvec, NULL); continue; diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c index bc311421..16377c54 100644 --- a/libmultipath/dmparser.c +++ b/libmultipath/dmparser.c @@ -152,6 +152,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 2b47f5f8..9dea6f92 100644 --- a/libmultipath/propsel.c +++ b/libmultipath/propsel.c @@ -27,6 +27,7 @@ #include "strbuf.h" #include #include +#include pgpolicyfn *pgpolicies[] = { NULL, @@ -414,6 +415,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; @@ -429,6 +483,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 8a07d470..b4f75de0 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 */ @@ -387,6 +393,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 f7de5140..e1a787d4 100644 --- a/multipath/multipath.conf.5 +++ b/multipath/multipath.conf.5 @@ -468,8 +468,11 @@ precedence. See KNOWN ISSUES. 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\fR .RE