All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH 1/1] syscalls/fsmount01: Add test for new mount API v5.2
@ 2020-02-06 16:27 Petr Vorel
  2020-02-07  8:18 ` Zorro Lang
  2020-02-07 13:20 ` Cyril Hrubis
  0 siblings, 2 replies; 6+ messages in thread
From: Petr Vorel @ 2020-02-06 16:27 UTC (permalink / raw)
  To: ltp

From: Zorro Lang <zlang@redhat.com>

Add basic tests tests for new mount API from kernel v5.2.
Testing mount and umount filesystems with fsopen(), fsconfig(),
fsmount() and move_mount().

Signed-off-by: Zorro Lang <zlang@redhat.com>
Reported-by: Cyril Hrubis <chrubis@suse.cz>
[ pvorel: cleanup autotools and other fixes ]
Signed-off-by: Petr Vorel <pvorel@suse.cz>
---
Hi,

I implemented fixes for "newmount" Zorro's patch, hoping this is a final
version. Changes are minor, asked by Cyril + rename test to fsmount01,
headers cleanup (but <sys/mount.h> kept + use SAFE_FOPEN()).

Kind regards,
Petr

 configure.ac                                  |  4 +
 include/lapi/newmount.h                       | 95 ++++++++++++++++++
 include/lapi/syscalls/powerpc64.in            |  4 +
 runtest/syscalls                              |  2 +
 testcases/kernel/syscalls/fsmount/.gitignore  |  1 +
 testcases/kernel/syscalls/fsmount/Makefile    |  8 ++
 testcases/kernel/syscalls/fsmount/fsmount01.c | 99 +++++++++++++++++++
 7 files changed, 213 insertions(+)
 create mode 100644 include/lapi/newmount.h
 create mode 100644 testcases/kernel/syscalls/fsmount/.gitignore
 create mode 100644 testcases/kernel/syscalls/fsmount/Makefile
 create mode 100644 testcases/kernel/syscalls/fsmount/fsmount01.c

