Commit cc82b3dc authored by Yiyang Chen's avatar Yiyang Chen Committed by Andrew Morton
Browse files

tools/accounting: handle truncated taskstats netlink messages

procacct and getdelays use a fixed receive buffer for taskstats generic
netlink messages.  A multi-threaded process exit can emit a single
PID+TGID notification large enough to exceed that buffer on newer kernels.

Switch to recvmsg() so MSG_TRUNC is detected explicitly, increase the
message buffer size, and report truncated datagrams clearly instead of
misparsing them as fatal netlink errors.

Also print the taskstats version in debug output to make version
mismatches easier to diagnose while inspecting taskstats traffic.

Link: https://lkml.kernel.org/r/520308bb4cbbaf8dc2c7296b5f60f11e12fb30a5.1774810498.git.cyyzero16@gmail.com


Signed-off-by: default avatarYiyang Chen <cyyzero16@gmail.com>
Cc: Balbir Singh <bsingharora@gmail.com>
Cc: Dr. Thomas Orgis <thomas.orgis@uni-hamburg.de>
Cc: Fan Yu <fan.yu9@zte.com.cn>
Cc: Wang Yaxin <wang.yaxin@zte.com.cn>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 16c4f021
Loading
Loading
Loading
Loading
+37 −4
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ int print_task_context_switch_counts;
	}

/* Maximum size of response requested or message sent */
#define MAX_MSG_SIZE	1024
#define MAX_MSG_SIZE	2048
/* Maximum number of cpus expected to be specified in a cpumask */
#define MAX_CPUS	32

@@ -115,6 +115,32 @@ static int create_nl_socket(int protocol)
	return -1;
}

static int recv_taskstats_msg(int sd, struct msgtemplate *msg)
{
	struct sockaddr_nl nladdr;
	struct iovec iov = {
		.iov_base = msg,
		.iov_len = sizeof(*msg),
	};
	struct msghdr hdr = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	int ret;

	ret = recvmsg(sd, &hdr, 0);
	if (ret < 0)
		return -1;
	if (hdr.msg_flags & MSG_TRUNC) {
		errno = EMSGSIZE;
		return -1;
	}

	return ret;
}


static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
	     __u8 genl_cmd, __u16 nla_type,
@@ -633,10 +659,14 @@ int main(int argc, char *argv[])
	}

	do {
		rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
		rep_len = recv_taskstats_msg(nl_sd, &msg);
		PRINTF("received %d bytes\n", rep_len);

		if (rep_len < 0) {
			if (errno == EMSGSIZE)
				fprintf(stderr,
					"dropped truncated taskstats netlink message, please increase MAX_MSG_SIZE\n");
			else
				fprintf(stderr, "nonfatal reply error: errno %d\n",
					errno);
			continue;
@@ -680,6 +710,9 @@ int main(int argc, char *argv[])
							printf("TGID\t%d\n", rtid);
						break;
					case TASKSTATS_TYPE_STATS:
						PRINTF("version %u\n",
						       ((struct taskstats *)
							NLA_DATA(na))->version);
						if (print_delays)
							print_delayacct((struct taskstats *) NLA_DATA(na));
						if (print_io_accounting)
+36 −4
Original line number Diff line number Diff line
@@ -71,7 +71,7 @@ int print_task_context_switch_counts;
	}

/* Maximum size of response requested or message sent */
#define MAX_MSG_SIZE	1024
#define MAX_MSG_SIZE	2048
/* Maximum number of cpus expected to be specified in a cpumask */
#define MAX_CPUS	32

@@ -121,6 +121,32 @@ static int create_nl_socket(int protocol)
	return -1;
}

static int recv_taskstats_msg(int sd, struct msgtemplate *msg)
{
	struct sockaddr_nl nladdr;
	struct iovec iov = {
		.iov_base = msg,
		.iov_len = sizeof(*msg),
	};
	struct msghdr hdr = {
		.msg_name = &nladdr,
		.msg_namelen = sizeof(nladdr),
		.msg_iov = &iov,
		.msg_iovlen = 1,
	};
	int ret;

	ret = recvmsg(sd, &hdr, 0);
	if (ret < 0)
		return -1;
	if (hdr.msg_flags & MSG_TRUNC) {
		errno = EMSGSIZE;
		return -1;
	}

	return ret;
}


static int send_cmd(int sd, __u16 nlmsg_type, __u32 nlmsg_pid,
	     __u8 genl_cmd, __u16 nla_type,
@@ -239,6 +265,8 @@ void handle_aggr(int mother, struct nlattr *na, int fd)
			PRINTF("TGID\t%d\n", rtid);
			break;
		case TASKSTATS_TYPE_STATS:
			PRINTF("version %u\n",
			       ((struct taskstats *)NLA_DATA(na))->version);
			if (mother == TASKSTATS_TYPE_AGGR_PID)
				print_procacct((struct taskstats *) NLA_DATA(na));
			if (fd) {
@@ -347,10 +375,14 @@ int main(int argc, char *argv[])
	}

	do {
		rep_len = recv(nl_sd, &msg, sizeof(msg), 0);
		rep_len = recv_taskstats_msg(nl_sd, &msg);
		PRINTF("received %d bytes\n", rep_len);

		if (rep_len < 0) {
			if (errno == EMSGSIZE)
				fprintf(stderr,
					"dropped truncated taskstats netlink message, please increase MAX_MSG_SIZE\n");
			else
				fprintf(stderr, "nonfatal reply error: errno %d\n",
					errno);
			continue;