On Sun, 20 Jul 2014, David Herrmann wrote:
> Setting SEAL_WRITE is not possible if there're pending GUP users. This
> commit adds selftests for memfd+sealing that use FUSE to create pending
> page-references. FUSE is very helpful here in that it allows us to delay
> direct-IO operations for an arbitrary amount of time. This way, we can
> force the kernel to pin pages and then run our normal selftests.
>
> Signed-off-by: David Herrmann
Acked-by: Hugh Dickins
My "Permission denied" problem was actually not with /dev/fuse,
but with the executability (or not) of ./run_fuse_test.sh.
I see now that your git patch has create mode 100755, but that
got missed when I applied it to my tree with "patch -p1".
I would not be surprised if it goes missing on its way through
the quilt-style mmotm, or I may be under-rating akpm. Personally,
I'd change the Makefile one way or another, not to rely on 755.
> ---
> tools/testing/selftests/memfd/.gitignore | 2 +
> tools/testing/selftests/memfd/Makefile | 14 +-
> tools/testing/selftests/memfd/fuse_mnt.c | 110 +
> tools/testing/selftests/memfd/fuse_test.c | 311
> +
> tools/testing/selftests/memfd/run_fuse_test.sh | 14 ++
> 5 files changed, 450 insertions(+), 1 deletion(-)
> create mode 100755 tools/testing/selftests/memfd/fuse_mnt.c
> create mode 100644 tools/testing/selftests/memfd/fuse_test.c
> create mode 100755 tools/testing/selftests/memfd/run_fuse_test.sh
>
> diff --git a/tools/testing/selftests/memfd/.gitignore
> b/tools/testing/selftests/memfd/.gitignore
> index bcc8ee2..afe87c4 100644
> --- a/tools/testing/selftests/memfd/.gitignore
> +++ b/tools/testing/selftests/memfd/.gitignore
> @@ -1,2 +1,4 @@
> +fuse_mnt
> +fuse_test
> memfd_test
> memfd-test-file
> diff --git a/tools/testing/selftests/memfd/Makefile
> b/tools/testing/selftests/memfd/Makefile
> index 36653b9..6816c49 100644
> --- a/tools/testing/selftests/memfd/Makefile
> +++ b/tools/testing/selftests/memfd/Makefile
> @@ -7,6 +7,7 @@ ifeq ($(ARCH),x86_64)
> ARCH := X86
> endif
>
> +CFLAGS += -D_FILE_OFFSET_BITS=64
> CFLAGS += -I../../../../arch/x86/include/generated/uapi/
> CFLAGS += -I../../../../arch/x86/include/uapi/
> CFLAGS += -I../../../../include/uapi/
> @@ -25,5 +26,16 @@ ifeq ($(ARCH),X86)
> endif
> @./memfd_test || echo "memfd_test: [FAIL]"
>
> +build_fuse:
> +ifeq ($(ARCH),X86)
> + gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt
> + gcc $(CFLAGS) fuse_test.c -o fuse_test
> +else
> + echo "Not an x86 target, can't build memfd selftest"
> +endif
> +
> +run_fuse: build_fuse
> + @./run_fuse_test.sh || echo "fuse_test: [FAIL]"
> +
> clean:
> - $(RM) memfd_test
> + $(RM) memfd_test fuse_test
> diff --git a/tools/testing/selftests/memfd/fuse_mnt.c
> b/tools/testing/selftests/memfd/fuse_mnt.c
> new file mode 100755
> index 000..feacf12
> --- /dev/null
> +++ b/tools/testing/selftests/memfd/fuse_mnt.c
> @@ -0,0 +1,110 @@
> +/*
> + * memfd test file-system
> + * This file uses FUSE to create a dummy file-system with only one file
> /memfd.
> + * This file is read-only and takes 1s per read.
> + *
> + * This file-system is used by the memfd test-cases to force the kernel to
> pin
> + * pages during reads(). Due to the 1s delay of this file-system, this is a
> + * nice way to test race-conditions against get_user_pages() in the kernel.
> + *
> + * We use direct_io==1 to force the kernel to use direct-IO for this
> + * file-system.
> + */
> +
> +#define FUSE_USE_VERSION 26
> +
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +
> +static const char memfd_content[] = "memfd-example-content";
> +static const char memfd_path[] = "/memfd";
> +
> +static int memfd_getattr(const char *path, struct stat *st)
> +{
> + memset(st, 0, sizeof(*st));
> +
> + if (!strcmp(path, "/")) {
> + st->st_mode = S_IFDIR | 0755;
> + st->st_nlink = 2;
> + } else if (!strcmp(path, memfd_path)) {
> + st->st_mode = S_IFREG | 0444;
> + st->st_nlink = 1;
> + st->st_size = strlen(memfd_content);
> + } else {
> + return -ENOENT;
> + }
> +
> + return 0;
> +}
> +
> +static int memfd_readdir(const char *path,
> + void *buf,
> + fuse_fill_dir_t filler,
> + off_t offset,
> + struct fuse_file_info *fi)
> +{
> + if (strcmp(path, "/"))
> + return -ENOENT;
> +
> + filler(buf, ".", NULL, 0);
> + filler(buf, "..", NULL, 0);
> + filler(buf, memfd_path + 1, NULL, 0);
> +
> + return 0;
> +}
> +
> +static int memfd_open(const char *path, struct fuse_file_info *fi)
> +{
> + if (strcmp(path, memfd_path))
> + return -ENOENT;
> +
> + if ((fi->flags & 3) != O_RDONLY)
> + return -EACCES;
> +
> + /* force direct-IO */
> + fi->direct_io = 1