fs: dlm: introduce generic listen
authorAlexander Aring <aahringo@redhat.com>
Fri, 16 Jul 2021 20:22:41 +0000 (16:22 -0400)
committerDavid Teigland <teigland@redhat.com>
Mon, 19 Jul 2021 16:53:43 +0000 (11:53 -0500)
This patch combines each transport layer listen functionality into one
listen function. Per transport layer differences are provided by
additional callbacks in dlm_proto_ops.

This patch drops silently sock_set_keepalive() for listen tcp sockets
only. This socket option is not set at connecting sockets, I also don't
see the sense of set keepalive for sockets which are created by accept()
only.

Signed-off-by: Alexander Aring <aahringo@redhat.com>
Signed-off-by: David Teigland <teigland@redhat.com>
fs/dlm/lowcomms.c

index 9a4e7421567ee6469909d86052fcbb7a490751ad..a042ea413f74ff6a8b051b13903ac974186ce6e9 100644 (file)
@@ -143,6 +143,13 @@ struct dlm_node_addr {
 };
 
 struct dlm_proto_ops {
+       const char *name;
+       int proto;
+
+       int (*listen_validate)(void);
+       void (*listen_sockopts)(struct socket *sock);
+       int (*listen_bind)(struct socket *sock);
+
        /* What to do to connect */
        void (*connect_action)(struct connection *con);
        /* What to do to shutdown */
@@ -1327,59 +1334,6 @@ out:
        return;
 }
 
-/* On error caller must run dlm_close_sock() for the
- * listen connection socket.
- */
-static int tcp_create_listen_sock(struct listen_connection *con,
-                                 struct sockaddr_storage *saddr)
-{
-       struct socket *sock = NULL;
-       int result = 0;
-       int addr_len;
-
-       if (dlm_local_addr[0]->ss_family == AF_INET)
-               addr_len = sizeof(struct sockaddr_in);
-       else
-               addr_len = sizeof(struct sockaddr_in6);
-
-       /* Create a socket to communicate with */
-       result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family,
-                                 SOCK_STREAM, IPPROTO_TCP, &sock);
-       if (result < 0) {
-               log_print("Can't create listening comms socket");
-               goto create_out;
-       }
-
-       sock_set_mark(sock->sk, dlm_config.ci_mark);
-
-       /* Turn off Nagle's algorithm */
-       tcp_sock_set_nodelay(sock->sk);
-
-       sock_set_reuseaddr(sock->sk);
-
-       add_listen_sock(sock, con);
-
-       /* Bind to our port */
-       make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len);
-       result = sock->ops->bind(sock, (struct sockaddr *) saddr, addr_len);
-       if (result < 0) {
-               log_print("Can't bind to port %d", dlm_config.ci_tcp_port);
-               goto create_out;
-       }
-       sock_set_keepalive(sock->sk);
-
-       result = sock->ops->listen(sock, 5);
-       if (result < 0) {
-               log_print("Can't listen on port %d", dlm_config.ci_tcp_port);
-               goto create_out;
-       }
-
-       return 0;
-
-create_out:
-       return result;
-}
-
 /* Get local addresses */
 static void init_local(void)
 {
@@ -1406,63 +1360,6 @@ static void deinit_local(void)
                kfree(dlm_local_addr[i]);
 }
 
-/* Initialise SCTP socket and bind to all interfaces
- * On error caller must run dlm_close_sock() for the
- * listen connection socket.
- */
-static int sctp_listen_for_all(struct listen_connection *con)
-{
-       struct socket *sock = NULL;
-       int result = -EINVAL;
-
-       log_print("Using SCTP for communications");
-
-       result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family,
-                                 SOCK_STREAM, IPPROTO_SCTP, &sock);
-       if (result < 0) {
-               log_print("Can't create comms socket, check SCTP is loaded");
-               goto out;
-       }
-
-       sock_set_rcvbuf(sock->sk, NEEDED_RMEM);
-       sock_set_mark(sock->sk, dlm_config.ci_mark);
-       sctp_sock_set_nodelay(sock->sk);
-
-       add_listen_sock(sock, con);
-
-       /* Bind to all addresses. */
-       result = sctp_bind_addrs(con->sock, dlm_config.ci_tcp_port);
-       if (result < 0)
-               goto out;
-
-       result = sock->ops->listen(sock, 5);
-       if (result < 0) {
-               log_print("Can't set socket listening");
-               goto out;
-       }
-
-       return 0;
-
-out:
-       return result;
-}
-
-static int tcp_listen_for_all(void)
-{
-       /* We don't support multi-homed hosts */
-       if (dlm_local_count > 1) {
-               log_print("TCP protocol can't handle multi-homed hosts, "
-                         "try SCTP");
-               return -EINVAL;
-       }
-
-       log_print("Using TCP for communications");
-
-       return tcp_create_listen_sock(&listen_con, dlm_local_addr[0]);
-}
-
-
-
 static struct writequeue_entry *new_writequeue_entry(struct connection *con,
                                                     gfp_t allocation)
 {
@@ -1959,13 +1856,112 @@ void dlm_lowcomms_stop(void)
        dlm_proto_ops = NULL;
 }
 
