diff mbox series

[1/5] syscalls/inotify12: Introduce test for inotify mask flags

Message ID 20220613143826.1328830-2-amir73il@gmail.com
State Accepted
Headers show
Series Fanotify tests for FAN_MARK_EVICTABLE | expand

Commit Message

Amir Goldstein June 13, 2022, 2:38 p.m. UTC
Test behavior of IN_ONESHOT and IN_EXCL_UNLINK.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
 runtest/syscalls                              |   1 +
 testcases/kernel/syscalls/inotify/.gitignore  |   1 +
 testcases/kernel/syscalls/inotify/inotify12.c | 168 ++++++++++++++++++
 3 files changed, 170 insertions(+)
 create mode 100644 testcases/kernel/syscalls/inotify/inotify12.c

Comments

Amir Goldstein June 13, 2022, 2:58 p.m. UTC | #1
On Mon, Jun 13, 2022 at 5:38 PM Amir Goldstein <amir73il@gmail.com> wrote:
>
> Test behavior of IN_ONESHOT and IN_EXCL_UNLINK.
>
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>
> ---
>  runtest/syscalls                              |   1 +
>  testcases/kernel/syscalls/inotify/.gitignore  |   1 +
>  testcases/kernel/syscalls/inotify/inotify12.c | 168 ++++++++++++++++++
>  3 files changed, 170 insertions(+)
>  create mode 100644 testcases/kernel/syscalls/inotify/inotify12.c
>
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 3b26d19e6..1259e41f1 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -588,6 +588,7 @@ inotify08 inotify08
>  inotify09 inotify09
>  inotify10 inotify10
>  inotify11 inotify11
> +inotify12 inotify12
>
>  fanotify01 fanotify01
>  fanotify02 fanotify02
> diff --git a/testcases/kernel/syscalls/inotify/.gitignore b/testcases/kernel/syscalls/inotify/.gitignore
> index 593cf6c04..f6e5c546a 100644
> --- a/testcases/kernel/syscalls/inotify/.gitignore
> +++ b/testcases/kernel/syscalls/inotify/.gitignore
> @@ -9,3 +9,4 @@
>  /inotify09
>  /inotify10
>  /inotify11
> +/inotify12
> diff --git a/testcases/kernel/syscalls/inotify/inotify12.c b/testcases/kernel/syscalls/inotify/inotify12.c
> new file mode 100644
> index 000000000..fe72771c5
> --- /dev/null
> +++ b/testcases/kernel/syscalls/inotify/inotify12.c
> @@ -0,0 +1,168 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2022 CTERA Networks. All Rights Reserved.
> + *
> + * Author: Amir Goldstein <amir73il@gmail.com>
> + */
> +
> +/*\
> + * [Description]
> + * Test special inotify mask flags.
> + *
> + * Regression test for kernel commit a32e697cda27:
> + *
> + *     inotify: show inotify mask flags in proc fdinfo
> + */
> +
> +#include "config.h"
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <signal.h>
> +#include <sys/wait.h>
> +
> +#include "tst_test.h"
> +#include "tst_safe_macros.h"
> +#include "inotify.h"
> +
> +#if defined(HAVE_SYS_INOTIFY_H)
> +#include <sys/inotify.h>
> +
> +#define EVENT_MAX 32
> +/* Size of the event structure, not including the name */
> +#define EVENT_SIZE     (sizeof(struct inotify_event))
> +#define EVENT_BUF_LEN  (EVENT_MAX * (EVENT_SIZE + 16))
> +
> +#define        TEST_FILE       "test_file"
> +
> +static char event_buf[EVENT_BUF_LEN];
> +
> +static struct tcase {
> +       const char *tname;
> +       unsigned int mask;
> +       int expect_events;
> +} tcases[] = {
> +       {
> +               "Watch for multi events",
> +               IN_MODIFY,
> +               2,
> +       },
> +       {
> +               "Watch for single event",
> +               IN_MODIFY | IN_ONESHOT,
> +               1,
> +       },
> +       {
> +               "Watch for events on linked file",
> +               IN_MODIFY | IN_EXCL_UNLINK,
> +               1,
> +       },
> +};
> +
> +int fd_notify;
> +
> +static void verify_inotify(unsigned int n)
> +{
> +       struct tcase *tc = &tcases[n];
> +       int fd, len;
> +       unsigned int tmpmask;
> +       char procfdinfo[100];
> +       struct inotify_event *event = (struct inotify_event *)event_buf;
> +
> +       tst_res(TINFO, "Test #%d: %s", n, tc->tname);
> +
> +       fd_notify = SAFE_MYINOTIFY_INIT1(O_NONBLOCK);
> +
> +       SAFE_FILE_PRINTF(TEST_FILE, "1");
> +
> +       SAFE_MYINOTIFY_ADD_WATCH(fd_notify, ".", tc->mask);
> +
> +       sprintf(procfdinfo, "/proc/%d/fdinfo/%d", (int)getpid(), fd_notify);
> +       if (FILE_LINES_SCANF(procfdinfo, "inotify wd:%*d ino:%*x sdev:%*x mask:%x",
> +                            &tmpmask)) {
> +               tst_res(TFAIL, "Could not parse inotify fdinfo");
> +       } else if (tmpmask != tc->mask) {
> +               tst_res(TFAIL, "Incorrect mask %x in inotify fdinfo (expected %x)",
> +                       tmpmask, tc->mask);
> +       } else {
> +               tst_res(TPASS, "Correct mask in inotify fdinfo");
> +       }
> +
> +       fd = SAFE_OPEN(TEST_FILE, O_RDWR);
> +       SAFE_WRITE(1, fd, "2", 1);
> +
> +       /*
> +        * Read the 1st IN_MODIFY event
> +        */
> +       len = SAFE_READ(0, fd_notify, event_buf, EVENT_BUF_LEN);
> +
> +       if (len < (int)sizeof(*event)) {
> +               tst_res(TFAIL, "Got no events");
> +       } else if (event->mask == IN_MODIFY) {
> +               tst_res(TPASS, "Got 1st event as expected");
> +       } else {
> +               tst_res(TFAIL, "Got event 0x%x (expected 0x%x)",
> +                               event->mask, IN_MODIFY);
> +       }
> +
> +       /*
> +        * Unlink file so IN_EXCL_UNLINK won't get IN_ACCESS event.
> +        * IN_ONESHOT won't get IN_ACCESS event because IN_MODIFY
> +        * was already generated.
> +        */
> +       SAFE_UNLINK(TEST_FILE);
> +       SAFE_WRITE(1, fd, "3", 1);
> +       SAFE_CLOSE(fd);
> +
> +       /*
> +        * Possibly read the 2nd IN_MODIFY event
> +        */
> +       errno = 0;
> +       len = read(fd_notify, event_buf, EVENT_BUF_LEN);
> +       SAFE_CLOSE(fd_notify);
> +       if (len < 0 && errno == EAGAIN) {
> +               /* Treat no event same as we treat IN_IGNORED */
> +               event->mask = IN_IGNORED;
> +       } else if (len < (int)sizeof(*event)) {
> +               tst_res(TFAIL | TERRNO, "Failed to read events");
> +               return;
> +       }
> +
> +       if (event->mask == IN_MODIFY) {
> +               if (tc->expect_events > 1)
> +                       tst_res(TPASS, "Got 2nd event as expected");
> +               else
> +                       tst_res(TFAIL, "Got unexpected 2nd event");
> +       } else if (event->mask == IN_IGNORED) {
> +               if (tc->expect_events == 1)
> +                       tst_res(TPASS, "Got no more events as expected");
> +               else
> +                       tst_res(TFAIL, "Got only one event (expected %d)",
> +                                       tc->expect_events);
> +       } else {
> +               tst_res(TFAIL, "Got unexpected event 0x%x",
> +                               event->mask);
> +       }
> +}
> +
> +static void cleanup(void)
> +{
> +       if (fd_notify > 0)
> +               SAFE_CLOSE(fd_notify);
> +}
> +
> +static struct tst_test test = {
> +       .timeout = 10,

OOPS should be changed to .max_runtime = 10

> +       .needs_tmpdir = 1,
> +       .cleanup = cleanup,
> +       .test = verify_inotify,
> +       .tcnt = ARRAY_SIZE(tcases),
> +       .tags = (const struct tst_tag[]) {
> +               {"linux-git", "a32e697cda27"},
> +               {}

Missing }

Sorry, I hadn't notice this build failure before posting.

Thanks,
Amir.
Petr Vorel June 13, 2022, 3:23 p.m. UTC | #2
Hi Amir,

> > diff --git a/testcases/kernel/syscalls/inotify/inotify12.c b/testcases/kernel/syscalls/inotify/inotify12.c
...
> > +static struct tst_test test = {
> > +       .timeout = 10,

> OOPS should be changed to .max_runtime = 10

> > +       .needs_tmpdir = 1,
> > +       .cleanup = cleanup,
> > +       .test = verify_inotify,
> > +       .tcnt = ARRAY_SIZE(tcases),
> > +       .tags = (const struct tst_tag[]) {
> > +               {"linux-git", "a32e697cda27"},
> > +               {}

> Missing }

> Sorry, I hadn't notice this build failure before posting.

No big deal, we can fix this before merge.

And we have to try again to decide how to quickly merge tests for rc kernel.

Kind regards,
Petr
Petr Vorel June 13, 2022, 3:48 p.m. UTC | #3
Hi Amir,

...
> +/*\
> + * [Description]
> + * Test special inotify mask flags.
> + *
> + * Regression test for kernel commit a32e697cda27:
> + *
> + *     inotify: show inotify mask flags in proc fdinfo

For our documentation it's better to be formatted like:
 * Regression test for kernel commit:
 * a32e697cda27 ("inotify: show inotify mask flags in proc fdinfo")

because spaces before text make it formatted as code.
No need to repost, I'll fix it before merge.

...
> +static struct tcase {
> +	const char *tname;
> +	unsigned int mask;
> +	int expect_events;
> +} tcases[] = {
> +	{
> +		"Watch for multi events",
> +		IN_MODIFY,
> +		2,
> +	},
> +	{
> +		"Watch for single event",
> +		IN_MODIFY | IN_ONESHOT,
> +		1,
> +	},
> +	{
> +		"Watch for events on linked file",
> +		IN_MODIFY | IN_EXCL_UNLINK,
> +		1,
> +	},
> +};
> +
> +int fd_notify;
nit: this should be static
(make check or make check-inotify12 is your friend).
Again, no need to repost, I'll fix it before merge.

Code itself looks pretty good as always, thanks!
Reviewed-by: Petr Vorel <pvorel@suse.cz>

Kind regards,
Petr
Amir Goldstein June 13, 2022, 4:03 p.m. UTC | #4
On Mon, Jun 13, 2022 at 6:23 PM Petr Vorel <pvorel@suse.cz> wrote:
>
> Hi Amir,
>
> > > diff --git a/testcases/kernel/syscalls/inotify/inotify12.c b/testcases/kernel/syscalls/inotify/inotify12.c
> ...
> > > +static struct tst_test test = {
> > > +       .timeout = 10,
>
> > OOPS should be changed to .max_runtime = 10
>
> > > +       .needs_tmpdir = 1,
> > > +       .cleanup = cleanup,
> > > +       .test = verify_inotify,
> > > +       .tcnt = ARRAY_SIZE(tcases),
> > > +       .tags = (const struct tst_tag[]) {
> > > +               {"linux-git", "a32e697cda27"},
> > > +               {}
>
> > Missing }
>
> > Sorry, I hadn't notice this build failure before posting.
>
> No big deal, we can fix this before merge.
>
> And we have to try again to decide how to quickly merge tests for rc kernel.

Right.. forgot about that.
FWIW, the specific fix of test inotify12 is already in stable kernels
(v5.10.121, ...)

Thanks,
Amir.
Petr Vorel June 13, 2022, 4:05 p.m. UTC | #5
> On Mon, Jun 13, 2022 at 6:23 PM Petr Vorel <pvorel@suse.cz> wrote:

> > Hi Amir,

> > > > diff --git a/testcases/kernel/syscalls/inotify/inotify12.c b/testcases/kernel/syscalls/inotify/inotify12.c
> > ...
> > > > +static struct tst_test test = {
> > > > +       .timeout = 10,

> > > OOPS should be changed to .max_runtime = 10

> > > > +       .needs_tmpdir = 1,
> > > > +       .cleanup = cleanup,
> > > > +       .test = verify_inotify,
> > > > +       .tcnt = ARRAY_SIZE(tcases),
> > > > +       .tags = (const struct tst_tag[]) {
> > > > +               {"linux-git", "a32e697cda27"},
> > > > +               {}

> > > Missing }

> > > Sorry, I hadn't notice this build failure before posting.

> > No big deal, we can fix this before merge.

> > And we have to try again to decide how to quickly merge tests for rc kernel.

> Right.. forgot about that.
> FWIW, the specific fix of test inotify12 is already in stable kernels
> (v5.10.121, ...)
Correct, I have searched for this before. That means we merge this one very
soon. I'm just waiting if Jan has some comments.

Kind regards,
Petr

> Thanks,
> Amir.
Jan Kara June 14, 2022, 10:19 a.m. UTC | #6
On Mon 13-06-22 17:38:22, Amir Goldstein wrote:
> Test behavior of IN_ONESHOT and IN_EXCL_UNLINK.
> 
> Signed-off-by: Amir Goldstein <amir73il@gmail.com>

Looks good to me after fixing those small bugs you've found. Feel free to
add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  runtest/syscalls                              |   1 +
>  testcases/kernel/syscalls/inotify/.gitignore  |   1 +
>  testcases/kernel/syscalls/inotify/inotify12.c | 168 ++++++++++++++++++
>  3 files changed, 170 insertions(+)
>  create mode 100644 testcases/kernel/syscalls/inotify/inotify12.c
> 
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 3b26d19e6..1259e41f1 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -588,6 +588,7 @@ inotify08 inotify08
>  inotify09 inotify09
>  inotify10 inotify10
>  inotify11 inotify11
> +inotify12 inotify12
>  
>  fanotify01 fanotify01
>  fanotify02 fanotify02
> diff --git a/testcases/kernel/syscalls/inotify/.gitignore b/testcases/kernel/syscalls/inotify/.gitignore
> index 593cf6c04..f6e5c546a 100644
> --- a/testcases/kernel/syscalls/inotify/.gitignore
> +++ b/testcases/kernel/syscalls/inotify/.gitignore
> @@ -9,3 +9,4 @@
>  /inotify09
>  /inotify10
>  /inotify11
> +/inotify12
> diff --git a/testcases/kernel/syscalls/inotify/inotify12.c b/testcases/kernel/syscalls/inotify/inotify12.c
> new file mode 100644
> index 000000000..fe72771c5
> --- /dev/null
> +++ b/testcases/kernel/syscalls/inotify/inotify12.c
> @@ -0,0 +1,168 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2022 CTERA Networks. All Rights Reserved.
> + *
> + * Author: Amir Goldstein <amir73il@gmail.com>
> + */
> +
> +/*\
> + * [Description]
> + * Test special inotify mask flags.
> + *
> + * Regression test for kernel commit a32e697cda27:
> + *
> + *     inotify: show inotify mask flags in proc fdinfo
> + */
> +
> +#include "config.h"
> +
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <signal.h>
> +#include <sys/wait.h>
> +
> +#include "tst_test.h"
> +#include "tst_safe_macros.h"
> +#include "inotify.h"
> +
> +#if defined(HAVE_SYS_INOTIFY_H)
> +#include <sys/inotify.h>
> +
> +#define EVENT_MAX 32
> +/* Size of the event structure, not including the name */
> +#define EVENT_SIZE	(sizeof(struct inotify_event))
> +#define EVENT_BUF_LEN	(EVENT_MAX * (EVENT_SIZE + 16))
> +
> +#define	TEST_FILE	"test_file"
> +
> +static char event_buf[EVENT_BUF_LEN];
> +
> +static struct tcase {
> +	const char *tname;
> +	unsigned int mask;
> +	int expect_events;
> +} tcases[] = {
> +	{
> +		"Watch for multi events",
> +		IN_MODIFY,
> +		2,
> +	},
> +	{
> +		"Watch for single event",
> +		IN_MODIFY | IN_ONESHOT,
> +		1,
> +	},
> +	{
> +		"Watch for events on linked file",
> +		IN_MODIFY | IN_EXCL_UNLINK,
> +		1,
> +	},
> +};
> +
> +int fd_notify;
> +
> +static void verify_inotify(unsigned int n)
> +{
> +	struct tcase *tc = &tcases[n];
> +	int fd, len;
> +	unsigned int tmpmask;
> +	char procfdinfo[100];
> +	struct inotify_event *event = (struct inotify_event *)event_buf;
> +
> +	tst_res(TINFO, "Test #%d: %s", n, tc->tname);
> +
> +	fd_notify = SAFE_MYINOTIFY_INIT1(O_NONBLOCK);
> +
> +	SAFE_FILE_PRINTF(TEST_FILE, "1");
> +
> +	SAFE_MYINOTIFY_ADD_WATCH(fd_notify, ".", tc->mask);
> +
> +	sprintf(procfdinfo, "/proc/%d/fdinfo/%d", (int)getpid(), fd_notify);
> +	if (FILE_LINES_SCANF(procfdinfo, "inotify wd:%*d ino:%*x sdev:%*x mask:%x",
> +			     &tmpmask)) {
> +		tst_res(TFAIL, "Could not parse inotify fdinfo");
> +	} else if (tmpmask != tc->mask) {
> +		tst_res(TFAIL, "Incorrect mask %x in inotify fdinfo (expected %x)",
> +			tmpmask, tc->mask);
> +	} else {
> +		tst_res(TPASS, "Correct mask in inotify fdinfo");
> +	}
> +
> +	fd = SAFE_OPEN(TEST_FILE, O_RDWR);
> +	SAFE_WRITE(1, fd, "2", 1);
> +
> +	/*
> +	 * Read the 1st IN_MODIFY event
> +	 */
> +	len = SAFE_READ(0, fd_notify, event_buf, EVENT_BUF_LEN);
> +
> +	if (len < (int)sizeof(*event)) {
> +		tst_res(TFAIL, "Got no events");
> +	} else if (event->mask == IN_MODIFY) {
> +		tst_res(TPASS, "Got 1st event as expected");
> +	} else {
> +		tst_res(TFAIL, "Got event 0x%x (expected 0x%x)",
> +				event->mask, IN_MODIFY);
> +	}
> +
> +	/*
> +	 * Unlink file so IN_EXCL_UNLINK won't get IN_ACCESS event.
> +	 * IN_ONESHOT won't get IN_ACCESS event because IN_MODIFY
> +	 * was already generated.
> +	 */
> +	SAFE_UNLINK(TEST_FILE);
> +	SAFE_WRITE(1, fd, "3", 1);
> +	SAFE_CLOSE(fd);
> +
> +	/*
> +	 * Possibly read the 2nd IN_MODIFY event
> +	 */
> +	errno = 0;
> +	len = read(fd_notify, event_buf, EVENT_BUF_LEN);
> +	SAFE_CLOSE(fd_notify);
> +	if (len < 0 && errno == EAGAIN) {
> +		/* Treat no event same as we treat IN_IGNORED */
> +		event->mask = IN_IGNORED;
> +	} else if (len < (int)sizeof(*event)) {
> +		tst_res(TFAIL | TERRNO, "Failed to read events");
> +		return;
> +	}
> +
> +	if (event->mask == IN_MODIFY) {
> +		if (tc->expect_events > 1)
> +			tst_res(TPASS, "Got 2nd event as expected");
> +		else
> +			tst_res(TFAIL, "Got unexpected 2nd event");
> +	} else if (event->mask == IN_IGNORED) {
> +		if (tc->expect_events == 1)
> +			tst_res(TPASS, "Got no more events as expected");
> +		else
> +			tst_res(TFAIL, "Got only one event (expected %d)",
> +					tc->expect_events);
> +	} else {
> +		tst_res(TFAIL, "Got unexpected event 0x%x",
> +				event->mask);
> +	}
> +}
> +
> +static void cleanup(void)
> +{
> +	if (fd_notify > 0)
> +		SAFE_CLOSE(fd_notify);
> +}
> +
> +static struct tst_test test = {
> +	.timeout = 10,
> +	.needs_tmpdir = 1,
> +	.cleanup = cleanup,
> +	.test = verify_inotify,
> +	.tcnt = ARRAY_SIZE(tcases),
> +	.tags = (const struct tst_tag[]) {
> +		{"linux-git", "a32e697cda27"},
> +		{}
> +};
> +
> +#else
> +	TST_TEST_TCONF("system doesn't have required inotify support");
> +#endif
> -- 
> 2.25.1
>
Petr Vorel June 14, 2022, 11:28 a.m. UTC | #7
Hi all,

> Looks good to me after fixing those small bugs you've found. Feel free to
> add:

> Reviewed-by: Jan Kara <jack@suse.cz>

> 								Honza

Jan, thanks for your review!
Patch merged.

Kind regards,
Petr
diff mbox series

Patch

diff --git a/runtest/syscalls b/runtest/syscalls
index 3b26d19e6..1259e41f1 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -588,6 +588,7 @@  inotify08 inotify08
 inotify09 inotify09
 inotify10 inotify10
 inotify11 inotify11
+inotify12 inotify12
 
 fanotify01 fanotify01
 fanotify02 fanotify02
diff --git a/testcases/kernel/syscalls/inotify/.gitignore b/testcases/kernel/syscalls/inotify/.gitignore
index 593cf6c04..f6e5c546a 100644
--- a/testcases/kernel/syscalls/inotify/.gitignore
+++ b/testcases/kernel/syscalls/inotify/.gitignore
@@ -9,3 +9,4 @@ 
 /inotify09
 /inotify10
 /inotify11
+/inotify12
diff --git a/testcases/kernel/syscalls/inotify/inotify12.c b/testcases/kernel/syscalls/inotify/inotify12.c
new file mode 100644
index 000000000..fe72771c5
--- /dev/null
+++ b/testcases/kernel/syscalls/inotify/inotify12.c
@@ -0,0 +1,168 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 CTERA Networks. All Rights Reserved.
+ *
+ * Author: Amir Goldstein <amir73il@gmail.com>
+ */
+
+/*\
+ * [Description]
+ * Test special inotify mask flags.
+ *
+ * Regression test for kernel commit a32e697cda27:
+ *
+ *     inotify: show inotify mask flags in proc fdinfo
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#include "tst_test.h"
+#include "tst_safe_macros.h"
+#include "inotify.h"
+
+#if defined(HAVE_SYS_INOTIFY_H)
+#include <sys/inotify.h>
+
+#define EVENT_MAX 32
+/* Size of the event structure, not including the name */
+#define EVENT_SIZE	(sizeof(struct inotify_event))
+#define EVENT_BUF_LEN	(EVENT_MAX * (EVENT_SIZE + 16))
+
+#define	TEST_FILE	"test_file"
+
+static char event_buf[EVENT_BUF_LEN];
+
+static struct tcase {
+	const char *tname;
+	unsigned int mask;
+	int expect_events;
+} tcases[] = {
+	{
+		"Watch for multi events",
+		IN_MODIFY,
+		2,
+	},
+	{
+		"Watch for single event",
+		IN_MODIFY | IN_ONESHOT,
+		1,
+	},
+	{
+		"Watch for events on linked file",
+		IN_MODIFY | IN_EXCL_UNLINK,
+		1,
+	},
+};
+
+int fd_notify;
+
+static void verify_inotify(unsigned int n)
+{
+	struct tcase *tc = &tcases[n];
+	int fd, len;
+	unsigned int tmpmask;
+	char procfdinfo[100];
+	struct inotify_event *event = (struct inotify_event *)event_buf;
+
+	tst_res(TINFO, "Test #%d: %s", n, tc->tname);
+
+	fd_notify = SAFE_MYINOTIFY_INIT1(O_NONBLOCK);
+
+	SAFE_FILE_PRINTF(TEST_FILE, "1");
+
+	SAFE_MYINOTIFY_ADD_WATCH(fd_notify, ".", tc->mask);
+
+	sprintf(procfdinfo, "/proc/%d/fdinfo/%d", (int)getpid(), fd_notify);
+	if (FILE_LINES_SCANF(procfdinfo, "inotify wd:%*d ino:%*x sdev:%*x mask:%x",
+			     &tmpmask)) {
+		tst_res(TFAIL, "Could not parse inotify fdinfo");
+	} else if (tmpmask != tc->mask) {
+		tst_res(TFAIL, "Incorrect mask %x in inotify fdinfo (expected %x)",
+			tmpmask, tc->mask);
+	} else {
+		tst_res(TPASS, "Correct mask in inotify fdinfo");
+	}
+
+	fd = SAFE_OPEN(TEST_FILE, O_RDWR);
+	SAFE_WRITE(1, fd, "2", 1);
+
+	/*
+	 * Read the 1st IN_MODIFY event
+	 */
+	len = SAFE_READ(0, fd_notify, event_buf, EVENT_BUF_LEN);
+
+	if (len < (int)sizeof(*event)) {
+		tst_res(TFAIL, "Got no events");
+	} else if (event->mask == IN_MODIFY) {
+		tst_res(TPASS, "Got 1st event as expected");
+	} else {
+		tst_res(TFAIL, "Got event 0x%x (expected 0x%x)",
+				event->mask, IN_MODIFY);
+	}
+
+	/*
+	 * Unlink file so IN_EXCL_UNLINK won't get IN_ACCESS event.
+	 * IN_ONESHOT won't get IN_ACCESS event because IN_MODIFY
+	 * was already generated.
+	 */
+	SAFE_UNLINK(TEST_FILE);
+	SAFE_WRITE(1, fd, "3", 1);
+	SAFE_CLOSE(fd);
+
+	/*
+	 * Possibly read the 2nd IN_MODIFY event
+	 */
+	errno = 0;
+	len = read(fd_notify, event_buf, EVENT_BUF_LEN);
+	SAFE_CLOSE(fd_notify);
+	if (len < 0 && errno == EAGAIN) {
+		/* Treat no event same as we treat IN_IGNORED */
+		event->mask = IN_IGNORED;
+	} else if (len < (int)sizeof(*event)) {
+		tst_res(TFAIL | TERRNO, "Failed to read events");
+		return;
+	}
+
+	if (event->mask == IN_MODIFY) {
+		if (tc->expect_events > 1)
+			tst_res(TPASS, "Got 2nd event as expected");
+		else
+			tst_res(TFAIL, "Got unexpected 2nd event");
+	} else if (event->mask == IN_IGNORED) {
+		if (tc->expect_events == 1)
+			tst_res(TPASS, "Got no more events as expected");
+		else
+			tst_res(TFAIL, "Got only one event (expected %d)",
+					tc->expect_events);
+	} else {
+		tst_res(TFAIL, "Got unexpected event 0x%x",
+				event->mask);
+	}
+}
+
+static void cleanup(void)
+{
+	if (fd_notify > 0)
+		SAFE_CLOSE(fd_notify);
+}
+
+static struct tst_test test = {
+	.timeout = 10,
+	.needs_tmpdir = 1,
+	.cleanup = cleanup,
+	.test = verify_inotify,
+	.tcnt = ARRAY_SIZE(tcases),
+	.tags = (const struct tst_tag[]) {
+		{"linux-git", "a32e697cda27"},
+		{}
+};
+
+#else
+	TST_TEST_TCONF("system doesn't have required inotify support");
+#endif