On Wed 20-11-13 22:48:57, [email protected] wrote:
> > > > +               /* If we expected failure there's nothing to clean up */
> > > > +               if (expect == -1)
> > > > +                       return;
> > > > +
> > > > +               if (test_event)
> > > > +                       test_event(file);
> > > > +
> > > > +               if (myfanotify_mark(fd_notify, FAN_MARK_REMOVE | flag,
> > > > +                                   FAN_OPEN, AT_FDCWD, file) < 0) {
> > > > +                       tst_brkm(TBROK | TERRNO, cleanup,
> > > > +                           "fanotify_mark (%d, FAN_MARK_REMOVE | %s, "
> > > > +                           "FAN_OPEN, AT_FDCWD, \"%s\") failed",
> > > > +                           fd_notify, flagstr, file);
> > > > +               }
> > > > +       }
> > > > +}
> > > > +
> > > > +#define check_mark(file, flag, expect, func) __check_mark(file, flag, 
> > > > #flag, expect, func)
> > > > +
> > > > +static void __do_open(char *file, int flag, char *flagstr)
> > > > +{
> > > > +       int fd;
> > > > +
> > > > +       if ((fd = open(file, O_RDONLY | flag)) < 0) {
> > > > +               tst_brkm(TBROK | TERRNO, cleanup,
> > > > +                   "open(%s, O_RDONLY | %s) failed", file, flagstr);
> > > > +       }
> > > > +       if (close(fd) < 0) {
> > > > +               tst_brkm(TBROK | TERRNO, cleanup,
> > > > +                   "close(%s) failed", file);
> > > > +       }
> > > > +}
> > > 
> > > We don't use identificators with double underscores in userspace, these
> > > are reserved for glibc and may cause failures in future. Especially
> > > names like __do_open may clash.
> >   Ah right, didn't write anything serious in userspace for a while :) I've
> > changed that to a single underscore.
> 
> That wouldn't do either, I've looked up the GNU manual that says that
> all functions or variables that begin with underscore are reserved.
> 
> http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html
  Ok, ok. I've got rid of the undescores completely.

> I will look at the v2 patch tomorrow.
  Don't bother, attached is v3 with underscores fixed and I also fixed that
signal handling stuff in fanotify03.c.

                                                                Honza
-- 
Jan Kara <[email protected]>
SUSE Labs, CR
>From aa8b5e7caf0c8360283c77ec1882d98025079c5e Mon Sep 17 00:00:00 2001
From: Jan Kara <[email protected]>
Date: Wed, 20 Nov 2013 00:06:47 +0100
Subject: [PATCH] fanotify: Add tests verifying fanotify syscalls

Signed-off-by: Jan Kara <[email protected]>
---
 configure.ac                                    |   1 +
 runtest/syscalls                                |   5 +
 testcases/kernel/syscalls/fanotify/Makefile     |  23 ++
 testcases/kernel/syscalls/fanotify/fanotify.h   |  39 +++
 testcases/kernel/syscalls/fanotify/fanotify01.c | 375 ++++++++++++++++++++++++
 testcases/kernel/syscalls/fanotify/fanotify02.c | 263 +++++++++++++++++
 testcases/kernel/syscalls/fanotify/fanotify03.c | 320 ++++++++++++++++++++
 testcases/kernel/syscalls/fanotify/fanotify04.c | 306 +++++++++++++++++++
 8 files changed, 1332 insertions(+)
 create mode 100644 testcases/kernel/syscalls/fanotify/Makefile
 create mode 100644 testcases/kernel/syscalls/fanotify/fanotify.h
 create mode 100644 testcases/kernel/syscalls/fanotify/fanotify01.c
 create mode 100644 testcases/kernel/syscalls/fanotify/fanotify02.c
 create mode 100644 testcases/kernel/syscalls/fanotify/fanotify03.c
 create mode 100644 testcases/kernel/syscalls/fanotify/fanotify04.c

diff --git a/configure.ac b/configure.ac
index 940f4f7bd757..4846afd35d93 100644
--- a/configure.ac
+++ b/configure.ac
@@ -43,6 +43,7 @@ AC_CHECK_HEADERS([ \
     linux/netlink.h \
     sys/epoll.h \
     sys/inotify.h \
+    sys/fanotify.h \
     sys/jfsdmapi.h \
     sys/prctl.h \
 ])
diff --git a/runtest/syscalls b/runtest/syscalls
index fa01ff73f3e8..12bae109729d 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -438,6 +438,11 @@ inotify02 inotify02
 inotify03 inotify03 -D DEVICE -T DEVICE_FS_TYPE
 inotify04 inotify04
 
+fanotify01 fanotify01
+fanotify02 fanotify02
+fanotify03 fanotify03
+fanotify04 fanotify04
+
 ioperm01 ioperm01
 ioperm02 ioperm02
 
