• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2020 CTERA Networks. All Rights Reserved.
4  *
5  * Started by Amir Goldstein <amir73il@gmail.com>
6  */
7 
8 /*\
9  * [Description]
10  * Check fanotify directory entry modification events, events on child and
11  * on self with group init flags:
12  *
13  * - FAN_REPORT_DFID_NAME (dir fid + name)
14  * - FAN_REPORT_DIR_FID   (dir fid)
15  * - FAN_REPORT_DIR_FID | FAN_REPORT_FID   (dir fid + child fid)
16  * - FAN_REPORT_DFID_NAME | FAN_REPORT_FID (dir fid + name + child fid)
17  */
18 
19 #define _GNU_SOURCE
20 #include "config.h"
21 
22 #include <stdio.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <sys/mount.h>
28 #include <sys/syscall.h>
29 #include "tst_test.h"
30 
31 #ifdef HAVE_SYS_FANOTIFY_H
32 #include "fanotify.h"
33 
34 #define EVENT_MAX 20
35 
36 /* Size of the event structure, not including file handle */
37 #define EVENT_SIZE (sizeof(struct fanotify_event_metadata) + \
38 		    sizeof(struct fanotify_event_info_fid))
39 /* Tripple events buffer size to account for file handles and names */
40 #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE * 3)
41 
42 
43 #define BUF_SIZE 256
44 
45 #ifdef HAVE_NAME_TO_HANDLE_AT
46 struct event_t {
47 	unsigned long long mask;
48 	struct fanotify_fid_t *fid;
49 	struct fanotify_fid_t *child_fid;
50 	char name[BUF_SIZE];
51 };
52 
53 static char fname1[BUF_SIZE + 11], fname2[BUF_SIZE + 11];
54 static char dname1[BUF_SIZE], dname2[BUF_SIZE];
55 static int fd_notify;
56 
57 static struct event_t event_set[EVENT_MAX];
58 
59 static char event_buf[EVENT_BUF_LEN];
60 
61 #define DIR_NAME1 "test_dir1"
62 #define DIR_NAME2 "test_dir2"
63 #define FILE_NAME1 "test_file1"
64 #define FILE_NAME2 "test_file2"
65 #define MOUNT_PATH "fs_mnt"
66 
67 static struct test_case_t {
68 	const char *tname;
69 	struct fanotify_group_type group;
70 	struct fanotify_mark_type mark;
71 	unsigned long mask;
72 	struct fanotify_mark_type sub_mark;
73 	unsigned long sub_mask;
74 } test_cases[] = {
75 	{
76 		"FAN_REPORT_DFID_NAME monitor filesystem for create/delete/move/open/close",
77 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME),
78 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
79 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
80 		/* Mount watch for events possible on children */
81 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
82 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
83 	},
84 	{
85 		"FAN_REPORT_DFID_NAME monitor directories for create/delete/move/open/close",
86 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME),
87 		INIT_FANOTIFY_MARK_TYPE(INODE),
88 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
89 		/* Watches for self events on subdir and events on subdir's children */
90 		INIT_FANOTIFY_MARK_TYPE(INODE),
91 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
92 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
93 	},
94 	{
95 		"FAN_REPORT_DIR_FID monitor filesystem for create/delete/move/open/close",
96 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID),
97 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
98 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
99 		/* Mount watch for events possible on children */
100 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
101 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
102 	},
103 	{
104 		"FAN_REPORT_DIR_FID monitor directories for create/delete/move/open/close",
105 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID),
106 		INIT_FANOTIFY_MARK_TYPE(INODE),
107 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
108 		/* Watches for self events on subdir and events on subdir's children */
109 		INIT_FANOTIFY_MARK_TYPE(INODE),
110 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
111 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
112 	},
113 	{
114 		"FAN_REPORT_DFID_FID monitor filesystem for create/delete/move/open/close",
115 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID),
116 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
117 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
118 		/* Mount watch for events possible on children */
119 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
120 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
121 	},
122 	{
123 		"FAN_REPORT_DFID_FID monitor directories for create/delete/move/open/close",
124 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID),
125 		INIT_FANOTIFY_MARK_TYPE(INODE),
126 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
127 		/* Watches for self events on subdir and events on subdir's children */
128 		INIT_FANOTIFY_MARK_TYPE(INODE),
129 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
130 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
131 	},
132 	{
133 		"FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/open/close",
134 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
135 		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
136 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
137 		/* Mount watch for events possible on children */
138 		INIT_FANOTIFY_MARK_TYPE(MOUNT),
139 		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
140 	},
141 	{
142 		"FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/open/close",
143 		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
144 		INIT_FANOTIFY_MARK_TYPE(INODE),
145 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
146 		/* Watches for self events on subdir and events on subdir's children */
147 		INIT_FANOTIFY_MARK_TYPE(INODE),
148 		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
149 		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
150 	},
151 };
152 
do_test(unsigned int number)153 static void do_test(unsigned int number)
154 {
155 	int fd, dirfd, len = 0, i = 0, test_num = 0, tst_count = 0;
156 	struct test_case_t *tc = &test_cases[number];
157 	struct fanotify_group_type *group = &tc->group;
158 	struct fanotify_mark_type *mark = &tc->mark;
159 	struct fanotify_mark_type *sub_mark = &tc->sub_mark;
160 	struct fanotify_fid_t root_fid, dir_fid, file_fid;
161 
162 	tst_res(TINFO, "Test #%d: %s", number, tc->tname);
163 
164 	fd_notify = SAFE_FANOTIFY_INIT(group->flag, 0);
165 
166 	/*
167 	 * Watch dir modify events with name in filesystem/dir
168 	 */
169 	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag, tc->mask,
170 			   AT_FDCWD, MOUNT_PATH);
171 
172 	/* Save the mount root fid */
173 	fanotify_save_fid(MOUNT_PATH, &root_fid);
174 
175 	/*
176 	 * Create subdir and watch open events "on children" with name.
177 	 * Make it a mount root.
178 	 */
179 	SAFE_MKDIR(dname1, 0755);
180 	SAFE_MOUNT(dname1, dname1, "none", MS_BIND, NULL);
181 
182 	/* Save the subdir fid */
183 	fanotify_save_fid(dname1, &dir_fid);
184 
185 	if (tc->sub_mask)
186 		SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | sub_mark->flag,
187 				   tc->sub_mask, AT_FDCWD, dname1);
188 
189 	event_set[tst_count].mask = FAN_CREATE | FAN_ONDIR;
190 	event_set[tst_count].fid = &root_fid;
191 	event_set[tst_count].child_fid = NULL;
192 	strcpy(event_set[tst_count].name, DIR_NAME1);
193 	tst_count++;
194 
195 	/* Generate modify events "on child" */
196 	fd = SAFE_CREAT(fname1, 0755);
197 
198 	/* Save the file fid */
199 	fanotify_save_fid(fname1, &file_fid);
200 
201 	SAFE_WRITE(1, fd, "1", 1);
202 	SAFE_RENAME(fname1, fname2);
203 
204 	SAFE_CLOSE(fd);
205 
206 	/* Generate delete events with fname2 */
207 	SAFE_UNLINK(fname2);
208 
209 	/* Read events on files in subdir */
210 	len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len);
211 
212 	/*
213 	 * FAN_CREATE|FAN_DELETE|FAN_MOVE events with the same name are merged.
214 	 */
215 	event_set[tst_count].mask = FAN_CREATE | FAN_MOVED_FROM;
216 	event_set[tst_count].fid = &dir_fid;
217 	event_set[tst_count].child_fid = NULL;
218 	strcpy(event_set[tst_count].name, FILE_NAME1);
219 	tst_count++;
220 	/*
221 	 * Event on non-dir child with the same name may be merged with the
222 	 * directory entry modification events above, unless FAN_REPORT_FID is
223 	 * set and child fid is reported. If FAN_REPORT_FID is set but
224 	 * FAN_REPORT_NAME is not set, then FAN_CREATE above is merged with
225 	 * FAN_DELETE below and FAN_OPEN will be merged with FAN_CLOSE.
226 	 */
227 	if (group->flag & FAN_REPORT_NAME) {
228 		event_set[tst_count].mask = FAN_OPEN;
229 		event_set[tst_count].fid = &dir_fid;
230 		event_set[tst_count].child_fid = &file_fid;
231 		strcpy(event_set[tst_count].name, FILE_NAME1);
232 		tst_count++;
233 	}
234 
235 	event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO;
236 	event_set[tst_count].fid = &dir_fid;
237 	event_set[tst_count].child_fid = NULL;
238 	strcpy(event_set[tst_count].name, FILE_NAME2);
239 	tst_count++;
240 	/*
241 	 * When not reporting name, open of FILE_NAME1 is merged
242 	 * with close of FILE_NAME2.
243 	 */
244 	if (!(group->flag & FAN_REPORT_NAME)) {
245 		event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_WRITE;
246 		event_set[tst_count].fid = &dir_fid;
247 		event_set[tst_count].child_fid = &file_fid;
248 		strcpy(event_set[tst_count].name, "");
249 		tst_count++;
250 	}
251 	/*
252 	 * Directory watch does not get self events on children.
253 	 * Filesystem watch gets self event w/o name info if FAN_REPORT_FID
254 	 * is set.
255 	 */
256 	if (mark->flag == FAN_MARK_FILESYSTEM && (group->flag & FAN_REPORT_FID)) {
257 		event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF;
258 		event_set[tst_count].fid = &file_fid;
259 		event_set[tst_count].child_fid = NULL;
260 		strcpy(event_set[tst_count].name, "");
261 		tst_count++;
262 	}
263 	/*
264 	 * When reporting name, close of FILE_NAME2 is not merged with
265 	 * open of FILE_NAME1 and it is received after the merged self
266 	 * events.
267 	 */
268 	if (group->flag & FAN_REPORT_NAME) {
269 		event_set[tst_count].mask = FAN_CLOSE_WRITE;
270 		event_set[tst_count].fid = &dir_fid;
271 		event_set[tst_count].child_fid = &file_fid;
272 		strcpy(event_set[tst_count].name, FILE_NAME2);
273 		tst_count++;
274 	}
275 
276 	dirfd = SAFE_OPEN(dname1, O_RDONLY | O_DIRECTORY);
277 	SAFE_CLOSE(dirfd);
278 
279 	SAFE_UMOUNT(dname1);
280 
281 	/*
282 	 * Directory watch gets open/close events on itself and on its subdirs.
283 	 * Filesystem watch gets open/close event on all directories with name ".".
284 	 */
285 	event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_NOWRITE | FAN_ONDIR;
286 	event_set[tst_count].fid = &dir_fid;
287 	event_set[tst_count].child_fid = NULL;
288 	strcpy(event_set[tst_count].name, ".");
289 	tst_count++;
290 	/*
291 	 * Directory watch gets self event on itself and filesystem watch gets
292 	 * self event on all directories with name ".".
293 	 */
294 	event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR;
295 	event_set[tst_count].fid = &dir_fid;
296 	event_set[tst_count].child_fid = NULL;
297 	strcpy(event_set[tst_count].name, ".");
298 	tst_count++;
299 
300 	SAFE_RENAME(dname1, dname2);
301 	SAFE_RMDIR(dname2);
302 
303 	/* Read more events on dirs */
304 	len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len);
305 
306 	event_set[tst_count].mask = FAN_MOVED_FROM | FAN_ONDIR;
307 	event_set[tst_count].fid = &root_fid;
308 	event_set[tst_count].child_fid = NULL;
309 	strcpy(event_set[tst_count].name, DIR_NAME1);
310 	tst_count++;
311 	event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO | FAN_ONDIR;
312 	event_set[tst_count].fid = &root_fid;
313 	event_set[tst_count].child_fid = NULL;
314 	strcpy(event_set[tst_count].name, DIR_NAME2);
315 	tst_count++;
316 	/* Expect no more events */
317 	event_set[tst_count].mask = 0;
318 
319 	/*
320 	 * Cleanup the marks
321 	 */
322 	SAFE_CLOSE(fd_notify);
323 	fd_notify = -1;
324 
325 	while (i < len) {
326 		struct event_t *expected = &event_set[test_num];
327 		struct fanotify_event_metadata *event;
328 		struct fanotify_event_info_fid *event_fid;
329 		struct fanotify_event_info_fid *child_fid;
330 		struct fanotify_fid_t *expected_fid = expected->fid;
331 		struct fanotify_fid_t *expected_child_fid = expected->child_fid;
332 		struct file_handle *file_handle;
333 		unsigned int fhlen;
334 		const char *filename;
335 		int namelen, info_type, mask_match, info_id = 0;
336 
337 		event = (struct fanotify_event_metadata *)&event_buf[i];
338 		event_fid = (struct fanotify_event_info_fid *)(event + 1);
339 		file_handle = (struct file_handle *)event_fid->handle;
340 		fhlen = file_handle->handle_bytes;
341 		filename = (char *)file_handle->f_handle + fhlen;
342 		child_fid = (void *)((char *)event_fid + event_fid->hdr.len);
343 		namelen = (char *)child_fid - (char *)filename;
344 		/* End of event_fid could have name, zero padding, both or none */
345 		if (namelen > 0) {
346 			namelen = strlen(filename);
347 		} else {
348 			filename = "";
349 			namelen = 0;
350 		}
351 		/* Is there a child fid after first fid record? */
352 		if (((char *)child_fid - (char *)event) >= event->event_len)
353 			child_fid = NULL;
354 
355 		if (!(group->flag & FAN_REPORT_FID))
356 			expected_child_fid = NULL;
357 
358 		if (!(group->flag & FAN_REPORT_NAME))
359 			expected->name[0] = 0;
360 
361 		if (expected->name[0]) {
362 			info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
363 		} else if (expected->mask & FAN_ONDIR) {
364 			info_type = FAN_EVENT_INFO_TYPE_DFID;
365 		} else if (expected->mask & (FAN_DELETE_SELF | FAN_MOVE_SELF)) {
366 			/* Self event on non-dir has only child fid */
367 			info_type = FAN_EVENT_INFO_TYPE_FID;
368 		} else {
369 			info_type = FAN_EVENT_INFO_TYPE_DFID;
370 		}
371 
372 		/*
373 		 * Event may contain more than the expected mask, but it must
374 		 * have all the bits in expected mask.
375 		 * Expected event on dir must not get event on non dir and the
376 		 * other way around.
377 		 */
378 		mask_match = ((event->mask & expected->mask) &&
379 			      !(expected->mask & ~event->mask) &&
380 			      !((event->mask ^ expected->mask) & FAN_ONDIR));
381 
382 check_match:
383 		if (test_num >= tst_count) {
384 			tst_res(TFAIL,
385 				"got unnecessary event: mask=%llx "
386 				"pid=%u fd=%d name='%s' "
387 				"len=%d info_type=%d info_len=%d fh_len=%d",
388 				(unsigned long long)event->mask,
389 				(unsigned)event->pid, event->fd, filename,
390 				event->event_len, event_fid->hdr.info_type,
391 				event_fid->hdr.len, fhlen);
392 		} else if (!fhlen || namelen < 0) {
393 			tst_res(TFAIL,
394 				"got event without fid: mask=%llx pid=%u fd=%d, "
395 				"len=%d info_type=%d info_len=%d fh_len=%d",
396 				(unsigned long long)event->mask,
397 				(unsigned)event->pid, event->fd,
398 				event->event_len, event_fid->hdr.info_type,
399 				event_fid->hdr.len, fhlen);
400 		} else if (!mask_match) {
401 			tst_res(TFAIL,
402 				"got event: mask=%llx (expected %llx) "
403 				"pid=%u fd=%d name='%s' "
404 				"len=%d info_type=%d info_len=%d fh_len=%d",
405 				(unsigned long long)event->mask, expected->mask,
406 				(unsigned)event->pid, event->fd, filename,
407 				event->event_len, event_fid->hdr.info_type,
408 				event_fid->hdr.len, fhlen);
409 		} else if (info_type != event_fid->hdr.info_type) {
410 			tst_res(TFAIL,
411 				"got event: mask=%llx pid=%u fd=%d, "
412 				"len=%d info_type=%d expected(%d) info_len=%d fh_len=%d",
413 				(unsigned long long)event->mask,
414 				(unsigned)event->pid, event->fd,
415 				event->event_len, event_fid->hdr.info_type,
416 				info_type, event_fid->hdr.len, fhlen);
417 		} else if (fhlen != expected_fid->handle.handle_bytes) {
418 			tst_res(TFAIL,
419 				"got event: mask=%llx pid=%u fd=%d name='%s' "
420 				"len=%d info_type=%d info_len=%d fh_len=%d expected(%d) "
421 				"fh_type=%d",
422 				(unsigned long long)event->mask,
423 				(unsigned)event->pid, event->fd, filename,
424 				event->event_len, info_type,
425 				event_fid->hdr.len, fhlen,
426 				expected_fid->handle.handle_bytes,
427 				file_handle->handle_type);
428 		} else if (file_handle->handle_type !=
429 			   expected_fid->handle.handle_type) {
430 			tst_res(TFAIL,
431 				"got event: mask=%llx pid=%u fd=%d name='%s' "
432 				"len=%d info_type=%d info_len=%d fh_len=%d "
433 				"fh_type=%d expected(%x)",
434 				(unsigned long long)event->mask,
435 				(unsigned)event->pid, event->fd, filename,
436 				event->event_len, info_type,
437 				event_fid->hdr.len, fhlen,
438 				file_handle->handle_type,
439 				expected_fid->handle.handle_type);
440 		} else if (memcmp(file_handle->f_handle,
441 				  expected_fid->handle.f_handle, fhlen)) {
442 			tst_res(TFAIL,
443 				"got event: mask=%llx pid=%u fd=%d name='%s' "
444 				"len=%d info_type=%d info_len=%d fh_len=%d "
445 				"fh_type=%d unexpected file handle (%x...)",
446 				(unsigned long long)event->mask,
447 				(unsigned)event->pid, event->fd, filename,
448 				event->event_len, info_type,
449 				event_fid->hdr.len, fhlen,
450 				file_handle->handle_type,
451 				*(int *)(file_handle->f_handle));
452 		} else if (memcmp(&event_fid->fsid, &expected_fid->fsid,
453 				  sizeof(event_fid->fsid)) != 0) {
454 			tst_res(TFAIL,
455 				"got event: mask=%llx pid=%u fd=%d name='%s' "
456 				"len=%d info_type=%d info_len=%d fh_len=%d "
457 				"fsid=%x.%x (expected %x.%x)",
458 				(unsigned long long)event->mask,
459 				(unsigned)event->pid, event->fd, filename,
460 				event->event_len, info_type,
461 				event_fid->hdr.len, fhlen,
462 				FSID_VAL_MEMBER(event_fid->fsid, 0),
463 				FSID_VAL_MEMBER(event_fid->fsid, 1),
464 				expected_fid->fsid.val[0],
465 				expected_fid->fsid.val[1]);
466 		} else if (strcmp(expected->name, filename)) {
467 			tst_res(TFAIL,
468 				"got event: mask=%llx "
469 				"pid=%u fd=%d name='%s' expected('%s') "
470 				"len=%d info_type=%d info_len=%d fh_len=%d",
471 				(unsigned long long)event->mask,
472 				(unsigned)event->pid, event->fd,
473 				filename, expected->name,
474 				event->event_len, event_fid->hdr.info_type,
475 				event_fid->hdr.len, fhlen);
476 		} else if (event->pid != getpid()) {
477 			tst_res(TFAIL,
478 				"got event: mask=%llx pid=%u "
479 				"(expected %u) fd=%d name='%s' "
480 				"len=%d info_type=%d info_len=%d fh_len=%d",
481 				(unsigned long long)event->mask,
482 				(unsigned)event->pid,
483 				(unsigned)getpid(),
484 				event->fd, filename,
485 				event->event_len, event_fid->hdr.info_type,
486 				event_fid->hdr.len, fhlen);
487 		} else if (!!child_fid != !!expected_child_fid) {
488 			tst_res(TFAIL,
489 				"got event: mask=%llx "
490 				"pid=%u fd=%d name='%s' num_info=%d (expected %d) "
491 				"len=%d info_type=%d info_len=%d fh_len=%d",
492 				(unsigned long long)event->mask,
493 				(unsigned)event->pid, event->fd,
494 				filename, 1 + !!child_fid, 1 + !!expected_child_fid,
495 				event->event_len, event_fid->hdr.info_type,
496 				event_fid->hdr.len, fhlen);
497 		} else if (child_fid) {
498 			tst_res(TINFO,
499 				"got event #%d: info #%d: info_type=%d info_len=%d fh_len=%d",
500 				test_num, info_id, event_fid->hdr.info_type,
501 				event_fid->hdr.len, fhlen);
502 
503 			/* Recheck event_fid match with child_fid */
504 			event_fid = child_fid;
505 			expected_fid = expected->child_fid;
506 			info_id = 1;
507 			info_type = FAN_EVENT_INFO_TYPE_FID;
508 			file_handle = (struct file_handle *)event_fid->handle;
509 			fhlen = file_handle->handle_bytes;
510 			child_fid = NULL;
511 			expected_child_fid = NULL;
512 			goto check_match;
513 		} else {
514 			tst_res(TPASS,
515 				"got event #%d: mask=%llx pid=%u fd=%d name='%s' "
516 				"len=%d; info #%d: info_type=%d info_len=%d fh_len=%d",
517 				test_num, (unsigned long long)event->mask,
518 				(unsigned)event->pid, event->fd, filename,
519 				event->event_len, info_id, event_fid->hdr.info_type,
520 				event_fid->hdr.len, fhlen);
521 		}
522 
523 		if (test_num < tst_count)
524 			test_num++;
525 
526 		if (mask_match) {
527 			/* In case of merged event match next expected mask */
528 			event->mask &= ~expected->mask | FAN_ONDIR;
529 			if (event->mask & ~FAN_ONDIR)
530 				continue;
531 		}
532 
533 		i += event->event_len;
534 		if (event->fd > 0)
535 			SAFE_CLOSE(event->fd);
536 	}
537 
538 	for (; test_num < tst_count; test_num++) {
539 		tst_res(TFAIL, "didn't get event: mask=%llx, name='%s'",
540 			 event_set[test_num].mask, event_set[test_num].name);
541 
542 	}
543 }
544 
setup(void)545 static void setup(void)
546 {
547 	REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_DIR_FID, MOUNT_PATH);
548 
549 	sprintf(dname1, "%s/%s", MOUNT_PATH, DIR_NAME1);
550 	sprintf(dname2, "%s/%s", MOUNT_PATH, DIR_NAME2);
551 	sprintf(fname1, "%s/%s", dname1, FILE_NAME1);
552 	sprintf(fname2, "%s/%s", dname1, FILE_NAME2);
553 }
554 
cleanup(void)555 static void cleanup(void)
556 {
557 	if (fd_notify > 0)
558 		SAFE_CLOSE(fd_notify);
559 }
560 
561 static struct tst_test test = {
562 	.test = do_test,
563 	.tcnt = ARRAY_SIZE(test_cases),
564 	.setup = setup,
565 	.cleanup = cleanup,
566 	.mount_device = 1,
567 	.mntpoint = MOUNT_PATH,
568 	.all_filesystems = 1,
569 	.needs_root = 1
570 };
571 
572 #else
573 	TST_TEST_TCONF("system does not have required name_to_handle_at() support");
574 #endif
575 #else
576 	TST_TEST_TCONF("system doesn't have required fanotify support");
577 #endif
578