@@ -8658,6 +8658,7 @@ S: Maintained
F: fs/notify/fanotify/
F: include/linux/fanotify.h
F: include/uapi/linux/fanotify.h
+F: samples/fanotify/
FARADAY FOTG210 USB2 DUAL-ROLE CONTROLLER
M: Linus Walleij <linus.walleij@linaro.org>
@@ -149,15 +149,33 @@ config SAMPLE_CONNECTOR
with it.
See also Documentation/driver-api/connector.rst
+config SAMPLE_FANOTIFY
+ bool "Build fanotify monitoring sample"
+ depends on FANOTIFY && CC_CAN_LINK && HEADERS_INSTALL
+ help
+ When enabled, this builds samples for fanotify.
+ There multiple samples for fanotify. Please see the
+ following configs for more details of these
+ samples.
+
config SAMPLE_FANOTIFY_ERROR
bool "Build fanotify error monitoring sample"
- depends on FANOTIFY && CC_CAN_LINK && HEADERS_INSTALL
+ depends on SAMPLE_FANOTIFY
help
When enabled, this builds an example code that uses the
FAN_FS_ERROR fanotify mechanism to monitor filesystem
errors.
See also Documentation/admin-guide/filesystem-monitoring.rst.
+config SAMPLE_FANOTIFY_FASTPATH
+ tristate "Build fanotify fastpath sample"
+ depends on SAMPLE_FANOTIFY && m
+ help
+ When enabled, this builds kernel module that contains a
+ fanotify fastpath handler.
+ The fastpath handler filters out certain filename
+ prefixes for the fanotify user.
+
config SAMPLE_HIDRAW
bool "hidraw sample"
depends on CC_CAN_LINK && HEADERS_INSTALL
@@ -6,7 +6,7 @@ subdir-$(CONFIG_SAMPLE_ANDROID_BINDERFS) += binderfs
subdir-$(CONFIG_SAMPLE_CGROUP) += cgroup
obj-$(CONFIG_SAMPLE_CONFIGFS) += configfs/
obj-$(CONFIG_SAMPLE_CONNECTOR) += connector/
-obj-$(CONFIG_SAMPLE_FANOTIFY_ERROR) += fanotify/
+obj-$(CONFIG_SAMPLE_FANOTIFY) += fanotify/
subdir-$(CONFIG_SAMPLE_HIDRAW) += hidraw
obj-$(CONFIG_SAMPLE_HW_BREAKPOINT) += hw_breakpoint/
obj-$(CONFIG_SAMPLE_KDB) += kdb/
@@ -1 +1,2 @@
fs-monitor
+fastpath-user
@@ -1,5 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
-userprogs-always-y += fs-monitor
+userprogs-always-$(CONFIG_SAMPLE_FANOTIFY_ERROR) += fs-monitor
userccflags += -I usr/include -Wall
+obj-$(CONFIG_SAMPLE_FANOTIFY_FASTPATH) += fastpath-mod.o
+
+userprogs-always-$(CONFIG_SAMPLE_FANOTIFY_FASTPATH) += fastpath-user
new file mode 100644
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/fsnotify.h>
+#include <linux/fanotify.h>
+#include <linux/module.h>
+#include <linux/path.h>
+#include <linux/file.h>
+
+static int sample_fp_handler(struct fsnotify_group *group,
+ struct fanotify_fastpath_hook *fp_hook,
+ struct fanotify_fastpath_event *fp_event)
+{
+ struct dentry *dentry;
+ struct path *subtree;
+
+ dentry = fsnotify_data_dentry(fp_event->data, fp_event->data_type);
+ if (!dentry)
+ return FAN_FP_RET_SEND_TO_USERSPACE;
+
+ subtree = fp_hook->data;
+
+ if (is_subdir(dentry, subtree->dentry))
+ return FAN_FP_RET_SEND_TO_USERSPACE;
+ return FAN_FP_RET_SKIP_EVENT;
+}
+
+static int sample_fp_init(struct fanotify_fastpath_hook *fp_hook, void *args)
+{
+ struct path *subtree;
+ struct file *file;
+ int fd;
+
+ fd = *(int *)args;
+
+ file = fget(fd);
+ if (!file)
+ return -EBADF;
+ subtree = kzalloc(sizeof(struct path), GFP_KERNEL);
+ if (!subtree) {
+ fput(file);
+ return -ENOMEM;
+ }
+ path_get(&file->f_path);
+ *subtree = file->f_path;
+ fput(file);
+ fp_hook->data = subtree;
+ return 0;
+}
+
+static void sample_fp_free(struct fanotify_fastpath_hook *fp_hook)
+{
+ struct path *subtree = fp_hook->data;
+
+ path_put(subtree);
+ kfree(subtree);
+}
+
+static struct fanotify_fastpath_ops fan_fp_ignore_a_ops = {
+ .fp_handler = sample_fp_handler,
+ .fp_init = sample_fp_init,
+ .fp_free = sample_fp_free,
+ .name = "monitor-subtree",
+ .owner = THIS_MODULE,
+ .flags = FAN_FP_F_SYS_ADMIN_ONLY,
+ .desc = "only emit events under a subtree",
+ .init_args = "struct {\n\tint subtree_fd;\n};",
+};
+
+static int __init fanotify_fastpath_sample_init(void)
+{
+ return fanotify_fastpath_register(&fan_fp_ignore_a_ops);
+}
+static void __exit fanotify_fastpath_sample_exit(void)
+{
+ fanotify_fastpath_unregister(&fan_fp_ignore_a_ops);
+}
+
+module_init(fanotify_fastpath_sample_init);
+module_exit(fanotify_fastpath_sample_exit);
+
+MODULE_AUTHOR("Song Liu");
+MODULE_DESCRIPTION("Example fanotify fastpath handler");
+MODULE_LICENSE("GPL");
new file mode 100644
@@ -0,0 +1,111 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/fanotify.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+static int total_event_cnt;
+
+static void handle_notifications(char *buffer, int len)
+{
+ struct fanotify_event_metadata *event =
+ (struct fanotify_event_metadata *) buffer;
+ struct fanotify_event_info_header *info;
+ struct fanotify_event_info_fid *fid;
+ struct file_handle *handle;
+ char *name;
+ int off;
+
+ for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) {
+ for (off = sizeof(*event) ; off < event->event_len;
+ off += info->len) {
+ info = (struct fanotify_event_info_header *)
+ ((char *) event + off);
+ switch (info->info_type) {
+ case FAN_EVENT_INFO_TYPE_DFID_NAME:
+ fid = (struct fanotify_event_info_fid *) info;
+ handle = (struct file_handle *)&fid->handle;
+ name = (char *)handle + sizeof(*handle) + handle->handle_bytes;
+
+ printf("Accessing file %s\n", name);
+ total_event_cnt++;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ struct fanotify_fastpath_args args = {
+ .name = "monitor-subtree",
+ .version = 1,
+ .flags = 0,
+ };
+ char buffer[BUFSIZ];
+ const char *msg;
+ int fanotify_fd;
+ int subtree_fd;
+
+ if (argc < 3) {
+ printf("Usage:\n"
+ "\t %s <mount point> <subtree to monitor>\n",
+ argv[0]);
+ return 1;
+ }
+
+ subtree_fd = open(argv[2], O_RDONLY | O_CLOEXEC);
+
+ if (subtree_fd < 0)
+ errx(1, "open subtree_fd");
+
+ args.init_args = (__u64)&subtree_fd;
+ args.init_args_size = sizeof(int);
+
+ fanotify_fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_NAME | FAN_REPORT_DIR_FID,
+ O_RDONLY);
+ if (fanotify_fd < 0) {
+ close(subtree_fd);
+ errx(1, "fanotify_init");
+ }
+
+ if (fanotify_mark(fanotify_fd, FAN_MARK_ADD | FAN_MARK_FILESYSTEM,
+ FAN_OPEN | FAN_ONDIR | FAN_EVENT_ON_CHILD,
+ AT_FDCWD, argv[1])) {
+ msg = "fanotify_mark";
+ goto err_out;
+ }
+
+ if (ioctl(fanotify_fd, FAN_IOC_ADD_FP, &args)) {
+ msg = "ioctl";
+ goto err_out;
+ }
+
+ while (total_event_cnt < 10) {
+ int n = read(fanotify_fd, buffer, BUFSIZ);
+
+ if (n < 0) {
+ msg = "read";
+ goto err_out;
+ }
+
+ handle_notifications(buffer, n);
+ }
+
+ ioctl(fanotify_fd, FAN_IOC_DEL_FP);
+ close(fanotify_fd);
+ close(subtree_fd);
+ return 0;
+
+err_out:
+ close(fanotify_fd);
+ close(subtree_fd);
+ errx(1, msg);
+ return 0;
+}
This fastpath handler monitors a subtree inside a mount point. To use it: [root] insmod ./fastpath-mod.ko [root] mkdir -p /tmp/a/b/c/d [root] ./fastpath-user /tmp/ /tmp/a/b & [root] touch /tmp/xx # Doesn't generate event [root]# touch /tmp/a/xxa # Doesn't generate event [root]# touch /tmp/a/b/xxab # Generates an event Accessing file xxab # this is the output from fastpath-user [root@]# touch /tmp/a/b/c/xxabc # Generates an event Accessing file xxabc # this is the output from fastpath-user Signed-off-by: Song Liu <song@kernel.org> --- MAINTAINERS | 1 + samples/Kconfig | 20 +++++- samples/Makefile | 2 +- samples/fanotify/.gitignore | 1 + samples/fanotify/Makefile | 5 +- samples/fanotify/fastpath-mod.c | 82 +++++++++++++++++++++++ samples/fanotify/fastpath-user.c | 111 +++++++++++++++++++++++++++++++ 7 files changed, 219 insertions(+), 3 deletions(-) create mode 100644 samples/fanotify/fastpath-mod.c create mode 100644 samples/fanotify/fastpath-user.c