bcc/libbpf-tools: Use fentry for vfsstat

Use fentry like vfsstat.py when it is available.

Signed-off-by: Kenta Tada <Kenta.Tada@sony.com>
diff --git a/libbpf-tools/trace_helpers.c b/libbpf-tools/trace_helpers.c
index 9ea0bb8..04a7a0b 100644
--- a/libbpf-tools/trace_helpers.c
+++ b/libbpf-tools/trace_helpers.c
@@ -1099,3 +1099,22 @@
 	fclose(f);
 	return false;
 }
+
+bool vmlinux_btf_exists(void)
+{
+	if (!access("/sys/kernel/btf/vmlinux", R_OK))
+		return true;
+	return false;
+}
+
+bool module_btf_exists(const char *mod)
+{
+	char sysfs_mod[80];
+
+	if (mod) {
+		snprintf(sysfs_mod, sizeof(sysfs_mod), "/sys/kernel/btf/%s", mod);
+		if (!access(sysfs_mod, R_OK))
+			return true;
+	}
+	return false;
+}
diff --git a/libbpf-tools/trace_helpers.h b/libbpf-tools/trace_helpers.h
index 90d07fe..019380a 100644
--- a/libbpf-tools/trace_helpers.h
+++ b/libbpf-tools/trace_helpers.h
@@ -92,4 +92,7 @@
  */
 bool kprobe_exists(const char *name);
 
+bool vmlinux_btf_exists(void);
+bool module_btf_exists(const char *mod);
+
 #endif /* __TRACE_HELPERS_H */
diff --git a/libbpf-tools/vfsstat.bpf.c b/libbpf-tools/vfsstat.bpf.c
index c9a710a..268f7d1 100644
--- a/libbpf-tools/vfsstat.bpf.c
+++ b/libbpf-tools/vfsstat.bpf.c
@@ -16,31 +16,61 @@
 }
 
 SEC("kprobe/vfs_read")
-int BPF_KPROBE(vfs_read)
+int BPF_KPROBE(kprobe_vfs_read)
 {
 	return inc_stats(S_READ);
 }
 
 SEC("kprobe/vfs_write")
-int BPF_KPROBE(vfs_write)
+int BPF_KPROBE(kprobe_vfs_write)
 {
 	return inc_stats(S_WRITE);
 }
 
 SEC("kprobe/vfs_fsync")
-int BPF_KPROBE(vfs_fsync)
+int BPF_KPROBE(kprobe_vfs_fsync)
 {
 	return inc_stats(S_FSYNC);
 }
 
 SEC("kprobe/vfs_open")
-int BPF_KPROBE(vfs_open)
+int BPF_KPROBE(kprobe_vfs_open)
 {
 	return inc_stats(S_OPEN);
 }
 
 SEC("kprobe/vfs_create")
-int BPF_KPROBE(vfs_create)
+int BPF_KPROBE(kprobe_vfs_create)
+{
+	return inc_stats(S_CREATE);
+}
+
+SEC("fentry/vfs_read")
+int BPF_PROG(fentry_vfs_read)
+{
+	return inc_stats(S_READ);
+}
+
+SEC("fentry/vfs_write")
+int BPF_PROG(fentry_vfs_write)
+{
+	return inc_stats(S_WRITE);
+}
+
+SEC("fentry/vfs_fsync")
+int BPF_PROG(fentry_vfs_fsync)
+{
+	return inc_stats(S_FSYNC);
+}
+
+SEC("fentry/vfs_open")
+int BPF_PROG(fentry_vfs_open)
+{
+	return inc_stats(S_OPEN);
+}
+
+SEC("fentry/vfs_create")
+int BPF_PROG(fentry_vfs_create)
 {
 	return inc_stats(S_CREATE);
 }
diff --git a/libbpf-tools/vfsstat.c b/libbpf-tools/vfsstat.c
index 0969af0..ec9f5ab 100644
--- a/libbpf-tools/vfsstat.c
+++ b/libbpf-tools/vfsstat.c
@@ -140,7 +140,7 @@
 		.doc = argp_program_doc,
 		.args_doc = args_doc,
 	};
-	struct vfsstat_bpf *obj;
+	struct vfsstat_bpf *skel;
 	int err;
 
 	err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
@@ -156,13 +156,34 @@
 		return 1;
 	}
 
-	obj = vfsstat_bpf__open_and_load();
-	if (!obj) {
-		fprintf(stderr, "failed to open and/or load BPF object\n");
+	skel = vfsstat_bpf__open();
+	if (!skel) {
+		fprintf(stderr, "failed to open BPF skelect\n");
 		return 1;
 	}
 
-	err = vfsstat_bpf__attach(obj);
+	/* It fallbacks to kprobes when kernel does not support fentry. */
+	if (vmlinux_btf_exists() && fentry_exists("vfs_read", NULL)) {
+		bpf_program__set_autoload(skel->progs.kprobe_vfs_read, false);
+		bpf_program__set_autoload(skel->progs.kprobe_vfs_write, false);
+		bpf_program__set_autoload(skel->progs.kprobe_vfs_fsync, false);
+		bpf_program__set_autoload(skel->progs.kprobe_vfs_open, false);
+		bpf_program__set_autoload(skel->progs.kprobe_vfs_create, false);
+	} else {
+		bpf_program__set_autoload(skel->progs.fentry_vfs_read, false);
+		bpf_program__set_autoload(skel->progs.fentry_vfs_write, false);
+		bpf_program__set_autoload(skel->progs.fentry_vfs_fsync, false);
+		bpf_program__set_autoload(skel->progs.fentry_vfs_open, false);
+		bpf_program__set_autoload(skel->progs.fentry_vfs_create, false);
+	}
+
+	err = vfsstat_bpf__load(skel);
+	if (err) {
+		fprintf(stderr, "failed to load BPF skelect: %d\n", err);
+		goto cleanup;
+	}
+
+	err = vfsstat_bpf__attach(skel);
 	if (err) {
 		fprintf(stderr, "failed to attach BPF programs: %s\n",
 				strerror(-err));
@@ -172,11 +193,11 @@
 	print_header();
 	do {
 		sleep(env.interval);
-		print_and_reset_stats(obj->bss->stats);
+		print_and_reset_stats(skel->bss->stats);
 	} while (!env.count || --env.count);
 
 cleanup:
-	vfsstat_bpf__destroy(obj);
+	vfsstat_bpf__destroy(skel);
 
 	return err != 0;
 }