Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

samples: Add fs error monitoring example

Introduce an example of a FAN_FS_ERROR fanotify user to track filesystem
errors.

Link: https://lore.kernel.org/r/20211025192746.66445-31-krisman@collabora.com
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.com>
Signed-off-by: Jan Kara <jack@suse.cz>

authored by

Gabriel Krisman Bertazi and committed by
Jan Kara
54510930 9a089b21

+157
+9
samples/Kconfig
··· 120 120 with it. 121 121 See also Documentation/driver-api/connector.rst 122 122 123 + config SAMPLE_FANOTIFY_ERROR 124 + bool "Build fanotify error monitoring sample" 125 + depends on FANOTIFY 126 + help 127 + When enabled, this builds an example code that uses the 128 + FAN_FS_ERROR fanotify mechanism to monitor filesystem 129 + errors. 130 + See also Documentation/admin-guide/filesystem-monitoring.rst. 131 + 123 132 config SAMPLE_HIDRAW 124 133 bool "hidraw sample" 125 134 depends on CC_CAN_LINK && HEADERS_INSTALL
+1
samples/Makefile
··· 5 5 subdir-$(CONFIG_SAMPLE_ANDROID_BINDERFS) += binderfs 6 6 obj-$(CONFIG_SAMPLE_CONFIGFS) += configfs/ 7 7 obj-$(CONFIG_SAMPLE_CONNECTOR) += connector/ 8 + obj-$(CONFIG_SAMPLE_FANOTIFY_ERROR) += fanotify/ 8 9 subdir-$(CONFIG_SAMPLE_HIDRAW) += hidraw 9 10 obj-$(CONFIG_SAMPLE_HW_BREAKPOINT) += hw_breakpoint/ 10 11 obj-$(CONFIG_SAMPLE_KDB) += kdb/
+5
samples/fanotify/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0-only 2 + userprogs-always-y += fs-monitor 3 + 4 + userccflags += -I usr/include -Wall 5 +
+142
samples/fanotify/fs-monitor.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2021, Collabora Ltd. 4 + */ 5 + 6 + #define _GNU_SOURCE 7 + #include <errno.h> 8 + #include <err.h> 9 + #include <stdlib.h> 10 + #include <stdio.h> 11 + #include <fcntl.h> 12 + #include <sys/fanotify.h> 13 + #include <sys/types.h> 14 + #include <unistd.h> 15 + #include <sys/types.h> 16 + 17 + #ifndef FAN_FS_ERROR 18 + #define FAN_FS_ERROR 0x00008000 19 + #define FAN_EVENT_INFO_TYPE_ERROR 5 20 + 21 + struct fanotify_event_info_error { 22 + struct fanotify_event_info_header hdr; 23 + __s32 error; 24 + __u32 error_count; 25 + }; 26 + #endif 27 + 28 + #ifndef FILEID_INO32_GEN 29 + #define FILEID_INO32_GEN 1 30 + #endif 31 + 32 + #ifndef FILEID_INVALID 33 + #define FILEID_INVALID 0xff 34 + #endif 35 + 36 + static void print_fh(struct file_handle *fh) 37 + { 38 + int i; 39 + uint32_t *h = (uint32_t *) fh->f_handle; 40 + 41 + printf("\tfh: "); 42 + for (i = 0; i < fh->handle_bytes; i++) 43 + printf("%hhx", fh->f_handle[i]); 44 + printf("\n"); 45 + 46 + printf("\tdecoded fh: "); 47 + if (fh->handle_type == FILEID_INO32_GEN) 48 + printf("inode=%u gen=%u\n", h[0], h[1]); 49 + else if (fh->handle_type == FILEID_INVALID && !fh->handle_bytes) 50 + printf("Type %d (Superblock error)\n", fh->handle_type); 51 + else 52 + printf("Type %d (Unknown)\n", fh->handle_type); 53 + 54 + } 55 + 56 + static void handle_notifications(char *buffer, int len) 57 + { 58 + struct fanotify_event_metadata *event = 59 + (struct fanotify_event_metadata *) buffer; 60 + struct fanotify_event_info_header *info; 61 + struct fanotify_event_info_error *err; 62 + struct fanotify_event_info_fid *fid; 63 + int off; 64 + 65 + for (; FAN_EVENT_OK(event, len); event = FAN_EVENT_NEXT(event, len)) { 66 + 67 + if (event->mask != FAN_FS_ERROR) { 68 + printf("unexpected FAN MARK: %llx\n", event->mask); 69 + goto next_event; 70 + } 71 + 72 + if (event->fd != FAN_NOFD) { 73 + printf("Unexpected fd (!= FAN_NOFD)\n"); 74 + goto next_event; 75 + } 76 + 77 + printf("FAN_FS_ERROR (len=%d)\n", event->event_len); 78 + 79 + for (off = sizeof(*event) ; off < event->event_len; 80 + off += info->len) { 81 + info = (struct fanotify_event_info_header *) 82 + ((char *) event + off); 83 + 84 + switch (info->info_type) { 85 + case FAN_EVENT_INFO_TYPE_ERROR: 86 + err = (struct fanotify_event_info_error *) info; 87 + 88 + printf("\tGeneric Error Record: len=%d\n", 89 + err->hdr.len); 90 + printf("\terror: %d\n", err->error); 91 + printf("\terror_count: %d\n", err->error_count); 92 + break; 93 + 94 + case FAN_EVENT_INFO_TYPE_FID: 95 + fid = (struct fanotify_event_info_fid *) info; 96 + 97 + printf("\tfsid: %x%x\n", 98 + fid->fsid.val[0], fid->fsid.val[1]); 99 + print_fh((struct file_handle *) &fid->handle); 100 + break; 101 + 102 + default: 103 + printf("\tUnknown info type=%d len=%d:\n", 104 + info->info_type, info->len); 105 + } 106 + } 107 + next_event: 108 + printf("---\n\n"); 109 + } 110 + } 111 + 112 + int main(int argc, char **argv) 113 + { 114 + int fd; 115 + 116 + char buffer[BUFSIZ]; 117 + 118 + if (argc < 2) { 119 + printf("Missing path argument\n"); 120 + return 1; 121 + } 122 + 123 + fd = fanotify_init(FAN_CLASS_NOTIF|FAN_REPORT_FID, O_RDONLY); 124 + if (fd < 0) 125 + errx(1, "fanotify_init"); 126 + 127 + if (fanotify_mark(fd, FAN_MARK_ADD|FAN_MARK_FILESYSTEM, 128 + FAN_FS_ERROR, AT_FDCWD, argv[1])) { 129 + errx(1, "fanotify_mark"); 130 + } 131 + 132 + while (1) { 133 + int n = read(fd, buffer, BUFSIZ); 134 + 135 + if (n < 0) 136 + errx(1, "read"); 137 + 138 + handle_notifications(buffer, n); 139 + } 140 + 141 + return 0; 142 + }