[lvm-devel] master - lvmlockd: fix sending debug info to lvmlockctl

David Teigland teigland at fedoraproject.org
Thu Aug 20 19:07:55 UTC 2015


Gitweb:        http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=1fae121b222927584a7a88cd3f4f1ba2aadb4931
Commit:        1fae121b222927584a7a88cd3f4f1ba2aadb4931
Parent:        180f92d3dc9891d4536a69de25dcb285979cd9e4
Author:        David Teigland <teigland at redhat.com>
AuthorDate:    Thu Aug 20 14:00:12 2015 -0500
Committer:     David Teigland <teigland at redhat.com>
CommitterDate: Thu Aug 20 14:07:11 2015 -0500

lvmlockd: fix sending debug info to lvmlockctl

Single messages sent over unix sockets are limited in
size to /proc/sys/net/core/wmem_max, so send the 1MB
debug buffer in smaller chunks to avoid EMSGSIZE.

Also look for EAGAIN and retry sending for a limited
time when the reader is slower than the writer.

Also shift the location of that code so it's the same
as other requests.
---
 daemons/lvmlockd/lvmlockctl.c    |    9 +++-
 daemons/lvmlockd/lvmlockd-core.c |  114 ++++++++++++++++++++++++++------------
 2 files changed, 86 insertions(+), 37 deletions(-)

