Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a05376fe5 |
4 changed files with 710 additions and 1 deletions
|
|
@ -0,0 +1,59 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
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 <fge@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
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
|
||||
|
||||
229
0012-multipath-tools-libdmmp-Improve-timeout-mechanism.patch
Normal file
229
0012-multipath-tools-libdmmp-Improve-timeout-mechanism.patch
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
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 <fge@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
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 <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <json.h>
|
||||
+#include <time.h>
|
||||
#include <mpath_cmd.h>
|
||||
|
||||
#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
|
||||
|
||||
409
0013-multipath-tools-libdmmp-New-function-to-flush-and-re.patch
Normal file
409
0013-multipath-tools-libdmmp-New-function-to-flush-and-re.patch
Normal file
|
|
@ -0,0 +1,409 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Gris Ge <fge@redhat.com>
|
||||
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 <fge@redhat.com>
|
||||
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
|
||||
---
|
||||
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 <stdint.h>
|
||||
+#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
@@ -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 <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
+#include <stdbool.h>
|
||||
|
||||
#include <libdmmp/libdmmp.h>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
|
@ -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 <bmarzins@redhat.com> 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 <bmarzins@redhat.com> 0.7.1-8.git847cc43
|
||||
- Refresh 0001-libmultipath-update-3PARdata-builtin-config.patch
|
||||
- Add 0010-RH-warn-on-invalid-regex-instead-of-failing.patch
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue