Message ID | 6639dd7a9ff9929ce79f4f353f3e1db075594ea2.1555763787.git.mbobrowski@mbobrowski.org |
---|---|
State | Superseded |
Headers | show |
Series | FAN_REPORT_FID and Directory Modification Events | expand |
Hi! I've tried these tests on buildservice to check that there are no problems on slightly older distributions and found two. The first one is that we do define fallback definitions in fanotify.h but then ifdef the whole test code in #if defined(HAVE_SYS_FANOTIFY_H) so that it's efectively disabled on older distros even with fallback definitions in place. Also it's TST_TEST_TCONF() but that is just easy to fix typo. I guess that we can remove the ifdef and sys/fanotify.h include from the test sources since we conditionally include the sys/fanotify.h in the local fanotify.h already. The second one is that we fail to compile on older distributions because of missing name_to_handle_at() so we need configure check for that syscall and fallback definition in lapi/ header, or at least configure check and ifdef in the fanotify_get_fid() function. Which should be as easy as adding a name_to_handle_at line to AC_CHECK_FUNCS() in the configure.ac and using the macro from config.h. > diff --git a/runtest/syscalls b/runtest/syscalls > index 2b8ca71..dfdc6cb 100644 > --- a/runtest/syscalls > +++ b/runtest/syscalls > @@ -537,6 +537,7 @@ fanotify09 fanotify09 > fanotify10 fanotify10 > fanotify11 fanotify11 > fanotify12 fanotify12 > +fanotify13 fanotify13 > > ioperm01 ioperm01 > ioperm02 ioperm02 > diff --git a/testcases/kernel/syscalls/fanotify/.gitignore b/testcases/kernel/syscalls/fanotify/.gitignore > index 4256b8c..16bdd99 100644 > --- a/testcases/kernel/syscalls/fanotify/.gitignore > +++ b/testcases/kernel/syscalls/fanotify/.gitignore > @@ -10,4 +10,5 @@ > /fanotify10 > /fanotify11 > /fanotify12 > +/fanotify13 > /fanotify_child > diff --git a/testcases/kernel/syscalls/fanotify/fanotify.h b/testcases/kernel/syscalls/fanotify/fanotify.h > index 14654b7..e9b23cc 100644 > --- a/testcases/kernel/syscalls/fanotify/fanotify.h > +++ b/testcases/kernel/syscalls/fanotify/fanotify.h > @@ -29,6 +29,11 @@ > #define __FANOTIFY_H__ > > #include "config.h" > +#include <sys/statfs.h> > +#include <sys/types.h> > +#include <sys/stat.h> > +#include <errno.h> > +#include <fcntl.h> > > #if defined(HAVE_SYS_FANOTIFY_H) > > @@ -57,9 +62,6 @@ static long fanotify_mark(int fd, unsigned int flags, uint64_t mask, > #ifndef FAN_REPORT_TID > #define FAN_REPORT_TID 0x00000100 > #endif > -#ifndef FAN_REPORT_FID > -#define FAN_REPORT_FID 0x00000200 > -#endif > > #ifndef FAN_MARK_INODE > #define FAN_MARK_INODE 0 > @@ -89,6 +91,50 @@ struct fanotify_mark_type { > const char * name; > }; > > +#ifndef FAN_REPORT_FID > +#define FAN_REPORT_FID 0x00000200 > + > +struct fanotify_event_info_header { > + uint8_t info_type; > + uint8_t pad; > + uint16_t len; > +}; > + > +struct fanotify_event_info_fid { > + struct fanotify_event_info_header hdr; > + __kernel_fsid_t fsid; > + unsigned char handle[0]; > +}; > + > +/* > + * Helper function used to obtain __kernel_fsid_t and file_handle objects > + * for a given path. Used by test files correlated to FAN_REPORT_FID > + * functionality. > + */ > +static inline void fanotify_get_fid(const char *path, __kernel_fsid_t *fsid, > + struct file_handle *handle) > +{ > + int mount_id; > + struct statfs stats; > + > + if (statfs(path, &stats) == -1) > + tst_brk(TBROK | TERRNO, > + "statfs(%s, ...) failed", path); > + memcpy(fsid, &stats.f_fsid, sizeof(stats.f_fsid)); > + > + if (name_to_handle_at(AT_FDCWD, path, handle, &mount_id, 0) == -1) { > + if (errno == EOPNOTSUPP) { > + tst_res(TCONF, > + "filesystem %s does not support file handles", > + tst_device->fs_type); Btw, here the tst_res() does not make much sense sice the code will continue and we will exit the test with the tst_brk() below. Shouldn't we use tst_brk() here as well? > + } > + tst_brk(TBROK | TERRNO, > + "name_to_handle_at(AT_FDCWD, %s, ...) failed", path); > + } > +} > + > +#endif > + > #define INIT_FANOTIFY_MARK_TYPE(t) \ > { FAN_MARK_ ## t, "FAN_MARK_" #t }
On Fri, Apr 26, 2019 at 05:27:48PM +0200, Cyril Hrubis wrote: > Hi! > I've tried these tests on buildservice to check that there are no > problems on slightly older distributions and found two. > > The first one is that we do define fallback definitions in fanotify.h > but then ifdef the whole test code in #if defined(HAVE_SYS_FANOTIFY_H) > so that it's efectively disabled on older distros even with fallback > definitions in place. Also it's TST_TEST_TCONF() but that is just easy > to fix typo. I guess that we can remove the ifdef and sys/fanotify.h > include from the test sources since we conditionally include the > sys/fanotify.h in the local fanotify.h already. OK. In that case I can write a patch that is to be applied prior to this series which essentially just removes this specific preprocessor conditional directive from all the source files. Would you like me to do this? > The second one is that we fail to compile on older distributions because > of missing name_to_handle_at() so we need configure check for that > syscall and fallback definition in lapi/ header, or at least configure > check and ifdef in the fanotify_get_fid() function. Which should be as > easy as adding a name_to_handle_at line to AC_CHECK_FUNCS() in the > configure.ac and using the macro from config.h. Sure. I've gone ahead an updated it to accommodate for this. Prior to submitting through another patches series, changes can be found here: https://github.com/matthewbobrowski/ltp/commit/54264db0e574d2f90e716a510fcb1da11ee174dc. I think we can do better and also provide a fallback definition though, thoughts? Don't believe that it would take much effort. > > diff --git a/runtest/syscalls b/runtest/syscalls > > index 2b8ca71..dfdc6cb 100644 > > --- a/runtest/syscalls > > +++ b/runtest/syscalls > > @@ -537,6 +537,7 @@ fanotify09 fanotify09 > > fanotify10 fanotify10 > > fanotify11 fanotify11 > > fanotify12 fanotify12 > > +fanotify13 fanotify13 > > > > ioperm01 ioperm01 > > ioperm02 ioperm02 > > diff --git a/testcases/kernel/syscalls/fanotify/.gitignore b/testcases/kernel/syscalls/fanotify/.gitignore > > index 4256b8c..16bdd99 100644 > > --- a/testcases/kernel/syscalls/fanotify/.gitignore > > +++ b/testcases/kernel/syscalls/fanotify/.gitignore > > @@ -10,4 +10,5 @@ > > /fanotify10 > > /fanotify11 > > /fanotify12 > > +/fanotify13 > > /fanotify_child > > diff --git a/testcases/kernel/syscalls/fanotify/fanotify.h b/testcases/kernel/syscalls/fanotify/fanotify.h > > index 14654b7..e9b23cc 100644 > > --- a/testcases/kernel/syscalls/fanotify/fanotify.h > > +++ b/testcases/kernel/syscalls/fanotify/fanotify.h > > @@ -29,6 +29,11 @@ > > #define __FANOTIFY_H__ > > > > #include "config.h" > > +#include <sys/statfs.h> > > +#include <sys/types.h> > > +#include <sys/stat.h> > > +#include <errno.h> > > +#include <fcntl.h> > > > > #if defined(HAVE_SYS_FANOTIFY_H) > > > > @@ -57,9 +62,6 @@ static long fanotify_mark(int fd, unsigned int flags, uint64_t mask, > > #ifndef FAN_REPORT_TID > > #define FAN_REPORT_TID 0x00000100 > > #endif > > -#ifndef FAN_REPORT_FID > > -#define FAN_REPORT_FID 0x00000200 > > -#endif > > > > #ifndef FAN_MARK_INODE > > #define FAN_MARK_INODE 0 > > @@ -89,6 +91,50 @@ struct fanotify_mark_type { > > const char * name; > > }; > > > > +#ifndef FAN_REPORT_FID > > +#define FAN_REPORT_FID 0x00000200 > > + > > +struct fanotify_event_info_header { > > + uint8_t info_type; > > + uint8_t pad; > > + uint16_t len; > > +}; > > + > > +struct fanotify_event_info_fid { > > + struct fanotify_event_info_header hdr; > > + __kernel_fsid_t fsid; > > + unsigned char handle[0]; > > +}; > > + > > +/* > > + * Helper function used to obtain __kernel_fsid_t and file_handle objects > > + * for a given path. Used by test files correlated to FAN_REPORT_FID > > + * functionality. > > + */ > > +static inline void fanotify_get_fid(const char *path, __kernel_fsid_t *fsid, > > + struct file_handle *handle) > > +{ > > + int mount_id; > > + struct statfs stats; > > + > > + if (statfs(path, &stats) == -1) > > + tst_brk(TBROK | TERRNO, > > + "statfs(%s, ...) failed", path); > > + memcpy(fsid, &stats.f_fsid, sizeof(stats.f_fsid)); > > + > > + if (name_to_handle_at(AT_FDCWD, path, handle, &mount_id, 0) == -1) { > > + if (errno == EOPNOTSUPP) { > > + tst_res(TCONF, > > + "filesystem %s does not support file handles", > > + tst_device->fs_type); > > Btw, here the tst_res() does not make much sense sice the code will > continue and we will exit the test with the tst_brk() below. Shouldn't > we use tst_brk() here as well? Yes, we should be using tst_brk(...) instead. Thanks for picking this up. > > + } > > + tst_brk(TBROK | TERRNO, > > + "name_to_handle_at(AT_FDCWD, %s, ...) failed", path); > > + } > > +} > > + > > +#endif > > + > > #define INIT_FANOTIFY_MARK_TYPE(t) \ > > { FAN_MARK_ ## t, "FAN_MARK_" #t }
Hi Cyril, Any feedback on the below? On Sat, Apr 27, 2019 at 02:53:44PM +1000, Matthew Bobrowski wrote: > On Fri, Apr 26, 2019 at 05:27:48PM +0200, Cyril Hrubis wrote: > > Hi! > > I've tried these tests on buildservice to check that there are no > > problems on slightly older distributions and found two. > > > > The first one is that we do define fallback definitions in fanotify.h > > but then ifdef the whole test code in #if defined(HAVE_SYS_FANOTIFY_H) > > so that it's efectively disabled on older distros even with fallback > > definitions in place. Also it's TST_TEST_TCONF() but that is just easy > > to fix typo. I guess that we can remove the ifdef and sys/fanotify.h > > include from the test sources since we conditionally include the > > sys/fanotify.h in the local fanotify.h already. > > OK. In that case I can write a patch that is to be applied prior to this series > which essentially just removes this specific preprocessor conditional directive > from all the source files. Would you like me to do this? > > > The second one is that we fail to compile on older distributions because > > of missing name_to_handle_at() so we need configure check for that > > syscall and fallback definition in lapi/ header, or at least configure > > check and ifdef in the fanotify_get_fid() function. Which should be as > > easy as adding a name_to_handle_at line to AC_CHECK_FUNCS() in the > > configure.ac and using the macro from config.h. > > Sure. I've gone ahead an updated it to accommodate for this. Prior to > submitting through another patches series, changes can be found here: > https://github.com/matthewbobrowski/ltp/commit/54264db0e574d2f90e716a510fcb1da11ee174dc. > > I think we can do better and also provide a fallback definition though, > thoughts? Don't believe that it would take much effort. > > > > diff --git a/runtest/syscalls b/runtest/syscalls > > > index 2b8ca71..dfdc6cb 100644 > > > --- a/runtest/syscalls > > > +++ b/runtest/syscalls > > > @@ -537,6 +537,7 @@ fanotify09 fanotify09 > > > fanotify10 fanotify10 > > > fanotify11 fanotify11 > > > fanotify12 fanotify12 > > > +fanotify13 fanotify13 > > > > > > ioperm01 ioperm01 > > > ioperm02 ioperm02 > > > diff --git a/testcases/kernel/syscalls/fanotify/.gitignore b/testcases/kernel/syscalls/fanotify/.gitignore > > > index 4256b8c..16bdd99 100644 > > > --- a/testcases/kernel/syscalls/fanotify/.gitignore > > > +++ b/testcases/kernel/syscalls/fanotify/.gitignore > > > @@ -10,4 +10,5 @@ > > > /fanotify10 > > > /fanotify11 > > > /fanotify12 > > > +/fanotify13 > > > /fanotify_child > > > diff --git a/testcases/kernel/syscalls/fanotify/fanotify.h b/testcases/kernel/syscalls/fanotify/fanotify.h > > > index 14654b7..e9b23cc 100644 > > > --- a/testcases/kernel/syscalls/fanotify/fanotify.h > > > +++ b/testcases/kernel/syscalls/fanotify/fanotify.h > > > @@ -29,6 +29,11 @@ > > > #define __FANOTIFY_H__ > > > > > > #include "config.h" > > > +#include <sys/statfs.h> > > > +#include <sys/types.h> > > > +#include <sys/stat.h> > > > +#include <errno.h> > > > +#include <fcntl.h> > > > > > > #if defined(HAVE_SYS_FANOTIFY_H) > > > > > > @@ -57,9 +62,6 @@ static long fanotify_mark(int fd, unsigned int flags, uint64_t mask, > > > #ifndef FAN_REPORT_TID > > > #define FAN_REPORT_TID 0x00000100 > > > #endif > > > -#ifndef FAN_REPORT_FID > > > -#define FAN_REPORT_FID 0x00000200 > > > -#endif > > > > > > #ifndef FAN_MARK_INODE > > > #define FAN_MARK_INODE 0 > > > @@ -89,6 +91,50 @@ struct fanotify_mark_type { > > > const char * name; > > > }; > > > > > > +#ifndef FAN_REPORT_FID > > > +#define FAN_REPORT_FID 0x00000200 > > > + > > > +struct fanotify_event_info_header { > > > + uint8_t info_type; > > > + uint8_t pad; > > > + uint16_t len; > > > +}; > > > + > > > +struct fanotify_event_info_fid { > > > + struct fanotify_event_info_header hdr; > > > + __kernel_fsid_t fsid; > > > + unsigned char handle[0]; > > > +}; > > > + > > > +/* > > > + * Helper function used to obtain __kernel_fsid_t and file_handle objects > > > + * for a given path. Used by test files correlated to FAN_REPORT_FID > > > + * functionality. > > > + */ > > > +static inline void fanotify_get_fid(const char *path, __kernel_fsid_t *fsid, > > > + struct file_handle *handle) > > > +{ > > > + int mount_id; > > > + struct statfs stats; > > > + > > > + if (statfs(path, &stats) == -1) > > > + tst_brk(TBROK | TERRNO, > > > + "statfs(%s, ...) failed", path); > > > + memcpy(fsid, &stats.f_fsid, sizeof(stats.f_fsid)); > > > + > > > + if (name_to_handle_at(AT_FDCWD, path, handle, &mount_id, 0) == -1) { > > > + if (errno == EOPNOTSUPP) { > > > + tst_res(TCONF, > > > + "filesystem %s does not support file handles", > > > + tst_device->fs_type); > > > > Btw, here the tst_res() does not make much sense sice the code will > > continue and we will exit the test with the tst_brk() below. Shouldn't > > we use tst_brk() here as well? > > Yes, we should be using tst_brk(...) instead. Thanks for picking this up. > > > > + } > > > + tst_brk(TBROK | TERRNO, > > > + "name_to_handle_at(AT_FDCWD, %s, ...) failed", path); > > > + } > > > +} > > > + > > > +#endif > > > + > > > #define INIT_FANOTIFY_MARK_TYPE(t) \ > > > { FAN_MARK_ ## t, "FAN_MARK_" #t }
On Sat, Apr 27, 2019 at 7:53 AM Matthew Bobrowski <mbobrowski@mbobrowski.org> wrote: > > On Fri, Apr 26, 2019 at 05:27:48PM +0200, Cyril Hrubis wrote: > > Hi! > > I've tried these tests on buildservice to check that there are no > > problems on slightly older distributions and found two. > > > > The first one is that we do define fallback definitions in fanotify.h > > but then ifdef the whole test code in #if defined(HAVE_SYS_FANOTIFY_H) > > so that it's efectively disabled on older distros even with fallback > > definitions in place. Also it's TST_TEST_TCONF() but that is just easy > > to fix typo. I guess that we can remove the ifdef and sys/fanotify.h > > include from the test sources since we conditionally include the > > sys/fanotify.h in the local fanotify.h already. > > OK. In that case I can write a patch that is to be applied prior to this series > which essentially just removes this specific preprocessor conditional directive > from all the source files. Would you like me to do this? If I understand the concern correctly, it is not really important to address now for these new tests that check functionality only available since kernel v5.1. It could be addressed by followup work. > > > The second one is that we fail to compile on older distributions because > > of missing name_to_handle_at() so we need configure check for that > > syscall and fallback definition in lapi/ header, or at least configure > > check and ifdef in the fanotify_get_fid() function. Which should be as > > easy as adding a name_to_handle_at line to AC_CHECK_FUNCS() in the > > configure.ac and using the macro from config.h. > > Sure. I've gone ahead an updated it to accommodate for this. Prior to > submitting through another patches series, changes can be found here: > https://github.com/matthewbobrowski/ltp/commit/54264db0e574d2f90e716a510fcb1da11ee174dc. > > I think we can do better and also provide a fallback definition though, > thoughts? Don't believe that it would take much effort. > No reason to do that. Those tests will only be supported on kernel >= v5.1 old distros are less interesting for these tests. Please post the patches for fanotify_dirent_3 branch. Thanks, Amir.
On Wed, May 15, 2019 at 05:50:03PM +0300, Amir Goldstein wrote: > > On Fri, Apr 26, 2019 at 05:27:48PM +0200, Cyril Hrubis wrote: > > > Hi! > > > I've tried these tests on buildservice to check that there are no > > > problems on slightly older distributions and found two. > > > > > > The first one is that we do define fallback definitions in fanotify.h > > > but then ifdef the whole test code in #if defined(HAVE_SYS_FANOTIFY_H) > > > so that it's efectively disabled on older distros even with fallback > > > definitions in place. Also it's TST_TEST_TCONF() but that is just easy > > > to fix typo. I guess that we can remove the ifdef and sys/fanotify.h > > > include from the test sources since we conditionally include the > > > sys/fanotify.h in the local fanotify.h already. > > > > OK. In that case I can write a patch that is to be applied prior to this series > > which essentially just removes this specific preprocessor conditional directive > > from all the source files. Would you like me to do this? > > If I understand the concern correctly, it is not really important > to address now for these new tests that check functionality only available > since kernel v5.1. It could be addressed by followup work. OK, no problem, this is fine with me. > > > The second one is that we fail to compile on older distributions because > > > of missing name_to_handle_at() so we need configure check for that > > > syscall and fallback definition in lapi/ header, or at least configure > > > check and ifdef in the fanotify_get_fid() function. Which should be as > > > easy as adding a name_to_handle_at line to AC_CHECK_FUNCS() in the > > > configure.ac and using the macro from config.h. > > > > Sure. I've gone ahead an updated it to accommodate for this. Prior to > > submitting through another patches series, changes can be found here: > > https://github.com/matthewbobrowski/ltp/commit/54264db0e574d2f90e716a510fcb1da11ee174dc. > > > > I think we can do better and also provide a fallback definition though, > > thoughts? Don't believe that it would take much effort. > > No reason to do that. Those tests will only be supported on kernel >= v5.1 > old distros are less interesting for these tests. > > Please post the patches for fanotify_dirent_3 branch. OK. I've rebased fanotify_dirent_3 of upstream/master and resubmitting the patch series now.
diff --git a/runtest/syscalls b/runtest/syscalls index 2b8ca71..dfdc6cb 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -537,6 +537,7 @@ fanotify09 fanotify09 fanotify10 fanotify10 fanotify11 fanotify11 fanotify12 fanotify12 +fanotify13 fanotify13 ioperm01 ioperm01 ioperm02 ioperm02 diff --git a/testcases/kernel/syscalls/fanotify/.gitignore b/testcases/kernel/syscalls/fanotify/.gitignore index 4256b8c..16bdd99 100644 --- a/testcases/kernel/syscalls/fanotify/.gitignore +++ b/testcases/kernel/syscalls/fanotify/.gitignore @@ -10,4 +10,5 @@ /fanotify10 /fanotify11 /fanotify12 +/fanotify13 /fanotify_child diff --git a/testcases/kernel/syscalls/fanotify/fanotify.h b/testcases/kernel/syscalls/fanotify/fanotify.h index 14654b7..e9b23cc 100644 --- a/testcases/kernel/syscalls/fanotify/fanotify.h +++ b/testcases/kernel/syscalls/fanotify/fanotify.h @@ -29,6 +29,11 @@ #define __FANOTIFY_H__ #include "config.h" +#include <sys/statfs.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fcntl.h> #if defined(HAVE_SYS_FANOTIFY_H) @@ -57,9 +62,6 @@ static long fanotify_mark(int fd, unsigned int flags, uint64_t mask, #ifndef FAN_REPORT_TID #define FAN_REPORT_TID 0x00000100 #endif -#ifndef FAN_REPORT_FID -#define FAN_REPORT_FID 0x00000200 -#endif #ifndef FAN_MARK_INODE #define FAN_MARK_INODE 0 @@ -89,6 +91,50 @@ struct fanotify_mark_type { const char * name; }; +#ifndef FAN_REPORT_FID +#define FAN_REPORT_FID 0x00000200 + +struct fanotify_event_info_header { + uint8_t info_type; + uint8_t pad; + uint16_t len; +}; + +struct fanotify_event_info_fid { + struct fanotify_event_info_header hdr; + __kernel_fsid_t fsid; + unsigned char handle[0]; +}; + +/* + * Helper function used to obtain __kernel_fsid_t and file_handle objects + * for a given path. Used by test files correlated to FAN_REPORT_FID + * functionality. + */ +static inline void fanotify_get_fid(const char *path, __kernel_fsid_t *fsid, + struct file_handle *handle) +{ + int mount_id; + struct statfs stats; + + if (statfs(path, &stats) == -1) + tst_brk(TBROK | TERRNO, + "statfs(%s, ...) failed", path); + memcpy(fsid, &stats.f_fsid, sizeof(stats.f_fsid)); + + if (name_to_handle_at(AT_FDCWD, path, handle, &mount_id, 0) == -1) { + if (errno == EOPNOTSUPP) { + tst_res(TCONF, + "filesystem %s does not support file handles", + tst_device->fs_type); + } + tst_brk(TBROK | TERRNO, + "name_to_handle_at(AT_FDCWD, %s, ...) failed", path); + } +} + +#endif + #define INIT_FANOTIFY_MARK_TYPE(t) \ { FAN_MARK_ ## t, "FAN_MARK_" #t } diff --git a/testcases/kernel/syscalls/fanotify/fanotify13.c b/testcases/kernel/syscalls/fanotify/fanotify13.c new file mode 100644 index 0000000..820f139 --- /dev/null +++ b/testcases/kernel/syscalls/fanotify/fanotify13.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 Matthew Bobrowski. All Rights Reserved. + * + * Started by Matthew Bobrowski <mbobrowski@mbobrowski.org> + * + * DESCRIPTION + * Validate that the values returned within an event when + * FAN_REPORT_FID is specified matches those that are obtained via + * explicit invocation to system calls statfs(2) and + * name_to_handle_at(2). + */ +#define _GNU_SOURCE +#include "config.h" + +#include <stdio.h> +#include <string.h> +#include <sys/statfs.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include "tst_test.h" +#include "fanotify.h" + +#if defined(HAVE_SYS_FANOTIFY_H) +#include <sys/fanotify.h> + +#define PATH_LEN 128 +#define BUF_SIZE 256 +#define DIR_ONE "dir_one" +#define FILE_ONE "file_one" +#define FILE_TWO "file_two" +#define MOUNT_PATH "mntpoint" +#define EVENT_MAX ARRAY_SIZE(objects) +#define DIR_PATH_ONE MOUNT_PATH"/"DIR_ONE +#define FILE_PATH_ONE MOUNT_PATH"/"FILE_ONE +#define FILE_PATH_TWO MOUNT_PATH"/"FILE_TWO + +struct event_t { + unsigned long long expected_mask; + __kernel_fsid_t fsid; + struct file_handle handle; + char buf[MAX_HANDLE_SZ]; +}; + +static struct object_t { + const char *path; + int is_dir; +} objects[] = { + {FILE_PATH_ONE, 0}, + {FILE_PATH_TWO, 0}, + {DIR_PATH_ONE, 1} +}; + +static struct test_case_t { + struct fanotify_mark_type mark; + unsigned long long mask; +} test_cases[] = { + { + INIT_FANOTIFY_MARK_TYPE(INODE), + FAN_OPEN | FAN_CLOSE_NOWRITE + }, + { + INIT_FANOTIFY_MARK_TYPE(INODE), + FAN_OPEN | FAN_CLOSE_NOWRITE | FAN_ONDIR + }, + { + INIT_FANOTIFY_MARK_TYPE(MOUNT), + FAN_OPEN | FAN_CLOSE_NOWRITE + }, + { + INIT_FANOTIFY_MARK_TYPE(MOUNT), + FAN_OPEN | FAN_CLOSE_NOWRITE | FAN_ONDIR + }, + { + INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), + FAN_OPEN | FAN_CLOSE_NOWRITE + }, + { + INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), + FAN_OPEN | FAN_CLOSE_NOWRITE | FAN_ONDIR + } +}; + +static int fanotify_fd; +static char events_buf[BUF_SIZE]; +static struct event_t event_set[EVENT_MAX]; + +static void create_objects(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(objects); i++) { + if (objects[i].is_dir) + SAFE_MKDIR(objects[i].path, 0755); + else + SAFE_FILE_PRINTF(objects[i].path, "0"); + } +} + +static void get_object_stats(void) +{ + unsigned int i; + for (i = 0; i < ARRAY_SIZE(objects); i++) { + event_set[i].handle.handle_bytes = MAX_HANDLE_SZ; + fanotify_get_fid(objects[i].path, &event_set[i].fsid, + &event_set[i].handle); + } +} + +static void do_setup(void) +{ + int fd; + + /* Check for kernel fanotify support */ + fd = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY); + SAFE_CLOSE(fd); + + /* Create file and directory objects for testing */ + create_objects(); + + /* Get the filesystem fsid and file handle for each created object */ + get_object_stats(); +} + + +static int setup_marks(unsigned int fd, struct test_case_t *tc) +{ + unsigned int i; + struct fanotify_mark_type *mark = &tc->mark; + + for (i = 0; i < ARRAY_SIZE(objects); i++) { + if (fanotify_mark(fd, FAN_MARK_ADD | mark->flag, tc->mask, + AT_FDCWD, objects[i].path) == -1) { + if (errno == EINVAL && + mark->flag & FAN_MARK_FILESYSTEM) { + tst_res(TCONF, + "FAN_MARK_FILESYSTEM not supported by " + "kernel"); + return 1; + } else if (errno == ENODEV && + !event_set[i].fsid.val[0] && + !event_set[i].fsid.val[1]) { + tst_res(TCONF, + "FAN_REPORT_FID not supported on " + "filesystem type %s", + tst_device->fs_type); + return 1; + } + tst_brk(TBROK | TERRNO, + "fanotify_mark(%d, FAN_MARK_ADD, FAN_OPEN, " + "AT_FDCWD, %s) failed", + fanotify_fd, objects[i].path); + } + + /* Setup the expected mask for each generated event */ + event_set[i].expected_mask = tc->mask; + if (!objects[i].is_dir) + event_set[i].expected_mask &= ~FAN_ONDIR; + } + return 0; +} + +static void do_test(unsigned int number) +{ + unsigned int i; + int len, fds[ARRAY_SIZE(objects)]; + + struct file_handle *event_file_handle; + struct fanotify_event_metadata *metadata; + struct fanotify_event_info_fid *event_fid; + struct test_case_t *tc = &test_cases[number]; + struct fanotify_mark_type *mark = &tc->mark; + + tst_res(TINFO, + "Test #%d: FAN_REPORT_FID with mark flag: %s", + number, mark->name); + + fanotify_fd = fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_FID, O_RDONLY); + if (fanotify_fd == -1) { + if (errno == EINVAL) { + tst_res(TCONF, + "FAN_REPORT_FID not supported by kernel"); + return; + } + tst_brk(TBROK | TERRNO, + "fanotify_init(FAN_CLASS_NOTIF | FAN_REPORT_FID, " + "O_RDONLY) failed"); + } + + /* Place marks on a set of objects and setup the expected masks + * for each event that is expected to be generated + */ + if (setup_marks(fanotify_fd, tc) != 0) + return; + + /* Generate sequence of FAN_OPEN events on objects */ + for (i = 0; i < ARRAY_SIZE(objects); i++) + fds[i] = SAFE_OPEN(objects[i].path, O_RDONLY); + + /* Generate sequence of FAN_CLOSE_NOWRITE events on objects. Each + * FAN_CLOSE_NOWRITE event is expected to be merged with its + * respective FAN_OPEN event that was performed on the same object + */ + for (i = 0; i < ARRAY_SIZE(objects); i++) { + if (fds[i] > 0) + SAFE_CLOSE(fds[i]); + } + + /* Read events from event queue */ + len = SAFE_READ(0, fanotify_fd, events_buf, BUF_SIZE); + + /* Iterate over event queue */ + for (i = 0, metadata = (struct fanotify_event_metadata *) events_buf; + FAN_EVENT_OK(metadata, len); + metadata = FAN_EVENT_NEXT(metadata, len), i++) { + event_fid = (struct fanotify_event_info_fid *) (metadata + 1); + event_file_handle = (struct file_handle *) event_fid->handle; + + /* File descriptor is redundant with FAN_REPORT_FID */ + if (metadata->fd != FAN_NOFD) + tst_res(TFAIL, + "Unexpectedly received file descriptor %d in " + "event. Expected to get FAN_NOFD(%d)", + metadata->fd, FAN_NOFD); + + /* Ensure that the correct mask has been reported in event */ + if (metadata->mask != event_set[i].expected_mask) + tst_res(TFAIL, + "Unexpected mask received: %llx (expected: " + "%llx) in event", + metadata->mask, + event_set[i].expected_mask); + + /* Verify handle_bytes returned in event */ + if (event_file_handle->handle_bytes + != event_set[i].handle.handle_bytes) { + tst_res(TFAIL, + "handle_bytes (%x) returned in event does not " + "equal to handle_bytes (%x) returned in " + "name_to_handle_at(2)", + event_file_handle->handle_bytes, + event_set[i].handle.handle_bytes); + continue; + } + + /* Verify handle_type returned in event */ + if (event_file_handle->handle_type != + event_set[i].handle.handle_type) { + tst_res(TFAIL, + "handle_type (%x) returned in event does not " + "equal to handle_type (%x) returned in " + "name_to_handle_at(2)", + event_file_handle->handle_type, + event_set[i].handle.handle_type); + continue; + } + + /* Verify file identifier f_handle returned in event */ + if (memcmp(event_file_handle->f_handle, + event_set[i].handle.f_handle, + event_set[i].handle.handle_bytes) != 0) { + tst_res(TFAIL, + "event_file_handle->f_handle does not match " + "event_set[i].handle.f_handle returned in " + "name_to_handle_at(2)"); + continue; + } + + /* Verify filesystem ID fsid returned in event */ + if (memcmp(&event_fid->fsid, &event_set[i].fsid, + sizeof(event_set[i].fsid)) != 0) { + tst_res(TFAIL, + "event_fid.fsid != stat.f_fsid that was " + "obtained via statfs(2)"); + continue; + } + + tst_res(TPASS, + "got event: mask=%llx, pid=%d, fid=%x.%x.%lx values " + "returned in event match those returned in statfs(2) " + "and name_to_handle_at(2)", + metadata->mask, + getpid(), + event_fid->fsid.val[0], + event_fid->fsid.val[1], + *(unsigned long *) event_file_handle->f_handle); + } +} + +static void do_cleanup(void) +{ + if (fanotify_fd > 0) + SAFE_CLOSE(fanotify_fd); +} + +static struct tst_test test = { + .setup = do_setup, + .test = do_test, + .tcnt = ARRAY_SIZE(test_cases), + .cleanup = do_cleanup, + .needs_root = 1, + .needs_tmpdir = 1, + .mount_device = 1, + .mntpoint = MOUNT_PATH, + .all_filesystems = 1 +}; + +#else + TST_TEST_CONF("System does not have required fanotify support"); +#endif