From 6a05376fe509b24618e45ea235d57edd3b9c6735 Mon Sep 17 00:00:00 2001 From: Benjamin Marzinski Date: Wed, 13 Dec 2017 16:07:24 -0600 Subject: [PATCH] device-mapper-multipath-0.7.1-9.git847cc43 Add 0011-multipath-tools-Remove-the-limitation-of-IPC-command.patch Add 0012-multipath-tools-libdmmp-Improve-timeout-mechanism.patch Add 0013-multipath-tools-libdmmp-New-function-to-flush-and-re.patch * Add dmmp_reconfig() and dmmp_flush_mpath() functions --- ...Remove-the-limitation-of-IPC-command.patch | 59 +++ ...ls-libdmmp-Improve-timeout-mechanism.patch | 229 ++++++++++ ...libdmmp-New-function-to-flush-and-re.patch | 409 ++++++++++++++++++ device-mapper-multipath.spec | 14 +- 4 files changed, 710 insertions(+), 1 deletion(-) create mode 100644 0011-multipath-tools-Remove-the-limitation-of-IPC-command.patch create mode 100644 0012-multipath-tools-libdmmp-Improve-timeout-mechanism.patch create mode 100644 0013-multipath-tools-libdmmp-New-function-to-flush-and-re.patch diff --git a/0011-multipath-tools-Remove-the-limitation-of-IPC-command.patch b/0011-multipath-tools-Remove-the-limitation-of-IPC-command.patch new file mode 100644 index 0000000..dfccf22 --- /dev/null +++ b/0011-multipath-tools-Remove-the-limitation-of-IPC-command.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Wed, 16 Aug 2017 20:34:07 +0800 +Subject: [PATCH] multipath-tools: Remove the limitation of IPC command reply + length. + +Issue: + libmpathcmd will reply error 22(Invalid argument) when having 1000 + mpath. + +Root cause: + libmpathcmd return error when reply string length exceeded the 65535. + +Fix: + Remove the limitation on reply data length. + +Extra: + Initially this limitation was removed and improved by commit + bb219efb131aef61c331f181193bf1d80e6b2a99 + but then was added back via commit + 7381c3f2b19903cc56d1ddafb13e8ad3afc08580 + +Signed-off-by: Gris Ge +Signed-off-by: Benjamin Marzinski +--- + libmpathcmd/mpath_cmd.c | 4 ---- + libmpathcmd/mpath_cmd.h | 1 - + 2 files changed, 5 deletions(-) + +diff --git a/libmpathcmd/mpath_cmd.c b/libmpathcmd/mpath_cmd.c +index 1496b68..af618cf 100644 +--- a/libmpathcmd/mpath_cmd.c ++++ b/libmpathcmd/mpath_cmd.c +@@ -142,10 +142,6 @@ int mpath_recv_reply(int fd, char **reply, unsigned int timeout) + len = mpath_recv_reply_len(fd, timeout); + if (len <= 0) + return len; +- if (len > MAX_REPLY_LEN) { +- errno = EINVAL; +- return -1; +- } + *reply = malloc(len); + if (!*reply) + return -1; +diff --git a/libmpathcmd/mpath_cmd.h b/libmpathcmd/mpath_cmd.h +index 6534474..b57b708 100644 +--- a/libmpathcmd/mpath_cmd.h ++++ b/libmpathcmd/mpath_cmd.h +@@ -26,7 +26,6 @@ extern "C" { + + #define DEFAULT_SOCKET "/org/kernel/linux/storage/multipathd" + #define DEFAULT_REPLY_TIMEOUT 4000 +-#define MAX_REPLY_LEN 65536 + + + /* +-- +2.7.4 + diff --git a/0012-multipath-tools-libdmmp-Improve-timeout-mechanism.patch b/0012-multipath-tools-libdmmp-Improve-timeout-mechanism.patch new file mode 100644 index 0000000..d384288 --- /dev/null +++ b/0012-multipath-tools-libdmmp-Improve-timeout-mechanism.patch @@ -0,0 +1,229 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Wed, 16 Aug 2017 20:34:08 +0800 +Subject: [PATCH] multipath-tools: libdmmp: Improve timeout mechanism + +Issue: + libdmmp return error of timeout before user requested timeout was + met. + This happens when multipathd daemon is starting with a lot(1k+) mpaths. + +Root cause: + The multipath has two timeout settings: + 1. 'uxsock_timeout' in multipath.conf + 2. libmpathcmd timeout argument. + And the first is not controllable in current libdmmp code. + +Fix: + * Only keep 1 timeout setting in libdmmp: + dmmp_context_timeout_set()/dmmp_context_timeout_get(). + * libdmmp will keep reply until meet user requested timeout. + * Allow user to set timeout as 0 which mean infinite, only return + when error or pass. + * Updated libdmmp.h document to to indicate timeout 0 as infinite. + * Increase timeout setting in libdmmp test case to test this + mechanism. + +Signed-off-by: Gris Ge +Signed-off-by: Benjamin Marzinski +--- + libdmmp/libdmmp.c | 136 ++++++++++++++++++++++++++++++++++++-------- + libdmmp/libdmmp/libdmmp.h | 1 + + libdmmp/test/libdmmp_test.c | 2 +- + 3 files changed, 114 insertions(+), 25 deletions(-) + +diff --git a/libdmmp/libdmmp.c b/libdmmp/libdmmp.c +index 3906335..6db348b 100644 +--- a/libdmmp/libdmmp.c ++++ b/libdmmp/libdmmp.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + + #include "libdmmp/libdmmp.h" +@@ -54,6 +55,17 @@ struct dmmp_context { + unsigned int tmo; + }; + ++/* ++ * The multipathd daemon are using "uxsock_timeout" to define timeout value, ++ * if timeout at daemon side, we will get message "timeout\n". ++ * To unify this timeout with `dmmp_context_timeout_set()`, this function ++ * will keep retry mpath_process_cmd() tile meet the time of ++ * dmmp_context_timeout_get(). ++ * Need to free `*output` string manually. ++ */ ++static int _process_cmd(struct dmmp_context *ctx, int fd, const char *cmd, ++ char **output); ++ + _dmmp_getter_func_gen(dmmp_context_log_priority_get, + struct dmmp_context, ctx, log_priority, + int); +@@ -169,32 +181,11 @@ int dmmp_mpath_array_get(struct dmmp_context *ctx, + goto out; + } + +- if (mpath_process_cmd(socket_fd, _DMMP_IPC_SHOW_JSON_CMD, +- &j_str, ctx->tmo) != 0) { +- errno_save = errno; +- memset(errno_str_buff, 0, _ERRNO_STR_BUFF_SIZE); +- strerror_r(errno_save, errno_str_buff, _ERRNO_STR_BUFF_SIZE); +- if (errno_save == ETIMEDOUT) { +- rc = DMMP_ERR_IPC_TIMEOUT; +- _error(ctx, "IPC communication timeout, try to " +- "increase it via dmmp_context_timeout_set()"); +- goto out; +- } +- _error(ctx, "IPC failed when process command '%s' with " +- "error %d(%s)", _DMMP_IPC_SHOW_JSON_CMD, errno_save, +- errno_str_buff); +- rc = DMMP_ERR_IPC_ERROR; +- goto out; +- } +- +- if ((j_str == NULL) || (strlen(j_str) == 0)) { +- _error(ctx, "IPC return empty reply for command %s", +- _DMMP_IPC_SHOW_JSON_CMD); +- rc = DMMP_ERR_IPC_ERROR; +- goto out; +- } ++ _good(_process_cmd(ctx, socket_fd, _DMMP_IPC_SHOW_JSON_CMD, &j_str), ++ rc, out); + + _debug(ctx, "Got json output from multipathd: '%s'", j_str); ++ + j_token = json_tokener_new(); + if (j_token == NULL) { + rc = DMMP_ERR_BUG; +@@ -283,3 +274,100 @@ out: + + return rc; + } ++ ++static int _process_cmd(struct dmmp_context *ctx, int fd, const char *cmd, ++ char **output) ++{ ++ int errno_save = 0; ++ int rc = DMMP_OK; ++ char errno_str_buff[_ERRNO_STR_BUFF_SIZE]; ++ struct timespec start_ts; ++ struct timespec cur_ts; ++ unsigned int ipc_tmo = 0; ++ bool flag_check_tmo = false; ++ unsigned int elapsed = 0; ++ ++ assert(output != NULL); ++ assert(ctx != NULL); ++ assert(cmd != NULL); ++ ++ *output = NULL; ++ ++ if (clock_gettime(CLOCK_MONOTONIC, &start_ts) != 0) { ++ _error(ctx, "BUG: Failed to get CLOCK_MONOTONIC time " ++ "via clock_gettime(), error %d", errno); ++ return DMMP_ERR_BUG; ++ } ++ ++ ipc_tmo = ctx->tmo; ++ if (ctx->tmo == 0) ++ ipc_tmo = _DEFAULT_UXSOCK_TIMEOUT; ++ ++invoke: ++ _debug(ctx, "Invoking IPC command '%s' with IPC tmo %u miliseconds", ++ cmd, ipc_tmo); ++ flag_check_tmo = false; ++ if (mpath_process_cmd(fd, cmd, output, ipc_tmo) != 0) { ++ errno_save = errno; ++ memset(errno_str_buff, 0, _ERRNO_STR_BUFF_SIZE); ++ strerror_r(errno_save, errno_str_buff, _ERRNO_STR_BUFF_SIZE); ++ if (errno_save == ETIMEDOUT) { ++ flag_check_tmo = true; ++ } else { ++ _error(ctx, "IPC failed when process command '%s' with " ++ "error %d(%s)", cmd, errno_save, errno_str_buff); ++ _debug(ctx, "%s", *output); ++ rc = DMMP_ERR_IPC_ERROR; ++ goto out; ++ } ++ } ++ if ((*output != NULL) && ++ (strncmp(*output, "timeout", strlen("timeout")) == 0)) ++ flag_check_tmo = true; ++ ++ if (flag_check_tmo == true) { ++ free(*output); ++ *output = NULL; ++ if (ctx->tmo == 0) { ++ _debug(ctx, "IPC timeout, but user requested infinite " ++ "timeout"); ++ goto invoke; ++ } ++ ++ if (clock_gettime(CLOCK_MONOTONIC, &cur_ts) != 0) { ++ _error(ctx, "BUG: Failed to get CLOCK_MONOTONIC time " ++ "via clock_gettime(), error %d", errno); ++ rc = DMMP_ERR_BUG; ++ goto out; ++ } ++ elapsed = (cur_ts.tv_sec - start_ts.tv_sec) * 1000 + ++ (cur_ts.tv_nsec - start_ts.tv_nsec) / 1000000; ++ ++ if (elapsed >= ctx->tmo) { ++ rc = DMMP_ERR_IPC_TIMEOUT; ++ _error(ctx, "Timeout, try to increase it via " ++ "dmmp_context_timeout_set()"); ++ goto out; ++ } ++ if (ctx->tmo != 0) ++ ipc_tmo = ctx->tmo - elapsed; ++ ++ _debug(ctx, "IPC timeout, but user requested timeout has not " ++ "reached yet, still have %u milliseconds", ipc_tmo); ++ goto invoke; ++ } else { ++ if ((*output == NULL) || (strlen(*output) == 0)) { ++ _error(ctx, "IPC return empty reply for command %s", ++ cmd); ++ rc = DMMP_ERR_IPC_ERROR; ++ goto out; ++ } ++ } ++ ++out: ++ if (rc != DMMP_OK) { ++ free(*output); ++ *output = NULL; ++ } ++ return rc; ++} +diff --git a/libdmmp/libdmmp/libdmmp.h b/libdmmp/libdmmp/libdmmp.h +index 0679158..3f3fd01 100644 +--- a/libdmmp/libdmmp/libdmmp.h ++++ b/libdmmp/libdmmp/libdmmp.h +@@ -171,6 +171,7 @@ DMMP_DLL_EXPORT void dmmp_context_free(struct dmmp_context *ctx); + * + * @tmo: + * Timeout in milliseconds(1 seconds equal 1000 milliseconds). ++ * 0 means infinite, function only return when error or pass. + * + * Return: + * void +diff --git a/libdmmp/test/libdmmp_test.c b/libdmmp/test/libdmmp_test.c +index 00b40e9..dad0e28 100644 +--- a/libdmmp/test/libdmmp_test.c ++++ b/libdmmp/test/libdmmp_test.c +@@ -35,7 +35,7 @@ + } while(0) + #define PASS(...) fprintf(stdout, "PASS: "__VA_ARGS__ ); + #define FILE_NAME_SIZE 256 +-#define TMO 10000 /* Forcing timeout to 10 seconds */ ++#define TMO 60000 /* Forcing timeout to 60 seconds */ + + int test_paths(struct dmmp_path_group *mp_pg) + { +-- +2.7.4 + diff --git a/0013-multipath-tools-libdmmp-New-function-to-flush-and-re.patch b/0013-multipath-tools-libdmmp-New-function-to-flush-and-re.patch new file mode 100644 index 0000000..1f8c50e --- /dev/null +++ b/0013-multipath-tools-libdmmp-New-function-to-flush-and-re.patch @@ -0,0 +1,409 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Gris Ge +Date: Wed, 16 Aug 2017 20:34:09 +0800 +Subject: [PATCH] multipath-tools: libdmmp: New function to flush and reconfig + +New functions: + * dmmp_reconfig() to invoke reconfiguration of multipathd daemon. + * dmmp_flush_mpath() to flush/del unused mpath. + +Signed-off-by: Gris Ge +Signed-off-by: Benjamin Marzinski +--- + libdmmp/libdmmp.c | 143 +++++++++++++++++++++++++++++++++++++------- + libdmmp/libdmmp/libdmmp.h | 60 +++++++++++++++++++ + libdmmp/libdmmp_misc.c | 5 +- + libdmmp/test/libdmmp_test.c | 47 ++++++++++++++- + 4 files changed, 229 insertions(+), 26 deletions(-) + +diff --git a/libdmmp/libdmmp.c b/libdmmp/libdmmp.c +index 6db348b..b4e7f08 100644 +--- a/libdmmp/libdmmp.c ++++ b/libdmmp/libdmmp.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2015 - 2016 Red Hat, Inc. ++ * Copyright (C) 2015 - 2017 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -19,6 +19,7 @@ + */ + + #include ++#include + #include + #include + #include +@@ -45,6 +46,8 @@ + #define _DMMP_JSON_MAJOR_VERSION 0 + #define _DMMP_JSON_MAPS_KEY "maps" + #define _ERRNO_STR_BUFF_SIZE 256 ++#define _IPC_MAX_CMD_LEN 512 ++/* ^ Was _MAX_CMD_LEN in ./libmultipath/uxsock.h */ + + struct dmmp_context { + void (*log_func)(struct dmmp_context *ctx, int priority, +@@ -66,6 +69,8 @@ struct dmmp_context { + static int _process_cmd(struct dmmp_context *ctx, int fd, const char *cmd, + char **output); + ++static int _ipc_connect(struct dmmp_context *ctx, int *fd); ++ + _dmmp_getter_func_gen(dmmp_context_log_priority_get, + struct dmmp_context, ctx, log_priority, + int); +@@ -153,9 +158,7 @@ int dmmp_mpath_array_get(struct dmmp_context *ctx, + uint32_t i = 0; + int cur_json_major_version = -1; + int ar_maps_len = -1; +- int socket_fd = -1; +- int errno_save = 0; +- char errno_str_buff[_ERRNO_STR_BUFF_SIZE]; ++ int ipc_fd = -1; + + assert(ctx != NULL); + assert(dmmp_mps != NULL); +@@ -164,24 +167,9 @@ int dmmp_mpath_array_get(struct dmmp_context *ctx, + *dmmp_mps = NULL; + *dmmp_mp_count = 0; + +- socket_fd = mpath_connect(); +- if (socket_fd == -1) { +- errno_save = errno; +- memset(errno_str_buff, 0, _ERRNO_STR_BUFF_SIZE); +- strerror_r(errno_save, errno_str_buff, _ERRNO_STR_BUFF_SIZE); +- if (errno_save == ECONNREFUSED) { +- rc = DMMP_ERR_NO_DAEMON; +- _error(ctx, "Socket connection refuse. " +- "Maybe multipathd daemon is not running"); +- } else { +- _error(ctx, "IPC failed with error %d(%s)", errno_save, +- errno_str_buff); +- rc = DMMP_ERR_IPC_ERROR; +- } +- goto out; +- } ++ _good(_ipc_connect(ctx, &ipc_fd), rc, out); + +- _good(_process_cmd(ctx, socket_fd, _DMMP_IPC_SHOW_JSON_CMD, &j_str), ++ _good(_process_cmd(ctx, ipc_fd, _DMMP_IPC_SHOW_JSON_CMD, &j_str), + rc, out); + + _debug(ctx, "Got json output from multipathd: '%s'", j_str); +@@ -258,8 +246,8 @@ int dmmp_mpath_array_get(struct dmmp_context *ctx, + } + + out: +- if (socket_fd >= 0) +- mpath_disconnect(socket_fd); ++ if (ipc_fd >= 0) ++ mpath_disconnect(ipc_fd); + free(j_str); + if (j_token != NULL) + json_tokener_free(j_token); +@@ -371,3 +359,112 @@ out: + } + return rc; + } ++ ++static int _ipc_connect(struct dmmp_context *ctx, int *fd) ++{ ++ int rc = DMMP_OK; ++ int errno_save = 0; ++ char errno_str_buff[_ERRNO_STR_BUFF_SIZE]; ++ ++ assert(ctx != NULL); ++ assert(fd != NULL); ++ ++ *fd = -1; ++ ++ *fd = mpath_connect(); ++ if (*fd == -1) { ++ errno_save = errno; ++ memset(errno_str_buff, 0, _ERRNO_STR_BUFF_SIZE); ++ strerror_r(errno_save, errno_str_buff, _ERRNO_STR_BUFF_SIZE); ++ if (errno_save == ECONNREFUSED) { ++ rc = DMMP_ERR_NO_DAEMON; ++ _error(ctx, "Socket connection refuse. " ++ "Maybe multipathd daemon is not running"); ++ } else { ++ _error(ctx, "IPC failed with error %d(%s)", errno_save, ++ errno_str_buff); ++ rc = DMMP_ERR_IPC_ERROR; ++ } ++ } ++ return rc; ++} ++ ++int dmmp_flush_mpath(struct dmmp_context *ctx, const char *mpath_name) ++{ ++ int rc = DMMP_OK; ++ struct dmmp_mpath **dmmp_mps = NULL; ++ uint32_t dmmp_mp_count = 0; ++ uint32_t i = 0; ++ bool found = false; ++ int ipc_fd = -1; ++ char cmd[_IPC_MAX_CMD_LEN]; ++ char *output = NULL; ++ ++ assert(ctx != NULL); ++ assert(mpath_name != NULL); ++ ++ snprintf(cmd, _IPC_MAX_CMD_LEN, "del map %s", mpath_name); ++ if (strlen(cmd) == _IPC_MAX_CMD_LEN - 1) { ++ rc = DMMP_ERR_INVALID_ARGUMENT; ++ _error(ctx, "Invalid mpath name %s", mpath_name); ++ goto out; ++ } ++ ++ _good(_ipc_connect(ctx, &ipc_fd), rc, out); ++ _good(_process_cmd(ctx, ipc_fd, cmd, &output), rc, out); ++ ++ /* _process_cmd() already make sure output is not NULL */ ++ ++ if (strncmp(output, "fail", strlen("fail")) == 0) { ++ /* Check whether specified mpath exits */ ++ _good(dmmp_mpath_array_get(ctx, &dmmp_mps, &dmmp_mp_count), ++ rc, out); ++ ++ for (i = 0; i < dmmp_mp_count; ++i) { ++ if (strcmp(dmmp_mpath_name_get(dmmp_mps[i]), ++ mpath_name) == 0) { ++ found = true; ++ break; ++ } ++ } ++ ++ if (found == false) { ++ rc = DMMP_ERR_MPATH_NOT_FOUND; ++ _error(ctx, "Specified mpath %s not found", mpath_name); ++ goto out; ++ } ++ ++ rc = DMMP_ERR_MPATH_BUSY; ++ _error(ctx, "Specified mpath is in use"); ++ } else if (strncmp(output, "ok", strlen("ok")) != 0) { ++ rc = DMMP_ERR_BUG; ++ _error(ctx, "Got unexpected output for cmd '%s': '%s'", ++ cmd, output); ++ } ++ ++out: ++ if (ipc_fd >= 0) ++ mpath_disconnect(ipc_fd); ++ dmmp_mpath_array_free(dmmp_mps, dmmp_mp_count); ++ free(output); ++ return rc; ++} ++ ++int dmmp_reconfig(struct dmmp_context *ctx) ++{ ++ int rc = DMMP_OK; ++ int ipc_fd = -1; ++ char *output = NULL; ++ char cmd[_IPC_MAX_CMD_LEN]; ++ ++ snprintf(cmd, _IPC_MAX_CMD_LEN, "%s", "reconfigure"); ++ ++ _good(_ipc_connect(ctx, &ipc_fd), rc, out); ++ _good(_process_cmd(ctx, ipc_fd, cmd, &output), rc, out); ++ ++out: ++ if (ipc_fd >= 0) ++ mpath_disconnect(ipc_fd); ++ free(output); ++ return rc; ++} +diff --git a/libdmmp/libdmmp/libdmmp.h b/libdmmp/libdmmp/libdmmp.h +index 3f3fd01..72b79b9 100644 +--- a/libdmmp/libdmmp/libdmmp.h ++++ b/libdmmp/libdmmp/libdmmp.h +@@ -39,6 +39,9 @@ extern "C" { + #define DMMP_ERR_IPC_ERROR 4 + #define DMMP_ERR_NO_DAEMON 5 + #define DMMP_ERR_INCOMPATIBLE 6 ++#define DMMP_ERR_MPATH_BUSY 7 ++#define DMMP_ERR_MPATH_NOT_FOUND 8 ++#define DMMP_ERR_INVALID_ARGUMENT 9 + + /* + * Use the syslog severity level as log priority +@@ -647,6 +650,63 @@ DMMP_DLL_EXPORT uint32_t dmmp_path_status_get(struct dmmp_path *dmmp_p); + */ + DMMP_DLL_EXPORT const char *dmmp_path_status_str(uint32_t path_status); + ++/** ++ * dmmp_flush_mpath() - Flush specified multipath device map if unused. ++ * ++ * Flush a multipath device map specified as parameter, if unused. ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * @mpath_name: ++ * const char *. The name of multipath device map. ++ * ++ * Return: ++ * int. Valid error codes are: ++ * ++ * * DMMP_OK ++ * ++ * * DMMP_ERR_BUG ++ * ++ * * DMMP_ERR_NO_MEMORY ++ * ++ * * DMMP_ERR_NO_DAEMON ++ * ++ * * DMMP_ERR_MPATH_BUSY ++ * ++ * * DMMP_ERR_MPATH_NOT_FOUND ++ * ++ * * DMMP_ERR_INVALID_ARGUMENT ++ * ++ * Error number could be converted to string by dmmp_strerror(). ++ */ ++DMMP_DLL_EXPORT int dmmp_flush_mpath(struct dmmp_context *ctx, ++ const char *mpath_name); ++ ++/** ++ * dmmp_reconfig() - Instruct multipathd daemon to do reconfiguration. ++ * ++ * Instruct multipathd daemon to do reconfiguration. ++ * ++ * @ctx: ++ * Pointer of 'struct dmmp_context'. ++ * If this pointer is NULL, your program will be terminated by assert. ++ * ++ * Return: ++ * int. Valid error codes are: ++ * ++ * * DMMP_OK ++ * ++ * * DMMP_ERR_BUG ++ * ++ * * DMMP_ERR_NO_MEMORY ++ * ++ * * DMMP_ERR_NO_DAEMON ++ * ++ * Error number could be converted to string by dmmp_strerror(). ++ */ ++DMMP_DLL_EXPORT int dmmp_reconfig(struct dmmp_context *ctx); ++ + #ifdef __cplusplus + } /* End of extern "C" */ + #endif +diff --git a/libdmmp/libdmmp_misc.c b/libdmmp/libdmmp_misc.c +index 27f1161..435ddfa 100644 +--- a/libdmmp/libdmmp_misc.c ++++ b/libdmmp/libdmmp_misc.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2015 - 2016 Red Hat, Inc. ++ * Copyright (C) 2015 - 2017 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -46,6 +46,9 @@ static const struct _num_str_conv _DMMP_RC_MSG_CONV[] = { + {DMMP_ERR_IPC_ERROR, "Error when communicate with multipathd daemon"}, + {DMMP_ERR_NO_DAEMON, "The multipathd daemon not started"}, + {DMMP_ERR_INCOMPATIBLE, "Incompatible multipathd daemon version"}, ++ {DMMP_ERR_MPATH_BUSY, "Specified multipath device map is in use"}, ++ {DMMP_ERR_MPATH_NOT_FOUND, "Specified multipath not found"}, ++ {DMMP_ERR_INVALID_ARGUMENT, "Invalid argument"}, + }; + + _dmmp_str_func_gen(dmmp_strerror, int, rc, _DMMP_RC_MSG_CONV); +diff --git a/libdmmp/test/libdmmp_test.c b/libdmmp/test/libdmmp_test.c +index dad0e28..56bd03e 100644 +--- a/libdmmp/test/libdmmp_test.c ++++ b/libdmmp/test/libdmmp_test.c +@@ -1,5 +1,5 @@ + /* +- * Copyright (C) 2015-2016 Red Hat, Inc. ++ * Copyright (C) 2015-2017 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + + #include + +@@ -106,11 +107,14 @@ int main(int argc, char *argv[]) + struct dmmp_context *ctx = NULL; + struct dmmp_mpath **dmmp_mps = NULL; + uint32_t dmmp_mp_count = 0; ++ uint32_t old_dmmp_mp_count = 0; + const char *name = NULL; + const char *wwid = NULL; + const char *kdev = NULL; + uint32_t i = 0; + int rc = EXIT_SUCCESS; ++ const char *old_name = NULL; ++ bool found = false; + + ctx = dmmp_context_new(); + dmmp_context_log_priority_set(ctx, DMMP_LOG_PRIORITY_DEBUG); +@@ -119,7 +123,7 @@ int main(int argc, char *argv[]) + dmmp_context_timeout_set(ctx, TMO); + if (dmmp_context_timeout_get(ctx) != TMO) + FAIL(rc, out, "dmmp_context_timeout_set(): Failed to set " +- "timeout to %u", TMO); ++ "timeout to %u\n", TMO); + + if (dmmp_mpath_array_get(ctx, &dmmp_mps, &dmmp_mp_count) != 0) + FAIL(rc, out, "dmmp_mpath_array_get(): rc != 0\n"); +@@ -140,7 +144,46 @@ int main(int argc, char *argv[]) + if (rc != 0) + goto out; + } ++ ++ old_name = strdup(name); ++ if (old_name == NULL) ++ FAIL(rc, out, "strdup(): no memory\n"); ++ ++ old_dmmp_mp_count = dmmp_mp_count; ++ + dmmp_mpath_array_free(dmmp_mps, dmmp_mp_count); ++ ++ if (dmmp_flush_mpath(ctx, old_name) != DMMP_OK) ++ FAIL(rc, out, "dmmp_flush_mpath(): Failed\n"); ++ ++ PASS("dmmp_flush_mpath(): OK\n"); ++ ++ if (dmmp_reconfig(ctx) != DMMP_OK) ++ FAIL(rc, out, "dmmp_reconfig(): Failed\n"); ++ ++ PASS("dmmp_reconfig(): OK\n"); ++ ++ if (dmmp_mpath_array_get(ctx, &dmmp_mps, &dmmp_mp_count) != 0) ++ FAIL(rc, out, "dmmp_mpath_array_get(): rc != 0\n"); ++ if (dmmp_mp_count == 0) ++ FAIL(rc, out, "dmmp_mpath_array_get(): " ++ "Got no multipath devices\n"); ++ ++ if (dmmp_mp_count != old_dmmp_mp_count) ++ FAIL(rc, out, "Got different mpath count after reconfig: " ++ "old %" PRIu32 ", new %" PRIu32 "\n", old_dmmp_mp_count, ++ dmmp_mp_count); ++ ++ for (i = 0; i < dmmp_mp_count; ++i) { ++ if (strcmp(old_name, dmmp_mpath_name_get(dmmp_mps[i])) == 0) { ++ found = true; ++ break; ++ } ++ } ++ if (found == false) ++ FAIL(rc, out, "dmmp_reconfig() does not recreate deleted " ++ "mpath %s\n", old_name); ++ + out: + dmmp_context_free(ctx); + exit(rc); +-- +2.7.4 + diff --git a/device-mapper-multipath.spec b/device-mapper-multipath.spec index 6c8aca1..41780c6 100644 --- a/device-mapper-multipath.spec +++ b/device-mapper-multipath.spec @@ -1,7 +1,7 @@ Summary: Tools to manage multipath devices using device-mapper Name: device-mapper-multipath Version: 0.7.1 -Release: 8.git847cc43%{?dist} +Release: 9.git847cc43%{?dist} License: GPL+ Group: System Environment/Base URL: http://christophe.varoqui.free.fr/ @@ -21,6 +21,9 @@ Patch0007: 0007-RH-add-mpathconf.patch Patch0008: 0008-RH-add-wwids-from-kernel-cmdline-mpath.wwids-with-A.patch Patch0009: 0009-RH-trigger-change-uevent-on-new-device-creation.patch Patch0010: 0010-RH-warn-on-invalid-regex-instead-of-failing.patch +Patch0011: 0011-multipath-tools-Remove-the-limitation-of-IPC-command.patch +Patch0012: 0012-multipath-tools-libdmmp-Improve-timeout-mechanism.patch +Patch0013: 0013-multipath-tools-libdmmp-New-function-to-flush-and-re.patch # runtime Requires: %{name}-libs = %{version}-%{release} @@ -109,6 +112,9 @@ device-mapper-multipath's libdmmp C API library %patch0008 -p1 %patch0009 -p1 %patch0010 -p1 +%patch0011 -p1 +%patch0012 -p1 +%patch0013 -p1 cp %{SOURCE1} . %build @@ -230,6 +236,12 @@ fi %{_pkgconfdir}/libdmmp.pc %changelog +* Wed Dec 13 2017 Benjamin Marzinski 0.7.1-9.git847cc43 +- Add 0011-multipath-tools-Remove-the-limitation-of-IPC-command.patch +- Add 0012-multipath-tools-libdmmp-Improve-timeout-mechanism.patch +- Add 0013-multipath-tools-libdmmp-New-function-to-flush-and-re.patch + * Add dmmp_reconfig() and dmmp_flush_mpath() functions + * Tue Nov 7 2017 Benjamin Marzinski 0.7.1-8.git847cc43 - Refresh 0001-libmultipath-update-3PARdata-builtin-config.patch - Add 0010-RH-warn-on-invalid-regex-instead-of-failing.patch