diff --git a/libbpf b/libbpf index c91f1175e2273825767160fdc54448c19c97ba13..b940fc498656a2d9f295fab0a9dbf530267bdcd6 160000 --- a/libbpf +++ b/libbpf @@ -1 +1 @@ -Subproject commit c91f1175e2273825767160fdc54448c19c97ba13 +Subproject commit b940fc498656a2d9f295fab0a9dbf530267bdcd6 diff --git a/src/Makefile b/src/Makefile index f46ca8a47e8f818e644029a340f21ba5c951250e..a873021953c09fc40ffc4172975ccfb01754370c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -9,7 +9,7 @@ INCLUDES := -I$(OUTPUT) -idirafter $(abspath ../libbpf/include) CFLAGS := -g -Wall ARCH := $(shell uname -m | sed 's/x86_64/x86/') -APPS = minimal bootstrap uprobe task_mmap task_bulk_minimal task_find task_filter_magic # task_ag task_sleep task task_bulk +APPS = minimal bootstrap uprobe task_mmap task_bulk task_bulk_minimal task_find task_filter_magic # task_ag task_sleep task # Get Clang's default includes on this system. We'll explicitly add these dirs # to the includes list when compiling with `-target bpf` because otherwise some diff --git a/src/task_find.bpf.c b/src/task_find.bpf.c index c9b6a01bf2721e88b2e0ab0698ba0dc8a8fc19af..cb36f8338ad4e35be7c017c46ec9357cd7f86ab9 100644 --- a/src/task_find.bpf.c +++ b/src/task_find.bpf.c @@ -12,12 +12,12 @@ struct { __uint(type, BPF_MAP_TYPE_ARRAY); __uint(max_entries, NR_STATE_MAP_KEYS); __type(key, int); - __type(value, int); + __type(value, unsigned long); } state_map SEC(".maps"); struct { __uint(type, BPF_MAP_TYPE_ARRAY); - __uint(max_entries, MAX_DEPTH); + __uint(max_entries, MAX_DEPTH * 2); __type(key, int); __type(value, int); } dfd_map SEC(".maps"); @@ -27,10 +27,11 @@ void *u_ascend; void *u_newline; void *u_iterdents64_buf; size_t root_namelen; - +void *u_statbuf; int type; +int flags; -static long iter_dir(uint32_t d_type, size_t namelen, bool print) { +static long iter_dir(uint32_t d_type, size_t namelen, bool match) { long err = 0; if (namelen + 1 > PATHLEN) { @@ -39,43 +40,72 @@ static long iter_dir(uint32_t d_type, size_t namelen, bool print) { goto end; } - int *curr_depth_p = bpf_map_lookup_elem(&state_map, &CURR_DEPTH_KEY); + unsigned long *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)"); goto end; } - int depth = *curr_depth_p; + unsigned long depth = *curr_depth_p; if (depth >= MAX_DEPTH) { bpf_printk("Error: max_depth exceeded"); err = -1; goto end; } - - void *name_user = u_iterdents64_buf + depth * PATHLEN; - if (print) { - write(STDOUT_FILENO, name_user, namelen); - write(STDOUT_FILENO, u_newline, 1); - } - if (d_type != DT_DIR) { - goto end; - } - int *parent_dfd = bpf_map_lookup_elem(&dfd_map, &depth); if (!parent_dfd) { bpf_printk("Error: bpf_map_lookup_elem(&dfd_map, depth)"); goto end; } + void *name_user = u_iterdents64_buf + depth * PATHLEN; + if (match) { + if (flags & PRINT_MATCHES) { + write(STDOUT_FILENO, name_user, namelen); + write(STDOUT_FILENO, u_newline, 1); + } + if (flags & SUMMARIZE_DISK_USAGE) { + err = bpf_task_sys_newfstatat_4(*parent_dfd, (uint64_t) name_user, + (uint64_t) u_statbuf, AT_SYMLINK_NOFOLLOW); + if (err) { + bpf_printk("Error"); + goto end; + } + struct stat statbuf; + err = bpf_probe_read_user(&statbuf, sizeof(statbuf), u_statbuf); + if (err) { + bpf_printk("Error"); + goto end; + } + unsigned long *disk_usage_p = bpf_map_lookup_elem(&state_map, &DISK_USAGE_KEY); + if (!disk_usage_p) { + bpf_printk("Error: bpf_map_lookup_elem(&state_map, &DISK_USAGE_KEY)"); + goto end; + } + unsigned long n = *disk_usage_p; + n += statbuf.st_size; + err = bpf_map_update_elem(&state_map, &DISK_USAGE_KEY, &n, BPF_ANY); + if (err) { + bpf_printk("Error"); + goto end; + } + } + } + + if (d_type != DT_DIR) { + goto end; + } int dfd = openat(*parent_dfd, name_user, O_RDONLY | O_DIRECTORY, 0777); if (dfd < 0) { bpf_printk("Warning: openat failed, is someone modifying the tree?"); /* Not a directory, no need to iterate. */ goto end; } - write(STDOUT_FILENO, name_user, namelen); - write(STDOUT_FILENO, u_descend, 2); + if (flags & PRINT_MATCHES) { + write(STDOUT_FILENO, name_user, namelen); + write(STDOUT_FILENO, u_descend, 2); + } - int child_depth = depth + 1; + unsigned long child_depth = depth + 1; void *child_name_user = u_iterdents64_buf + child_depth * PATHLEN; err = bpf_map_update_elem(&state_map, &CURR_DEPTH_KEY, &child_depth, BPF_ANY); @@ -93,7 +123,7 @@ static long iter_dir(uint32_t d_type, size_t namelen, bool print) { 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; + goto reset_depth; } err = bpf_task_iterdents64(dfd, *prog_fd, child_name_user, PATHLEN); @@ -108,7 +138,9 @@ reset_depth: bpf_printk("bpf_map_update_elem(&state_map, &CURR_DEPTH_KEY, depth, BPF_ANY) = %d", err); } close: - write(STDOUT_FILENO, u_ascend, 3); + if (flags & PRINT_MATCHES) { + write(STDOUT_FILENO, u_ascend, 3); + } err = bpf_task_sys_close_1(dfd); if (err) { bpf_printk("close(%d) = %d", dfd, err); @@ -122,7 +154,7 @@ int entry(void *ctx) { long err = 0; - err = iter_dir(DT_DIR, root_namelen, false); + err = iter_dir(DT_DIR, root_namelen, true); if (err) { goto end; } @@ -147,7 +179,7 @@ int process_dirent(struct bpf_dirent64 *d) { } } - err = iter_dir(d->d_type, d->namelen, type != -1 && d->d_type == type); + err = iter_dir(d->d_type, d->namelen, type == -1 || d->d_type == type); if (err) { goto end; } diff --git a/src/task_find.c b/src/task_find.c index c553a87b74f76f1542f6e184d53bd6439babd546..31a3efcc2a1199ad6b89b3f75f110e348ecc52fe 100644 --- a/src/task_find.c +++ b/src/task_find.c @@ -28,6 +28,7 @@ #include <inttypes.h> #include <sys/resource.h> +#include <bpf/bpf.h> #include <bpf/libbpf.h> #include "task_find.skel.h" #include "task_find.h" @@ -157,7 +158,7 @@ static void print_usage(char **argv) { fprintf(stderr, "Usage: %s [-D --debug] [-v --variant bpf] PATH -name LITERAL\n", argv[0]); } -static int bpf_find(const char *path, const char *name, bool debug, int type) { +static int bpf_find(const char *path, const char *name, bool debug, int type, int flags) { struct NAME_BPF *skel; int err = 0, ret = EXIT_SUCCESS; @@ -184,6 +185,10 @@ static int bpf_find(const char *path, const char *name, bool debug, int type) { skel->bss->root_namelen = strlen(path); skel->bss->type = type; + skel->bss->flags = flags; + + struct stat statbuf; + skel->bss->u_statbuf = &statbuf; /* Load & verify BPF programs */ err = BPF_LOAD(skel); @@ -193,17 +198,25 @@ static int bpf_find(const char *path, const char *name, bool debug, int type) { goto destroy; } - /* BPF_NOEXIST means: add new element if it doesn't exist */ int value = bpf_program__fd(skel->progs.process_dirent); err = bpf_map_update_elem(bpf_map__fd(skel->maps.state_map), &PDPF_KEY, &value, BPF_ANY); if (err == -1) { perror("bpf_map_update_elem(bpf_map__fd(skel->maps.state_map), &PDPF_KEY, &value, BPF_NOEXIST)"); + ret = EXIT_FAILURE; goto destroy; } int root_key = 0, root_value = AT_FDCWD; err = bpf_map_update_elem(bpf_map__fd(skel->maps.dfd_map), &root_key, &root_value, BPF_ANY); if (err == -1) { + ret = EXIT_FAILURE; + goto destroy; + } + + unsigned long zero = 0; + err = bpf_map_update_elem(bpf_map__fd(skel->maps.state_map), &DISK_USAGE_KEY, &zero, BPF_ANY); + if (err == -1) { + ret = EXIT_FAILURE; goto destroy; } @@ -215,6 +228,14 @@ static int bpf_find(const char *path, const char *name, bool debug, int type) { goto destroy; } + unsigned long total_disk_usage; + err = bpf_map_lookup_elem(bpf_map__fd(skel->maps.state_map), &DISK_USAGE_KEY, &total_disk_usage); + if (err) { + ret = EXIT_FAILURE; + goto destroy; + } + printf("%lu %s\n", total_disk_usage, path); + destroy: BPF_DESTROY(skel); return ret; @@ -234,15 +255,9 @@ struct linux_dirent64 { /* Same as in GNU find. */ #define BUF_SIZE (32*1024) -enum action { - SUMMARIZE_DISK_USAGE = 1, - PRINT_LIBC = 1 << 1, - PRINT_MATCHES = 1 << 2, -}; - static int do_user_find(unsigned char d_type, int parent_dfd, const char *name, const char *search_name, int search_type, bool debug, - int flags, size_t *disk_usage_total) { + int flags, unsigned long *disk_usage_total) { int err = 0; size_t namelen = strlen(name); @@ -250,8 +265,8 @@ static int do_user_find(unsigned char d_type, int parent_dfd, const char *name, return 0; } - bool match = (search_type != -1 && d_type == search_type) - || (search_name != NULL && strcmp(search_name, name) == 0); + bool match = (search_type == -1 || d_type == search_type) + && (search_name == NULL || strcmp(search_name, name) == 0); if (match) { if (flags & PRINT_MATCHES) { if (flags & PRINT_LIBC) { @@ -262,10 +277,9 @@ static int do_user_find(unsigned char d_type, int parent_dfd, const char *name, } } - if (d_type == DT_REG && - flags & SUMMARIZE_DISK_USAGE) { + if (flags & SUMMARIZE_DISK_USAGE) { struct stat statbuf; - err = fstatat(parent_dfd, name, &statbuf, 0); + err = fstatat(parent_dfd, name, &statbuf, AT_SYMLINK_NOFOLLOW); if (err) { perror("fstatat"); exit(EXIT_FAILURE); @@ -329,11 +343,11 @@ close: static int user_find(const char *path, const char *search_name, bool debug, int search_type, int flags) { - size_t disk_usage_total = 0; + unsigned long disk_usage_total = 0; int err = do_user_find(DT_DIR, AT_FDCWD, path, search_name, search_type, debug, flags, &disk_usage_total); if (!err) { - printf("%zu %s\n", disk_usage_total, path); + printf("%lu %s\n", disk_usage_total, path); } return err; } @@ -431,7 +445,7 @@ int main(int argc, char **argv) int ret; if (variant_bpf) { - ret = bpf_find(path, name, debug, type); + ret = bpf_find(path, name, debug, type, flags); } else { ret = user_find(path, name, debug, type, flags); } diff --git a/src/task_find.h b/src/task_find.h index 5703074e6750709ffc8c6871bfd7a30187f2f5df..1d9bb534872a63fa427295d2a73d99a502e97bb6 100644 --- a/src/task_find.h +++ b/src/task_find.h @@ -1,7 +1,7 @@ #ifndef __TASK_H_ #define __TASK_H_ -#define MAX_DEPTH 32 +#define MAX_DEPTH 16 #define UBUF_SIZE 1024 #define PATHLEN 512 @@ -14,6 +14,13 @@ struct __packed __attribute__((__aligned__(4096))) bpfmem { * bpf_map_*() helpers. */ static int PDPF_KEY = 0; static int CURR_DEPTH_KEY = 1; -#define NR_STATE_MAP_KEYS 2 +static int DISK_USAGE_KEY = 2; +#define NR_STATE_MAP_KEYS 3 + +enum action { + SUMMARIZE_DISK_USAGE = 1, + PRINT_LIBC = 1 << 1, + PRINT_MATCHES = 1 << 2, +}; #endif // __TASK_H_ diff --git a/src/task_lib.bpf.h b/src/task_lib.bpf.h index 7545e82bdc9e49af6d083725fbd7d394720dd5e3..ad1d13657c96c783aeb244db9a6690cc83c624aa 100644 --- a/src/task_lib.bpf.h +++ b/src/task_lib.bpf.h @@ -25,7 +25,6 @@ typedef uintptr_t size_t; typedef intptr_t ssize_t; typedef __u64 ino64_t; typedef __u64 off64_t; -typedef off64_t off_t; #define STDIN_FILENO 0 #define STDOUT_FILENO 1 @@ -94,16 +93,18 @@ struct timespec { long tv_nsec; /* nanoseconds */ }; -/* fstat(2) */ -/* TODO: fix */ -typedef int dev_t; -typedef int ino_t; -typedef int mode_t; -typedef int nlink_t; -typedef int uid_t; -typedef int gid_t; -typedef int blksize_t; -typedef int blkcnt_t; +/* for stat(), via linux/tools/include/nolibc/nolibc.h */ +typedef unsigned int dev_t; +typedef unsigned long ino_t; +typedef unsigned int mode_t; +typedef signed int pid_t; +typedef unsigned int uid_t; +typedef unsigned int gid_t; +typedef unsigned long nlink_t; +typedef signed long off_t; +typedef signed long blksize_t; +typedef signed long blkcnt_t; +typedef signed long time_t; struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* Inode number */