1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2014 SUSE Linux.  All Rights Reserved.
4  *
5  * Started by Jan Kara <jack@suse.cz>
6  *
7  * DESCRIPTION
8  *     Check that fanotify overflow event is properly generated
9  *
10  * ALGORITHM
11  *     Generate enough events without reading them and check that overflow
12  *     event is generated.
13  */
14 #define _GNU_SOURCE
15 #include "config.h"
16 
17 #include <stdio.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <fcntl.h>
21 #include <errno.h>
22 #include <string.h>
23 #include <sys/syscall.h>
24 #include "tst_test.h"
25 #include "fanotify.h"
26 
27 #if defined(HAVE_SYS_FANOTIFY_H)
28 #include <sys/fanotify.h>
29 
30 #define MOUNT_PATH "fs_mnt"
31 
32 /* Currently this is fixed in kernel... */
33 #define MAX_EVENTS 16384
34 
35 #define BUF_SIZE 256
36 static char fname[BUF_SIZE];
37 static int fd, fd_notify;
38 
39 struct fanotify_event_metadata event;
40 
test01(void)41 void test01(void)
42 {
43 	int i;
44 	int len;
45 
46 	/*
47 	 * generate events
48 	 */
49 	for (i = 0; i < MAX_EVENTS + 1; i++) {
50 		sprintf(fname, MOUNT_PATH"/fname_%d", i);
51 		fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0644);
52 		SAFE_CLOSE(fd);
53 	}
54 
55 	while (1) {
56 		/*
57 		 * get list on events
58 		 */
59 		len = read(fd_notify, &event, sizeof(event));
60 		if (len < 0) {
61 			if (errno == -EAGAIN) {
62 				tst_res(TFAIL, "Overflow event not "
63 					"generated!\n");
64 				break;
65 			}
66 			tst_brk(TBROK | TERRNO,
67 				"read of notification event failed");
68 			break;
69 		}
70 		if (event.fd != FAN_NOFD)
71 			close(event.fd);
72 
73 		/*
74 		 * check events
75 		 */
76 		if (event.mask != FAN_OPEN &&
77 		    event.mask != FAN_Q_OVERFLOW) {
78 			tst_res(TFAIL,
79 				"got event: mask=%llx (expected %llx)"
80 				"pid=%u fd=%d",
81 				(unsigned long long)event.mask,
82 				(unsigned long long)FAN_OPEN,
83 				(unsigned)event.pid, event.fd);
84 			break;
85 		}
86 		if (event.mask == FAN_Q_OVERFLOW) {
87 			if (event.fd != FAN_NOFD) {
88 				tst_res(TFAIL,
89 					"invalid overflow event: "
90 					"mask=%llx pid=%u fd=%d",
91 					(unsigned long long)event.mask,
92 					(unsigned)event.pid,
93 					event.fd);
94 				break;
95 			}
96 			tst_res(TPASS,
97 				"got event: mask=%llx pid=%u fd=%d",
98 				(unsigned long long)event.mask,
99 				(unsigned)event.pid, event.fd);
100 				break;
101 		}
102 	}
103 }
104 
setup(void)105 static void setup(void)
106 {
107 	fd_notify = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF | FAN_NONBLOCK,
108 			O_RDONLY);
109 
110 	if (fanotify_mark(fd_notify, FAN_MARK_MOUNT | FAN_MARK_ADD, FAN_OPEN,
111 			  AT_FDCWD, MOUNT_PATH) < 0) {
112 		tst_brk(TBROK | TERRNO,
113 			"fanotify_mark (%d, FAN_MARK_MOUNT | FAN_MARK_ADD, "
114 			"FAN_OPEN, AT_FDCWD, \".\") failed",
115 			fd_notify);
116 	}
117 }
118 
cleanup(void)119 static void cleanup(void)
120 {
121 	if (fd_notify > 0)
122 		SAFE_CLOSE(fd_notify);
123 }
124 
125 static struct tst_test test = {
126 	.test_all = test01,
127 	.setup = setup,
128 	.cleanup = cleanup,
129 	.needs_root = 1,
130 	.mount_device = 1,
131 	.mntpoint = MOUNT_PATH,
132 };
133 #else
134 	TST_TEST_TCONF("system doesn't have required fanotify support");
135 #endif
136