Commit 2dc6b115 authored by Alexander Aring's avatar Alexander Aring Committed by David Teigland

fs: dlm: introduce generic listen

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: default avatarAlexander Aring <aahringo@redhat.com>
Signed-off-by: default avatarDavid Teigland <teigland@redhat.com>
parent a66c008c
......@@ -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 @@ static void tcp_connect_to_sock(struct connection *con)
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();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment