xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/fanotify/fanotify05.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2014 SUSE Linux.  All Rights Reserved.
4*49cdfc7eSAndroid Build Coastguard Worker  *
5*49cdfc7eSAndroid Build Coastguard Worker  * Started by Jan Kara <[email protected]>
6*49cdfc7eSAndroid Build Coastguard Worker  */
7*49cdfc7eSAndroid Build Coastguard Worker 
8*49cdfc7eSAndroid Build Coastguard Worker /*\
9*49cdfc7eSAndroid Build Coastguard Worker  * [Description]
10*49cdfc7eSAndroid Build Coastguard Worker  * Check that fanotify overflow event is properly generated.
11*49cdfc7eSAndroid Build Coastguard Worker  *
12*49cdfc7eSAndroid Build Coastguard Worker  * [Algorithm]
13*49cdfc7eSAndroid Build Coastguard Worker  * Generate enough events without reading them and check that overflow
14*49cdfc7eSAndroid Build Coastguard Worker  * event is generated.
15*49cdfc7eSAndroid Build Coastguard Worker  */
16*49cdfc7eSAndroid Build Coastguard Worker 
17*49cdfc7eSAndroid Build Coastguard Worker #define _GNU_SOURCE
18*49cdfc7eSAndroid Build Coastguard Worker #include "config.h"
19*49cdfc7eSAndroid Build Coastguard Worker 
20*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
21*49cdfc7eSAndroid Build Coastguard Worker #include <sys/stat.h>
22*49cdfc7eSAndroid Build Coastguard Worker #include <sys/types.h>
23*49cdfc7eSAndroid Build Coastguard Worker #include <errno.h>
24*49cdfc7eSAndroid Build Coastguard Worker #include <libgen.h>
25*49cdfc7eSAndroid Build Coastguard Worker #include <stdlib.h>
26*49cdfc7eSAndroid Build Coastguard Worker #include <string.h>
27*49cdfc7eSAndroid Build Coastguard Worker #include <sys/syscall.h>
28*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
29*49cdfc7eSAndroid Build Coastguard Worker #include "tst_timer.h"
30*49cdfc7eSAndroid Build Coastguard Worker 
31*49cdfc7eSAndroid Build Coastguard Worker #ifdef HAVE_SYS_FANOTIFY_H
32*49cdfc7eSAndroid Build Coastguard Worker #include "fanotify.h"
33*49cdfc7eSAndroid Build Coastguard Worker 
34*49cdfc7eSAndroid Build Coastguard Worker #define MOUNT_PATH "fs_mnt"
35*49cdfc7eSAndroid Build Coastguard Worker #define FNAME_PREFIX "fname_"
36*49cdfc7eSAndroid Build Coastguard Worker #define FNAME_PREFIX_LEN 6
37*49cdfc7eSAndroid Build Coastguard Worker #define PATH_PREFIX MOUNT_PATH "/" FNAME_PREFIX
38*49cdfc7eSAndroid Build Coastguard Worker 
39*49cdfc7eSAndroid Build Coastguard Worker #define SYSFS_MAX_EVENTS "/proc/sys/fs/fanotify/max_queued_events"
40*49cdfc7eSAndroid Build Coastguard Worker 
41*49cdfc7eSAndroid Build Coastguard Worker /* In older kernels this limit is fixed in kernel */
42*49cdfc7eSAndroid Build Coastguard Worker #define DEFAULT_MAX_EVENTS 16384
43*49cdfc7eSAndroid Build Coastguard Worker 
44*49cdfc7eSAndroid Build Coastguard Worker static int max_events;
45*49cdfc7eSAndroid Build Coastguard Worker 
46*49cdfc7eSAndroid Build Coastguard Worker static struct tcase {
47*49cdfc7eSAndroid Build Coastguard Worker 	const char *tname;
48*49cdfc7eSAndroid Build Coastguard Worker 	unsigned int init_flags;
49*49cdfc7eSAndroid Build Coastguard Worker } tcases[] = {
50*49cdfc7eSAndroid Build Coastguard Worker 	{
51*49cdfc7eSAndroid Build Coastguard Worker 		"Limited queue",
52*49cdfc7eSAndroid Build Coastguard Worker 		FAN_CLASS_NOTIF,
53*49cdfc7eSAndroid Build Coastguard Worker 	},
54*49cdfc7eSAndroid Build Coastguard Worker 	{
55*49cdfc7eSAndroid Build Coastguard Worker 		"Unlimited queue",
56*49cdfc7eSAndroid Build Coastguard Worker 		FAN_CLASS_NOTIF | FAN_UNLIMITED_QUEUE,
57*49cdfc7eSAndroid Build Coastguard Worker 	},
58*49cdfc7eSAndroid Build Coastguard Worker };
59*49cdfc7eSAndroid Build Coastguard Worker 
60*49cdfc7eSAndroid Build Coastguard Worker #define BUF_SIZE 256
61*49cdfc7eSAndroid Build Coastguard Worker static char fname[BUF_SIZE];
62*49cdfc7eSAndroid Build Coastguard Worker static char symlnk[BUF_SIZE];
63*49cdfc7eSAndroid Build Coastguard Worker static char fdpath[BUF_SIZE];
64*49cdfc7eSAndroid Build Coastguard Worker static int fd, fd_notify;
65*49cdfc7eSAndroid Build Coastguard Worker 
66*49cdfc7eSAndroid Build Coastguard Worker static struct fanotify_event_metadata event;
67*49cdfc7eSAndroid Build Coastguard Worker 
event_res(struct fanotify_event_metadata * event,int i)68*49cdfc7eSAndroid Build Coastguard Worker static void event_res(struct fanotify_event_metadata *event, int i)
69*49cdfc7eSAndroid Build Coastguard Worker {
70*49cdfc7eSAndroid Build Coastguard Worker 	int len = 0;
71*49cdfc7eSAndroid Build Coastguard Worker 	const char *filename;
72*49cdfc7eSAndroid Build Coastguard Worker 
73*49cdfc7eSAndroid Build Coastguard Worker 	sprintf(symlnk, "/proc/self/fd/%d", event->fd);
74*49cdfc7eSAndroid Build Coastguard Worker 	len = readlink(symlnk, fdpath, sizeof(fdpath));
75*49cdfc7eSAndroid Build Coastguard Worker 	if (len < 0)
76*49cdfc7eSAndroid Build Coastguard Worker 		len = 0;
77*49cdfc7eSAndroid Build Coastguard Worker 	fdpath[len] = 0;
78*49cdfc7eSAndroid Build Coastguard Worker 	filename = basename(fdpath);
79*49cdfc7eSAndroid Build Coastguard Worker 
80*49cdfc7eSAndroid Build Coastguard Worker 	if (len > FNAME_PREFIX_LEN && atoi(filename + FNAME_PREFIX_LEN) != i)
81*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TFAIL, "Got event #%d out of order filename=%s", i, filename);
82*49cdfc7eSAndroid Build Coastguard Worker 	else if (i == 0)
83*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "Got event #%d filename=%s", i, filename);
84*49cdfc7eSAndroid Build Coastguard Worker }
85*49cdfc7eSAndroid Build Coastguard Worker 
generate_events(int open_flags,int num_files)86*49cdfc7eSAndroid Build Coastguard Worker static void generate_events(int open_flags, int num_files)
87*49cdfc7eSAndroid Build Coastguard Worker {
88*49cdfc7eSAndroid Build Coastguard Worker 	long long elapsed_ms;
89*49cdfc7eSAndroid Build Coastguard Worker 	int i;
90*49cdfc7eSAndroid Build Coastguard Worker 
91*49cdfc7eSAndroid Build Coastguard Worker 	tst_timer_start(CLOCK_MONOTONIC);
92*49cdfc7eSAndroid Build Coastguard Worker 
93*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < num_files; i++) {
94*49cdfc7eSAndroid Build Coastguard Worker 		sprintf(fname, PATH_PREFIX "%d", i);
95*49cdfc7eSAndroid Build Coastguard Worker 		fd = SAFE_OPEN(fname, open_flags, 0644);
96*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(fd);
97*49cdfc7eSAndroid Build Coastguard Worker 	}
98*49cdfc7eSAndroid Build Coastguard Worker 
99*49cdfc7eSAndroid Build Coastguard Worker 	tst_timer_stop();
100*49cdfc7eSAndroid Build Coastguard Worker 
101*49cdfc7eSAndroid Build Coastguard Worker 	elapsed_ms = tst_timer_elapsed_ms();
102*49cdfc7eSAndroid Build Coastguard Worker 
103*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "%s %d files in %llims",
104*49cdfc7eSAndroid Build Coastguard Worker 		(open_flags & O_CREAT) ? "Created" : "Opened", i, elapsed_ms);
105*49cdfc7eSAndroid Build Coastguard Worker }
106*49cdfc7eSAndroid Build Coastguard Worker 
test_fanotify(unsigned int n)107*49cdfc7eSAndroid Build Coastguard Worker static void test_fanotify(unsigned int n)
108*49cdfc7eSAndroid Build Coastguard Worker {
109*49cdfc7eSAndroid Build Coastguard Worker 	struct tcase *tc = &tcases[n];
110*49cdfc7eSAndroid Build Coastguard Worker 	int len, nevents = 0, got_overflow = 0;
111*49cdfc7eSAndroid Build Coastguard Worker 	int num_files = max_events + 1;
112*49cdfc7eSAndroid Build Coastguard Worker 	int expect_overflow = !(tc->init_flags & FAN_UNLIMITED_QUEUE);
113*49cdfc7eSAndroid Build Coastguard Worker 
114*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "Test #%d: %s", n, tc->tname);
115*49cdfc7eSAndroid Build Coastguard Worker 
116*49cdfc7eSAndroid Build Coastguard Worker 	fd_notify = SAFE_FANOTIFY_INIT(tc->init_flags | FAN_NONBLOCK, O_RDONLY);
117*49cdfc7eSAndroid Build Coastguard Worker 
118*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_MOUNT | FAN_MARK_ADD, FAN_OPEN,
119*49cdfc7eSAndroid Build Coastguard Worker 			   AT_FDCWD, MOUNT_PATH);
120*49cdfc7eSAndroid Build Coastguard Worker 
121*49cdfc7eSAndroid Build Coastguard Worker 	/*
122*49cdfc7eSAndroid Build Coastguard Worker 	 * Generate events on unique files so they won't be merged
123*49cdfc7eSAndroid Build Coastguard Worker 	 */
124*49cdfc7eSAndroid Build Coastguard Worker 	generate_events(O_RDWR | O_CREAT, num_files);
125*49cdfc7eSAndroid Build Coastguard Worker 
126*49cdfc7eSAndroid Build Coastguard Worker 	/*
127*49cdfc7eSAndroid Build Coastguard Worker 	 * Generate more events on the same files that me be merged
128*49cdfc7eSAndroid Build Coastguard Worker 	 */
129*49cdfc7eSAndroid Build Coastguard Worker 	generate_events(O_RDONLY, num_files);
130*49cdfc7eSAndroid Build Coastguard Worker 
131*49cdfc7eSAndroid Build Coastguard Worker 	while (1) {
132*49cdfc7eSAndroid Build Coastguard Worker 		/*
133*49cdfc7eSAndroid Build Coastguard Worker 		 * get list on events
134*49cdfc7eSAndroid Build Coastguard Worker 		 */
135*49cdfc7eSAndroid Build Coastguard Worker 		len = read(fd_notify, &event, sizeof(event));
136*49cdfc7eSAndroid Build Coastguard Worker 		if (len < 0) {
137*49cdfc7eSAndroid Build Coastguard Worker 			if (errno != EAGAIN) {
138*49cdfc7eSAndroid Build Coastguard Worker 				tst_brk(TBROK | TERRNO,
139*49cdfc7eSAndroid Build Coastguard Worker 					"read of notification event failed");
140*49cdfc7eSAndroid Build Coastguard Worker 			}
141*49cdfc7eSAndroid Build Coastguard Worker 			if (!got_overflow)
142*49cdfc7eSAndroid Build Coastguard Worker 				tst_res(expect_overflow ? TFAIL : TPASS, "Overflow event not generated!\n");
143*49cdfc7eSAndroid Build Coastguard Worker 			break;
144*49cdfc7eSAndroid Build Coastguard Worker 		}
145*49cdfc7eSAndroid Build Coastguard Worker 		if (event.fd != FAN_NOFD) {
146*49cdfc7eSAndroid Build Coastguard Worker 			/*
147*49cdfc7eSAndroid Build Coastguard Worker 			 * Verify that events generated on unique files
148*49cdfc7eSAndroid Build Coastguard Worker 			 * are received by the same order they were generated.
149*49cdfc7eSAndroid Build Coastguard Worker 			 */
150*49cdfc7eSAndroid Build Coastguard Worker 			if (nevents < num_files)
151*49cdfc7eSAndroid Build Coastguard Worker 				event_res(&event, nevents);
152*49cdfc7eSAndroid Build Coastguard Worker 			close(event.fd);
153*49cdfc7eSAndroid Build Coastguard Worker 		}
154*49cdfc7eSAndroid Build Coastguard Worker 		nevents++;
155*49cdfc7eSAndroid Build Coastguard Worker 
156*49cdfc7eSAndroid Build Coastguard Worker 		/*
157*49cdfc7eSAndroid Build Coastguard Worker 		 * check events
158*49cdfc7eSAndroid Build Coastguard Worker 		 */
159*49cdfc7eSAndroid Build Coastguard Worker 		if (event.mask != FAN_OPEN &&
160*49cdfc7eSAndroid Build Coastguard Worker 		    event.mask != FAN_Q_OVERFLOW) {
161*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TFAIL,
162*49cdfc7eSAndroid Build Coastguard Worker 				"got event: mask=%llx (expected %llx) pid=%u fd=%d",
163*49cdfc7eSAndroid Build Coastguard Worker 				(unsigned long long)event.mask,
164*49cdfc7eSAndroid Build Coastguard Worker 				(unsigned long long)FAN_OPEN,
165*49cdfc7eSAndroid Build Coastguard Worker 				(unsigned int)event.pid, event.fd);
166*49cdfc7eSAndroid Build Coastguard Worker 			break;
167*49cdfc7eSAndroid Build Coastguard Worker 		}
168*49cdfc7eSAndroid Build Coastguard Worker 		if (event.mask == FAN_Q_OVERFLOW) {
169*49cdfc7eSAndroid Build Coastguard Worker 			if (got_overflow || event.fd != FAN_NOFD) {
170*49cdfc7eSAndroid Build Coastguard Worker 				tst_res(TFAIL,
171*49cdfc7eSAndroid Build Coastguard Worker 					"%s overflow event: mask=%llx pid=%u fd=%d",
172*49cdfc7eSAndroid Build Coastguard Worker 					got_overflow ? "unexpected" : "invalid",
173*49cdfc7eSAndroid Build Coastguard Worker 					(unsigned long long)event.mask,
174*49cdfc7eSAndroid Build Coastguard Worker 					(unsigned int)event.pid,
175*49cdfc7eSAndroid Build Coastguard Worker 					event.fd);
176*49cdfc7eSAndroid Build Coastguard Worker 				break;
177*49cdfc7eSAndroid Build Coastguard Worker 			}
178*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(expect_overflow ? TPASS : TFAIL,
179*49cdfc7eSAndroid Build Coastguard Worker 				"Got an overflow event: pid=%u fd=%d",
180*49cdfc7eSAndroid Build Coastguard Worker 				(unsigned int)event.pid, event.fd);
181*49cdfc7eSAndroid Build Coastguard Worker 			got_overflow = 1;
182*49cdfc7eSAndroid Build Coastguard Worker 		}
183*49cdfc7eSAndroid Build Coastguard Worker 	}
184*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "Got %d events", nevents);
185*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_CLOSE(fd_notify);
186*49cdfc7eSAndroid Build Coastguard Worker }
187*49cdfc7eSAndroid Build Coastguard Worker 
setup(void)188*49cdfc7eSAndroid Build Coastguard Worker static void setup(void)
189*49cdfc7eSAndroid Build Coastguard Worker {
190*49cdfc7eSAndroid Build Coastguard Worker 	int fd;
191*49cdfc7eSAndroid Build Coastguard Worker 
192*49cdfc7eSAndroid Build Coastguard Worker 	/* Check for kernel fanotify support */
193*49cdfc7eSAndroid Build Coastguard Worker 	fd = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY);
194*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_CLOSE(fd);
195*49cdfc7eSAndroid Build Coastguard Worker 
196*49cdfc7eSAndroid Build Coastguard Worker 	/* In older kernels this limit is fixed in kernel */
197*49cdfc7eSAndroid Build Coastguard Worker 	if (access(SYSFS_MAX_EVENTS, F_OK) && errno == ENOENT)
198*49cdfc7eSAndroid Build Coastguard Worker 		max_events = DEFAULT_MAX_EVENTS;
199*49cdfc7eSAndroid Build Coastguard Worker 	else
200*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_FILE_SCANF(SYSFS_MAX_EVENTS, "%d", &max_events);
201*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "max_queued_events=%d", max_events);
202*49cdfc7eSAndroid Build Coastguard Worker }
203*49cdfc7eSAndroid Build Coastguard Worker 
cleanup(void)204*49cdfc7eSAndroid Build Coastguard Worker static void cleanup(void)
205*49cdfc7eSAndroid Build Coastguard Worker {
206*49cdfc7eSAndroid Build Coastguard Worker 	if (fd_notify > 0)
207*49cdfc7eSAndroid Build Coastguard Worker 		SAFE_CLOSE(fd_notify);
208*49cdfc7eSAndroid Build Coastguard Worker }
209*49cdfc7eSAndroid Build Coastguard Worker 
210*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
211*49cdfc7eSAndroid Build Coastguard Worker 	.test = test_fanotify,
212*49cdfc7eSAndroid Build Coastguard Worker 	.tcnt = ARRAY_SIZE(tcases),
213*49cdfc7eSAndroid Build Coastguard Worker 	.setup = setup,
214*49cdfc7eSAndroid Build Coastguard Worker 	.cleanup = cleanup,
215*49cdfc7eSAndroid Build Coastguard Worker 	.needs_root = 1,
216*49cdfc7eSAndroid Build Coastguard Worker 	.mount_device = 1,
217*49cdfc7eSAndroid Build Coastguard Worker 	.mntpoint = MOUNT_PATH,
218*49cdfc7eSAndroid Build Coastguard Worker };
219*49cdfc7eSAndroid Build Coastguard Worker #else
220*49cdfc7eSAndroid Build Coastguard Worker 	TST_TEST_TCONF("system doesn't have required fanotify support");
221*49cdfc7eSAndroid Build Coastguard Worker #endif
222