Re: [PATCH v4 5/6] selftests: add memfd/sealing page-pinning tests

2014-07-23 Thread Hugh Dickins
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

[PATCH v4 5/6] selftests: add memfd/sealing page-pinning tests

2014-07-20 Thread David Herrmann
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 
---
 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;
+
+   return 0;
+}
+
+static int memfd_read(const char *path,
+ char *buf,
+ size_t size,
+ off_t offset,
+ struct fuse_file_info *fi)
+{
+   size_t len;
+
+   if (strcmp(path, memfd_path) != 0)
+   return -ENOENT;
+
+   sleep(1);
+
+   len = strlen(memfd_content);
+   if (offset < len) {
+   if (offset + size > len)
+   size = len - offset;
+
+   memcpy(buf, memfd_content + offset, size);
+   } else {
+   size = 0;
+   }
+
+   return size;
+}
+
+static struct fuse_operations memfd_ops = {
+   .getattr= memfd_get