Commit 93bc2e9e authored by Dominique Martinet's avatar Dominique Martinet Committed by Daniel Borkmann
Browse files

bpftool, musl compat: Replace nftw with FTW_ACTIONRETVAL

musl nftw implementation does not support FTW_ACTIONRETVAL. There have been
multiple attempts at pushing the feature in musl upstream, but it has been
refused or ignored all the times:

  https://www.openwall.com/lists/musl/2021/03/26/1
  https://www.openwall.com/lists/musl/2022/01/22/1



In this case we only care about /proc/<pid>/fd/<fd>, so it's not too difficult
to reimplement directly instead, and the new implementation makes 'bpftool perf'
slightly faster because it doesn't needlessly stat/readdir unneeded directories
(54ms -> 13ms on my machine).

Signed-off-by: default avatarDominique Martinet <asmadeus@codewreck.org>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
Acked-by: default avatarQuentin Monnet <quentin@isovalent.com>
Link: https://lore.kernel.org/bpf/20220424051022.2619648-4-asmadeus@codewreck.org
parent 003fed59
Loading
Loading
Loading
Loading
+57 −55
Original line number Diff line number Diff line
@@ -11,7 +11,7 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <ftw.h>
#include <dirent.h>

#include <bpf/bpf.h>

@@ -147,81 +147,83 @@ static void print_perf_plain(int pid, int fd, __u32 prog_id, __u32 fd_type,
	}
}

static int show_proc(const char *fpath, const struct stat *sb,
		     int tflag, struct FTW *ftwbuf)
static int show_proc(void)
{
	struct dirent *proc_de, *pid_fd_de;
	__u64 probe_offset, probe_addr;
	__u32 len, prog_id, fd_type;
	int err, pid = 0, fd = 0;
	DIR *proc, *pid_fd;
	int err, pid, fd;
	const char *pch;
	char buf[4096];

	/* prefix always /proc */
	pch = fpath + 5;
	if (*pch == '\0')
		return 0;
	proc = opendir("/proc");
	if (!proc)
		return -1;

	while ((proc_de = readdir(proc))) {
		pid = 0;
		pch = proc_de->d_name;

		/* pid should be all numbers */
	pch++;
		while (isdigit(*pch)) {
			pid = pid * 10 + *pch - '0';
			pch++;
		}
	if (*pch == '\0')
		return 0;
	if (*pch != '/')
		return FTW_SKIP_SUBTREE;
		if (*pch != '\0')
			continue;

	/* check /proc/<pid>/fd directory */
	pch++;
	if (strncmp(pch, "fd", 2))
		return FTW_SKIP_SUBTREE;
	pch += 2;
	if (*pch == '\0')
		return 0;
	if (*pch != '/')
		return FTW_SKIP_SUBTREE;
		err = snprintf(buf, sizeof(buf), "/proc/%s/fd", proc_de->d_name);
		if (err < 0 || err >= (int)sizeof(buf))
			continue;

	/* check /proc/<pid>/fd/<fd_num> */
	pch++;
		pid_fd = opendir(buf);
		if (!pid_fd)
			continue;

		while ((pid_fd_de = readdir(pid_fd))) {
			fd = 0;
			pch = pid_fd_de->d_name;

			/* fd should be all numbers */
			while (isdigit(*pch)) {
				fd = fd * 10 + *pch - '0';
				pch++;
			}
			if (*pch != '\0')
		return FTW_SKIP_SUBTREE;
				continue;

			/* query (pid, fd) for potential perf events */
			len = sizeof(buf);
	err = bpf_task_fd_query(pid, fd, 0, buf, &len, &prog_id, &fd_type,
			err = bpf_task_fd_query(pid, fd, 0, buf, &len,
						&prog_id, &fd_type,
						&probe_offset, &probe_addr);
			if (err < 0)
		return 0;
				continue;

			if (json_output)
		print_perf_json(pid, fd, prog_id, fd_type, buf, probe_offset,
				probe_addr);
				print_perf_json(pid, fd, prog_id, fd_type, buf,
						probe_offset, probe_addr);
			else
		print_perf_plain(pid, fd, prog_id, fd_type, buf, probe_offset,
				 probe_addr);

				print_perf_plain(pid, fd, prog_id, fd_type, buf,
						 probe_offset, probe_addr);
		}
		closedir(pid_fd);
	}
	closedir(proc);
	return 0;
}

static int do_show(int argc, char **argv)
{
	int flags = FTW_ACTIONRETVAL | FTW_PHYS;
	int err = 0, nopenfd = 16;
	int err;

	if (!has_perf_query_support())
		return -1;

	if (json_output)
		jsonw_start_array(json_wtr);
	if (nftw("/proc", show_proc, nopenfd, flags) == -1) {
		p_err("%s", strerror(errno));
		err = -1;
	}
	err = show_proc();
	if (json_output)
		jsonw_end_array(json_wtr);