All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/3] multipath-tools: Remove the limitation of IPC command reply length.
@ 2017-08-16 12:34 Gris Ge
  2017-08-16 12:34 ` [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism Gris Ge
  0 siblings, 1 reply; 5+ messages in thread
From: Gris Ge @ 2017-08-16 12:34 UTC (permalink / raw)
  To: dm-devel; +Cc: Gris Ge

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>
---
 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 1496b682..af618cff 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 6534474c..b57b708b 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.14.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism
  2017-08-16 12:34 [PATCH 1/3] multipath-tools: Remove the limitation of IPC command reply length Gris Ge
@ 2017-08-16 12:34 ` Gris Ge
  2017-08-16 12:34   ` [PATCH 3/3] multipath-tools: libdmmp: New function to flush and reconfig Gris Ge
  2017-08-17 21:29   ` [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism Martin Wilck
  0 siblings, 2 replies; 5+ messages in thread
From: Gris Ge @ 2017-08-16 12:34 UTC (permalink / raw)
  To: dm-devel; +Cc: Gris Ge

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>
---
 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 3906335a..6db348b4 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 06791586..3f3fd017 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 00b40e90..dad0e280 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.14.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] multipath-tools: libdmmp: New function to flush and reconfig
  2017-08-16 12:34 ` [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism Gris Ge
@ 2017-08-16 12:34   ` Gris Ge
  2017-08-17 21:29   ` [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism Martin Wilck
  1 sibling, 0 replies; 5+ messages in thread
From: Gris Ge @ 2017-08-16 12:34 UTC (permalink / raw)
  To: dm-devel; +Cc: Gris Ge

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>
---
 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 6db348b4..b4e7f08f 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 3f3fd017..72b79b97 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 27f1161a..435ddfa5 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 dad0e280..56bd03e7 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.14.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism
  2017-08-16 12:34 ` [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism Gris Ge
  2017-08-16 12:34   ` [PATCH 3/3] multipath-tools: libdmmp: New function to flush and reconfig Gris Ge
@ 2017-08-17 21:29   ` Martin Wilck
  2017-08-28 12:58     ` Gris Ge
  1 sibling, 1 reply; 5+ messages in thread
From: Martin Wilck @ 2017-08-17 21:29 UTC (permalink / raw)
  To: dm-devel

On Wed, 2017-08-16 at 20:34 +0800, Gris Ge wrote:
> 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.

Maybe I'm missing something here, but if you just retry the timed-out
command, isn't it likely that you'll hit the uxsock_timeout again and
again?

Best,
Martin

-- 
Dr. Martin Wilck <mwilck@suse.com>, Tel. +49 (0)911 74053 2107
SUSE Linux GmbH, GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)

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

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism
  2017-08-17 21:29   ` [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism Martin Wilck
@ 2017-08-28 12:58     ` Gris Ge
  0 siblings, 0 replies; 5+ messages in thread
From: Gris Ge @ 2017-08-28 12:58 UTC (permalink / raw)
  To: Martin Wilck; +Cc: dm-devel


[-- Attachment #1.1: Type: text/plain, Size: 623 bytes --]

On Thu, Aug 17, 2017 at 11:29:56PM +0200, Martin Wilck wrote:
> On Wed, 2017-08-16 at 20:34 +0800, Gris Ge wrote:
> > Issue:
> >     libdmmp return error of timeout before user requested timeout was
> >     met.
>
> Maybe I'm missing something here, but if you just retry the timed-out
> command, isn't it likely that you'll hit the uxsock_timeout again and
> again?
>
> Best,
> Martin
Hi Martin,

You will get timeout again after `uxsock_timeout` seconds if the
daemon/multipathd haven't finish its work on dm tables and invoking path
checker. But eventually, you will the requested data.

-- 
Gris Ge

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2017-08-28 12:58 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-16 12:34 [PATCH 1/3] multipath-tools: Remove the limitation of IPC command reply length Gris Ge
2017-08-16 12:34 ` [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism Gris Ge
2017-08-16 12:34   ` [PATCH 3/3] multipath-tools: libdmmp: New function to flush and reconfig Gris Ge
2017-08-17 21:29   ` [PATCH 2/3] multipath-tools: libdmmp: Improve timeout mechanism Martin Wilck
2017-08-28 12:58     ` Gris Ge

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.