diff mbox series

syscalls/statx01: Add stx_mnt_id check

Message ID 1637832900-4753-1-git-send-email-xuyang2018.jy@fujitsu.com
State Changes Requested
Headers show
Series syscalls/statx01: Add stx_mnt_id check | expand

Commit Message

Yang Xu Nov. 25, 2021, 9:35 a.m. UTC
This member was added since linux 5.8. We compare this value with the value in two places.
1.the mount_id filed in /proc/self/mountinfo
2.the mnt_id field in /proc/pid/fdinfo/fd

Reference url:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fa2fcf4
https://git.kernel.org/pub/scm/docs/man-pages/man-pages.git/commit/?id=728009a47497b6

Signed-off-by: Yang Xu <xuyang2018.jy@fujitsu.com>
---
 configure.ac                              |  4 ++
 testcases/kernel/syscalls/statx/statx01.c | 55 +++++++++++++++++++++--
 2 files changed, 56 insertions(+), 3 deletions(-)

Comments

Cyril Hrubis Nov. 29, 2021, 9:09 a.m. UTC | #1
Hi!
> +static int file_fd = -1;
> +
> +#ifdef HAVE_STRUCT_STATX_STX_MNT_ID
> +static void test_mnt_id(struct statx *buf)
> +{
> +	FILE *file;
> +	char line[PATH_MAX];
> +	int pid;
> +	unsigned int line_mjr, line_mnr, mnt_id;

Shouldn't we check the STATX_MNT_ID bit here before we event attempt to
continue? Otherwise if we compile the test with headers where stx_mnt_id
is defined then run it on old kernel there will be garbage in the
stx_mnt_id field.

> +	file = SAFE_FOPEN("/proc/self/mountinfo", "r");
> +
> +	while (fgets(line, sizeof(line), file)) {
> +		if (sscanf(line, "%d %*d %d:%d", &mnt_id, &line_mjr, &line_mnr) != 3)
> +			continue;
> +
> +		if (line_mjr == buf->stx_dev_major && line_mnr == buf->stx_dev_minor)
> +			break;
> +	}
> +
> +	SAFE_FCLOSE(file);
> +
> +	if (buf->stx_mnt_id == mnt_id)
> +		tst_res(TPASS,
> +			"statx.stx_mnt_id equals to mount_id(%d) in /proc/self/mountinfo",
> +			mnt_id);
> +	else
> +		tst_res(TFAIL,
> +			"statx.stx_mnt_id(%d) is different from mount_id(%d) in /proc/self/mountinfo",
> +			buf->stx_mnt_id, mnt_id);
> +
> +	pid = getpid();
> +	snprintf(line, PATH_MAX, "/proc/%d/fdinfo/%d", pid, file_fd);
> +	TST_ASSERT_FILE_INT(line, "mnt_id:", buf->stx_mnt_id);
> +}
> +#endif
> +
>  static void test_normal_file(void)
>  {
>  	struct statx buff;
> @@ -106,6 +146,11 @@ static void test_normal_file(void)
>  		tst_res(TFAIL, "stx_nlink(%u) is different from expected(1)",
>  			buff.stx_nlink);
>  
> +#ifdef HAVE_STRUCT_STATX_STX_MNT_ID
> +	test_mnt_id(&buff);
> +#else
> +	tst_res(TCONF, "stx_mnt_id was not supported until linux 5.8.");

This is confusing at best, if we end up here we were missing the
structure member during compilation regardless the kernel version.

So this message really should be:

"stx_mnt_id not defined in struct statx"
Yang Xu Nov. 30, 2021, 3:40 a.m. UTC | #2
Hi Cyril
> Hi!
>> +static int file_fd = -1;
>> +
>> +#ifdef HAVE_STRUCT_STATX_STX_MNT_ID
>> +static void test_mnt_id(struct statx *buf)
>> +{
>> +	FILE *file;
>> +	char line[PATH_MAX];
>> +	int pid;
>> +	unsigned int line_mjr, line_mnr, mnt_id;
>
> Shouldn't we check the STATX_MNT_ID bit here before we event attempt to
> continue? Otherwise if we compile the test with headers where stx_mnt_id
> is defined then run it on old kernel there will be garbage in the
> stx_mnt_id field.
Agree.
>
>> +	file = SAFE_FOPEN("/proc/self/mountinfo", "r");
>> +
>> +	while (fgets(line, sizeof(line), file)) {
>> +		if (sscanf(line, "%d %*d %d:%d",&mnt_id,&line_mjr,&line_mnr) != 3)
>> +			continue;
>> +
>> +		if (line_mjr == buf->stx_dev_major&&  line_mnr == buf->stx_dev_minor)
>> +			break;
>> +	}
>> +
>> +	SAFE_FCLOSE(file);
>> +
>> +	if (buf->stx_mnt_id == mnt_id)
>> +		tst_res(TPASS,
>> +			"statx.stx_mnt_id equals to mount_id(%d) in /proc/self/mountinfo",
>> +			mnt_id);
>> +	else
>> +		tst_res(TFAIL,
>> +			"statx.stx_mnt_id(%d) is different from mount_id(%d) in /proc/self/mountinfo",
>> +			buf->stx_mnt_id, mnt_id);
>> +
>> +	pid = getpid();
>> +	snprintf(line, PATH_MAX, "/proc/%d/fdinfo/%d", pid, file_fd);
>> +	TST_ASSERT_FILE_INT(line, "mnt_id:", buf->stx_mnt_id);
>> +}
>> +#endif
>> +
>>   static void test_normal_file(void)
>>   {
>>   	struct statx buff;
>> @@ -106,6 +146,11 @@ static void test_normal_file(void)
>>   		tst_res(TFAIL, "stx_nlink(%u) is different from expected(1)",
>>   			buff.stx_nlink);
>>
>> +#ifdef HAVE_STRUCT_STATX_STX_MNT_ID
>> +	test_mnt_id(&buff);
>> +#else
>> +	tst_res(TCONF, "stx_mnt_id was not supported until linux 5.8.");
>
> This is confusing at best, if we end up here we were missing the
> structure member during compilation regardless the kernel version.
>
> So this message really should be:
>
> "stx_mnt_id not defined in struct statx"
Will do it in v2.

Best Regards
Yang Xu
>
>
diff mbox series

Patch

diff --git a/configure.ac b/configure.ac
index 9101617ea..4751b14d2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -152,6 +152,10 @@  AC_CHECK_FUNCS(mkdtemp,[],AC_MSG_ERROR(mkdtemp() not found!))
 AC_CHECK_MEMBERS([struct fanotify_event_info_fid.fsid.__val],,,[#include <sys/fanotify.h>])
 AC_CHECK_MEMBERS([struct perf_event_mmap_page.aux_head],,,[#include <linux/perf_event.h>])
 AC_CHECK_MEMBERS([struct sigaction.sa_sigaction],[],[],[#include <signal.h>])
+AC_CHECK_MEMBERS([struct statx.stx_mnt_id],,,[
+#define _GNU_SOURCE
+#include <sys/stat.h>
+])
 
 AC_CHECK_MEMBERS([struct utsname.domainname],,,[
 #define _GNU_SOURCE
diff --git a/testcases/kernel/syscalls/statx/statx01.c b/testcases/kernel/syscalls/statx/statx01.c
index bf7d21c5d..6d0e7d590 100644
--- a/testcases/kernel/syscalls/statx/statx01.c
+++ b/testcases/kernel/syscalls/statx/statx01.c
@@ -17,6 +17,7 @@ 
  * 4) blocks
  * 5) size
  * 6) nlink
+ * 7) mnt_id
  *
  * A file is created and metadata values are set with
  * predefined values.
@@ -39,9 +40,11 @@ 
 #include <stdio.h>
 #include <sys/types.h>
 #include <sys/sysmacros.h>
+#include <unistd.h>
 #include "tst_test.h"
 #include "tst_safe_macros.h"
 #include "lapi/stat.h"
+#include "tst_safe_stdio.h"
 #include <string.h>
 #include <inttypes.h>
 
@@ -54,6 +57,43 @@ 
 #define MAJOR 8
 #define MINOR 1
 
+static int file_fd = -1;
+
+#ifdef HAVE_STRUCT_STATX_STX_MNT_ID
+static void test_mnt_id(struct statx *buf)
+{
+	FILE *file;
+	char line[PATH_MAX];
+	int pid;
+	unsigned int line_mjr, line_mnr, mnt_id;
+
+	file = SAFE_FOPEN("/proc/self/mountinfo", "r");
+
+	while (fgets(line, sizeof(line), file)) {
+		if (sscanf(line, "%d %*d %d:%d", &mnt_id, &line_mjr, &line_mnr) != 3)
+			continue;
+
+		if (line_mjr == buf->stx_dev_major && line_mnr == buf->stx_dev_minor)
+			break;
+	}
+
+	SAFE_FCLOSE(file);
+
+	if (buf->stx_mnt_id == mnt_id)
+		tst_res(TPASS,
+			"statx.stx_mnt_id equals to mount_id(%d) in /proc/self/mountinfo",
+			mnt_id);
+	else
+		tst_res(TFAIL,
+			"statx.stx_mnt_id(%d) is different from mount_id(%d) in /proc/self/mountinfo",
+			buf->stx_mnt_id, mnt_id);
+
+	pid = getpid();
+	snprintf(line, PATH_MAX, "/proc/%d/fdinfo/%d", pid, file_fd);
+	TST_ASSERT_FILE_INT(line, "mnt_id:", buf->stx_mnt_id);
+}
+#endif
+
 static void test_normal_file(void)
 {
 	struct statx buff;
@@ -106,6 +146,11 @@  static void test_normal_file(void)
 		tst_res(TFAIL, "stx_nlink(%u) is different from expected(1)",
 			buff.stx_nlink);
 
+#ifdef HAVE_STRUCT_STATX_STX_MNT_ID
+	test_mnt_id(&buff);
+#else
+	tst_res(TCONF, "stx_mnt_id was not supported until linux 5.8.");
+#endif
 }
 
 static void test_device_file(void)
@@ -137,7 +182,6 @@  static void test_device_file(void)
 			buff.stx_rdev_minor, MINOR);
 }
 
-
 struct tcase {
 	void (*tfunc)(void);
 } tcases[] = {
@@ -153,7 +197,6 @@  static void run(unsigned int i)
 static void setup(void)
 {
 	char data_buff[SIZE];
-	int file_fd;
 
 	umask(0);
 
@@ -161,15 +204,21 @@  static void setup(void)
 
 	file_fd =  SAFE_OPEN(TESTFILE, O_RDWR|O_CREAT, MODE);
 	SAFE_WRITE(1, file_fd, data_buff, sizeof(data_buff));
-	SAFE_CLOSE(file_fd);
 
 	SAFE_MKNOD(DEVICEFILE, S_IFBLK | 0777, makedev(MAJOR, MINOR));
 }
 
+static void cleanup(void)
+{
+	if (file_fd > -1)
+		SAFE_CLOSE(file_fd);
+}
+
 static struct tst_test test = {
 	.test = run,
 	.tcnt = ARRAY_SIZE(tcases),
 	.setup = setup,
+	.cleanup = cleanup,
 	.min_kver = "4.11",
 	.needs_devfs = 1,
 	.mntpoint = MNTPOINT,