conman/Reset-delay-for-unixsock-connect-from-inotify.patch
Egbert Eich 3317d2586d - Replace
If-connect-fails-let-other-side-accept-connection-and-come-back.patch
  by:
  Reset-delay-for-unixsock-connect-from-inotify.patch:
  Upstream chose to fix bsc#1101647 slightly differently.

OBS-URL: https://build.opensuse.org/package/show/network:cluster/conman?expand=0&rev=29
2018-08-23 09:48:24 +00:00

136 lines
5.4 KiB
Diff

From: Egbert Eich <eich@suse.com>
Date: Wed Jul 18 11:26:07 2018 +0200
Subject: Reset delay for unixsock connect from inotify
Patch-mainline: Not yet
Git-repo: https://github.com/dun/conman
Git-commit: 8f5bd09162307a23efb8532a95c4e4a562ce30fe
References: bsc#1101647
Consoles over UNIX domain sockets use inotify to detect when their
socket appears in the filesystem. This inotify event is triggered
when the remote has successfully called bind(). However, the remote
may not have called listen() before the inotify event is serviced
by conmand. In such a case, connect() will fail with ECONNREFUSED,
after which the connection delay will be increased before the next
connection attempt. This can result in connection establishment
taking up to UNIXSOCK_MAX_TIMEOUT seconds once the socket appears.
To handle this case, reset the connection delay to UNIXSOCK_MIN_TIMEOUT
when a connection attempt triggered by inotify fails.
[cdunlap@llnl.gov: Restructured to use isViaInotify flag]
Signed-off-by: Egbert Eich <eich@suse.com>
Signed-off-by: Chris Dunlap <cdunlap@llnl.gov>
Closes #28
Closes #29
Signed-off-by: Egbert Eich <eich@suse.de>
---
server-unixsock.c | 36 ++++++++++++++++++++++++++++++++++--
server.h | 1 +
2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/server-unixsock.c b/server-unixsock.c
index e683ec7..b44adb4 100644
--- a/server-unixsock.c
+++ b/server-unixsock.c
@@ -45,6 +45,7 @@
#include "util-str.h"
+static int open_unixsock_obj_via_inotify(obj_t *unixsock);
static size_t max_unixsock_dev_strlen(void);
static int connect_unixsock_obj(obj_t *unixsock);
static int disconnect_unixsock_obj(obj_t *unixsock);
@@ -140,6 +141,7 @@ obj_t * create_unixsock_obj(server_conf_t *conf, char *name, char *dev,
unixsock->aux.unixsock.logfile = NULL;
unixsock->aux.unixsock.timer = -1;
unixsock->aux.unixsock.state = CONMAN_UNIXSOCK_DOWN;
+ unixsock->aux.unixsock.isViaInotify = 0;
unixsock->aux.unixsock.delay = UNIXSOCK_MIN_TIMEOUT;
/*
* Add obj to the master conf->objs list.
@@ -147,7 +149,7 @@ obj_t * create_unixsock_obj(server_conf_t *conf, char *name, char *dev,
list_append(conf->objs, unixsock);
rv = inevent_add(unixsock->aux.unixsock.dev,
- (inevent_cb_f) open_unixsock_obj, unixsock);
+ (inevent_cb_f) open_unixsock_obj_via_inotify, unixsock);
if (rv < 0) {
log_msg(LOG_INFO,
"Console [%s] unable to register device \"%s\" for inotify events",
@@ -177,6 +179,23 @@ int open_unixsock_obj(obj_t *unixsock)
}
+static int open_unixsock_obj_via_inotify(obj_t *unixsock)
+{
+/* Opens the specified 'unixsock' obj via an inotify callback.
+ * Returns 0 if the console is successfully opened; o/w, returns -1.
+ */
+ unixsock_obj_t *auxp;
+
+ assert(unixsock != NULL);
+ assert(is_unixsock_obj(unixsock));
+
+ auxp = &(unixsock->aux.unixsock);
+ auxp->isViaInotify = 1;
+
+ return(open_unixsock_obj(unixsock));
+}
+
+
static size_t max_unixsock_dev_strlen(void)
{
/* Returns the maximum string length allowed for a unix domain device.
@@ -199,6 +218,7 @@ static int connect_unixsock_obj(obj_t *unixsock)
* Returns 0 if the connection is successfully completed; o/w, returns -1.
*/
unixsock_obj_t *auxp;
+ int isViaInotify;
struct stat st;
struct sockaddr_un saddr;
size_t n;
@@ -210,6 +230,9 @@ static int connect_unixsock_obj(obj_t *unixsock)
auxp = &(unixsock->aux.unixsock);
+ isViaInotify = auxp->isViaInotify;
+ auxp->isViaInotify = 0;
+
if (auxp->timer >= 0) {
(void) tpoll_timeout_cancel(tp_global, auxp->timer);
auxp->timer = -1;
@@ -250,11 +273,20 @@ static int connect_unixsock_obj(obj_t *unixsock)
set_fd_nonblocking(unixsock->fd);
set_fd_closed_on_exec(unixsock->fd);
- /* FIXME: Check to see if connect() on a nonblocking unix domain socket
+ /* If a connect() triggered via an inotify event fails, reset the
+ * reconnect delay to its minimum to quickly re-attempt the connection.
+ * This handles the case where the remote has successfully called bind()
+ * (triggering the inotify event) but has not yet called listen().
+ * FIXME: Check to see if connect() on a nonblocking unix domain socket
* can return EINPROGRESS. I don't think it can.
*/
if (connect(unixsock->fd,
(struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
+ if (isViaInotify) {
+ auxp->delay = UNIXSOCK_MIN_TIMEOUT;
+ DPRINTF((15, "Reset [%s] reconnect delay due to inotify event\n",
+ unixsock->name));
+ }
log_msg(LOG_INFO, "Console [%s] cannot connect to device \"%s\": %s",
unixsock->name, auxp->dev, strerror(errno));
return(disconnect_unixsock_obj(unixsock));
diff --git a/server.h b/server.h
index 8ccbcf9..6cc7c1b 100644
--- a/server.h
+++ b/server.h
@@ -180,6 +180,7 @@ typedef struct unixsock_obj { /* UNIXSOCK AUX OBJ DATA: */
int timer; /* timer id for reconnects */
int delay; /* secs 'til next reconnect attempt */
unsigned state:1; /* unixsock_state_t conn state */
+ unsigned isViaInotify:1; /* true if triggered via inotify */
} unixsock_obj_t;
/* Refer to struct ipmiconsole_ipmi_config in <ipmiconsole.h>.