Verify that when inode has an ignore mask set, it is properly reflected when notifying a mountpoint. The test verifies fix "fanotify: Fix notification of groups with inode & mount marks" in the Linux kernel.
Signed-off-by: Jan Kara <j...@suse.cz> --- runtest/syscalls | 1 + testcases/kernel/syscalls/.gitignore | 1 + testcases/kernel/syscalls/fanotify/fanotify06.c | 267 ++++++++++++++++++++++++ 3 files changed, 269 insertions(+) create mode 100644 testcases/kernel/syscalls/fanotify/fanotify06.c diff --git a/runtest/syscalls b/runtest/syscalls index 6b8de24fea82..44969f387df6 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -449,6 +449,7 @@ fanotify02 fanotify02 fanotify03 fanotify03 fanotify04 fanotify04 fanotify05 fanotify05 +fanotify06 fanotify06 ioperm01 ioperm01 ioperm02 ioperm02 diff --git a/testcases/kernel/syscalls/.gitignore b/testcases/kernel/syscalls/.gitignore index 41fec072d783..92c0bf51487b 100644 --- a/testcases/kernel/syscalls/.gitignore +++ b/testcases/kernel/syscalls/.gitignore @@ -1050,5 +1050,6 @@ /fanotify/fanotify03 /fanotify/fanotify04 /fanotify/fanotify05 +/fanotify/fanotify06 /perf_event_open/perf_event_open01 /perf_event_open/perf_event_open02 diff --git a/testcases/kernel/syscalls/fanotify/fanotify06.c b/testcases/kernel/syscalls/fanotify/fanotify06.c new file mode 100644 index 000000000000..fb2ad2f51bcf --- /dev/null +++ b/testcases/kernel/syscalls/fanotify/fanotify06.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2014 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 <j...@suse.cz> + * + * DESCRIPTION + * Check that fanotify properly merges ignore mask of an inode and + * mountpoint. + */ +#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 = "fanotify06"; + +#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); + +unsigned int fanotify_prio[] = { + FAN_CLASS_PRE_CONTENT, + FAN_CLASS_CONTENT, + FAN_CLASS_NOTIF +}; +#define FANOTIFY_PRIORITIES ARRAY_SIZE(fanotify_prio) + +#define GROUPS_PER_PRIO 3 + +int TST_TOTAL = GROUPS_PER_PRIO * FANOTIFY_PRIORITIES; + +#define BUF_SIZE 256 +static char fname[BUF_SIZE]; +static int fd; +static int fd_notify[FANOTIFY_PRIORITIES][GROUPS_PER_PRIO]; + +static char event_buf[EVENT_BUF_LEN]; + +static void create_fanotify_groups(void) +{ + unsigned int p, i; + int ret; + + for (p = 0; p < FANOTIFY_PRIORITIES; p++) { + for (i = 0; i < GROUPS_PER_PRIO; i++) { + fd_notify[p][i] = fanotify_init(fanotify_prio[p] | + FAN_NONBLOCK, + O_RDONLY); + if (fd_notify[p][i] < 0) { + if (errno == ENOSYS) { + tst_brkm(TCONF, cleanup, + "fanotify is not configured in" + " this kernel."); + } else { + tst_brkm(TBROK | TERRNO, cleanup, + "fanotify_init failed"); + } + } + /* Add mount mark for each group */ + ret = fanotify_mark(fd_notify[p][i], + FAN_MARK_ADD | FAN_MARK_MOUNT, + FAN_MODIFY, + AT_FDCWD, "."); + if (ret < 0) { + tst_brkm(TBROK | TERRNO, cleanup, + "fanotify_mark(%d, FAN_MARK_ADD | " + "FAN_MARK_MOUNT, FAN_MODIFY, AT_FDCWD," + " '.') failed", fd_notify[p][i]); + } + /* Add ignore mark for groups with higher priority */ + if (p == 0) + continue; + ret = fanotify_mark(fd_notify[p][i], + FAN_MARK_ADD | + FAN_MARK_IGNORED_MASK | + FAN_MARK_IGNORED_SURV_MODIFY, + FAN_MODIFY, AT_FDCWD, fname); + if (ret < 0) { + tst_brkm(TBROK | TERRNO, cleanup, + "fanotify_mark(%d, FAN_MARK_ADD | " + "FAN_MARK_IGNORED_MASK | " + "FAN_MARK_IGNORED_SURV_MODIFY, " + "FAN_MODIFY, AT_FDCWD, %s) failed", + fd_notify[p][i], fname); + } + } + } +} + +static void cleanup_fanotify_groups(void) +{ + unsigned int i, p; + + for (p = 0; p < FANOTIFY_PRIORITIES; p++) { + for (i = 0; i < GROUPS_PER_PRIO; i++) { + if (fd_notify[p][i] && fd_notify[p][i] != -1) { + if (close(fd_notify[p][i]) == -1) + tst_resm(TWARN, "close(%d) failed", + fd_notify[p][i]); + fd_notify[p][i] = 0; + } + } + } +} + +static void verify_event(int group, struct fanotify_event_metadata *event) +{ + if (event->mask != FAN_MODIFY) { + tst_resm(TFAIL, "group %d get event: mask %llx (expected %llx) " + "pid=%u fd=%u", group, (unsigned long long)event->mask, + (unsigned long long)FAN_MODIFY, + (unsigned)event->pid, event->fd); + } else if (event->pid != getpid()) { + tst_resm(TFAIL, "group %d get event: mask %llx pid=%u " + "(expected %u) fd=%u", group, + (unsigned long long)event->mask, (unsigned)event->pid, + (unsigned)getpid(), event->fd); + } else { + tst_resm(TPASS, "group %d get event: mask %llx pid=%u fd=%u", + group, (unsigned long long)event->mask, + (unsigned)event->pid, event->fd); + } +} + +int main(int ac, char **av) +{ + int lc; + const 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; + unsigned int p, i; + struct fanotify_event_metadata *event; + + create_fanotify_groups(); + + /* + * generate sequence of events + */ + fd = SAFE_OPEN(cleanup, fname, O_RDWR); + SAFE_WRITE(cleanup, 1, fd, fname, strlen(fname)); + SAFE_CLOSE(cleanup, fd); + + /* First verify all groups without ignore mask got the event */ + for (i = 0; i < GROUPS_PER_PRIO; i++) { + ret = read(fd_notify[0][i], event_buf, EVENT_BUF_LEN); + if (ret < 0) { + if (errno == EAGAIN) { + tst_resm(TFAIL, "group %d did not get " + "event", i); + } + tst_brkm(TBROK | TERRNO, cleanup, + "reading fanotify events failed"); + } + if (ret < (int)FAN_EVENT_METADATA_LEN) { + tst_brkm(TBROK, cleanup, + "short read when reading fanotify " + "events (%d < %d)", ret, + (int)EVENT_BUF_LEN); + } + event = (struct fanotify_event_metadata *)event_buf; + if (ret > event->event_len) { + tst_resm(TFAIL, "group %d got more than one " + "event (%d > %d)", i, ret, + event->event_len); + } else + verify_event(i, event); + close(event->fd); + } + for (p = 1; p < FANOTIFY_PRIORITIES; p++) { + for (i = 0; i < GROUPS_PER_PRIO; i++) { + ret = read(fd_notify[p][i], event_buf, EVENT_BUF_LEN); + if (ret > 0) { + tst_resm(TFAIL, "group %d got event", + p*GROUPS_PER_PRIO + i); + } else if (ret == 0) { + tst_brkm(TBROK, cleanup, "zero length " + "read from fanotify fd"); + } else if (errno != EAGAIN) { + tst_brkm(TBROK | TERRNO, cleanup, + "reading fanotify events failed"); + } else { + tst_resm(TPASS, "group %d got no event", + p*GROUPS_PER_PRIO + i); + } + } + } + cleanup_fanotify_groups(); + } + + 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); +} + +static void cleanup(void) +{ + cleanup_fanotify_groups(); + TEST_CLEANUP; + tst_rmdir(); +} + +#else + +int main(void) +{ + tst_brkm(TCONF, NULL, "system doesn't have required fanotify support"); +} + +#endif -- 1.8.1.4 ------------------------------------------------------------------------------ _______________________________________________ Ltp-list mailing list Ltp-list@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/ltp-list