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 * - FAN_REPORT_DFID_NAME_TARGET (dir fid + name + created/deleted file fid)
18 */
19
20#define _GNU_SOURCE
21#include "config.h"
22
23#include <stdio.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <errno.h>
27#include <string.h>
28#include <sys/mount.h>
29#include <sys/syscall.h>
30#include "tst_test.h"
31
32#ifdef HAVE_SYS_FANOTIFY_H
33#include "fanotify.h"
34
35#define EVENT_MAX 20
36
37/* Size of the event structure, not including file handle */
38#define EVENT_SIZE (sizeof(struct fanotify_event_metadata) + \
39		    sizeof(struct fanotify_event_info_fid))
40
41/* Tripple events buffer size to account for file handles and names */
42#define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE * 3)
43
44#define BUF_SIZE 256
45
46#ifdef HAVE_NAME_TO_HANDLE_AT
47struct event_t {
48	unsigned long long mask;
49	struct fanotify_fid_t *fid;
50	struct fanotify_fid_t *child_fid;
51	char name[BUF_SIZE];
52	char name2[BUF_SIZE];
53	char *old_name;
54	char *new_name;
55};
56
57static char fname1[BUF_SIZE + 11], fname2[BUF_SIZE + 11];
58static char dname1[BUF_SIZE], dname2[BUF_SIZE], tmpdir[BUF_SIZE];
59static int fd_notify;
60
61static struct event_t event_set[EVENT_MAX];
62
63static char event_buf[EVENT_BUF_LEN];
64
65#define DIR_NAME1 "test_dir1"
66#define DIR_NAME2 "test_dir2"
67#define FILE_NAME1 "test_file1"
68#define FILE_NAME2 "test_file2"
69#define MOUNT_PATH "fs_mnt"
70#define TEMP_DIR MOUNT_PATH "/temp_dir"
71
72static int fan_report_target_fid_unsupported;
73static int rename_events_unsupported;
74
75static struct test_case_t {
76	const char *tname;
77	struct fanotify_group_type group;
78	struct fanotify_mark_type mark;
79	unsigned long mask;
80	struct fanotify_mark_type sub_mark;
81	unsigned long sub_mask;
82	unsigned long tmpdir_ignored_mask;
83} test_cases[] = {
84	{
85		"FAN_REPORT_DFID_NAME monitor filesystem for create/delete/move/open/close",
86		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME),
87		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
88		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
89		/* Mount watch for events possible on children */
90		INIT_FANOTIFY_MARK_TYPE(MOUNT),
91		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
92		0,
93	},
94	{
95		"FAN_REPORT_DFID_NAME monitor directories for create/delete/move/open/close",
96		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME),
97		INIT_FANOTIFY_MARK_TYPE(INODE),
98		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
99		/* Watches for self events on subdir and events on subdir's children */
100		INIT_FANOTIFY_MARK_TYPE(INODE),
101		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
102		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
103		0,
104	},
105	{
106		"FAN_REPORT_DIR_FID monitor filesystem for create/delete/move/open/close",
107		INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID),
108		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
109		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
110		/* Mount watch for events possible on children */
111		INIT_FANOTIFY_MARK_TYPE(MOUNT),
112		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
113		0,
114	},
115	{
116		"FAN_REPORT_DIR_FID monitor directories for create/delete/move/open/close",
117		INIT_FANOTIFY_GROUP_TYPE(REPORT_DIR_FID),
118		INIT_FANOTIFY_MARK_TYPE(INODE),
119		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
120		/* Watches for self events on subdir and events on subdir's children */
121		INIT_FANOTIFY_MARK_TYPE(INODE),
122		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
123		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
124		0,
125	},
126	{
127		"FAN_REPORT_DFID_FID monitor filesystem for create/delete/move/open/close",
128		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID),
129		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
130		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
131		/* Mount watch for events possible on children */
132		INIT_FANOTIFY_MARK_TYPE(MOUNT),
133		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
134		0,
135	},
136	{
137		"FAN_REPORT_DFID_FID monitor directories for create/delete/move/open/close",
138		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_FID),
139		INIT_FANOTIFY_MARK_TYPE(INODE),
140		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
141		/* Watches for self events on subdir and events on subdir's children */
142		INIT_FANOTIFY_MARK_TYPE(INODE),
143		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
144		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
145		0,
146	},
147	{
148		"FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/open/close",
149		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
150		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
151		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
152		/* Mount watch for events possible on children */
153		INIT_FANOTIFY_MARK_TYPE(MOUNT),
154		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
155		0,
156	},
157	{
158		"FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/open/close",
159		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
160		INIT_FANOTIFY_MARK_TYPE(INODE),
161		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
162		/* Watches for self events on subdir and events on subdir's children */
163		INIT_FANOTIFY_MARK_TYPE(INODE),
164		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
165		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
166		0,
167	},
168	{
169		"FAN_REPORT_DFID_NAME_TARGET monitor filesystem for create/delete/move/open/close",
170		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
171		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
172		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
173		/* Mount watch for events possible on children */
174		INIT_FANOTIFY_MARK_TYPE(MOUNT),
175		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
176		0,
177	},
178	{
179		"FAN_REPORT_DFID_NAME_TARGET monitor directories for create/delete/move/open/close",
180		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
181		INIT_FANOTIFY_MARK_TYPE(INODE),
182		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR,
183		/* Watches for self events on subdir and events on subdir's children */
184		INIT_FANOTIFY_MARK_TYPE(INODE),
185		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
186		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
187		0,
188	},
189	{
190		"FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/rename/open/close",
191		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
192		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
193		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
194		/* Mount watch for events possible on children */
195		INIT_FANOTIFY_MARK_TYPE(MOUNT),
196		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
197		0,
198	},
199	{
200		"FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/rename/open/close",
201		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
202		INIT_FANOTIFY_MARK_TYPE(INODE),
203		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR,
204		/* Watches for self events on subdir and events on subdir's children */
205		INIT_FANOTIFY_MARK_TYPE(INODE),
206		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
207		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
208		0,
209	},
210	{
211		"FAN_REPORT_DFID_NAME_TARGET monitor filesystem for create/delete/move/rename/open/close",
212		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
213		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
214		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
215		/* Mount watch for events possible on children */
216		INIT_FANOTIFY_MARK_TYPE(MOUNT),
217		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
218		0,
219	},
220	{
221		"FAN_REPORT_DFID_NAME_TARGET monitor directories for create/delete/move/rename/open/close",
222		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET),
223		INIT_FANOTIFY_MARK_TYPE(INODE),
224		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR,
225		/* Watches for self events on subdir and events on subdir's children */
226		INIT_FANOTIFY_MARK_TYPE(INODE),
227		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
228		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
229		0,
230	},
231	{
232		"FAN_REPORT_DFID_NAME_FID monitor directories and ignore FAN_RENAME events to/from temp directory",
233		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
234		INIT_FANOTIFY_MARK_TYPE(INODE),
235		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR,
236		/* Watches for self events on subdir and events on subdir's children */
237		INIT_FANOTIFY_MARK_TYPE(INODE),
238		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR |
239		FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD,
240		/* Ignore FAN_RENAME to/from tmpdir */
241		FAN_MOVE | FAN_RENAME,
242	},
243	{
244		"FAN_REPORT_DFID_NAME_FID monitor filesystem and ignore FAN_RENAME events to/from temp directory",
245		INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID),
246		INIT_FANOTIFY_MARK_TYPE(FILESYSTEM),
247		FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR,
248		/* Mount watch for events possible on children */
249		INIT_FANOTIFY_MARK_TYPE(MOUNT),
250		FAN_OPEN | FAN_CLOSE | FAN_ONDIR,
251		/* Ignore FAN_RENAME to/from tmpdir */
252		FAN_MOVE | FAN_RENAME,
253	},
254};
255
256static void do_test(unsigned int number)
257{
258	int fd, dirfd, len = 0, i = 0, test_num = 0, tst_count = 0;
259	struct test_case_t *tc = &test_cases[number];
260	struct fanotify_group_type *group = &tc->group;
261	struct fanotify_mark_type *mark = &tc->mark;
262	struct fanotify_mark_type *sub_mark = &tc->sub_mark;
263	struct fanotify_fid_t root_fid, dir_fid, file_fid;
264	struct fanotify_fid_t *child_fid = NULL, *subdir_fid = NULL;
265	int report_name = (group->flag & FAN_REPORT_NAME);
266	int report_target_fid = (group->flag & FAN_REPORT_TARGET_FID);
267	int report_rename = (tc->mask & FAN_RENAME);
268	int fs_mark = (mark->flag == FAN_MARK_FILESYSTEM);
269	int rename_ignored = (tc->tmpdir_ignored_mask & FAN_RENAME);
270
271	tst_res(TINFO, "Test #%d: %s", number, tc->tname);
272
273	if (report_rename && rename_events_unsupported) {
274		tst_res(TCONF, "FAN_RENAME not supported in kernel?");
275		return;
276	}
277
278	if (fan_report_target_fid_unsupported && report_target_fid) {
279		FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_TARGET_FID,
280					    fan_report_target_fid_unsupported);
281		return;
282	}
283
284	fd_notify = SAFE_FANOTIFY_INIT(group->flag, 0);
285
286	/*
287	 * Watch dir modify events with name in filesystem/dir
288	 */
289	SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | mark->flag, tc->mask,
290			   AT_FDCWD, MOUNT_PATH);
291
292	/* Save the mount root fid */
293	fanotify_save_fid(MOUNT_PATH, &root_fid);
294
295	/*
296	 * Create subdir and watch open events "on children" with name.
297	 * Make it a mount root.
298	 */
299	SAFE_MKDIR(dname1, 0755);
300	SAFE_MOUNT(dname1, dname1, "none", MS_BIND, NULL);
301
302	/* Save the subdir fid */
303	fanotify_save_fid(dname1, &dir_fid);
304	/* With FAN_REPORT_TARGET_FID, report subdir fid also for dirent events */
305	if (report_target_fid)
306		subdir_fid = &dir_fid;
307
308	if (tc->sub_mask)
309		SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | sub_mark->flag,
310				   tc->sub_mask, AT_FDCWD, dname1);
311	/*
312	 * ignore FAN_RENAME to/from tmpdir, so we won't get the FAN_RENAME events
313	 * when subdir is moved via tmpdir.
314	 * FAN_MOVE is also set in ignored mark of tmpdir, but it will have no effect
315	 * and the MOVED_FROM/TO events will still be reported.
316	 */
317	if (tc->tmpdir_ignored_mask)
318		SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD |
319				   FAN_MARK_IGNORED_MASK |
320				   FAN_MARK_IGNORED_SURV_MODIFY,
321				   tc->tmpdir_ignored_mask, AT_FDCWD, TEMP_DIR);
322
323	memset(event_set, 0, sizeof(event_set));
324	event_set[tst_count].mask = FAN_CREATE | FAN_ONDIR;
325	event_set[tst_count].fid = &root_fid;
326	event_set[tst_count].child_fid = subdir_fid;
327	strcpy(event_set[tst_count].name, DIR_NAME1);
328	tst_count++;
329
330	/* Generate modify events "on child" */
331	fd = SAFE_CREAT(fname1, 0755);
332
333	/* Save the file fid */
334	fanotify_save_fid(fname1, &file_fid);
335	/* With FAN_REPORT_TARGET_FID, report child fid also for dirent events */
336	if (report_target_fid)
337		child_fid = &file_fid;
338
339	SAFE_WRITE(SAFE_WRITE_ALL, fd, "1", 1);
340	SAFE_RENAME(fname1, fname2);
341
342	SAFE_CLOSE(fd);
343
344	/* Generate delete events with fname2 */
345	SAFE_UNLINK(fname2);
346
347	/* Read events on files in subdir */
348	len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len);
349
350	/*
351	 * FAN_CREATE|FAN_DELETE|FAN_MOVE events with the same name are merged.
352	 */
353	event_set[tst_count].mask = FAN_CREATE | FAN_MOVED_FROM;
354	event_set[tst_count].fid = &dir_fid;
355	event_set[tst_count].child_fid = child_fid;
356	strcpy(event_set[tst_count].name, FILE_NAME1);
357	tst_count++;
358	/*
359	 * Event on non-dir child with the same name may be merged with the
360	 * directory entry modification events above, unless FAN_REPORT_FID is
361	 * set and child fid is reported. If FAN_REPORT_FID is set but
362	 * FAN_REPORT_NAME is not set, then FAN_CREATE above is merged with
363	 * FAN_DELETE below and FAN_OPEN will be merged with FAN_CLOSE.
364	 */
365	if (report_name) {
366		event_set[tst_count].mask = FAN_OPEN;
367		event_set[tst_count].fid = &dir_fid;
368		event_set[tst_count].child_fid = &file_fid;
369		strcpy(event_set[tst_count].name, FILE_NAME1);
370		tst_count++;
371	}
372	/*
373	 * FAN_RENAME event is independent of MOVED_FROM/MOVED_TO and not merged
374	 * with any other event because it has different info records.
375	 */
376	if (report_rename) {
377		event_set[tst_count].mask = FAN_RENAME;
378		event_set[tst_count].fid = &dir_fid;
379		event_set[tst_count].child_fid = child_fid;
380		strcpy(event_set[tst_count].name, FILE_NAME1);
381		strcpy(event_set[tst_count].name2, FILE_NAME2);
382		event_set[tst_count].old_name = event_set[tst_count].name;
383		event_set[tst_count].new_name = event_set[tst_count].name2;
384		tst_count++;
385	}
386
387	event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO;
388	/*
389	 * With FAN_REPORT_TARGET_FID, close of FILE_NAME2 is merged with
390	 * moved_to and delete events, because they all have parent and
391	 * child fid records.
392	 */
393	if (report_target_fid)
394		event_set[tst_count].mask |= FAN_CLOSE_WRITE;
395	event_set[tst_count].fid = &dir_fid;
396	event_set[tst_count].child_fid = child_fid;
397	strcpy(event_set[tst_count].name, FILE_NAME2);
398	tst_count++;
399	/*
400	 * When not reporting name, open of FILE_NAME1 is merged
401	 * with close of FILE_NAME2.
402	 */
403	if (!report_name) {
404		event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_WRITE;
405		event_set[tst_count].fid = &dir_fid;
406		event_set[tst_count].child_fid = &file_fid;
407		strcpy(event_set[tst_count].name, "");
408		tst_count++;
409	}
410	/*
411	 * Directory watch does not get self events on children.
412	 * Filesystem watch gets self event w/o name info if FAN_REPORT_FID
413	 * is set.
414	 */
415	if (fs_mark && (group->flag & FAN_REPORT_FID)) {
416		event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF;
417		event_set[tst_count].fid = &file_fid;
418		event_set[tst_count].child_fid = NULL;
419		strcpy(event_set[tst_count].name, "");
420		tst_count++;
421	}
422	/*
423	 * Without FAN_REPORT_TARGET_FID, close of FILE_NAME2 is not merged with
424	 * open of FILE_NAME1 and it is received after the merged self events.
425	 */
426	if (report_name && !report_target_fid) {
427		event_set[tst_count].mask = FAN_CLOSE_WRITE;
428		event_set[tst_count].fid = &dir_fid;
429		event_set[tst_count].child_fid = &file_fid;
430		strcpy(event_set[tst_count].name, FILE_NAME2);
431		tst_count++;
432	}
433
434	dirfd = SAFE_OPEN(dname1, O_RDONLY | O_DIRECTORY);
435	SAFE_CLOSE(dirfd);
436
437	SAFE_UMOUNT(dname1);
438
439	/*
440	 * Directory watch gets open/close events on itself and on its subdirs.
441	 * Filesystem watch gets open/close event on all directories with name ".".
442	 */
443	event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_NOWRITE | FAN_ONDIR;
444	event_set[tst_count].fid = &dir_fid;
445	event_set[tst_count].child_fid = NULL;
446	strcpy(event_set[tst_count].name, ".");
447	tst_count++;
448	/*
449	 * Directory watch gets self event on itself and filesystem watch gets
450	 * self event on all directories with name ".".
451	 */
452	event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR;
453	event_set[tst_count].fid = &dir_fid;
454	event_set[tst_count].child_fid = NULL;
455	strcpy(event_set[tst_count].name, ".");
456	tst_count++;
457
458	/*
459	 * If only root dir and subdir are watched, a rename via an unwatched tmpdir
460	 * will observe the same MOVED_FROM/MOVED_TO events as a direct rename,
461	 * but will observe 2 FAN_RENAME events with 1 info dir+name record each
462	 * instead of 1 FAN_RENAME event with 2 dir+name info records.
463	 *
464	 * If tmpdir is ignoring FAN_RENAME, we will get the MOVED_FROM/MOVED_TO
465	 * events and will not get the FAN_RENAME event for rename via tmpdir.
466	 */
467	if (!fs_mark || rename_ignored) {
468		SAFE_RENAME(dname1, tmpdir);
469		SAFE_RENAME(tmpdir, dname2);
470	} else {
471		SAFE_RENAME(dname1, dname2);
472	}
473	SAFE_RMDIR(dname2);
474
475	/* Read more events on dirs */
476	len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len);
477
478	/*
479	 * FAN_RENAME event is independent of MOVED_FROM/MOVED_TO and not merged
480	 * with any other event because it has different info records.
481	 * When renamed via an unwatched tmpdir, the 1st FAN_RENAME event has the
482	 * info record of root_fid+DIR_NAME1 and the 2nd FAN_RENAME event has the
483	 * info record of root_fid+DIR_NAME2.
484	 * If tmpdir is ignoring FAN_RENAME, we get no FAN_RENAME events at all.
485	 */
486	if (report_rename && !rename_ignored) {
487		event_set[tst_count].mask = FAN_RENAME | FAN_ONDIR;
488		event_set[tst_count].fid = &root_fid;
489		event_set[tst_count].child_fid = subdir_fid;
490		strcpy(event_set[tst_count].name, DIR_NAME1);
491		event_set[tst_count].old_name = event_set[tst_count].name;
492		if (fs_mark) {
493			strcpy(event_set[tst_count].name2, DIR_NAME2);
494			event_set[tst_count].new_name = event_set[tst_count].name2;
495		}
496		tst_count++;
497	}
498	event_set[tst_count].mask = FAN_MOVED_FROM | FAN_ONDIR;
499	event_set[tst_count].fid = &root_fid;
500	event_set[tst_count].child_fid = subdir_fid;
501	strcpy(event_set[tst_count].name, DIR_NAME1);
502	tst_count++;
503	if (report_rename && !fs_mark && !rename_ignored) {
504		event_set[tst_count].mask = FAN_RENAME | FAN_ONDIR;
505		event_set[tst_count].fid = &root_fid;
506		event_set[tst_count].child_fid = subdir_fid;
507		strcpy(event_set[tst_count].name, DIR_NAME2);
508		event_set[tst_count].new_name = event_set[tst_count].name;
509		tst_count++;
510	}
511	event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO | FAN_ONDIR;
512	event_set[tst_count].fid = &root_fid;
513	event_set[tst_count].child_fid = subdir_fid;
514	strcpy(event_set[tst_count].name, DIR_NAME2);
515	tst_count++;
516	/* Expect no more events */
517	event_set[tst_count].mask = 0;
518
519	/*
520	 * Cleanup the marks
521	 */
522	SAFE_CLOSE(fd_notify);
523	fd_notify = -1;
524
525	while (i < len) {
526		struct event_t *expected = &event_set[test_num];
527		struct fanotify_event_metadata *event;
528		struct fanotify_event_info_fid *event_fid;
529		struct fanotify_event_info_fid *child_fid;
530		struct fanotify_fid_t *expected_fid = expected->fid;
531		struct fanotify_fid_t *expected_child_fid = expected->child_fid;
532		struct file_handle *file_handle;
533		unsigned int fhlen;
534		const char *filename;
535		int namelen, info_type, mask_match, info_id = 0;
536
537		event = (struct fanotify_event_metadata *)&event_buf[i];
538		event_fid = (struct fanotify_event_info_fid *)(event + 1);
539		file_handle = (struct file_handle *)event_fid->handle;
540		fhlen = file_handle->handle_bytes;
541		filename = (char *)file_handle->f_handle + fhlen;
542		child_fid = (void *)((char *)event_fid + event_fid->hdr.len);
543		namelen = (char *)child_fid - (char *)filename;
544		/* End of event_fid could have name, zero padding, both or none */
545		if (namelen > 0) {
546			namelen = strlen(filename);
547		} else {
548			filename = "";
549			namelen = 0;
550		}
551		/* Is there a child fid after first fid record? */
552		if (((char *)child_fid - (char *)event) >= event->event_len)
553			child_fid = NULL;
554
555		if (!(group->flag & FAN_REPORT_FID))
556			expected_child_fid = NULL;
557
558		if (!report_name)
559			expected->name[0] = 0;
560
561		if (expected->mask & FAN_RENAME) {
562			/* If old name is not reported, first record is new name */
563			info_type = expected->old_name ?
564				FAN_EVENT_INFO_TYPE_OLD_DFID_NAME :
565				FAN_EVENT_INFO_TYPE_NEW_DFID_NAME;
566			/* The 2nd fid is same as 1st becaue we rename in same parent */
567			if (expected->name2[0])
568				expected_child_fid = expected_fid;
569		} else if (expected->name[0]) {
570			info_type = FAN_EVENT_INFO_TYPE_DFID_NAME;
571		} else if (expected->mask & FAN_ONDIR) {
572			info_type = FAN_EVENT_INFO_TYPE_DFID;
573		} else if (expected->mask & (FAN_DELETE_SELF | FAN_MOVE_SELF)) {
574			/* Self event on non-dir has only child fid */
575			info_type = FAN_EVENT_INFO_TYPE_FID;
576		} else {
577			info_type = FAN_EVENT_INFO_TYPE_DFID;
578		}
579
580		/*
581		 * Event may contain more than the expected mask, but it must
582		 * have all the bits in expected mask.
583		 * Expected event on dir must not get event on non dir and the
584		 * other way around.
585		 */
586		mask_match = ((event->mask & expected->mask) &&
587			      !(expected->mask & ~event->mask) &&
588			      !((event->mask ^ expected->mask) & FAN_ONDIR));
589
590check_match:
591		if (test_num >= tst_count) {
592			tst_res(TFAIL,
593				"got unnecessary event: mask=%llx "
594				"pid=%u fd=%d name='%s' "
595				"len=%d info_type=%d info_len=%d fh_len=%d",
596				(unsigned long long)event->mask,
597				(unsigned int)event->pid, event->fd, filename,
598				event->event_len, event_fid->hdr.info_type,
599				event_fid->hdr.len, fhlen);
600		} else if (!fhlen || namelen < 0) {
601			tst_res(TFAIL,
602				"got event without fid: mask=%llx pid=%u fd=%d, "
603				"len=%d info_type=%d info_len=%d fh_len=%d",
604				(unsigned long long)event->mask,
605				(unsigned int)event->pid, event->fd,
606				event->event_len, event_fid->hdr.info_type,
607				event_fid->hdr.len, fhlen);
608		} else if (!mask_match) {
609			tst_res(TFAIL,
610				"got event: mask=%llx (expected %llx) "
611				"pid=%u fd=%d name='%s' "
612				"len=%d info_type=%d info_len=%d fh_len=%d",
613				(unsigned long long)event->mask, expected->mask,
614				(unsigned int)event->pid, event->fd, filename,
615				event->event_len, event_fid->hdr.info_type,
616				event_fid->hdr.len, fhlen);
617		} else if (info_type != event_fid->hdr.info_type) {
618			tst_res(TFAIL,
619				"got event: mask=%llx pid=%u fd=%d, "
620				"len=%d info_type=%d expected(%d) info_len=%d fh_len=%d",
621				(unsigned long long)event->mask,
622				(unsigned int)event->pid, event->fd,
623				event->event_len, event_fid->hdr.info_type,
624				info_type, event_fid->hdr.len, fhlen);
625		} else if (fhlen != expected_fid->handle.handle_bytes) {
626			tst_res(TFAIL,
627				"got event: mask=%llx pid=%u fd=%d name='%s' "
628				"len=%d info_type=%d info_len=%d fh_len=%d expected(%d) "
629				"fh_type=%d",
630				(unsigned long long)event->mask,
631				(unsigned int)event->pid, event->fd, filename,
632				event->event_len, info_type,
633				event_fid->hdr.len, fhlen,
634				expected_fid->handle.handle_bytes,
635				file_handle->handle_type);
636		} else if (file_handle->handle_type !=
637			   expected_fid->handle.handle_type) {
638			tst_res(TFAIL,
639				"got event: mask=%llx pid=%u fd=%d name='%s' "
640				"len=%d info_type=%d info_len=%d fh_len=%d "
641				"fh_type=%d expected(%x)",
642				(unsigned long long)event->mask,
643				(unsigned int)event->pid, event->fd, filename,
644				event->event_len, info_type,
645				event_fid->hdr.len, fhlen,
646				file_handle->handle_type,
647				expected_fid->handle.handle_type);
648		} else if (memcmp(file_handle->f_handle,
649				  expected_fid->handle.f_handle, fhlen)) {
650			tst_res(TFAIL,
651				"got event: mask=%llx pid=%u fd=%d name='%s' "
652				"len=%d info_type=%d info_len=%d fh_len=%d "
653				"fh_type=%d unexpected file handle (%x...)",
654				(unsigned long long)event->mask,
655				(unsigned int)event->pid, event->fd, filename,
656				event->event_len, info_type,
657				event_fid->hdr.len, fhlen,
658				file_handle->handle_type,
659				*(int *)(file_handle->f_handle));
660		} else if (memcmp(&event_fid->fsid, &expected_fid->fsid,
661				  sizeof(event_fid->fsid)) != 0) {
662			tst_res(TFAIL,
663				"got event: mask=%llx pid=%u fd=%d name='%s' "
664				"len=%d info_type=%d info_len=%d fh_len=%d "
665				"fsid=%x.%x (expected %x.%x)",
666				(unsigned long long)event->mask,
667				(unsigned int)event->pid, event->fd, filename,
668				event->event_len, info_type,
669				event_fid->hdr.len, fhlen,
670				FSID_VAL_MEMBER(event_fid->fsid, 0),
671				FSID_VAL_MEMBER(event_fid->fsid, 1),
672				expected_fid->fsid.val[0],
673				expected_fid->fsid.val[1]);
674		} else if (strcmp(expected->name, filename)) {
675			tst_res(TFAIL,
676				"got event: mask=%llx "
677				"pid=%u fd=%d name='%s' expected('%s') "
678				"len=%d info_type=%d info_len=%d fh_len=%d",
679				(unsigned long long)event->mask,
680				(unsigned int)event->pid, event->fd,
681				filename, expected->name,
682				event->event_len, event_fid->hdr.info_type,
683				event_fid->hdr.len, fhlen);
684		} else if (event->pid != getpid()) {
685			tst_res(TFAIL,
686				"got event: mask=%llx pid=%u "
687				"(expected %u) fd=%d name='%s' "
688				"len=%d info_type=%d info_len=%d fh_len=%d",
689				(unsigned long long)event->mask,
690				(unsigned int)event->pid,
691				(unsigned int)getpid(),
692				event->fd, filename,
693				event->event_len, event_fid->hdr.info_type,
694				event_fid->hdr.len, fhlen);
695		} else if (!!child_fid != !!expected_child_fid) {
696			tst_res(TFAIL,
697				"got event: mask=%llx "
698				"pid=%u fd=%d name='%s' num_info=%d (expected %d) "
699				"len=%d info_type=%d info_len=%d fh_len=%d",
700				(unsigned long long)event->mask,
701				(unsigned int)event->pid, event->fd,
702				filename, 1 + !!child_fid, 1 + !!expected_child_fid,
703				event->event_len, event_fid->hdr.info_type,
704				event_fid->hdr.len, fhlen);
705		} else if (child_fid) {
706			tst_res(TINFO,
707				"got event #%d: info #%d: info_type=%d info_len=%d fh_len=%d",
708				test_num, info_id, event_fid->hdr.info_type,
709				event_fid->hdr.len, fhlen);
710
711			/* Recheck event_fid match with child_fid */
712			event_fid = child_fid;
713			expected_fid = expected->child_fid;
714			info_id = 1;
715			info_type = FAN_EVENT_INFO_TYPE_FID;
716			/*
717			 * With FAN_RENAME event, expect a second record of
718			 * type NEW_DFID_NAME, which in our case
719			 * has the same fid as the source dir in 1st record.
720			 * TODO: check the 2nd name and the 3rd child fid record.
721			 */
722			if (event->mask & FAN_RENAME && expected->name2[0]) {
723				info_type = FAN_EVENT_INFO_TYPE_NEW_DFID_NAME;
724				expected_fid = expected->fid;
725			}
726			file_handle = (struct file_handle *)event_fid->handle;
727			fhlen = file_handle->handle_bytes;
728			child_fid = NULL;
729			expected_child_fid = NULL;
730			goto check_match;
731		} else {
732			tst_res(TPASS,
733				"got event #%d: mask=%llx pid=%u fd=%d name='%s' "
734				"len=%d; info #%d: info_type=%d info_len=%d fh_len=%d",
735				test_num, (unsigned long long)event->mask,
736				(unsigned int)event->pid, event->fd, filename,
737				event->event_len, info_id, event_fid->hdr.info_type,
738				event_fid->hdr.len, fhlen);
739		}
740
741		if (test_num < tst_count)
742			test_num++;
743
744		if (mask_match) {
745			/* In case of merged event match next expected mask */
746			event->mask &= ~expected->mask | FAN_ONDIR;
747			if (event->mask & ~FAN_ONDIR)
748				continue;
749		}
750
751		i += event->event_len;
752		if (event->fd > 0)
753			SAFE_CLOSE(event->fd);
754	}
755
756	for (; test_num < tst_count; test_num++) {
757		tst_res(TFAIL, "didn't get event: mask=%llx, name='%s'",
758			 event_set[test_num].mask, event_set[test_num].name);
759
760	}
761}
762
763static void setup(void)
764{
765	REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_DIR_FID, MOUNT_PATH);
766	fan_report_target_fid_unsupported =
767		fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME_TARGET, MOUNT_PATH);
768	rename_events_unsupported =
769		fanotify_events_supported_by_kernel(FAN_RENAME, FAN_REPORT_DFID_NAME, 0);
770
771	SAFE_MKDIR(TEMP_DIR, 0755);
772	sprintf(dname1, "%s/%s", MOUNT_PATH, DIR_NAME1);
773	sprintf(dname2, "%s/%s", MOUNT_PATH, DIR_NAME2);
774	sprintf(tmpdir, "%s/%s", TEMP_DIR, DIR_NAME2);
775	sprintf(fname1, "%s/%s", dname1, FILE_NAME1);
776	sprintf(fname2, "%s/%s", dname1, FILE_NAME2);
777}
778
779static void cleanup(void)
780{
781	if (fd_notify > 0)
782		SAFE_CLOSE(fd_notify);
783}
784
785static struct tst_test test = {
786	.test = do_test,
787	.tcnt = ARRAY_SIZE(test_cases),
788	.setup = setup,
789	.cleanup = cleanup,
790	.mount_device = 1,
791	.mntpoint = MOUNT_PATH,
792	.all_filesystems = 1,
793	.needs_root = 1
794};
795
796#else
797	TST_TEST_TCONF("system does not have required name_to_handle_at() support");
798#endif
799#else
800	TST_TEST_TCONF("system doesn't have required fanotify support");
801#endif
802