[LTP] [PATCH] fanotify09: check merging of events on child subdir
Amir Goldstein
amir73il@gmail.com
Mon Nov 5 11:07:22 CET 2018
In a setup of mount mark and directory inode mark on children
mount mark should not be getting double events "on child" and "on self"
for the same action.
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
---
Jan,
FYI, this patch improves fanotify09 to cover the bug fixed by
kernel patch "fanotify: fix handling of events on child sub-directory".
Note that this patch is based on a cleanup patch available at [1].
Thanks,
Amir.
[1] https://github.com/amir73il/ltp/commits/fanotify_cleanup
.../kernel/syscalls/fanotify/fanotify09.c | 104 ++++++++++++------
1 file changed, 68 insertions(+), 36 deletions(-)
diff --git a/testcases/kernel/syscalls/fanotify/fanotify09.c b/testcases/kernel/syscalls/fanotify/fanotify09.c
index 511ccc0e0..ef948c8a9 100644
--- a/testcases/kernel/syscalls/fanotify/fanotify09.c
+++ b/testcases/kernel/syscalls/fanotify/fanotify09.c
@@ -39,16 +39,20 @@
#define BUF_SIZE 256
static char fname[BUF_SIZE];
+static char symlnk[BUF_SIZE];
+static char fdpath[BUF_SIZE];
static int fd_notify[NUM_GROUPS];
static char event_buf[EVENT_BUF_LEN];
#define MOUNT_NAME "mntpoint"
+#define DIR_NAME "testdir"
static int mount_created;
static void create_fanotify_groups(void)
{
unsigned int i, onchild;
+ const char *onchildstr;
int ret;
for (i = 0; i < NUM_GROUPS; i++) {
@@ -56,34 +60,39 @@ static void create_fanotify_groups(void)
FAN_NONBLOCK,
O_RDONLY);
- /* Add mount mark for each group without MODIFY event */
- ret = fanotify_mark(fd_notify[i],
- FAN_MARK_ADD | FAN_MARK_MOUNT,
- FAN_CLOSE_NOWRITE,
+ onchild = i == 0 ? FAN_EVENT_ON_CHILD | FAN_ONDIR : 0;
+ onchildstr = i == 0 ? " | FAN_EVENT_ON_CHILD | FAN_ONDIR" : "";
+
+ /*
+ * Add mount mark for each group without MODIFY event.
+ * The first group only gets events on directories - the request
+ * for events on child for mount mark is ignored.
+ */
+ ret = fanotify_mark(fd_notify[i], FAN_MARK_ADD | FAN_MARK_MOUNT,
+ FAN_CLOSE_NOWRITE | onchild,
AT_FDCWD, ".");
if (ret < 0) {
tst_brk(TBROK | TERRNO,
"fanotify_mark(%d, FAN_MARK_ADD | "
- "FAN_MARK_MOUNT, FAN_MODIFY, AT_FDCWD,"
- " '.') failed", fd_notify[i]);
+ "FAN_MARK_MOUNT, FAN_CLOSE_NOWRITE%s"
+ ", AT_FDCWD, '.') failed",
+ fd_notify[i], onchildstr);
}
/*
- * Add inode mark on parent for each group with MODIFY
- * event, but only one group requests events on child.
+ * Add inode mark on parent for each group with MODIFY event,
+ * but only one group requests events on child (and subdirs).
* The one mark with FAN_EVENT_ON_CHILD is needed for
* setting the DCACHE_FSNOTIFY_PARENT_WATCHED dentry
* flag.
*/
- onchild = (i == 0) ? FAN_EVENT_ON_CHILD : 0;
- ret = fanotify_mark(fd_notify[i],
- FAN_MARK_ADD,
- FAN_MODIFY | onchild, AT_FDCWD, ".");
+ ret = fanotify_mark(fd_notify[i], FAN_MARK_ADD,
+ FAN_MODIFY | onchild,
+ AT_FDCWD, ".");
if (ret < 0) {
tst_brk(TBROK | TERRNO,
"fanotify_mark(%d, FAN_MARK_ADD, "
"FAN_MODIFY%s, AT_FDCWD, '.') failed",
- fd_notify[i],
- onchild ? " | FAN_EVENT_ON_CHILD" : "");
+ fd_notify[i], onchildstr);
}
}
}
@@ -98,12 +107,13 @@ static void cleanup_fanotify_groups(void)
}
}
-static void verify_event(int group, struct fanotify_event_metadata *event)
+static void verify_event(int group, struct fanotify_event_metadata *event,
+ __u32 expect)
{
- if (event->mask != FAN_MODIFY) {
+ if (event->mask != expect) {
tst_res(TFAIL, "group %d got event: mask %llx (expected %llx) "
"pid=%u fd=%d", group, (unsigned long long)event->mask,
- (unsigned long long)FAN_MODIFY,
+ (unsigned long long)expect,
(unsigned)event->pid, event->fd);
} else if (event->pid != getpid()) {
tst_res(TFAIL, "group %d got event: mask %llx pid=%u "
@@ -111,17 +121,23 @@ static void verify_event(int group, struct fanotify_event_metadata *event)
(unsigned long long)event->mask, (unsigned)event->pid,
(unsigned)getpid(), event->fd);
} else {
- tst_res(TPASS, "group %d got event: mask %llx pid=%u fd=%d",
+ int len;
+ sprintf(symlnk, "/proc/self/fd/%d", event->fd);
+ len = readlink(symlnk, fdpath, sizeof(fdpath));
+ if (len < 0)
+ len = 0;
+ fdpath[len] = 0;
+ tst_res(TPASS, "group %d got event: mask %llx pid=%u fd=%d path=%s",
group, (unsigned long long)event->mask,
- (unsigned)event->pid, event->fd);
+ (unsigned)event->pid, event->fd, fdpath);
}
}
void test01(void)
{
- int ret;
+ int ret, dirfd;
unsigned int i;
- struct fanotify_event_metadata *event;
+ struct fanotify_event_metadata *event, *ev;
create_fanotify_groups();
@@ -129,8 +145,17 @@ void test01(void)
* generate MODIFY event and no FAN_CLOSE_NOWRITE event.
*/
SAFE_FILE_PRINTF(fname, "1");
+ /*
+ * generate FAN_CLOSE_NOWRITE event on a child subdir.
+ */
+ dirfd = SAFE_OPEN(DIR_NAME, O_RDONLY);
+ if (dirfd >= 0)
+ SAFE_CLOSE(dirfd);
- /* First verify the first group got the MODIFY event */
+ /*
+ * First verify the first group got the file MODIFY event and got just
+ * one FAN_CLOSE_NOWRITE event.
+ */
ret = read(fd_notify[0], event_buf, EVENT_BUF_LEN);
if (ret < 0) {
if (errno == EAGAIN) {
@@ -140,26 +165,32 @@ void test01(void)
"reading fanotify events failed");
}
}
- if (ret < (int)FAN_EVENT_METADATA_LEN) {
+ if (ret < 2 * (int)FAN_EVENT_METADATA_LEN) {
tst_brk(TBROK,
- "short read when reading fanotify "
- "events (%d < %d)", ret,
- (int)EVENT_BUF_LEN);
+ "short read when reading fanotify events (%d < %d)",
+ ret, 2 * (int)FAN_EVENT_METADATA_LEN);
}
event = (struct fanotify_event_metadata *)event_buf;
- if (ret > (int)event->event_len) {
- tst_res(TFAIL, "first group got more than one "
- "event (%d > %d)", ret,
- event->event_len);
- } else {
- verify_event(0, event);
+ verify_event(0, event, FAN_MODIFY);
+ verify_event(0, event + 1, FAN_CLOSE_NOWRITE);
+ if (ret > 2 * (int)FAN_EVENT_METADATA_LEN) {
+ tst_res(TFAIL,
+ "first group got more than two events (%d > %d)",
+ ret, 2 * (int)FAN_EVENT_METADATA_LEN);
+ }
+ /* Close all file descriptors of read events */
+ for (ev = event; ret >= (int)FAN_EVENT_METADATA_LEN; ev++) {
+ if (ev->fd != FAN_NOFD)
+ SAFE_CLOSE(ev->fd);
+ ret -= (int)FAN_EVENT_METADATA_LEN;
}
- if (event->fd != FAN_NOFD)
- SAFE_CLOSE(event->fd);
- /* Then verify the rest of the groups did not get the MODIFY event */
+ /*
+ * Then verify the rest of the groups did not get the MODIFY event and
+ * did not get the FAN_CLOSE_NOWRITE event on subdir.
+ */
for (i = 1; i < NUM_GROUPS; i++) {
- ret = read(fd_notify[i], event_buf, EVENT_BUF_LEN);
+ ret = read(fd_notify[i], event_buf, FAN_EVENT_METADATA_LEN);
if (ret > 0) {
tst_res(TFAIL, "group %d got event", i);
if (event->fd != FAN_NOFD)
@@ -187,6 +218,7 @@ static void setup(void)
SAFE_MOUNT(MOUNT_NAME, MOUNT_NAME, "none", MS_BIND, NULL);
mount_created = 1;
SAFE_CHDIR(MOUNT_NAME);
+ SAFE_MKDIR(DIR_NAME, 0755);
sprintf(fname, "tfile_%d", getpid());
SAFE_FILE_PRINTF(fname, "1");
--
2.17.1
More information about the ltp
mailing list