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/ipc.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
 1 files changed, 86 insertions(+), 6 deletions(-)

diff --git a/exec/ipc.c b/exec/ipc.c
index 5337d25..bf3102c 100644
--- a/exec/ipc.c
+++ b/exec/ipc.c
@@ -99,6 +99,7 @@
 #define MSG_SEND_UNLOCKED      1
 
 static unsigned int g_gid_valid = 0;
+static int32_t libais_server_fd = -1;
 
 static void (*ipc_serialize_lock_fn) (void);
 
@@ -161,6 +162,15 @@ static int priv_change (struct conn_info *conn_info);
 
 static void ipc_disconnect (struct conn_info *conn_info);
 
+static void server_socket_publish(void);
+
+static void server_socket_withdraw(void);
+
+static void server_socket_check(void);
+
+static int poll_handler_accept (poll_handle handle, int fd,
+       int revent, void *data);
+
 static int ipc_thread_active (void *conn)
 {
        struct conn_info *conn_info = (struct conn_info *)conn;
@@ -211,6 +221,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();
                free (conn_info);
                return (-1);
        }
@@ -257,6 +268,7 @@ static inline int conn_info_destroy (struct conn_info 
*conn_info)
                free (conn_info->private_data);
        }
        close (conn_info->fd);
+       server_socket_check();
        free (conn_info);
        ipc_serialize_unlock_fn();
        return (-1);
@@ -773,7 +785,12 @@ retry_accept:
        }
 
        if (new_fd == -1) {
-               log_printf (LOG_LEVEL_ERROR, "ERROR: Could not accept Library 
connection: %s\n", strerror (errno));
+               log_printf (LOG_LEVEL_ERROR,
+                       "ERROR: Could not accept Library connection: %s\n",
+                       strerror (errno));
+               if (errno == EMFILE || errno == ENFILE) {
+                       server_socket_withdraw();
+               }
                return (0); /* This is an error, but -1 would indicate 
disconnect from poll loop */
        }
 
@@ -802,6 +819,7 @@ retry_accept:
        if (res != 0) {
                close (new_fd);
        }
+       server_socket_check();
 
        return (0);
 }
@@ -835,14 +853,23 @@ void openais_ipc_init (
        void (*serialize_lock_fn) (void),
        void (*serialize_unlock_fn) (void))
 {
-       int libais_server_fd;
-       struct sockaddr_un un_addr;
-       int res;
-
        ipc_serialize_lock_fn = serialize_lock_fn;
 
        ipc_serialize_unlock_fn = serialize_unlock_fn;
 
+       server_socket_publish();
+
+       g_gid_valid = gid_valid;
+}
+
+static void server_socket_publish(void)
+{
+       int32_t res = 0;
+       struct sockaddr_un un_addr;
+
+       log_printf(LOG_LEVEL_WARNING,
+               "Publishing socket for client connections.\n");
+
        /*
         * Create socket for libais clients, name socket, listen for connections
         */
@@ -885,8 +912,61 @@ void openais_ipc_init (
          */
         poll_dispatch_add (aisexec_poll_handle, libais_server_fd,
                 POLLIN|POLLNVAL, 0, poll_handler_accept);
+}
 
-       g_gid_valid = gid_valid;
+static void server_socket_withdraw(void)
+{
+       log_printf(LOG_LEVEL_WARNING,
+               "Withdrawing socket for client connections.\n");
+
+       poll_dispatch_delete(aisexec_poll_handle, libais_server_fd);
+       shutdown(libais_server_fd, SHUT_RDWR);
+       close(libais_server_fd);
+       libais_server_fd = -1;
+}
+
+/*
+ * 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)
+{
+       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(LOG_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(LOG_LEVEL_DEBUG,
+               "(lim.rlim_cur:%lu - (open_socks:%d + reserved:%d) == %d\n",
+               lim.rlim_cur, open_socks, COROIPC_NUM_RESERVED_SOCKETS, res);
+       return res;
+}
+
+static void server_socket_check(void)
+{
+       int32_t num = num_avail_sockets();
+
+       if (libais_server_fd == -1 && num > 0) {
+               server_socket_publish();
+       }
+       else if (libais_server_fd != -1 && num <= 0) {
+               server_socket_withdraw();
+       }
 }
 
 void openais_ipc_exit (void)
-- 
1.7.1

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

Reply via email to