From e04ef376c3ee89b52a5befa82f1fe768cfd08cf1 Mon Sep 17 00:00:00 2001
From: Luis Gerhorst <privat@luisgerhorst.de>
Date: Sat, 10 Jul 2021 11:08:13 +0200
Subject: [PATCH] task_find: Optimize, avoid open on regular files

Using perf record it was determined that most time in both find
task_find.bpf.c is spent in openat, therefore this has to be avoided.
---
 src/task_find.bpf.c | 30 +++++++++++++++++-------------
 src/task_lib.bpf.h  | 11 +++++++++++
 2 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/src/task_find.bpf.c b/src/task_find.bpf.c
index 13352a1..cbac40d 100644
--- a/src/task_find.bpf.c
+++ b/src/task_find.bpf.c
@@ -28,7 +28,7 @@ void *u_newline;
 void *u_iterdents64_buf;
 size_t root_namelen;
 
-static long iter_dir(size_t namelen, bool print) {
+static long iter_dir(uint32_t d_type, size_t namelen, bool print) {
 	long err = 0;
 
 	if (namelen + 1 > PATHLEN) {
@@ -37,12 +37,6 @@ static long iter_dir(size_t namelen, bool print) {
 		goto end;
 	}
 
-	int *prog_fd = bpf_map_lookup_elem(&state_map, &PDPF_KEY);
-	if (!prog_fd) {
-		bpf_printk("Error: !bpf_map_lookup_elem(&state_map, &PDPF_KEY)");
-		goto end;
-	}
-
 	int *curr_depth_p = bpf_map_lookup_elem(&state_map, &CURR_DEPTH_KEY);
 	if (!curr_depth_p) {
 		bpf_printk("Error: bpf_map_lookup_elem(&state_map, &CURR_DEPTH_KEY)");
@@ -56,6 +50,13 @@ static long iter_dir(size_t namelen, bool print) {
 	}
 
 	void *name_user = u_iterdents64_buf + depth * PATHLEN;
+	if (d_type != DT_DIR) {
+		if (print) {
+			write(STDOUT_FILENO, name_user, namelen);
+			write(STDOUT_FILENO, u_newline, 1);
+		}
+		goto end;
+	}
 
 	int *parent_dfd = bpf_map_lookup_elem(&dfd_map, &depth);
 	if (!parent_dfd) {
@@ -65,10 +66,7 @@ static long iter_dir(size_t namelen, bool print) {
 
 	int dfd = openat(*parent_dfd, name_user, O_RDONLY | O_DIRECTORY, 0777);
 	if (dfd < 0) {
-		if (print) {
-			write(STDOUT_FILENO, name_user, namelen);
-			write(STDOUT_FILENO, u_newline, 1);
-		}
+		bpf_printk("Warning: openat failed, is someone modifying the tree?");
 		/* Not a directory, no need to iterate. */
 		goto end;
 	}
@@ -90,6 +88,12 @@ static long iter_dir(size_t namelen, bool print) {
 		goto reset_depth;
 	}
 
+	int *prog_fd = bpf_map_lookup_elem(&state_map, &PDPF_KEY);
+	if (!prog_fd) {
+		bpf_printk("Error: !bpf_map_lookup_elem(&state_map, &PDPF_KEY)");
+		goto end;
+	}
+
 	err = bpf_task_iterdents64(dfd, *prog_fd, child_name_user, PATHLEN);
 	if (err) {
 		bpf_printk("Error: iterdents64(%d, %d) = %d", dfd, *prog_fd, err);
@@ -116,7 +120,7 @@ int entry(void *ctx)
 {
 	long err = 0;
 
-	err = iter_dir(root_namelen, false);
+	err = iter_dir(DT_DIR, root_namelen, false);
 	if (err) {
 		goto end;
 	}
@@ -143,7 +147,7 @@ int process_dirent(struct bpf_dirent64 *d) {
 		}
 	}
 
-	err = iter_dir(d->namelen, match);
+	err = iter_dir(d->d_type, d->namelen, match);
 	if (err) {
 		goto end;
 	}
diff --git a/src/task_lib.bpf.h b/src/task_lib.bpf.h
index 84c7af2..7545e82 100644
--- a/src/task_lib.bpf.h
+++ b/src/task_lib.bpf.h
@@ -65,6 +65,17 @@ typedef off64_t off_t;
 #define SEEK_DATA	3	/* Seek to next data.  */
 #define SEEK_HOLE	4	/* Seek to next hole.  */
 
+/* these are defined by POSIX and also present in glibc's dirent.h */
+#define DT_UNKNOWN	0
+#define DT_FIFO		1
+#define DT_CHR		2
+#define DT_DIR		4
+#define DT_BLK		6
+#define DT_REG		8
+#define DT_LNK		10
+#define DT_SOCK		12
+#define DT_WHT		14
+
 /* Copied from man getdents64(2). */
 struct linux_dirent64 {
 	ino64_t        d_ino;    /* 64-bit inode number */
-- 
GitLab