diff mbox series

[v2,1/3] syscalls/fanotify13: new test to verify FAN_REPORT_FID functionality

Message ID 6639dd7a9ff9929ce79f4f353f3e1db075594ea2.1555763787.git.mbobrowski@mbobrowski.org
State Superseded
Headers show
Series FAN_REPORT_FID and Directory Modification Events | expand

Commit Message

Matthew Bobrowski April 20, 2019, 12:49 p.m. UTC
Newly defined test file to validate the fanotify FAN_REPORT_FID
functionality. A new line entry for this test file has been added within
runtest/syscalls.

Additionally, defined a helper function that can be used to obtain
__kernel_fsid_t and file_handle objects. This helper will be used by
tests related to FAN_REPORT_FID.

Signed-off-by: Matthew Bobrowski <mbobrowski@mbobrowski.org>
Reviewed-by: Amir Goldstein <amir73il@gmail.com>
---
 runtest/syscalls                                |   1 +
 testcases/kernel/syscalls/fanotify/.gitignore   |   1 +
 testcases/kernel/syscalls/fanotify/fanotify.h   |  52 +++-
 testcases/kernel/syscalls/fanotify/fanotify13.c | 313 ++++++++++++++++++++++++
 4 files changed, 364 insertions(+), 3 deletions(-)
 create mode 100644 testcases/kernel/syscalls/fanotify/fanotify13.c

Comments

Cyril Hrubis April 26, 2019, 3:27 p.m. UTC | #1
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 }
Matthew Bobrowski April 27, 2019, 4:53 a.m. UTC | #2
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 }
Matthew Bobrowski May 7, 2019, 7:40 a.m. UTC | #3
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 }
Amir Goldstein May 15, 2019, 2:50 p.m. UTC | #4
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.
Matthew Bobrowski May 19, 2019, 4:39 a.m. UTC | #5
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 mbox series

Patch

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