diff --git a/configure.ac b/configure.ac
index df4e8c832..05b7d0a72 100644
--- a/configure.ac
+++ b/configure.ac
@@ -80,6 +80,9 @@ AC_CHECK_FUNCS([ \
     execveat \
     fallocate \
     fchownat \
+    fsconfig \
+    fsmount \
+    fsopen \
     fstatat \
     getdents \
     getdents64 \
@@ -88,6 +91,7 @@ AC_CHECK_FUNCS([ \
     mkdirat \
     mknodat \
     modify_ldt \
+    move_mount \
     name_to_handle_at \
     openat \
     pidfd_open \
diff --git a/include/lapi/newmount.h b/include/lapi/newmount.h
new file mode 100644
index 000000000..d4efdb300
--- /dev/null
+++ b/include/lapi/newmount.h
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Red Hat, Inc.  All rights reserved.
+ * Author: Zorro Lang <zlang@redhat.com>
+ */
+
+#ifndef NEWMOUNT_H__
+#define NEWMOUNT_H__
+
+#include <stdint.h>
+#include <unistd.h>
+#include "config.h"
+#include "lapi/syscalls.h"
+
+#ifndef HAVE_FSOPEN
+static inline int fsopen(const char *fs_name, unsigned int flags)
+{
+	return tst_syscall(__NR_fsopen, fs_name, flags);
+}
+
+/*
+ * fsopen() flags.
+ */
+#define FSOPEN_CLOEXEC		0x00000001
+#endif	/* HAVE_FSOPEN */
+
+#ifndef HAVE_FSCONFIG
+static inline int fsconfig(int fsfd, unsigned int cmd,
+                           const char *key, const void *val, int aux)
+{
+	return tst_syscall(__NR_fsconfig, fsfd, cmd, key, val, aux);
+}
+
+/*
+ * The type of fsconfig() call made.
+ */
+enum fsconfig_command {
+	FSCONFIG_SET_FLAG	= 0,    /* Set parameter, supplying no value */
+	FSCONFIG_SET_STRING	= 1,    /* Set parameter, supplying a string value */
+	FSCONFIG_SET_BINARY	= 2,    /* Set parameter, supplying a binary blob value */
+	FSCONFIG_SET_PATH	= 3,    /* Set parameter, supplying an object by path */
+	FSCONFIG_SET_PATH_EMPTY	= 4,    /* Set parameter, supplying an object by (empty) path */
+	FSCONFIG_SET_FD		= 5,    /* Set parameter, supplying an object by fd */
+	FSCONFIG_CMD_CREATE	= 6,    /* Invoke superblock creation */
+	FSCONFIG_CMD_RECONFIGURE = 7,   /* Invoke superblock reconfiguration */
+};
+#endif	/* HAVE_FSCONFIG */
+
+#ifndef HAVE_FSMOUNT
+static inline int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags)
+{
+	return tst_syscall(__NR_fsmount, fsfd, flags, ms_flags);
+}
+
+/*
+ * fsmount() flags.
+ */
+#define FSMOUNT_CLOEXEC		0x00000001
+
+/*
+ * Mount attributes.
+ */
+#define MOUNT_ATTR_RDONLY	0x00000001 /* Mount read-only */
+#define MOUNT_ATTR_NOSUID	0x00000002 /* Ignore suid and sgid bits */
+#define MOUNT_ATTR_NODEV	0x00000004 /* Disallow access to device special files */
+#define MOUNT_ATTR_NOEXEC	0x00000008 /* Disallow program execution */
+#define MOUNT_ATTR__ATIME	0x00000070 /* Setting on how atime should be updated */
+#define MOUNT_ATTR_RELATIME	0x00000000 /* - Update atime relative to mtime/ctime. */
+#define MOUNT_ATTR_NOATIME	0x00000010 /* - Do not update access times. */
+#define MOUNT_ATTR_STRICTATIME	0x00000020 /* - Always perform atime updates */
+#define MOUNT_ATTR_NODIRATIME	0x00000080 /* Do not update directory access times */
+#endif	/* HAVE_FSMOUNT */
+
+#ifndef HAVE_MOVE_MOUNT
+static inline int move_mount(int from_dfd, const char *from_pathname,
+                             int to_dfd, const char *to_pathname,
+                             unsigned int flags)
+{
+	return tst_syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd,
+	                   to_pathname, flags);
+}
+
+/*
+ * move_mount() flags.
+ */
+#define MOVE_MOUNT_F_SYMLINKS		0x00000001 /* Follow symlinks on from path */
+#define MOVE_MOUNT_F_AUTOMOUNTS		0x00000002 /* Follow automounts on from path */
+#define MOVE_MOUNT_F_EMPTY_PATH		0x00000004 /* Empty from path permitted */
+#define MOVE_MOUNT_T_SYMLINKS		0x00000010 /* Follow symlinks on to path */
+#define MOVE_MOUNT_T_AUTOMOUNTS		0x00000020 /* Follow automounts on to path */
+#define MOVE_MOUNT_T_EMPTY_PATH		0x00000040 /* Empty to path permitted */
+#define MOVE_MOUNT__MASK		0x00000077
+#endif	/* HAVE_MOVE_MOUNT */
+
+#endif /* NEWMOUNT_H__ */
diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in
index 2c1f105c1..beb0e6812 100644
--- a/include/lapi/syscalls/powerpc64.in
+++ b/include/lapi/syscalls/powerpc64.in
@@ -371,3 +371,7 @@ pidfd_open 434
 pkey_mprotect 386
 pkey_alloc 384
 pkey_free 385
+move_mount 429
+fsopen 430
+fsconfig 431
+fsmount 432
diff --git a/runtest/syscalls b/runtest/syscalls
index 0743cf4e3..72e729c1c 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -341,6 +341,8 @@ fpathconf01 fpathconf01
 fremovexattr01 fremovexattr01
 fremovexattr02 fremovexattr02
 
+fsmount01 fsmount01
+
 fstat02 fstat02
 fstat02_64 fstat02_64
 fstat03 fstat03
diff --git a/testcases/kernel/syscalls/fsmount/.gitignore b/testcases/kernel/syscalls/fsmount/.gitignore
new file mode 100644
index 000000000..e2f01ea17
--- /dev/null
+++ b/testcases/kernel/syscalls/fsmount/.gitignore
@@ -0,0 +1 @@
+/fsmount01
diff --git a/testcases/kernel/syscalls/fsmount/Makefile b/testcases/kernel/syscalls/fsmount/Makefile
new file mode 100644
index 000000000..cc80d2efd
--- /dev/null
+++ b/testcases/kernel/syscalls/fsmount/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2019 Red Hat, Inc.  All rights reserved.
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/fsmount/fsmount01.c b/testcases/kernel/syscalls/fsmount/fsmount01.c
new file mode 100644
index 000000000..7ba50753f
--- /dev/null
+++ b/testcases/kernel/syscalls/fsmount/fsmount01.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Red Hat, Inc.  All rights reserved.
+ * Author: Zorro Lang <zlang@redhat.com>
+ *
+ * Use new mount API from v5.2 (fsopen(), fsconfig(), fsmount(), move_mount())
+ * to mount a filesystem without any specified mount options.
+ */
+
+#include <sys/mount.h>
+
+#include "tst_test.h"
+#include "lapi/newmount.h"
+#include "tst_safe_stdio.h"
+
+#define LINELENGTH 256
+#define MNTPOINT "newmount_point"
+static int sfd, mfd, is_mounted;
+
+static int ismount(char *mntpoint)
+{
+	int ret = 0;
+	FILE *file;
+	char line[LINELENGTH];
+
+	file = SAFE_FOPEN("/proc/mounts", "r");
+
+	while (fgets(line, LINELENGTH, file) != NULL) {
+		if (strstr(line, mntpoint) != NULL) {
+			ret = 1;
+			break;
+		}
+	}
+	SAFE_FCLOSE(file);
+	return ret;
+}
+
+static void cleanup(void)
+{
+	if (is_mounted) {
+		TEST(tst_umount(MNTPOINT));
+		if (TST_RET != 0)
+			tst_brk(TBROK | TTERRNO, "umount failed in cleanup");
+	}
+}
+
+static void test_newmount(void)
+{
+	TEST(fsopen(tst_device->fs_type, FSOPEN_CLOEXEC));
+	if (TST_RET < 0)
+		tst_brk(TBROK | TTERRNO, "fsopen %s", tst_device->fs_type);
+	sfd = TST_RET;
+	tst_res(TPASS, "fsopen %s", tst_device->fs_type);
+
+	TEST(fsconfig(sfd, FSCONFIG_SET_STRING, "source", tst_device->dev, 0));
+	if (TST_RET < 0)
+		tst_brk(TBROK | TTERRNO,
+		        "fsconfig set source to %s", tst_device->dev);
+	tst_res(TPASS, "fsconfig set source to %s", tst_device->dev);
+
+
+	TEST(fsconfig(sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0));
+	if (TST_RET < 0)
+		tst_brk(TBROK | TTERRNO, "fsconfig create superblock");
+	tst_res(TPASS, "fsconfig create superblock");
+
+	TEST(fsmount(sfd, FSMOUNT_CLOEXEC, 0));
+	if (TST_RET < 0)
+		tst_brk(TBROK | TTERRNO, "fsmount");
+	mfd = TST_RET;
+	tst_res(TPASS, "fsmount");
+	SAFE_CLOSE(sfd);
+
+	TEST(move_mount(mfd, "", AT_FDCWD, MNTPOINT, MOVE_MOUNT_F_EMPTY_PATH));
+	if (TST_RET < 0)
+		tst_brk(TBROK | TTERRNO, "move_mount attach to mount point");
+	is_mounted = 1;
+	tst_res(TPASS, "move_mount attach to mount point");
+	SAFE_CLOSE(mfd);
+
+	if (ismount(MNTPOINT)) {
+		tst_res(TPASS, "new mount API from v5.2 works");
+		TEST(tst_umount(MNTPOINT));
+		if (TST_RET != 0)
+			tst_brk(TBROK | TTERRNO, "umount failed");
+		is_mounted = 0;
+	} else
+		tst_res(TFAIL, "new mount API from v5.2 works");
+}
+
+static struct tst_test test = {
+	.test_all = test_newmount,
+	.cleanup = cleanup,
+	.needs_root = 1,
+	.mntpoint = MNTPOINT,
+	.format_device = 1,
+	.all_filesystems = 1,
+	.dev_fs_flags = TST_FS_SKIP_FUSE,
+};
-- 
2.24.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [LTP] [PATCH 1/1] syscalls/fsmount01: Add test for new mount API v5.2
  2020-02-06 16:27 [LTP] [PATCH 1/1] syscalls/fsmount01: Add test for new mount API v5.2 Petr Vorel
@ 2020-02-07  8:18 ` Zorro Lang
  2020-02-07  9:05   ` Petr Vorel
  2020-02-07 13:20 ` Cyril Hrubis
  1 sibling, 1 reply; 6+ messages in thread
From: Zorro Lang @ 2020-02-07  8:18 UTC (permalink / raw)
  To: ltp

On Thu, Feb 06, 2020 at 05:27:22PM +0100, Petr Vorel wrote:
> From: Zorro Lang <zlang@redhat.com>
> 
> Add basic tests tests for new mount API from kernel v5.2.
> Testing mount and umount filesystems with fsopen(), fsconfig(),
> fsmount() and move_mount().
> 
> Signed-off-by: Zorro Lang <zlang@redhat.com>
> Reported-by: Cyril Hrubis <chrubis@suse.cz>
> [ pvorel: cleanup autotools and other fixes ]
> Signed-off-by: Petr Vorel <pvorel@suse.cz>
> ---
> Hi,
> 
> I implemented fixes for "newmount" Zorro's patch, hoping this is a final
> version. Changes are minor, asked by Cyril + rename test to fsmount01,

Thanks so much!

I think I shouldn't ack a patch from myself. So I just ask a small question.
I noticed that you decide to use the name as "syscalls/fsmount/fsmount01".
I hope the "fsmount" is a general name, which doesn't mean fsmount() itself.
Due to I might write other cases don't aim to test fsmount(). E.g.
open_tree() and move_tree(). But I will name the name as fsmount?? . I hope
that meets your expectation.

Thanks,
Zorro

> headers cleanup (but <sys/mount.h> kept + use SAFE_FOPEN()).
> 
> Kind regards,
> Petr
> 
>  configure.ac                                  |  4 +
>  include/lapi/newmount.h                       | 95 ++++++++++++++++++
>  include/lapi/syscalls/powerpc64.in            |  4 +
>  runtest/syscalls                              |  2 +
>  testcases/kernel/syscalls/fsmount/.gitignore  |  1 +
>  testcases/kernel/syscalls/fsmount/Makefile    |  8 ++
>  testcases/kernel/syscalls/fsmount/fsmount01.c | 99 +++++++++++++++++++
>  7 files changed, 213 insertions(+)
>  create mode 100644 include/lapi/newmount.h
>  create mode 100644 testcases/kernel/syscalls/fsmount/.gitignore
>  create mode 100644 testcases/kernel/syscalls/fsmount/Makefile
>  create mode 100644 testcases/kernel/syscalls/fsmount/fsmount01.c
> 
> diff --git a/configure.ac b/configure.ac
> index df4e8c832..05b7d0a72 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -80,6 +80,9 @@ AC_CHECK_FUNCS([ \
>      execveat \
>      fallocate \
>      fchownat \
> +    fsconfig \
> +    fsmount \
> +    fsopen \
>      fstatat \
>      getdents \
>      getdents64 \
> @@ -88,6 +91,7 @@ AC_CHECK_FUNCS([ \
>      mkdirat \
>      mknodat \
>      modify_ldt \
> +    move_mount \
>      name_to_handle_at \
>      openat \
>      pidfd_open \
> diff --git a/include/lapi/newmount.h b/include/lapi/newmount.h
> new file mode 100644
> index 000000000..d4efdb300
> --- /dev/null
> +++ b/include/lapi/newmount.h
> @@ -0,0 +1,95 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019 Red Hat, Inc.  All rights reserved.
> + * Author: Zorro Lang <zlang@redhat.com>
> + */
> +
> +#ifndef NEWMOUNT_H__
> +#define NEWMOUNT_H__
> +
> +#include <stdint.h>
> +#include <unistd.h>
> +#include "config.h"
> +#include "lapi/syscalls.h"
> +
> +#ifndef HAVE_FSOPEN
> +static inline int fsopen(const char *fs_name, unsigned int flags)
> +{
> +	return tst_syscall(__NR_fsopen, fs_name, flags);
> +}
> +
> +/*
> + * fsopen() flags.
> + */
> +#define FSOPEN_CLOEXEC		0x00000001
> +#endif	/* HAVE_FSOPEN */
> +
> +#ifndef HAVE_FSCONFIG
> +static inline int fsconfig(int fsfd, unsigned int cmd,
> +                           const char *key, const void *val, int aux)
> +{
> +	return tst_syscall(__NR_fsconfig, fsfd, cmd, key, val, aux);
> +}
> +
> +/*
> + * The type of fsconfig() call made.
> + */
> +enum fsconfig_command {
> +	FSCONFIG_SET_FLAG	= 0,    /* Set parameter, supplying no value */
> +	FSCONFIG_SET_STRING	= 1,    /* Set parameter, supplying a string value */
> +	FSCONFIG_SET_BINARY	= 2,    /* Set parameter, supplying a binary blob value */
> +	FSCONFIG_SET_PATH	= 3,    /* Set parameter, supplying an object by path */
> +	FSCONFIG_SET_PATH_EMPTY	= 4,    /* Set parameter, supplying an object by (empty) path */
> +	FSCONFIG_SET_FD		= 5,    /* Set parameter, supplying an object by fd */
> +	FSCONFIG_CMD_CREATE	= 6,    /* Invoke superblock creation */
> +	FSCONFIG_CMD_RECONFIGURE = 7,   /* Invoke superblock reconfiguration */
> +};
> +#endif	/* HAVE_FSCONFIG */
> +
> +#ifndef HAVE_FSMOUNT
> +static inline int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags)
> +{
> +	return tst_syscall(__NR_fsmount, fsfd, flags, ms_flags);
> +}
> +
> +/*
> + * fsmount() flags.
> + */
> +#define FSMOUNT_CLOEXEC		0x00000001
> +
> +/*
> + * Mount attributes.
> + */
> +#define MOUNT_ATTR_RDONLY	0x00000001 /* Mount read-only */
> +#define MOUNT_ATTR_NOSUID	0x00000002 /* Ignore suid and sgid bits */
> +#define MOUNT_ATTR_NODEV	0x00000004 /* Disallow access to device special files */
> +#define MOUNT_ATTR_NOEXEC	0x00000008 /* Disallow program execution */
> +#define MOUNT_ATTR__ATIME	0x00000070 /* Setting on how atime should be updated */
> +#define MOUNT_ATTR_RELATIME	0x00000000 /* - Update atime relative to mtime/ctime. */
> +#define MOUNT_ATTR_NOATIME	0x00000010 /* - Do not update access times. */
> +#define MOUNT_ATTR_STRICTATIME	0x00000020 /* - Always perform atime updates */
> +#define MOUNT_ATTR_NODIRATIME	0x00000080 /* Do not update directory access times */
> +#endif	/* HAVE_FSMOUNT */
> +
> +#ifndef HAVE_MOVE_MOUNT
> +static inline int move_mount(int from_dfd, const char *from_pathname,
> +                             int to_dfd, const char *to_pathname,
> +                             unsigned int flags)
> +{
> +	return tst_syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd,
> +	                   to_pathname, flags);
> +}
> +
> +/*
> + * move_mount() flags.
> + */
> +#define MOVE_MOUNT_F_SYMLINKS		0x00000001 /* Follow symlinks on from path */
> +#define MOVE_MOUNT_F_AUTOMOUNTS		0x00000002 /* Follow automounts on from path */
> +#define MOVE_MOUNT_F_EMPTY_PATH		0x00000004 /* Empty from path permitted */
> +#define MOVE_MOUNT_T_SYMLINKS		0x00000010 /* Follow symlinks on to path */
> +#define MOVE_MOUNT_T_AUTOMOUNTS		0x00000020 /* Follow automounts on to path */
> +#define MOVE_MOUNT_T_EMPTY_PATH		0x00000040 /* Empty to path permitted */
> +#define MOVE_MOUNT__MASK		0x00000077
> +#endif	/* HAVE_MOVE_MOUNT */
> +
> +#endif /* NEWMOUNT_H__ */
> diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in
> index 2c1f105c1..beb0e6812 100644
> --- a/include/lapi/syscalls/powerpc64.in
> +++ b/include/lapi/syscalls/powerpc64.in
> @@ -371,3 +371,7 @@ pidfd_open 434
>  pkey_mprotect 386
>  pkey_alloc 384
>  pkey_free 385
> +move_mount 429
> +fsopen 430
> +fsconfig 431
> +fsmount 432
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 0743cf4e3..72e729c1c 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -341,6 +341,8 @@ fpathconf01 fpathconf01
>  fremovexattr01 fremovexattr01
>  fremovexattr02 fremovexattr02
>  
> +fsmount01 fsmount01
> +
>  fstat02 fstat02
>  fstat02_64 fstat02_64
>  fstat03 fstat03
> diff --git a/testcases/kernel/syscalls/fsmount/.gitignore b/testcases/kernel/syscalls/fsmount/.gitignore
> new file mode 100644
> index 000000000..e2f01ea17
> --- /dev/null
> +++ b/testcases/kernel/syscalls/fsmount/.gitignore
> @@ -0,0 +1 @@
> +/fsmount01
> diff --git a/testcases/kernel/syscalls/fsmount/Makefile b/testcases/kernel/syscalls/fsmount/Makefile
> new file mode 100644
> index 000000000..cc80d2efd
> --- /dev/null
> +++ b/testcases/kernel/syscalls/fsmount/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (C) 2019 Red Hat, Inc.  All rights reserved.
> +
> +top_srcdir		?= ../../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/syscalls/fsmount/fsmount01.c b/testcases/kernel/syscalls/fsmount/fsmount01.c
> new file mode 100644
> index 000000000..7ba50753f
> --- /dev/null
> +++ b/testcases/kernel/syscalls/fsmount/fsmount01.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019 Red Hat, Inc.  All rights reserved.
> + * Author: Zorro Lang <zlang@redhat.com>
> + *
> + * Use new mount API from v5.2 (fsopen(), fsconfig(), fsmount(), move_mount())
> + * to mount a filesystem without any specified mount options.
> + */
> +
> +#include <sys/mount.h>
> +
> +#include "tst_test.h"
> +#include "lapi/newmount.h"
> +#include "tst_safe_stdio.h"
> +
> +#define LINELENGTH 256
> +#define MNTPOINT "newmount_point"
> +static int sfd, mfd, is_mounted;
> +
> +static int ismount(char *mntpoint)
> +{
> +	int ret = 0;
> +	FILE *file;
> +	char line[LINELENGTH];
> +
> +	file = SAFE_FOPEN("/proc/mounts", "r");
> +
> +	while (fgets(line, LINELENGTH, file) != NULL) {
> +		if (strstr(line, mntpoint) != NULL) {
> +			ret = 1;
> +			break;
> +		}
> +	}
> +	SAFE_FCLOSE(file);
> +	return ret;
> +}
> +
> +static void cleanup(void)
> +{
> +	if (is_mounted) {
> +		TEST(tst_umount(MNTPOINT));
> +		if (TST_RET != 0)
> +			tst_brk(TBROK | TTERRNO, "umount failed in cleanup");
> +	}
> +}
> +
> +static void test_newmount(void)
> +{
> +	TEST(fsopen(tst_device->fs_type, FSOPEN_CLOEXEC));
> +	if (TST_RET < 0)
> +		tst_brk(TBROK | TTERRNO, "fsopen %s", tst_device->fs_type);
> +	sfd = TST_RET;
> +	tst_res(TPASS, "fsopen %s", tst_device->fs_type);
> +
> +	TEST(fsconfig(sfd, FSCONFIG_SET_STRING, "source", tst_device->dev, 0));
> +	if (TST_RET < 0)
> +		tst_brk(TBROK | TTERRNO,
> +		        "fsconfig set source to %s", tst_device->dev);
> +	tst_res(TPASS, "fsconfig set source to %s", tst_device->dev);
> +
> +
> +	TEST(fsconfig(sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0));
> +	if (TST_RET < 0)
> +		tst_brk(TBROK | TTERRNO, "fsconfig create superblock");
> +	tst_res(TPASS, "fsconfig create superblock");
> +
> +	TEST(fsmount(sfd, FSMOUNT_CLOEXEC, 0));
> +	if (TST_RET < 0)
> +		tst_brk(TBROK | TTERRNO, "fsmount");
> +	mfd = TST_RET;
> +	tst_res(TPASS, "fsmount");
> +	SAFE_CLOSE(sfd);
> +
> +	TEST(move_mount(mfd, "", AT_FDCWD, MNTPOINT, MOVE_MOUNT_F_EMPTY_PATH));
> +	if (TST_RET < 0)
> +		tst_brk(TBROK | TTERRNO, "move_mount attach to mount point");
> +	is_mounted = 1;
> +	tst_res(TPASS, "move_mount attach to mount point");
> +	SAFE_CLOSE(mfd);
> +
> +	if (ismount(MNTPOINT)) {
> +		tst_res(TPASS, "new mount API from v5.2 works");
> +		TEST(tst_umount(MNTPOINT));
> +		if (TST_RET != 0)
> +			tst_brk(TBROK | TTERRNO, "umount failed");
> +		is_mounted = 0;
> +	} else
> +		tst_res(TFAIL, "new mount API from v5.2 works");
> +}
> +
> +static struct tst_test test = {
> +	.test_all = test_newmount,
> +	.cleanup = cleanup,
> +	.needs_root = 1,
> +	.mntpoint = MNTPOINT,
> +	.format_device = 1,
> +	.all_filesystems = 1,
> +	.dev_fs_flags = TST_FS_SKIP_FUSE,
> +};
> -- 
> 2.24.1
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [LTP] [PATCH 1/1] syscalls/fsmount01: Add test for new mount API v5.2
  2020-02-07  8:18 ` Zorro Lang
@ 2020-02-07  9:05   ` Petr Vorel
  0 siblings, 0 replies; 6+ messages in thread
From: Petr Vorel @ 2020-02-07  9:05 UTC (permalink / raw)
  To: ltp

Hi Zorro,

> > I implemented fixes for "newmount" Zorro's patch, hoping this is a final
> > version. Changes are minor, asked by Cyril + rename test to fsmount01,

BTW I forget to add v5 to be clear that it's a follow up of Zorro's v4 [1].

> Thanks so much!
You're welcome :). We thank you to finally start writing tests for new syscalls,
we need to test all new ones.

> I think I shouldn't ack a patch from myself. So I just ask a small question.
> I noticed that you decide to use the name as "syscalls/fsmount/fsmount01".
> I hope the "fsmount" is a general name, which doesn't mean fsmount() itself.
> Due to I might write other cases don't aim to test fsmount(). E.g.
> open_tree() and move_tree(). But I will name the name as fsmount?? . I hope
> that meets your expectation.
I chose fsmount as I agreed with Cyril [2] that fsmount() is the main syscall
tested (although your test is testing all of them). If you look in various tests
in LTP, they often use many syscalls, but just one of them is the main one (e.g.
testcases/kernel/syscalls/mount/mount0*.c and testcases/kernel/syscalls/umount2/umount2_0*.c
are using both mount() and umount()), but we always use real syscalls name.

So when you test specifically just open_tree(), use that name.
I was thinking whether to change this approach in current topic (new mount API
from v5.2), but IMHO from long term perspective people search for particular
tests names, so newmount would hide it. But we can always change it in the
future.

Kind regards,
Petr

[1] https://patchwork.ozlabs.org/patch/1224056/
[2] https://lists.linux.it/pipermail/ltp/2020-January/015068.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [LTP] [PATCH 1/1] syscalls/fsmount01: Add test for new mount API v5.2
  2020-02-06 16:27 [LTP] [PATCH 1/1] syscalls/fsmount01: Add test for new mount API v5.2 Petr Vorel
  2020-02-07  8:18 ` Zorro Lang
@ 2020-02-07 13:20 ` Cyril Hrubis
  2020-02-07 14:04   ` Petr Vorel
  1 sibling, 1 reply; 6+ messages in thread
From: Cyril Hrubis @ 2020-02-07 13:20 UTC (permalink / raw)
  To: ltp

Hi!
> Add basic tests tests for new mount API from kernel v5.2.
> Testing mount and umount filesystems with fsopen(), fsconfig(),
> fsmount() and move_mount().
> 
> Signed-off-by: Zorro Lang <zlang@redhat.com>
> Reported-by: Cyril Hrubis <chrubis@suse.cz>
> [ pvorel: cleanup autotools and other fixes ]
> Signed-off-by: Petr Vorel <pvorel@suse.cz>
> ---
> Hi,
> 
> I implemented fixes for "newmount" Zorro's patch, hoping this is a final
> version. Changes are minor, asked by Cyril + rename test to fsmount01,
> headers cleanup (but <sys/mount.h> kept + use SAFE_FOPEN()).
> 
> Kind regards,
> Petr
> 
>  configure.ac                                  |  4 +
>  include/lapi/newmount.h                       | 95 ++++++++++++++++++
>  include/lapi/syscalls/powerpc64.in            |  4 +
>  runtest/syscalls                              |  2 +
>  testcases/kernel/syscalls/fsmount/.gitignore  |  1 +
>  testcases/kernel/syscalls/fsmount/Makefile    |  8 ++
>  testcases/kernel/syscalls/fsmount/fsmount01.c | 99 +++++++++++++++++++
>  7 files changed, 213 insertions(+)
>  create mode 100644 include/lapi/newmount.h
>  create mode 100644 testcases/kernel/syscalls/fsmount/.gitignore
>  create mode 100644 testcases/kernel/syscalls/fsmount/Makefile
>  create mode 100644 testcases/kernel/syscalls/fsmount/fsmount01.c
> 
> diff --git a/configure.ac b/configure.ac
> index df4e8c832..05b7d0a72 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -80,6 +80,9 @@ AC_CHECK_FUNCS([ \
>      execveat \
>      fallocate \
>      fchownat \
> +    fsconfig \
> +    fsmount \
> +    fsopen \
>      fstatat \
>      getdents \
>      getdents64 \
> @@ -88,6 +91,7 @@ AC_CHECK_FUNCS([ \
>      mkdirat \
>      mknodat \
>      modify_ldt \
> +    move_mount \
>      name_to_handle_at \
>      openat \
>      pidfd_open \
> diff --git a/include/lapi/newmount.h b/include/lapi/newmount.h
> new file mode 100644
> index 000000000..d4efdb300
> --- /dev/null
> +++ b/include/lapi/newmount.h
> @@ -0,0 +1,95 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019 Red Hat, Inc.  All rights reserved.
> + * Author: Zorro Lang <zlang@redhat.com>
> + */
> +
> +#ifndef NEWMOUNT_H__
> +#define NEWMOUNT_H__
> +
> +#include <stdint.h>
> +#include <unistd.h>
> +#include "config.h"
> +#include "lapi/syscalls.h"
> +
> +#ifndef HAVE_FSOPEN
> +static inline int fsopen(const char *fs_name, unsigned int flags)
> +{
> +	return tst_syscall(__NR_fsopen, fs_name, flags);
> +}
> +
> +/*
> + * fsopen() flags.
> + */
> +#define FSOPEN_CLOEXEC		0x00000001
> +#endif	/* HAVE_FSOPEN */
> +
> +#ifndef HAVE_FSCONFIG
> +static inline int fsconfig(int fsfd, unsigned int cmd,
> +                           const char *key, const void *val, int aux)
> +{
> +	return tst_syscall(__NR_fsconfig, fsfd, cmd, key, val, aux);
> +}
> +
> +/*
> + * The type of fsconfig() call made.
> + */
> +enum fsconfig_command {
> +	FSCONFIG_SET_FLAG	= 0,    /* Set parameter, supplying no value */
> +	FSCONFIG_SET_STRING	= 1,    /* Set parameter, supplying a string value */
> +	FSCONFIG_SET_BINARY	= 2,    /* Set parameter, supplying a binary blob value */
> +	FSCONFIG_SET_PATH	= 3,    /* Set parameter, supplying an object by path */
> +	FSCONFIG_SET_PATH_EMPTY	= 4,    /* Set parameter, supplying an object by (empty) path */
> +	FSCONFIG_SET_FD		= 5,    /* Set parameter, supplying an object by fd */
> +	FSCONFIG_CMD_CREATE	= 6,    /* Invoke superblock creation */
> +	FSCONFIG_CMD_RECONFIGURE = 7,   /* Invoke superblock reconfiguration */
> +};
> +#endif	/* HAVE_FSCONFIG */
> +
> +#ifndef HAVE_FSMOUNT
> +static inline int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags)
> +{
> +	return tst_syscall(__NR_fsmount, fsfd, flags, ms_flags);
> +}
> +
> +/*
> + * fsmount() flags.
> + */
> +#define FSMOUNT_CLOEXEC		0x00000001
> +
> +/*
> + * Mount attributes.
> + */
> +#define MOUNT_ATTR_RDONLY	0x00000001 /* Mount read-only */
> +#define MOUNT_ATTR_NOSUID	0x00000002 /* Ignore suid and sgid bits */
> +#define MOUNT_ATTR_NODEV	0x00000004 /* Disallow access to device special files */
> +#define MOUNT_ATTR_NOEXEC	0x00000008 /* Disallow program execution */
> +#define MOUNT_ATTR__ATIME	0x00000070 /* Setting on how atime should be updated */
> +#define MOUNT_ATTR_RELATIME	0x00000000 /* - Update atime relative to mtime/ctime. */
> +#define MOUNT_ATTR_NOATIME	0x00000010 /* - Do not update access times. */
> +#define MOUNT_ATTR_STRICTATIME	0x00000020 /* - Always perform atime updates */
> +#define MOUNT_ATTR_NODIRATIME	0x00000080 /* Do not update directory access times */
> +#endif	/* HAVE_FSMOUNT */
> +
> +#ifndef HAVE_MOVE_MOUNT
> +static inline int move_mount(int from_dfd, const char *from_pathname,
> +                             int to_dfd, const char *to_pathname,
> +                             unsigned int flags)
> +{
> +	return tst_syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd,
> +	                   to_pathname, flags);
> +}
> +
> +/*
> + * move_mount() flags.
> + */
> +#define MOVE_MOUNT_F_SYMLINKS		0x00000001 /* Follow symlinks on from path */
> +#define MOVE_MOUNT_F_AUTOMOUNTS		0x00000002 /* Follow automounts on from path */
> +#define MOVE_MOUNT_F_EMPTY_PATH		0x00000004 /* Empty from path permitted */
> +#define MOVE_MOUNT_T_SYMLINKS		0x00000010 /* Follow symlinks on to path */
> +#define MOVE_MOUNT_T_AUTOMOUNTS		0x00000020 /* Follow automounts on to path */
> +#define MOVE_MOUNT_T_EMPTY_PATH		0x00000040 /* Empty to path permitted */
> +#define MOVE_MOUNT__MASK		0x00000077
> +#endif	/* HAVE_MOVE_MOUNT */
> +
> +#endif /* NEWMOUNT_H__ */
> diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in
> index 2c1f105c1..beb0e6812 100644
> --- a/include/lapi/syscalls/powerpc64.in
> +++ b/include/lapi/syscalls/powerpc64.in
> @@ -371,3 +371,7 @@ pidfd_open 434
>  pkey_mprotect 386
>  pkey_alloc 384
>  pkey_free 385
> +move_mount 429
> +fsopen 430
> +fsconfig 431
> +fsmount 432
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 0743cf4e3..72e729c1c 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -341,6 +341,8 @@ fpathconf01 fpathconf01
>  fremovexattr01 fremovexattr01
>  fremovexattr02 fremovexattr02
>  
> +fsmount01 fsmount01
> +
>  fstat02 fstat02
>  fstat02_64 fstat02_64
>  fstat03 fstat03
> diff --git a/testcases/kernel/syscalls/fsmount/.gitignore b/testcases/kernel/syscalls/fsmount/.gitignore
> new file mode 100644
> index 000000000..e2f01ea17
> --- /dev/null
> +++ b/testcases/kernel/syscalls/fsmount/.gitignore
> @@ -0,0 +1 @@
> +/fsmount01
> diff --git a/testcases/kernel/syscalls/fsmount/Makefile b/testcases/kernel/syscalls/fsmount/Makefile
> new file mode 100644
> index 000000000..cc80d2efd
> --- /dev/null
> +++ b/testcases/kernel/syscalls/fsmount/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +# Copyright (C) 2019 Red Hat, Inc.  All rights reserved.
> +
> +top_srcdir		?= ../../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> diff --git a/testcases/kernel/syscalls/fsmount/fsmount01.c b/testcases/kernel/syscalls/fsmount/fsmount01.c
> new file mode 100644
> index 000000000..7ba50753f
> --- /dev/null
> +++ b/testcases/kernel/syscalls/fsmount/fsmount01.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2019 Red Hat, Inc.  All rights reserved.
> + * Author: Zorro Lang <zlang@redhat.com>
> + *
> + * Use new mount API from v5.2 (fsopen(), fsconfig(), fsmount(), move_mount())
> + * to mount a filesystem without any specified mount options.
> + */
> +
> +#include <sys/mount.h>
> +
> +#include "tst_test.h"
> +#include "lapi/newmount.h"
> +#include "tst_safe_stdio.h"
> +
> +#define LINELENGTH 256
> +#define MNTPOINT "newmount_point"
> +static int sfd, mfd, is_mounted;
> +
> +static int ismount(char *mntpoint)
> +{
> +	int ret = 0;
> +	FILE *file;
> +	char line[LINELENGTH];
> +
> +	file = SAFE_FOPEN("/proc/mounts", "r");
> +
> +	while (fgets(line, LINELENGTH, file) != NULL) {
> +		if (strstr(line, mntpoint) != NULL) {

It's not necessary to check against NULL, we can simply write these as:

	while (fgets(line, sizeof(line), file)) {
		...

> +			ret = 1;
> +			break;
> +		}
> +	}
> +	SAFE_FCLOSE(file);
> +	return ret;
> +}
> +
> +static void cleanup(void)
> +{
> +	if (is_mounted) {
> +		TEST(tst_umount(MNTPOINT));
> +		if (TST_RET != 0)
> +			tst_brk(TBROK | TTERRNO, "umount failed in cleanup");

I do remmeber commenting this that the tst_umount() already prints a
WARN which will fail the test anyways, so there is no point in handling
the return from tst_umount() here.

> +	}
> +}
> +
> +static void test_newmount(void)
> +{
> +	TEST(fsopen(tst_device->fs_type, FSOPEN_CLOEXEC));
> +	if (TST_RET < 0)
> +		tst_brk(TBROK | TTERRNO, "fsopen %s", tst_device->fs_type);
> +	sfd = TST_RET;
> +	tst_res(TPASS, "fsopen %s", tst_device->fs_type);
> +
> +	TEST(fsconfig(sfd, FSCONFIG_SET_STRING, "source", tst_device->dev, 0));
> +	if (TST_RET < 0)
> +		tst_brk(TBROK | TTERRNO,
> +		        "fsconfig set source to %s", tst_device->dev);
> +	tst_res(TPASS, "fsconfig set source to %s", tst_device->dev);
> +
> +
> +	TEST(fsconfig(sfd, FSCONFIG_CMD_CREATE, NULL, NULL, 0));
> +	if (TST_RET < 0)
> +		tst_brk(TBROK | TTERRNO, "fsconfig create superblock");
> +	tst_res(TPASS, "fsconfig create superblock");
> +
> +	TEST(fsmount(sfd, FSMOUNT_CLOEXEC, 0));
> +	if (TST_RET < 0)
> +		tst_brk(TBROK | TTERRNO, "fsmount");
> +	mfd = TST_RET;
> +	tst_res(TPASS, "fsmount");
> +	SAFE_CLOSE(sfd);
> +
> +	TEST(move_mount(mfd, "", AT_FDCWD, MNTPOINT, MOVE_MOUNT_F_EMPTY_PATH));
> +	if (TST_RET < 0)
> +		tst_brk(TBROK | TTERRNO, "move_mount attach to mount point");
> +	is_mounted = 1;
> +	tst_res(TPASS, "move_mount attach to mount point");
> +	SAFE_CLOSE(mfd);
> +
> +	if (ismount(MNTPOINT)) {
> +		tst_res(TPASS, "new mount API from v5.2 works");
> +		TEST(tst_umount(MNTPOINT));
> +		if (TST_RET != 0)
> +			tst_brk(TBROK | TTERRNO, "umount failed");

And here as well.

> +		is_mounted = 0;
> +	} else
> +		tst_res(TFAIL, "new mount API from v5.2 works");
> +}
> +
> +static struct tst_test test = {
> +	.test_all = test_newmount,
> +	.cleanup = cleanup,
> +	.needs_root = 1,
> +	.mntpoint = MNTPOINT,
> +	.format_device = 1,
> +	.all_filesystems = 1,
> +	.dev_fs_flags = TST_FS_SKIP_FUSE,
> +};

Apart from these two minor comments the test looks good, you can add my
Reviewed-by.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [LTP] [PATCH 1/1] syscalls/fsmount01: Add test for new mount API v5.2
  2020-02-07 13:20 ` Cyril Hrubis
@ 2020-02-07 14:04   ` Petr Vorel
  2020-02-07 14:08     ` Cyril Hrubis
  0 siblings, 1 reply; 6+ messages in thread
From: Petr Vorel @ 2020-02-07 14:04 UTC (permalink / raw)
  To: ltp

Hi,

> > +	while (fgets(line, LINELENGTH, file) != NULL) {
> > +		if (strstr(line, mntpoint) != NULL) {

> It's not necessary to check against NULL, we can simply write these as:

> 	while (fgets(line, sizeof(line), file)) {
> 		...

> > +			ret = 1;
> > +			break;
> > +		}
> > +	}
> > +	SAFE_FCLOSE(file);
> > +	return ret;
> > +}
> > +
> > +static void cleanup(void)
> > +{
> > +	if (is_mounted) {
> > +		TEST(tst_umount(MNTPOINT));
> > +		if (TST_RET != 0)
> > +			tst_brk(TBROK | TTERRNO, "umount failed in cleanup");

> I do remmeber commenting this that the tst_umount() already prints a
> WARN which will fail the test anyways, so there is no point in handling
> the return from tst_umount() here.
I guess SAFE_UMOUNT(MNTPOINT) will be the best.

...
> > +	if (ismount(MNTPOINT)) {
> > +		tst_res(TPASS, "new mount API from v5.2 works");
> > +		TEST(tst_umount(MNTPOINT));
> > +		if (TST_RET != 0)
> > +			tst_brk(TBROK | TTERRNO, "umount failed");

> And here as well.

> Apart from these two minor comments the test looks good, you can add my
> Reviewed-by.

Thanks for review, sorry for not catching these errors.
Going to fix it with your Reviewed-by, with these fixes.

Kind regards,
Petr

diff --git testcases/kernel/syscalls/fsmount/fsmount01.c testcases/kernel/syscalls/fsmount/fsmount01.c
index 7ba50753f..64e8c4744 100644
--- testcases/kernel/syscalls/fsmount/fsmount01.c
+++ testcases/kernel/syscalls/fsmount/fsmount01.c
@@ -25,7 +25,7 @@ static int ismount(char *mntpoint)
 
 	file = SAFE_FOPEN("/proc/mounts", "r");
 
-	while (fgets(line, LINELENGTH, file) != NULL) {
+	while (fgets(line, sizeof(line), file)) {
 		if (strstr(line, mntpoint) != NULL) {
 			ret = 1;
 			break;
@@ -37,11 +37,8 @@ static int ismount(char *mntpoint)
 
 static void cleanup(void)
 {
-	if (is_mounted) {
-		TEST(tst_umount(MNTPOINT));
-		if (TST_RET != 0)
-			tst_brk(TBROK | TTERRNO, "umount failed in cleanup");
-	}
+	if (is_mounted)
+		SAFE_UMOUNT(MNTPOINT)
 }
 
 static void test_newmount(void)
@@ -80,9 +77,7 @@ static void test_newmount(void)
 
 	if (ismount(MNTPOINT)) {
 		tst_res(TPASS, "new mount API from v5.2 works");
-		TEST(tst_umount(MNTPOINT));
-		if (TST_RET != 0)
-			tst_brk(TBROK | TTERRNO, "umount failed");
+		SAFE_UMOUNT(MNTPOINT)
 		is_mounted = 0;
 	} else
 		tst_res(TFAIL, "new mount API from v5.2 works");

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [LTP] [PATCH 1/1] syscalls/fsmount01: Add test for new mount API v5.2
  2020-02-07 14:04   ` Petr Vorel
@ 2020-02-07 14:08     ` Cyril Hrubis
  0 siblings, 0 replies; 6+ messages in thread
From: Cyril Hrubis @ 2020-02-07 14:08 UTC (permalink / raw)
  To: ltp

Hi!
> > I do remmeber commenting this that the tst_umount() already prints a
> > WARN which will fail the test anyways, so there is no point in handling
> > the return from tst_umount() here.
> I guess SAFE_UMOUNT(MNTPOINT) will be the best.

Actually no, because unlike the tst_umount() SAFE_UMOUNT() does not
retry, which will make the test faill if there is a background daemon
that is probing newly mounted filesystems.

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-02-07 14:08 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-02-06 16:27 [LTP] [PATCH 1/1] syscalls/fsmount01: Add test for new mount API v5.2 Petr Vorel
2020-02-07  8:18 ` Zorro Lang
2020-02-07  9:05   ` Petr Vorel
2020-02-07 13:20 ` Cyril Hrubis
2020-02-07 14:04   ` Petr Vorel
2020-02-07 14:08     ` Cyril Hrubis

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.