+static int dlm_listen_for_all(void)
+{
+       struct socket *sock;
+       int result;
+
+       log_print("Using %s for communications",
+                 dlm_proto_ops->name);
+
+       if (dlm_proto_ops->listen_validate) {
+               result = dlm_proto_ops->listen_validate();
+               if (result < 0)
+                       return result;
+       }
+
+       result = sock_create_kern(&init_net, dlm_local_addr[0]->ss_family,
+                                 SOCK_STREAM, dlm_proto_ops->proto, &sock);
+       if (result < 0) {
+               log_print("Can't create comms socket, check SCTP is loaded");
+               goto out;
+       }
+
+       sock_set_mark(sock->sk, dlm_config.ci_mark);
+       dlm_proto_ops->listen_sockopts(sock);
+
+       result = dlm_proto_ops->listen_bind(sock);
+       if (result < 0)
+               goto out;
+
+       save_listen_callbacks(sock);
+       add_listen_sock(sock, &listen_con);
+
+       INIT_WORK(&listen_con.rwork, process_listen_recv_socket);
+       result = sock->ops->listen(sock, 5);
+       if (result < 0) {
+               dlm_close_sock(&listen_con.sock);
+               goto out;
+       }
+
+       return 0;
+
+out:
+       sock_release(sock);
+       return result;
+}
+
+static int dlm_tcp_listen_validate(void)
+{
+       /* We don't support multi-homed hosts */
+       if (dlm_local_count > 1) {
+               log_print("TCP protocol can't handle multi-homed hosts, try SCTP");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void dlm_tcp_sockopts(struct socket *sock)
+{
+       /* Turn off Nagle's algorithm */
+       tcp_sock_set_nodelay(sock->sk);
+}
+
+static void dlm_tcp_listen_sockopts(struct socket *sock)
+{
+       dlm_tcp_sockopts(sock);
+       sock_set_reuseaddr(sock->sk);
+}
+
+static int dlm_tcp_listen_bind(struct socket *sock)
+{
+       int addr_len;
+
+       /* Bind to our port */
+       make_sockaddr(dlm_local_addr[0], dlm_config.ci_tcp_port, &addr_len);
+       return sock->ops->bind(sock, (struct sockaddr *)dlm_local_addr[0],
+                              addr_len);
+}
+
 static const struct dlm_proto_ops dlm_tcp_ops = {
+       .name = "TCP",
+       .proto = IPPROTO_TCP,
+       .listen_validate = dlm_tcp_listen_validate,
+       .listen_sockopts = dlm_tcp_listen_sockopts,
+       .listen_bind = dlm_tcp_listen_bind,
        .connect_action = tcp_connect_to_sock,
        .shutdown_action = dlm_tcp_shutdown,
        .eof_condition = tcp_eof_condition,
 };
 
+static int dlm_sctp_bind_listen(struct socket *sock)
+{
+       return sctp_bind_addrs(sock, dlm_config.ci_tcp_port);
+}
+
+static void dlm_sctp_sockopts(struct socket *sock)
+{
+       /* Turn off Nagle's algorithm */
+       sctp_sock_set_nodelay(sock->sk);
+       sock_set_rcvbuf(sock->sk, NEEDED_RMEM);
+}
+
 static const struct dlm_proto_ops dlm_sctp_ops = {
+       .name = "SCTP",
+       .proto = IPPROTO_SCTP,
+       .listen_sockopts = dlm_sctp_sockopts,
+       .listen_bind = dlm_sctp_bind_listen,
        .connect_action = sctp_connect_to_sock,
 };
 
@@ -1996,24 +1992,26 @@ int dlm_lowcomms_start(void)
        switch (dlm_config.ci_protocol) {
        case DLM_PROTO_TCP:
                dlm_proto_ops = &dlm_tcp_ops;
-               error = tcp_listen_for_all();
                break;
        case DLM_PROTO_SCTP:
                dlm_proto_ops = &dlm_sctp_ops;
-               error = sctp_listen_for_all(&listen_con);
                break;
        default:
                log_print("Invalid protocol identifier %d set",
                          dlm_config.ci_protocol);
                error = -EINVAL;
-               break;
+               goto fail_proto_ops;
        }
+
+       error = dlm_listen_for_all();
        if (error)
-               goto fail_unlisten;
+               goto fail_listen;
 
        return 0;
 
-fail_unlisten:
+fail_listen:
+       dlm_proto_ops = NULL;
+fail_proto_ops:
        dlm_allow_conn = 0;
        dlm_close_sock(&listen_con.sock);
        work_stop();