diff --git a/testcases/kernel/syscalls/fanotify/Makefile b/testcases/kernel/syscalls/fanotify/Makefile
new file mode 100644
index 000000000000..bb58878d7b1c
--- /dev/null
+++ b/testcases/kernel/syscalls/fanotify/Makefile
@@ -0,0 +1,23 @@
+#
+#  Copyright (c) Jan Kara <[email protected]>, 2013
+#
+#  This program is free software;  you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY;  without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
+#  the GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program;  if not, write to the Free Software
+#  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+#
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/fanotify/fanotify.h b/testcases/kernel/syscalls/fanotify/fanotify.h
new file mode 100644
index 000000000000..436e67da8945
--- /dev/null
+++ b/testcases/kernel/syscalls/fanotify/fanotify.h
@@ -0,0 +1,39 @@
+/*
+ * fanotify testcase common definitions.
+ *
+ * Copyright (c) 2012 Linux Test Project.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Jan Kara, November 2013
+ */
+
+#ifndef	_FANOTIFY_H
+#define	_FANOTIFY_H
+
+/* fanotify(7) wrappers */
+
+#define	myfanotify_init(flags, event_f_flags) \
+	syscall(__NR_fanotify_init, flags, event_f_flags)
+
+#define	myfanotify_mark(fd, flags, mask, dfd, pathname)	\
+	syscall(__NR_fanotify_mark, fd, flags, mask, dfd, pathname)
+
+#endif /* _FANOTIFY_H */
diff --git a/testcases/kernel/syscalls/fanotify/fanotify01.c b/testcases/kernel/syscalls/fanotify/fanotify01.c
new file mode 100644
index 000000000000..4d2468115f2b
--- /dev/null
+++ b/testcases/kernel/syscalls/fanotify/fanotify01.c
@@ -0,0 +1,375 @@
+/*
+ * Copyright (c) 2013 SUSE.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Started by Jan Kara <[email protected]>
+ *
+ * DESCRIPTION
+ *     Check that fanotify work for a file
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include "test.h"
+#include "usctest.h"
+#include "linux_syscall_numbers.h"
+#include "fanotify.h"
+#include "safe_macros.h"
+
+char *TCID = "fanotify01";
+int TST_TOTAL = 12;
+
+#if defined(HAVE_SYS_FANOTIFY_H)
+#include <sys/fanotify.h>
+
+#define EVENT_MAX 1024
+/* size of the event structure, not counting name */
+#define EVENT_SIZE  (sizeof (struct fanotify_event_metadata))
+/* reasonable guess as to size of 1024 events */
+#define EVENT_BUF_LEN        (EVENT_MAX * EVENT_SIZE)
+
+static void setup(void);
+static void cleanup(void);
+
+#define BUF_SIZE 256
+static char fname[BUF_SIZE];
+static char buf[BUF_SIZE];
+static int fd, fd_notify;
+
+static unsigned long long event_set[EVENT_MAX];
+
+static char event_buf[EVENT_BUF_LEN];
+
+int main(int ac, char **av)
+{
+	int lc;
+	char *msg;
+
+	if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
+		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+
+	setup();
+
+	for (lc = 0; TEST_LOOPING(lc); lc++) {
+		int ret, len, i = 0, test_num = 0;
+
+		tst_count = 0;
+
+		if (myfanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS | FAN_MODIFY |
+				    FAN_CLOSE | FAN_OPEN, AT_FDCWD, fname) < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+			    "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS | "
+			    "FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, %s) "
+			    "failed", fd_notify, fname);
+		}
+
+		/*
+		 * generate sequence of events
+		 */
+		fd = SAFE_OPEN(cleanup, fname, O_RDONLY);
+		event_set[tst_count] = FAN_OPEN;
+		tst_count++;
+
+		SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE);
+		event_set[tst_count] = FAN_ACCESS;
+		tst_count++;
+
+		SAFE_CLOSE(cleanup, fd);
+		event_set[tst_count] = FAN_CLOSE_NOWRITE;
+		tst_count++;
+
+		/*
+		 * Get list of events so far. We get events here to avoid
+		 * merging of following events with the previous ones.
+		 */
+		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf, EVENT_BUF_LEN);
+		len = ret;
+
+		fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700);
+		event_set[tst_count] = FAN_OPEN;
+		tst_count++;
+
+		SAFE_WRITE(cleanup, 1, fd, fname, strlen(fname));
+		event_set[tst_count] = FAN_MODIFY;
+		tst_count++;
+
+		SAFE_CLOSE(cleanup, fd);
+		event_set[tst_count] = FAN_CLOSE_WRITE;
+		tst_count++;
+
+		/*
+		 * get another list of events
+		 */
+		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
+				EVENT_BUF_LEN - len);
+		len += ret;
+
+		/*
+		 * Ignore mask testing
+		 */
+
+		/* Ignore access events */
+		if (myfanotify_mark(fd_notify,
+				    FAN_MARK_ADD | FAN_MARK_IGNORED_MASK,
+				    FAN_ACCESS, AT_FDCWD, fname) < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+			     "fanotify_mark (%d, FAN_MARK_ADD | "
+			     "FAN_MARK_IGNORED_MASK, FAN_ACCESS, "
+			     "AT_FDCWD, %s) failed", fd_notify, fname);
+		}
+
+		fd = SAFE_OPEN(cleanup, fname, O_RDWR);
+		event_set[tst_count] = FAN_OPEN;
+		tst_count++;
+
+		/* This event should be ignored */
+		SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE);
+
+		/*
+		 * get another list of events to verify the last one got ignored
+		 */
+		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
+				EVENT_BUF_LEN - len);
+		len += ret;
+
+		lseek(fd, 0, SEEK_SET);
+		/* Generate modify event to clear ignore mask */
+		SAFE_WRITE(cleanup, 1, fd, fname, 1);
+		event_set[tst_count] = FAN_MODIFY;
+		tst_count++;
+
+		/*
+		 * This event shouldn't be ignored because previous modification
+		 * should have removed the ignore mask
+		 */
+		SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE);
+		event_set[tst_count] = FAN_ACCESS;
+		tst_count++;
+
+		SAFE_CLOSE(cleanup, fd);
+		event_set[tst_count] = FAN_CLOSE_WRITE;
+		tst_count++;
+
+		/* Read events to verify previous access was properly generated */
+		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
+				EVENT_BUF_LEN - len);
+		len += ret;
+
+		/*
+		 * Now ignore open & close events regardless of file
+		 * modifications
+		 */
+		if (myfanotify_mark(fd_notify,
+				    FAN_MARK_ADD | FAN_MARK_IGNORED_MASK | FAN_MARK_IGNORED_SURV_MODIFY,
+				    FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname) < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+			     "fanotify_mark (%d, FAN_MARK_ADD | "
+			     "FAN_MARK_IGNORED_MASK | "
+			     "FAN_MARK_IGNORED_SURV_MODIFY, FAN_OPEN | "
+			     "FAN_CLOSE, AT_FDCWD, %s) failed", fd_notify,
+			     fname);
+		}
+
+		/* This event should be ignored */
+		fd = SAFE_OPEN(cleanup, fname, O_RDWR);
+
+		SAFE_WRITE(cleanup, 1, fd, fname, 1);
+		event_set[tst_count] = FAN_MODIFY;
+		tst_count++;
+
+		/* This event should be still ignored */
+		SAFE_CLOSE(cleanup, fd);
+
+		/* This event should still be ignored */
+		fd = SAFE_OPEN(cleanup, fname, O_RDWR);
+
+		/* Read events to verify open & close were ignored */
+		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
+				EVENT_BUF_LEN - len);
+		len += ret;
+
+		/* Now remove open and close from ignored mask */
+		if (myfanotify_mark(fd_notify,
+				    FAN_MARK_REMOVE | FAN_MARK_IGNORED_MASK,
+				    FAN_OPEN | FAN_CLOSE, AT_FDCWD, fname) < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+			     "fanotify_mark (%d, FAN_MARK_REMOVE | "
+			     "FAN_MARK_IGNORED_MASK, FAN_OPEN | "
+			     "FAN_CLOSE, AT_FDCWD, %s) failed", fd_notify,
+			     fname);
+		}
+
+		SAFE_CLOSE(cleanup, fd);
+		event_set[tst_count] = FAN_CLOSE_WRITE;
+		tst_count++;
+
+		/* Read events to verify close was generated */
+		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
+				EVENT_BUF_LEN - len);
+		len += ret;
+
+		if (TST_TOTAL != tst_count) {
+			tst_brkm(TBROK, cleanup,
+				 "TST_TOTAL (%d) and tst_count (%d) are not "
+				 "equal", TST_TOTAL, tst_count);
+		}
+		tst_count = 0;
+
+		/*
+		 * check events
+		 */
+		while (i < len) {
+			struct fanotify_event_metadata *event;
+
+			event = (struct fanotify_event_metadata *)&event_buf[i];
+			if (test_num >= TST_TOTAL) {
+				tst_resm(TFAIL,
+					 "get unnecessary event: mask=%llx "
+					 "pid=%u fd=%u",
+					 (unsigned long long)event->mask,
+					 (unsigned)event->pid, event->fd);
+			} else if (!(event->mask & event_set[test_num])) {
+				tst_resm(TFAIL,
+					 "get event: mask=%llx (expected %llx) "
+					 "pid=%u fd=%u",
+					 (unsigned long long)event->mask,
+					 event_set[test_num],
+					 (unsigned)event->pid, event->fd);
+			} else if (event->pid != getpid()) {
+				tst_resm(TFAIL,
+					 "get event: mask=%llx pid=%u "
+					 "(expected %u) fd=%u",
+					 (unsigned long long)event->mask,
+					 (unsigned)event->pid,
+					 (unsigned)getpid(),
+					 event->fd);
+			} else {
+				if (event->fd == -2)
+					goto pass;
+				ret = read(event->fd, buf, BUF_SIZE);
+				if (ret != strlen(fname)) {
+					tst_resm(TFAIL,
+						 "cannot read from returned fd "
+						 "of event: mask=%llx pid=%u "
+						 "fd=%u ret=%d (errno=%d)",
+						 (unsigned long long)event->mask,
+						 (unsigned)event->pid,
+						 event->fd, ret, errno);
+				} else if (memcmp(buf, fname, strlen(fname))) {
+					tst_resm(TFAIL,
+						 "wrong data read from returned fd "
+						 "of event: mask=%llx pid=%u "
+						 "fd=%u",
+						 (unsigned long long)event->mask,
+						 (unsigned)event->pid,
+						 event->fd);
+				} else {
+pass:
+					tst_resm(TPASS,
+					    "get event: mask=%llx pid=%u fd=%u",
+					    (unsigned long long)event->mask,
+					    (unsigned)event->pid, event->fd);
+				}
+			}
+			/*
+			 * We have verified the data now so close fd and
+			 * invalidate it so that we don't check it again
+			 * unnecessarily
+			 */
+			close(event->fd);
+			event->fd = -2;
+			event->mask &= ~event_set[test_num];
+			/* No events left in current mask? Go for next event */
+			if (event->mask == 0) {
+				i += event->event_len;
+			}
+			test_num++;
+		}
+		for (; test_num < TST_TOTAL; test_num++) {
+			tst_resm(TFAIL, "didn't get event: mask=%llx",
+				 event_set[test_num]);
+
+		}
+		/* Remove mark to clear FAN_MARK_IGNORED_SURV_MODIFY */
+		if (myfanotify_mark(fd_notify, FAN_MARK_REMOVE, FAN_ACCESS | FAN_MODIFY |
+				    FAN_CLOSE | FAN_OPEN, AT_FDCWD, fname) < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+			    "fanotify_mark (%d, FAN_MARK_REMOVE, FAN_ACCESS | "
+			    "FAN_MODIFY | FAN_CLOSE | FAN_OPEN, AT_FDCWD, %s) "
+			    "failed", fd_notify, fname);
+		}
+
+	}
+
+	cleanup();
+	tst_exit();
+}
+
+static void setup(void)
+{
+	tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+	TEST_PAUSE;
+
+	tst_tmpdir();
+
+	sprintf(fname, "tfile_%d", getpid());
+	fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700);
+	SAFE_WRITE(cleanup, 1, fd, fname, 1);
+
+	/* close the file we have open */
+	SAFE_CLOSE(cleanup, fd);
+
+	if ((fd_notify = myfanotify_init(FAN_CLASS_NOTIF, O_RDONLY)) < 0) {
+		if (errno == ENOSYS) {
+			tst_brkm(TCONF, cleanup,
+				 "fanotify is not configured in this kernel.");
+		} else {
+			tst_brkm(TBROK | TERRNO, cleanup,
+				 "fanotify_init failed");
+		}
+	}
+}
+
+static void cleanup(void)
+{
+	if (close(fd_notify) == -1) {
+		tst_resm(TWARN, "close(%d) failed", fd_notify);
+	}
+
+	TEST_CLEANUP;
+	tst_rmdir();
+}
+
+#else
+
+int main(void)
+{
+	tst_brkm(TCONF, NULL, "system doesn't have required fanotify support");
+}
+
+#endif
diff --git a/testcases/kernel/syscalls/fanotify/fanotify02.c b/testcases/kernel/syscalls/fanotify/fanotify02.c
new file mode 100644
index 000000000000..2d5096b1c1ef
--- /dev/null
+++ b/testcases/kernel/syscalls/fanotify/fanotify02.c
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2013 SUSE.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Started by Jan Kara <[email protected]>
+ *
+ * DESCRIPTION
+ *     Check that fanotify work for children of a directory
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include "test.h"
+#include "usctest.h"
+#include "linux_syscall_numbers.h"
+#include "fanotify.h"
+#include "safe_macros.h"
+
+char *TCID = "fanotify02";
+int TST_TOTAL = 8;
+
+#if defined(HAVE_SYS_FANOTIFY_H)
+#include <sys/fanotify.h>
+
+#define EVENT_MAX 1024
+/* size of the event structure, not counting name */
+#define EVENT_SIZE  (sizeof (struct fanotify_event_metadata))
+/* reasonable guess as to size of 1024 events */
+#define EVENT_BUF_LEN        (EVENT_MAX * EVENT_SIZE)
+
+static void setup(void);
+static void cleanup(void);
+
+#define BUF_SIZE 256
+static char fname[BUF_SIZE];
+static char buf[BUF_SIZE];
+static int fd, fd_notify;
+
+static unsigned long long event_set[EVENT_MAX];
+
+static char event_buf[EVENT_BUF_LEN];
+
+int main(int ac, char **av)
+{
+	int lc;
+	char *msg;
+
+	if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
+		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+
+	setup();
+
+	for (lc = 0; TEST_LOOPING(lc); lc++) {
+		int ret, len, i = 0, test_num = 0;
+
+		tst_count = 0;
+
+		if (myfanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS |
+				    FAN_MODIFY | FAN_CLOSE | FAN_OPEN |
+				    FAN_EVENT_ON_CHILD, AT_FDCWD, ".") < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+			    "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS | "
+			    "FAN_MODIFY | FAN_CLOSE | FAN_OPEN | "
+			    "FAN_EVENT_ON_CHILD, AT_FDCWD, '.') failed",
+			    fd_notify);
+		}
+
+		/*
+		 * generate sequence of events
+		 */
+		fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0700);
+		event_set[tst_count] = FAN_OPEN;
+		tst_count++;
+
+		SAFE_WRITE(cleanup, 1, fd, fname, strlen(fname));
+		event_set[tst_count] = FAN_MODIFY;
+		tst_count++;
+
+		SAFE_CLOSE(cleanup, fd);
+		event_set[tst_count] = FAN_CLOSE_WRITE;
+		tst_count++;
+
+		/*
+		 * Get list of events so far. We get events here to avoid
+		 * merging of following events with the previous ones.
+		 */
+		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf,
+				EVENT_BUF_LEN);
+		len = ret;
+
+		fd = SAFE_OPEN(cleanup, fname, O_RDONLY);
+		event_set[tst_count] = FAN_OPEN;
+		tst_count++;
+
+		SAFE_READ(cleanup, 0, fd, buf, BUF_SIZE);
+		event_set[tst_count] = FAN_ACCESS;
+		tst_count++;
+
+		SAFE_CLOSE(cleanup, fd);
+		event_set[tst_count] = FAN_CLOSE_NOWRITE;
+		tst_count++;
+
+		/*
+		 * get next events
+		 */
+		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
+				EVENT_BUF_LEN - len);
+		len += ret;
+
+		/*
+		 * now remove child mark
+		 */
+		if (myfanotify_mark(fd_notify, FAN_MARK_REMOVE,
+				    FAN_EVENT_ON_CHILD, AT_FDCWD, ".") < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+			    "fanotify_mark (%d, FAN_MARK REMOVE, "
+			    "FAN_EVENT_ON_CHILD, AT_FDCWD, '.') failed",
+			    fd_notify);
+		}
+
+		/*
+		 * Do something to verify events didn't get generated
+		 */
+		fd = SAFE_OPEN(cleanup, fname, O_RDONLY);
+
+		SAFE_CLOSE(cleanup, fd);
+
+		fd = SAFE_OPEN(cleanup, ".", O_RDONLY | O_DIRECTORY);
+		event_set[tst_count] = FAN_OPEN;
+		tst_count++;
+
+		SAFE_CLOSE(cleanup, fd);
+		event_set[tst_count] = FAN_CLOSE_NOWRITE;
+		tst_count++;
+
+		/*
+		 * Check events got generated only for the directory
+		 */
+		ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
+				EVENT_BUF_LEN - len);
+		len += ret;
+
+		if (TST_TOTAL != tst_count) {
+			tst_brkm(TBROK, cleanup,
+				 "TST_TOTAL and tst_count are not equal");
+		}
+		tst_count = 0;
+
+		/*
+		 * check events
+		 */
+		while (i < len) {
+			struct fanotify_event_metadata *event;
+
+			event = (struct fanotify_event_metadata *)&event_buf[i];
+			if (test_num >= TST_TOTAL) {
+				tst_resm(TFAIL,
+					 "get unnecessary event: mask=%llx "
+					 "pid=%u fd=%u",
+					 (unsigned long long)event->mask,
+					 (unsigned)event->pid, event->fd);
+			} else if (!(event->mask & event_set[test_num])) {
+				tst_resm(TFAIL,
+					 "get event: mask=%llx (expected %llx) "
+					 "pid=%u fd=%u",
+					 (unsigned long long)event->mask,
+					 event_set[test_num],
+					 (unsigned)event->pid, event->fd);
+			} else if (event->pid != getpid()) {
+				tst_resm(TFAIL,
+					 "get event: mask=%llx pid=%u "
+					 "(expected %u) fd=%u",
+					 (unsigned long long)event->mask,
+					 (unsigned)event->pid,
+					 (unsigned)getpid(),
+					 event->fd);
+			} else {
+				tst_resm(TPASS,
+					    "get event: mask=%llx pid=%u fd=%u",
+					    (unsigned long long)event->mask,
+					    (unsigned)event->pid, event->fd);
+			}
+			event->mask &= ~event_set[test_num];
+			/* No events left in current mask? Go for next event */
+			if (event->mask == 0) {
+				i += event->event_len;
+				close(event->fd);
+			}
+			test_num++;
+		}
+		for (; test_num < TST_TOTAL; test_num++) {
+			tst_resm(TFAIL, "didn't get event: mask=%llx",
+				 event_set[test_num]);
+
+		}
+	}
+
+	cleanup();
+	tst_exit();
+}
+
+static void setup(void)
+{
+	tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+	TEST_PAUSE;
+
+	tst_tmpdir();
+	sprintf(fname, "fname_%d", getpid());
+
+	if ((fd_notify = myfanotify_init(FAN_CLASS_NOTIF, O_RDONLY)) < 0) {
+		if (errno == ENOSYS) {
+			tst_brkm(TCONF, cleanup,
+				 "fanotify is not configured in this kernel.");
+		} else {
+			tst_brkm(TBROK | TERRNO, cleanup,
+				 "fanotify_init failed");
+		}
+	}
+}
+
+static void cleanup(void)
+{
+	if (close(fd_notify) == -1) {
+		tst_resm(TWARN, "close(%d) failed", fd_notify);
+	}
+
+	TEST_CLEANUP;
+	tst_rmdir();
+}
+
+#else
+
+int main(void)
+{
+	tst_brkm(TCONF, NULL, "system doesn't have required fanotify support");
+}
+
+#endif
diff --git a/testcases/kernel/syscalls/fanotify/fanotify03.c b/testcases/kernel/syscalls/fanotify/fanotify03.c
new file mode 100644
index 000000000000..b7682f4b9c3a
--- /dev/null
+++ b/testcases/kernel/syscalls/fanotify/fanotify03.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2013 SUSE.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Started by Jan Kara <[email protected]>
+ *
+ * DESCRIPTION
+ *     Check that fanotify permission events work
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/syscall.h>
+#include "test.h"
+#include "usctest.h"
+#include "linux_syscall_numbers.h"
+#include "fanotify.h"
+#include "safe_macros.h"
+
+char *TCID = "fanotify03";
+int TST_TOTAL = 3;
+
+#if defined(HAVE_SYS_FANOTIFY_H)
+#include <sys/fanotify.h>
+
+#define EVENT_MAX 1024
+/* size of the event structure, not counting name */
+#define EVENT_SIZE  (sizeof (struct fanotify_event_metadata))
+/* reasonable guess as to size of 1024 events */
+#define EVENT_BUF_LEN        (EVENT_MAX * EVENT_SIZE)
+
+static void setup(void);
+static void cleanup(void);
+
+#define BUF_SIZE 256
+static char fname[BUF_SIZE];
+static char buf[BUF_SIZE];
+static int fd_notify;
+
+static pid_t child_pid;
+
+static unsigned long long event_set[EVENT_MAX];
+static unsigned int event_resp[EVENT_MAX];
+
+static char event_buf[EVENT_BUF_LEN];
+
+static void generate_events(void)
+{
+	int fd;
+
+	/*
+	 * generate sequence of events
+	 */
+	if ((fd = open(fname, O_RDWR | O_CREAT, 0700)) == -1)
+		exit(1);
+	if (write(fd, fname, 1) == -1)
+		exit(2);
+
+	lseek(fd, 0, SEEK_SET);
+	if (read(fd, buf, BUF_SIZE) != -1)
+		exit(3);
+
+	if (close(fd) == -1)
+		exit(4);
+}
+
+static void child_handler(int tmp)
+{
+	/*
+	 * Close notification fd so that we cannot block while reading
+	 * from it
+	 */
+	close(fd_notify);
+	fd_notify = -1;
+}
+
+static void run_child(void)
+{
+	struct sigaction child_action;
+
+	child_action.sa_handler = child_handler;
+	sigemptyset(&child_action.sa_mask);
+	child_action.sa_flags = SA_NOCLDSTOP;
+
+	if (sigaction(SIGCHLD, &child_action, NULL) < 0) {
+		tst_brkm(TBROK | TERRNO, cleanup,
+			 "sigaction(SIGCHLD, &child_action, NULL) failed");
+	}
+
+	switch (child_pid = fork()) {
+	case 0:
+		/* Child will generate events now */
+		close(fd_notify);
+		generate_events();
+		exit(0);
+	case -1:
+		tst_brkm(TBROK | TERRNO, cleanup, "fork() failed");
+	}
+}
+
+static void check_child(void)
+{
+	struct sigaction child_action;
+	int child_ret;
+
+	child_action.sa_handler = SIG_IGN;
+	sigemptyset(&child_action.sa_mask);
+	child_action.sa_flags = SA_NOCLDSTOP;
+	if (sigaction(SIGCHLD, &child_action, NULL) < 0) {
+		tst_brkm(TBROK | TERRNO, cleanup,
+			 "sigaction(SIGCHLD, &child_action, NULL) failed");
+	}
+	if (waitpid(-1, &child_ret, 0) < 0) {
+		tst_brkm(TBROK | TERRNO, cleanup,
+				 "waitpid(-1, &child_ret, 0) failed");
+	}
+
+	if (WIFSIGNALED(child_ret)) {
+		tst_resm(TFAIL, "child exited due to signal %d",
+			 WTERMSIG(child_ret));
+	} else if (WIFEXITED(child_ret)) {
+		if (WEXITSTATUS(child_ret) == 0)
+			tst_resm(TPASS, "child exited correctly");
+		else
+			tst_resm(TFAIL, "child exited with status %d",
+				 WEXITSTATUS(child_ret));
+	} else
+		tst_resm(TFAIL, "child exited for unknown reason (status %d)",
+			 child_ret);
+}
+
+int main(int ac, char **av)
+{
+	int lc;
+	char *msg;
+	int fd_notify_backup = -1;
+
+	if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
+		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+
+	setup();
+
+	for (lc = 0; TEST_LOOPING(lc); lc++) {
+		int ret, len = 0, i = 0, test_num = 0;
+
+		if (fd_notify_backup == -1) {
+			fd_notify_backup = dup(fd_notify);
+			if (fd_notify_backup < 0)
+				tst_brkm(TBROK | TERRNO, cleanup,
+					 "dup(%d) failed", fd_notify);
+		}
+		run_child();
+
+		tst_count = 0;
+
+		event_set[tst_count] = FAN_OPEN_PERM;
+		event_resp[tst_count++] = FAN_ALLOW;
+		event_set[tst_count] = FAN_ACCESS_PERM;
+		event_resp[tst_count++] = FAN_DENY;
+
+		/* tst_count + 1 is for checking child return value */
+		if (TST_TOTAL != tst_count + 1) {
+			tst_brkm(TBROK, cleanup,
+				 "TST_TOTAL and tst_count do not match");
+		}
+		tst_count = 0;
+
+		/*
+		 * check events
+		 */
+		while (test_num < TST_TOTAL && fd_notify != -1) {
+			struct fanotify_event_metadata *event;
+
+			if (i == len) {
+				/* Get more events */
+				ret = read(fd_notify, event_buf + len,
+					   EVENT_BUF_LEN - len);
+				if (fd_notify == -1)
+					break;
+				if (ret < 0) {
+					tst_brkm(TBROK, cleanup,
+						 "read(%d, buf, %zu) failed",
+						 fd_notify, EVENT_BUF_LEN);
+				}
+				len += ret;
+			}
+
+			event = (struct fanotify_event_metadata *)&event_buf[i];
+			if (!(event->mask & event_set[test_num])) {
+				tst_resm(TFAIL,
+					 "get event: mask=%llx (expected %llx) "
+					 "pid=%u fd=%u",
+					 (unsigned long long)event->mask,
+					 event_set[test_num],
+					 (unsigned)event->pid, event->fd);
+			} else if (event->pid != child_pid) {
+				tst_resm(TFAIL,
+					 "get event: mask=%llx pid=%u "
+					 "(expected %u) fd=%u",
+					 (unsigned long long)event->mask,
+					 (unsigned)event->pid,
+					 (unsigned)child_pid,
+					 event->fd);
+			} else {
+				tst_resm(TPASS,
+					    "get event: mask=%llx pid=%u fd=%u",
+					    (unsigned long long)event->mask,
+					    (unsigned)event->pid, event->fd);
+			}
+			/* Write response to permission event */
+			if (event_set[test_num] & FAN_ALL_PERM_EVENTS) {
+				struct fanotify_response resp;
+
+				resp.fd = event->fd;
+				resp.response = event_resp[test_num];
+				SAFE_WRITE(cleanup, 1, fd_notify, &resp,
+					   sizeof(resp));
+			}
+			event->mask &= ~event_set[test_num];
+			/* No events left in current mask? Go for next event */
+			if (event->mask == 0) {
+				i += event->event_len;
+				close(event->fd);
+			}
+			test_num++;
+		}
+		for (; test_num < TST_TOTAL - 1; test_num++) {
+			tst_resm(TFAIL, "didn't get event: mask=%llx",
+				 event_set[test_num]);
+
+		}
+		check_child();
+		/* We got SIGCHLD while running, resetup fd_notify */
+		if (fd_notify == -1) {
+			fd_notify = fd_notify_backup;
+			fd_notify_backup = -1;
+		}
+	}
+
+	cleanup();
+	tst_exit();
+}
+
+static void setup(void)
+{
+	int fd;
+
+	tst_sig(FORK, DEF_HANDLER, cleanup);
+
+	TEST_PAUSE;
+
+	tst_tmpdir();
+	sprintf(fname, "fname_%d", getpid());
+	fd = SAFE_OPEN(cleanup, fname, O_CREAT | O_RDWR, 0644);
+	SAFE_WRITE(cleanup, 1, fd, fname, 1);
+	SAFE_CLOSE(cleanup, fd);
+
+	if ((fd_notify = myfanotify_init(FAN_CLASS_CONTENT, O_RDONLY)) < 0) {
+		if (errno == ENOSYS) {
+			tst_brkm(TCONF, cleanup,
+				 "fanotify is not configured in this kernel.");
+		} else {
+			tst_brkm(TBROK | TERRNO, cleanup,
+				 "fanotify_init failed");
+		}
+	}
+
+	if (myfanotify_mark(fd_notify, FAN_MARK_ADD, FAN_ACCESS_PERM |
+			    FAN_OPEN_PERM, AT_FDCWD, fname) < 0) {
+		tst_brkm(TBROK | TERRNO, cleanup,
+			 "fanotify_mark (%d, FAN_MARK_ADD, FAN_ACCESS_PERM | "
+			 "FAN_OPEN_PERM, AT_FDCWD, %s) failed", fd_notify, fname);
+	}
+
+}
+
+static void cleanup(void)
+{
+	if (fd_notify != -1 && close(fd_notify) == -1) {
+		tst_resm(TWARN, "close(%d) failed", fd_notify);
+	}
+
+	TEST_CLEANUP;
+	tst_rmdir();
+}
+
+#else
+
+int main(void)
+{
+	tst_brkm(TCONF, NULL, "system doesn't have required fanotify support");
+}
+
+#endif
diff --git a/testcases/kernel/syscalls/fanotify/fanotify04.c b/testcases/kernel/syscalls/fanotify/fanotify04.c
new file mode 100644
index 000000000000..1e4549c739c1
--- /dev/null
+++ b/testcases/kernel/syscalls/fanotify/fanotify04.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2013 SUSE.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Started by Jan Kara <[email protected]>
+ *
+ * DESCRIPTION
+ *     Check various fanotify special flags
+ */
+#include "config.h"
+
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/syscall.h>
+#include "test.h"
+#include "usctest.h"
+#include "linux_syscall_numbers.h"
+#include "fanotify.h"
+#include "safe_macros.h"
+
+char *TCID = "fanotify04";
+int TST_TOTAL = 9;
+
+#if defined(HAVE_SYS_FANOTIFY_H)
+#include <sys/fanotify.h>
+
+#define EVENT_MAX 1024
+/* size of the event structure, not counting name */
+#define EVENT_SIZE  (sizeof (struct fanotify_event_metadata))
+/* reasonable guess as to size of 1024 events */
+#define EVENT_BUF_LEN        (EVENT_MAX * EVENT_SIZE)
+
+static void setup(void);
+static void cleanup(void);
+
+#define BUF_SIZE 256
+static char fname[BUF_SIZE];
+static char sname[BUF_SIZE];
+static char dir[BUF_SIZE];
+static int fd_notify;
+
+static int len;
+static char event_buf[EVENT_BUF_LEN];
+
+static char *expect_str_fail(int expect)
+{
+	if (expect == 0)
+		return "failed";
+	return "unexpectedly succeeded";
+}
+
+static char *expect_str_pass(int expect)
+{
+	if (expect == 0)
+		return "succeeded";
+	return "failed";
+}
+
+static void check_mark(char *file, unsigned long long flag, char *flagstr,
+		       int expect, void (*test_event)(char *))
+{
+	if (myfanotify_mark(fd_notify, FAN_MARK_ADD | flag, FAN_OPEN, AT_FDCWD,
+			    file) != expect) {
+		tst_resm(TFAIL,
+		    "fanotify_mark (%d, FAN_MARK_ADD | %s, FAN_OPEN, AT_FDCWD, "
+		    "'%s') %s", fd_notify, flagstr, file, expect_str_fail(expect));
+	} else {
+		tst_resm(TPASS,
+		    "fanotify_mark (%d, FAN_MARK_ADD | %s, FAN_OPEN, AT_FDCWD, "
+		    "'%s') %s", fd_notify, flagstr, file, expect_str_pass(expect));
+
+		/* If we expected failure there's nothing to clean up */
+		if (expect == -1)
+			return;
+
+		if (test_event)
+			test_event(file);
+
+		if (myfanotify_mark(fd_notify, FAN_MARK_REMOVE | flag,
+				    FAN_OPEN, AT_FDCWD, file) < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+		    	    "fanotify_mark (%d, FAN_MARK_REMOVE | %s, "
+			    "FAN_OPEN, AT_FDCWD, '%s') failed",
+			    fd_notify, flagstr, file);
+		}
+	}
+}
+
+#define CHECK_MARK(file, flag, expect, func) check_mark(file, flag, #flag, expect, func)
+
+static void do_open(char *file, int flag, char *flagstr)
+{
+	int fd;
+
+	fd = SAFE_OPEN(cleanup, file, O_RDONLY | flag);
+	SAFE_CLOSE(cleanup, fd);
+}
+
+#define DO_OPEN(file, flag) do_open(file, flag, #flag)
+
+static void open_file(char *file)
+{
+	DO_OPEN(file, 0);
+}
+
+static void open_dir(char *file)
+{
+	DO_OPEN(file, O_DIRECTORY);
+}
+
+static void verify_event(int mask)
+{
+	int ret;
+	struct fanotify_event_metadata *event;
+	struct stat st;
+
+	/* Read the event */
+	ret = SAFE_READ(cleanup, 0, fd_notify, event_buf + len,
+			EVENT_BUF_LEN - len);
+	event = (struct fanotify_event_metadata *)&event_buf[len];
+	len += ret;
+
+	if (event->mask != FAN_OPEN) {
+		tst_resm(TFAIL, "got unexpected event %llx",
+			 (unsigned long long)event->mask);
+	} else if (fstat(event->fd, &st) < 0) {
+		tst_resm(TFAIL, "failed to stat event->fd (%s)",
+			 strerror(errno));
+	} else if ((st.st_mode & S_IFMT) != mask) {
+		tst_resm(TFAIL, "event->fd points to object of different type "
+			 "(%o != %o)", st.st_mode & S_IFMT, mask);
+	} else {
+		tst_resm(TPASS, "event generated properly for type %o", mask);
+	}
+	close(event->fd);
+}
+
+static void do_open_test(char *file, int flag, char *flagstr, int mask)
+{
+	do_open(file, flag, flagstr);
+
+	verify_event(mask);
+}
+
+#define DO_OPEN_TEST(file, flag, mask) do_open_test(file, flag, #flag, mask)
+
+static void test_open_file(char *file)
+{
+	DO_OPEN_TEST(file, 0, S_IFREG);
+}
+
+static void verify_no_event(void)
+{
+	int ret;
+
+	ret = read(fd_notify, event_buf + len, EVENT_BUF_LEN - len);
+	if (ret != -1) {
+		struct fanotify_event_metadata *event;
+
+		event = (struct fanotify_event_metadata *)&event_buf[len];
+		tst_resm(TFAIL, "seen unexpected event (mask %llx)",
+			 (unsigned long long)event->mask);
+		/* Cleanup fd from the event */
+		close(event->fd);
+	} else if (errno != EAGAIN) {
+		tst_resm(TFAIL | TERRNO, "read(%d, buf, %zu) failed", fd_notify,
+			 EVENT_BUF_LEN);
+	} else {
+		tst_resm(TPASS, "No event as expected");
+	}
+}
+
+static void test_open_symlink(char *file)
+{
+	/* Since mark is on a symlink, no event should be generated by opening a file */
+	DO_OPEN(file, 0);
+	verify_no_event();
+}
+
+int main(int ac, char **av)
+{
+	int lc;
+	char *msg;
+
+	if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL)
+		tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
+
+	setup();
+
+	for (lc = 0; TEST_LOOPING(lc); lc++) {
+		/* Check ONLYDIR on a directory */
+		CHECK_MARK(".", FAN_MARK_ONLYDIR, 0, NULL);
+
+		/* Check ONLYDIR without a directory */
+		CHECK_MARK(fname, FAN_MARK_ONLYDIR, -1, NULL);
+
+		/* Check DONT_FOLLOW for a symlink */
+		CHECK_MARK(sname, FAN_MARK_DONT_FOLLOW, 0, test_open_symlink);
+
+		/* Check without DONT_FOLLOW for a symlink */
+		CHECK_MARK(sname, 0, 0, test_open_file);
+
+		/* Verify FAN_MARK_FLUSH destroys all inode marks */
+		if (myfanotify_mark(fd_notify, FAN_MARK_ADD,
+		    		    FAN_OPEN, AT_FDCWD, fname) < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+			    "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN, "
+			    "AT_FDCWD, '%s') failed", fd_notify, fname);
+		}
+		if (myfanotify_mark(fd_notify, FAN_MARK_ADD,
+		    		    FAN_OPEN | FAN_ONDIR, AT_FDCWD, dir) < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+			    "fanotify_mark (%d, FAN_MARK_ADD, FAN_OPEN | "
+			    "FAN_ONDIR, AT_FDCWD, '%s') failed", fd_notify,
+			    dir);
+		}
+		open_file(fname);
+		verify_event(S_IFREG);
+		open_dir(dir);
+		verify_event(S_IFDIR);
+		if (myfanotify_mark(fd_notify, FAN_MARK_FLUSH,
+		    		    0, AT_FDCWD, ".") < 0) {
+			tst_brkm(TBROK | TERRNO, cleanup,
+			    "fanotify_mark (%d, FAN_MARK_FLUSH, 0, "
+			    "AT_FDCWD, '.') failed", fd_notify);
+		}
+
+		open_dir(dir);
+		verify_no_event();
+	}
+
+	cleanup();
+	tst_exit();
+}
+
+static void setup(void)
+{
+	int fd;
+
+	tst_sig(NOFORK, DEF_HANDLER, cleanup);
+
+	TEST_PAUSE;
+
+	tst_tmpdir();
+	sprintf(fname, "fname_%d", getpid());
+	fd = SAFE_OPEN(cleanup, fname, O_RDWR | O_CREAT, 0644);
+	SAFE_CLOSE(cleanup, fd);
+
+	sprintf(sname, "symlink_%d", getpid());
+	SAFE_SYMLINK(cleanup, fname, sname);
+
+	sprintf(dir, "dir_%d", getpid());
+	SAFE_MKDIR(cleanup, dir, 0755);
+
+	if ((fd_notify = myfanotify_init(FAN_CLASS_NOTIF | FAN_NONBLOCK,
+					 O_RDONLY)) < 0) {
+		if (errno == ENOSYS) {
+			tst_brkm(TCONF, cleanup,
+				 "fanotify is not configured in this kernel.");
+		} else {
+			tst_brkm(TBROK | TERRNO, cleanup,
+				 "fanotify_init failed");
+		}
+	}
+}
+
+static void cleanup(void)
+{
+	if (close(fd_notify) == -1) {
+		tst_resm(TWARN, "close(%d) failed", fd_notify);
+	}
+
+	TEST_CLEANUP;
+	tst_rmdir();
+}
+
+#else
+
+int main(void)
+{
+	tst_brkm(TCONF, NULL, "system doesn't have required fanotify support");
+}
+
+#endif
-- 
1.8.1.4

------------------------------------------------------------------------------
Shape the Mobile Experience: Free Subscription
Software experts and developers: Be at the forefront of tech innovation.
Intel(R) Software Adrenaline delivers strategic insight and game-changing 
conversations that shape the rapidly evolving mobile landscape. Sign up now. 
http://pubads.g.doubleclick.net/gampad/clk?id=63431311&iu=/4140/ostg.clktrk
_______________________________________________
Ltp-list mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/ltp-list

Reply via email to