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

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
Loading
Loading
Loading
Loading
+113 −115
Original line number Diff line number Diff line
@@ -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();