Whenever we accept a new connection or close an
existing one, check the number of available file
descriptors and either publish or withdraw the
IPC listening socket.

Signed-off-by: Angus Salkeld <asalk...@redhat.com>
---
 exec/coroipcs.c |  104 ++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 87 insertions(+), 17 deletions(-)

diff --git a/exec/coroipcs.c b/exec/coroipcs.c
index aca9053..05b6a17 100644
--- a/exec/coroipcs.c
+++ b/exec/coroipcs.c
@@ -169,6 +169,14 @@ struct conn_info {
        int poll_state;
 };
 
+static int32_t coro_server_fd = -1;
+
+static void server_socket_publish(void);
+
+static void server_socket_withdraw(void);
+
+static void server_socket_check(void);
+
 static int shared_mem_dispatch_bytes_left (const struct conn_info *conn_info);
 
 static void outq_flush (struct conn_info *conn_info);
@@ -180,8 +188,6 @@ static void ipc_disconnect (struct conn_info *conn_info);
 static void msg_send (void *conn, const struct iovec *iov, unsigned int 
iov_len,
                      int locked);
 
-static void _corosync_ipc_init(void);
-
 #define log_printf(level, format, args...) \
 do { \
        if (api->log_printf) \
@@ -513,6 +519,7 @@ static inline int conn_info_destroy (struct conn_info 
*conn_info)
                conn_info->state == CONN_STATE_DISCONNECT_INACTIVE) {
                list_del (&conn_info->list);
                close (conn_info->fd);
+               server_socket_check();
                api->free (conn_info);
                return (-1);
        }
@@ -568,6 +575,7 @@ static inline int conn_info_destroy (struct conn_info 
*conn_info)
                api->free (conn_info->private_data);
        }
        close (conn_info->fd);
+       server_socket_check();
        res = circular_memory_unmap (conn_info->dispatch_buffer, 
conn_info->dispatch_size);
        zcb_all_free (conn_info);
        api->free (conn_info);
@@ -959,7 +967,7 @@ extern void coroipcs_ipc_init_v2 (
        api->old_log_printf     = NULL;
 
        log_printf (LOGSYS_LEVEL_DEBUG, "you are using ipc api v2\n");
-       _corosync_ipc_init ();
+       server_socket_publish();
 }
 
 extern void coroipcs_ipc_init (
@@ -997,34 +1005,69 @@ extern void coroipcs_ipc_init (
 
        log_printf (LOGSYS_LEVEL_DEBUG, "you are using ipc api v1\n");
 
-       _corosync_ipc_init ();
+       server_socket_publish();
 }
 
-static void _corosync_ipc_init(void)
+/*
+ * The actual used sockets is 12 but allowing a larger number
+ * for safety.
+ */
+#define COROIPC_NUM_RESERVED_SOCKETS 25
+
+static int32_t num_avail_sockets(void)
 {
-       int server_fd;
+       struct rlimit lim;
+       int32_t open_socks = 0;
+       int32_t res;
+       struct list_head *list;
+
+       if (getrlimit(RLIMIT_NOFILE, &lim) == -1) {
+               char error_str[100];
+               strerror_r(errno, error_str, 100);
+               log_printf(LOGSYS_LEVEL_ERROR,
+                       "getrlimit: %s\n", error_str);
+               return -1;
+       }
+
+       for (list = conn_info_list_head.next; list != &conn_info_list_head;
+               list = list->next) {
+               open_socks++;
+       }
+       res = (lim.rlim_cur - (open_socks + COROIPC_NUM_RESERVED_SOCKETS));
+       log_printf(LOGSYS_LEVEL_DEBUG, "(lim.rlim_cur:%d - (open_socks:%d + 
reserved:%d) == %d\n",
+               lim.rlim_cur, open_socks, COROIPC_NUM_RESERVED_SOCKETS, res);
+       return res;
+}
+
+static void server_socket_publish(void)
+{
+       int32_t res = 0;
        struct sockaddr_un un_addr;
-       int res;
+
+       log_printf (LOGSYS_LEVEL_WARNING,
+               "Publishing socket for client connections.\n");
 
        /*
         * Create socket for IPC clients, name socket, listen for connections
         */
 #if defined(COROSYNC_SOLARIS)
-       server_fd = socket (PF_UNIX, SOCK_STREAM, 0);
+       coro_server_fd = socket (PF_UNIX, SOCK_STREAM, 0);
 #else
-       server_fd = socket (PF_LOCAL, SOCK_STREAM, 0);
+       coro_server_fd = socket (PF_LOCAL, SOCK_STREAM, 0);
 #endif
-       if (server_fd == -1) {
+       if (coro_server_fd == -1) {
                log_printf (LOGSYS_LEVEL_CRIT, "Cannot create client 
connections socket.\n");
                api->fatal_error ("Can't create library listen socket");
        }
 
-       res = fcntl (server_fd, F_SETFL, O_NONBLOCK);
+       res = fcntl (coro_server_fd, F_SETFL, O_NONBLOCK);
        if (res == -1) {
                char error_str[100];
-               strerror_r (errno, error_str, 100);
-               log_printf (LOGSYS_LEVEL_CRIT, "Could not set non-blocking 
operation on server socket: %s\n", error_str);
-               api->fatal_error ("Could not set non-blocking operation on 
server socket");
+               strerror_r(errno, error_str, 100);
+               log_printf(LOGSYS_LEVEL_CRIT,
+                       "Could not set non-blocking operation on server socket: 
%s\n",
+                       error_str);
+               api->fatal_error("Could not set non-blocking operation on 
server socket");
        }
 
        memset (&un_addr, 0, sizeof (struct sockaddr_un));
@@ -1048,7 +1091,7 @@ static void _corosync_ipc_init(void)
        }
 #endif
 
-       res = bind (server_fd, (struct sockaddr *)&un_addr, 
COROSYNC_SUN_LEN(&un_addr));
+       res = bind (coro_server_fd, (struct sockaddr *)&un_addr, 
COROSYNC_SUN_LEN(&un_addr));
        if (res) {
                char error_str[100];
                strerror_r (errno, error_str, 100);
@@ -1063,12 +1106,35 @@ static void _corosync_ipc_init(void)
 #if !defined(COROSYNC_LINUX)
        res = chmod (un_addr.sun_path, S_IRWXU|S_IRWXG|S_IRWXO);
 #endif
-       listen (server_fd, SERVER_BACKLOG);
+       listen (coro_server_fd, SERVER_BACKLOG);
 
        /*
         * Setup connection dispatch routine
         */
-       api->poll_accept_add (server_fd);
+       api->poll_accept_add (coro_server_fd);
+}
+
+static void server_socket_withdraw(void)
+{
+       log_printf(LOGSYS_LEVEL_WARNING,
+               "Withdrawing socket for client connections.\n");
+
+       api->poll_dispatch_destroy(coro_server_fd, NULL);
+       shutdown(coro_server_fd, SHUT_RDWR);
+       close(coro_server_fd);
+       coro_server_fd = -1;
+}
+
+static void server_socket_check(void)
+{
+       int32_t num = num_avail_sockets();
+
+       if (coro_server_fd == -1 && num > 0) {
+               server_socket_publish();
+       }
+       else if (coro_server_fd != -1 && num <= 0) {
+               server_socket_withdraw();
+       }
 }
 
 void coroipcs_ipc_exit (void)
@@ -1447,6 +1513,9 @@ retry_accept:
                strerror_r (errno, error_str, 100);
                log_printf (LOGSYS_LEVEL_ERROR,
                        "Could not accept Library connection: %s\n", error_str);
+               if (errno == EMFILE || errno == ENFILE) {
+                       server_socket_withdraw();
+               }
                return (0); /* This is an error, but -1 would indicate 
disconnect from poll loop */
        }
 
@@ -1476,6 +1545,7 @@ retry_accept:
        if (res != 0) {
                close (new_fd);
        }
+       server_socket_check();
 
        return (0);
 }
-- 
1.7.1

_______________________________________________
Openais mailing list
Openais@lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/openais

Reply via email to