diff --git a/daemons/lvmlockd/lvmlockctl.c b/daemons/lvmlockd/lvmlockctl.c
index e2ad9c5..14be4fc 100644
--- a/daemons/lvmlockd/lvmlockctl.c
+++ b/daemons/lvmlockd/lvmlockctl.c
@@ -379,6 +379,7 @@ static int setup_dump_socket(void)
 
 	rv = bind(s, (struct sockaddr *) &dump_addr, dump_addrlen);
 	if (rv < 0) {
+		rv = -errno;
 		if (!close(s))
 			log_error("failed to close dump socket");
 		return rv;
@@ -392,6 +393,7 @@ static int do_dump(const char *req_name)
 	daemon_reply reply;
 	int result;
 	int fd, rv = 0;
+	int count = 0;
 
 	fd = setup_dump_socket();
 	if (fd < 0) {
@@ -422,13 +424,18 @@ static int do_dump(const char *req_name)
 
 	memset(dump_buf, 0, sizeof(dump_buf));
 
-	rv = recvfrom(fd, dump_buf, dump_len, MSG_WAITALL,
+retry:
+	rv = recvfrom(fd, dump_buf + count, dump_len - count, MSG_WAITALL,
 		      (struct sockaddr *)&dump_addr, &dump_addrlen);
 	if (rv < 0) {
 		log_error("recvfrom error %d %d", rv, errno);
 		rv = -errno;
 		goto out;
 	}
+	count += rv;
+
+	if (count < dump_len)
+		goto retry;
 
 	rv = 0;
 	if ((info && dump) || !strcmp(req_name, "dump"))
diff --git a/daemons/lvmlockd/lvmlockd-core.c b/daemons/lvmlockd/lvmlockd-core.c
index 666f340..b99cb0b 100644
--- a/daemons/lvmlockd/lvmlockd-core.c
+++ b/daemons/lvmlockd/lvmlockd-core.c
@@ -265,6 +265,10 @@ static int alloc_new_structs; /* used for initializing in setup_structs */
 static int add_lock_action(struct action *act);
 static int str_to_lm(const char *str);
 static int clear_lockspace_inactive(char *name);
+static int setup_dump_socket(void);
+static void send_dump_buf(int fd, int dump_len);
+static int dump_info(int *dump_len);
+static int dump_log(int *dump_len);
 
 static int _syslog_name_to_num(const char *name)
 {
@@ -739,6 +743,10 @@ static const char *op_str(int x)
 		return "kill_vg";
 	case LD_OP_DROP_VG:
 		return "drop_vg";
+	case LD_OP_DUMP_LOG:
+		return "dump_log";
+	case LD_OP_DUMP_INFO:
+		return "dump_info";
 	default:
 		return "op_unknown";
 	};
@@ -3414,6 +3422,8 @@ static void client_send_result(struct client *cl, struct action *act)
 {
 	response res;
 	char result_flags[128];
+	int dump_len = 0;
+	int dump_fd = -1;
 
 	if (cl->dead) {
 		log_debug("client send %d skip dead", cl->id);
@@ -3498,6 +3508,33 @@ static void client_send_result(struct client *cl, struct action *act)
 					  "lv_lock_args = %s", lv_args,
 					  "result_flags = %s", result_flags[0] ? result_flags : "none",
 					  NULL);
+
+	} else if (act->op == LD_OP_DUMP_LOG || act->op == LD_OP_DUMP_INFO) {
+		/*
+		 * lvmlockctl creates the unix socket then asks us to write to it.
+		 * FIXME: move processing this to a new dedicated query thread to
+		 * avoid having a large data dump interfere with normal operation
+		 * of the client thread?
+		 */
+
+		dump_fd = setup_dump_socket();
+		if (dump_fd < 0)
+			act->result = dump_fd;
+		else if (act->op == LD_OP_DUMP_LOG)
+			act->result = dump_log(&dump_len);
+		else if (act->op == LD_OP_DUMP_INFO)
+			act->result = dump_info(&dump_len);
+		else
+			act->result = -EINVAL;
+
+		log_debug("send %s[%d.%u] dump result %d dump_len %d",
+			  cl->name[0] ? cl->name : "client", cl->pid, cl->id,
+			  act->result, dump_len);
+
+		res = daemon_reply_simple("OK",
+					  "result = %d", act->result,
+					  "dump_len = %d", dump_len,
+					  NULL);
 	} else {
 		/*
 		 * A normal reply.
@@ -3521,6 +3558,12 @@ static void client_send_result(struct client *cl, struct action *act)
 	buffer_destroy(&res.buffer);
 
 	client_resume(cl);
+
+	if (dump_fd >= 0) {
+		/* To avoid deadlock, send data here after the reply. */
+		send_dump_buf(dump_fd, dump_len);
+		close(dump_fd);
+	}
 }
 
 /* called from client_thread */
@@ -3894,23 +3937,43 @@ static int setup_dump_socket(void)
 	return s;
 }
 
-static int send_dump_buf(int fd, int dump_len)
+#define MAX_SEND_LEN 65536
+#define RESEND_DELAY_US 1000
+#define RESEND_DELAY_US_MAX 500000
+
+static void send_dump_buf(int fd, int dump_len)
 {
 	int pos = 0;
 	int ret;
+	int send_len;
+	int delay = 0;
 
-retry:
-	ret = sendto(fd, dump_buf + pos, dump_len - pos, MSG_DONTWAIT | MSG_NOSIGNAL,
+	if (!dump_len)
+		return;
+repeat:
+	if (dump_len - pos < MAX_SEND_LEN)
+		send_len = dump_len - pos;
+	else
+		send_len = MAX_SEND_LEN;
+
+	ret = sendto(fd, dump_buf + pos, send_len, MSG_NOSIGNAL | MSG_DONTWAIT,
 		     (struct sockaddr *)&dump_addr, dump_addrlen);
-	if (ret <= 0)
-		return ret;
+	if (ret < 0) {
+		if ((errno == EAGAIN || errno == EINTR) && (delay < RESEND_DELAY_US_MAX)) {
+			usleep(RESEND_DELAY_US);
+			delay += RESEND_DELAY_US;
+			goto repeat;
+		}
+		log_error("send_dump_buf delay %d errno %d", delay, errno);
+		return;
+	}
 
 	pos += ret;
 
 	if (pos < dump_len)
-		goto retry;
+		goto repeat;
 
-	return 0;
+	log_debug("send_dump_buf delay %d total %d", delay, pos);
 }
 
 static int print_structs(const char *prefix, int pos, int len)
@@ -4193,8 +4256,7 @@ static void client_recv_action(struct client *cl)
 		return;
 	}
 
-	if (op == LD_OP_HELLO || op == LD_OP_QUIT ||
-	    op == LD_OP_DUMP_INFO || op == LD_OP_DUMP_LOG) {
+	if (op == LD_OP_HELLO || op == LD_OP_QUIT) {
 
 		/*
 		 * FIXME: add the client command name to the hello messages
@@ -4215,37 +4277,11 @@ static void client_recv_action(struct client *cl)
 
 		buffer_init(&res.buffer);
 
-		if (op == LD_OP_DUMP_INFO || op == LD_OP_DUMP_LOG) {
-			int dump_len = 0;
-			int fd;
-
-			fd = setup_dump_socket();
-			if (fd < 0)
-				result = fd;
-			else if (op == LD_OP_DUMP_INFO)
-				result = dump_info(&dump_len);
-			else if (op == LD_OP_DUMP_LOG)
-				result = dump_log(&dump_len);
-			else
-				result = -EINVAL;
-
-			res = daemon_reply_simple("OK",
-					  "result = %d", result,
-					  "dump_len = %d", dump_len,
-					  NULL);
-			if (fd >= 0) {
-				send_dump_buf(fd, dump_len);
-				close(fd);
-			}
-
-		} else {
-			res = daemon_reply_simple("OK",
+		res = daemon_reply_simple("OK",
 					  "result = %d", result,
 					  "protocol = %s", lvmlockd_protocol,
 					  "version = %d", lvmlockd_protocol_version,
 					  NULL);
-		}
-
 		buffer_write(cl->fd, &res.buffer);
 		buffer_destroy(&res.buffer);
 		dm_config_destroy(req.cft);
@@ -4362,6 +4398,12 @@ static void client_recv_action(struct client *cl)
 	case LD_OP_STOP:
 		rv = rem_lockspace(act);
 		break;
+	case LD_OP_DUMP_LOG:
+	case LD_OP_DUMP_INFO:
+		/* The client thread reply will copy and send the dump. */
+		add_client_result(act);
+		rv = 0;
+		break;
 	case LD_OP_INIT:
 	case LD_OP_START_WAIT:
 	case LD_OP_STOP_ALL:




More information about the lvm-devel mailing list