1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-02-25 21:57:45 +03:00

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.
This commit is contained in:
David Teigland 2015-08-20 14:00:12 -05:00
parent 180f92d3dc
commit 1fae121b22
2 changed files with 86 additions and 37 deletions

View File

@ -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"))

View File

@ -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: