[PATCH][BIONIC] UBUNTU: SAUCE: Fix non-prefaulted page deadlock (LP: #1754584)

Colin King colin.king at canonical.com
Mon Mar 26 11:11:18 UTC 2018


From: Colin Ian King <colin.king at canonical.com>

BugLink: https://bugs.launchpad.net/bugs/1754584

Fix mmap'd libaio read on non-prefaulted page deadlock. This is a hot fix
from ZFS upstream that ensure pages are pre-faulted in to avoid deadlock.
Performing a read with the target data in a mmap'd page that is map'd into
the same blocks that are being read causes a lock on the page and a further
lock on the same page when the page is being faulted in, causing deadlock.
The current workaround is to prefault the page(s) before the pages are
read.

This is no current upstream commit ID for this fix, as it landed late on
Friday and it's not commited to upstream ZFS. The fix has passed our ZFS
regression tests and fixes the issue, so I'd like to get this included
into Bionic sooner than later.

Signed-off-by: Colin Ian King <colin.king at canonical.com>
---
 zfs/META                             |  2 +-
 zfs/Makefile.in                      |  2 +
 zfs/aclocal.m4                       |  1 +
 zfs/config/user-libaio.m4            | 14 ++++++
 zfs/config/user.m4                   |  1 +
 zfs/config/zfs-build.m4              |  4 +-
 zfs/configure                        | 77 ++++++++++++++++++++++++++++-----
 zfs/include/Makefile.in              |  2 +
 zfs/include/linux/Makefile.in        |  2 +
 zfs/include/sys/Makefile.in          |  2 +
 zfs/include/sys/crypto/Makefile.in   |  2 +
 zfs/include/sys/fm/Makefile.in       |  2 +
 zfs/include/sys/fm/fs/Makefile.in    |  2 +
 zfs/include/sys/fs/Makefile.in       |  2 +
 zfs/include/sys/sysevent/Makefile.in |  2 +
 zfs/include/sys/uio_impl.h           |  2 +-
 zfs/module/zcommon/zfs_uio.c         | 83 +++++++++++++++---------------------
 zfs/module/zfs/zfs_vnops.c           |  8 +++-
 zfs/zfs_config.h.in                  |  3 ++
 19 files changed, 149 insertions(+), 64 deletions(-)
 create mode 100644 zfs/config/user-libaio.m4

diff --git a/zfs/META b/zfs/META
index 3af1334..049b610 100644
--- a/zfs/META
+++ b/zfs/META
@@ -2,7 +2,7 @@ Meta:         1
 Name:         zfs
 Branch:       1.0
 Version:      0.7.5
-Release:      1ubuntu10
+Release:      1ubuntu11
 Release-Tags: relext
 License:      CDDL
 Author:       OpenZFS on Linux
diff --git a/zfs/Makefile.in b/zfs/Makefile.in
index 9dd300b..ed2c430 100644
--- a/zfs/Makefile.in
+++ b/zfs/Makefile.in
@@ -195,6 +195,7 @@ am__aclocal_m4_deps = $(top_srcdir)/config/always-arch.m4 \
 	$(top_srcdir)/config/toolchain-simd.m4 \
 	$(top_srcdir)/config/user-dracut.m4 \
 	$(top_srcdir)/config/user-frame-larger-than.m4 \
+	$(top_srcdir)/config/user-libaio.m4 \
 	$(top_srcdir)/config/user-libattr.m4 \
 	$(top_srcdir)/config/user-libblkid.m4 \
 	$(top_srcdir)/config/user-libtirpc.m4 \
@@ -426,6 +427,7 @@ KERNELCPPFLAGS = @KERNELCPPFLAGS@
 KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAIO = @LIBAIO@
 LIBATTR = @LIBATTR@
 LIBBLKID = @LIBBLKID@
 LIBOBJS = @LIBOBJS@
diff --git a/zfs/aclocal.m4 b/zfs/aclocal.m4
index 84d98a9..7d89c6e 100644
--- a/zfs/aclocal.m4
+++ b/zfs/aclocal.m4
@@ -1303,6 +1303,7 @@ m4_include([config/mount-helper.m4])
 m4_include([config/toolchain-simd.m4])
 m4_include([config/user-dracut.m4])
 m4_include([config/user-frame-larger-than.m4])
+m4_include([config/user-libaio.m4])
 m4_include([config/user-libattr.m4])
 m4_include([config/user-libblkid.m4])
 m4_include([config/user-libtirpc.m4])
diff --git a/zfs/config/user-libaio.m4 b/zfs/config/user-libaio.m4
new file mode 100644
index 0000000..d7a7cb5
--- /dev/null
+++ b/zfs/config/user-libaio.m4
@@ -0,0 +1,14 @@
+dnl #
+dnl # Check for libaio - only used for libaiot test cases.
+dnl #
+AC_DEFUN([ZFS_AC_CONFIG_USER_LIBAIO], [
+	LIBAIO=
+
+	AC_CHECK_HEADER([libaio.h], [
+	    user_libaio=yes
+	    AC_SUBST([LIBAIO], ["-laio"])
+	    AC_DEFINE([HAVE_LIBAIO], 1, [Define if you have libaio])
+	], [
+	    user_libaio=no
+	])
+])
diff --git a/zfs/config/user.m4 b/zfs/config/user.m4
index 2b033f5..941fcf0 100644
--- a/zfs/config/user.m4
+++ b/zfs/config/user.m4
@@ -13,6 +13,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [
 	ZFS_AC_CONFIG_USER_LIBTIRPC
 	ZFS_AC_CONFIG_USER_LIBBLKID
 	ZFS_AC_CONFIG_USER_LIBATTR
+	ZFS_AC_CONFIG_USER_LIBAIO
 	ZFS_AC_CONFIG_USER_LIBUDEV
 	ZFS_AC_CONFIG_USER_FRAME_LARGER_THAN
 	ZFS_AC_CONFIG_USER_RUNSTATEDIR
diff --git a/zfs/config/zfs-build.m4 b/zfs/config/zfs-build.m4
index 7651dc2..1224682 100644
--- a/zfs/config/zfs-build.m4
+++ b/zfs/config/zfs-build.m4
@@ -79,11 +79,11 @@ AC_DEFUN([ZFS_AC_CONFIG], [
 	AM_CONDITIONAL([CONFIG_KERNEL],
 	    [test "$ZFS_CONFIG" = kernel -o "$ZFS_CONFIG" = all] &&
 	    [test "x$enable_linux_builtin" != xyes ])
-	AM_CONDITIONAL([WANT_DEVNAME2DEVID],
-	    [test "x$user_libudev" = xyes ])
 	AM_CONDITIONAL([CONFIG_QAT],
 	    [test "$ZFS_CONFIG" = kernel -o "$ZFS_CONFIG" = all] &&
 	    [test "x$qatsrc" != x ])
+	AM_CONDITIONAL([WANT_DEVNAME2DEVID], [test "x$user_libudev" = xyes ])
+	AM_CONDITIONAL([WANT_MMAP_LIBAIO], [test "x$user_libaio" = xyes ])
 ])
 
 dnl #
diff --git a/zfs/configure b/zfs/configure
index aebe4bb..ea023e8 100755
--- a/zfs/configure
+++ b/zfs/configure
@@ -635,10 +635,12 @@ LIBOBJS
 DEBUG_ZFS
 DEBUG_STACKFLAGS
 DEBUG_CFLAGS
-CONFIG_QAT_FALSE
-CONFIG_QAT_TRUE
+WANT_MMAP_LIBAIO_FALSE
+WANT_MMAP_LIBAIO_TRUE
 WANT_DEVNAME2DEVID_FALSE
 WANT_DEVNAME2DEVID_TRUE
+CONFIG_QAT_FALSE
+CONFIG_QAT_TRUE
 CONFIG_KERNEL_FALSE
 CONFIG_KERNEL_TRUE
 CONFIG_USER_FALSE
@@ -648,6 +650,7 @@ ZONENAME
 NO_FORMAT_TRUNCATION
 FRAME_LARGER_THAN
 LIBUDEV
+LIBAIO
 LIBATTR
 LIBBLKID
 LIBTIRPC_CFLAGS
@@ -26908,6 +26911,27 @@ $as_echo "#define HAVE_LIBATTR 1" >>confdefs.h
 
 
 
+	LIBAIO=
+
+	ac_fn_c_check_header_mongrel "$LINENO" "libaio.h" "ac_cv_header_libaio_h" "$ac_includes_default"
+if test "x$ac_cv_header_libaio_h" = xyes; then :
+
+	    user_libaio=yes
+	    LIBAIO="-laio"
+
+
+$as_echo "#define HAVE_LIBAIO 1" >>confdefs.h
+
+
+else
+
+	    user_libaio=no
+
+fi
+
+
+
+
 	LIBUDEV=
 
 	ac_fn_c_check_header_mongrel "$LINENO" "libudev.h" "ac_cv_header_libudev_h" "$ac_includes_default"
@@ -27936,6 +27960,27 @@ $as_echo "#define HAVE_LIBATTR 1" >>confdefs.h
 
 
 
+	LIBAIO=
+
+	ac_fn_c_check_header_mongrel "$LINENO" "libaio.h" "ac_cv_header_libaio_h" "$ac_includes_default"
+if test "x$ac_cv_header_libaio_h" = xyes; then :
+
+	    user_libaio=yes
+	    LIBAIO="-laio"
+
+
+$as_echo "#define HAVE_LIBAIO 1" >>confdefs.h
+
+
+else
+
+	    user_libaio=no
+
+fi
+
+
+
+
 	LIBUDEV=
 
 	ac_fn_c_check_header_mongrel "$LINENO" "libudev.h" "ac_cv_header_libudev_h" "$ac_includes_default"
@@ -40914,6 +40959,15 @@ else
   CONFIG_KERNEL_FALSE=
 fi
 
+	 if test "$ZFS_CONFIG" = kernel -o "$ZFS_CONFIG" = all &&
+	    test "x$qatsrc" != x ; then
+  CONFIG_QAT_TRUE=
+  CONFIG_QAT_FALSE='#'
+else
+  CONFIG_QAT_TRUE='#'
+  CONFIG_QAT_FALSE=
+fi
+
 	 if test "x$user_libudev" = xyes ; then
   WANT_DEVNAME2DEVID_TRUE=
   WANT_DEVNAME2DEVID_FALSE='#'
@@ -40922,13 +40976,12 @@ else
   WANT_DEVNAME2DEVID_FALSE=
 fi
 
-	 if test "$ZFS_CONFIG" = kernel -o "$ZFS_CONFIG" = all &&
-	    test "x$qatsrc" != x ; then
-  CONFIG_QAT_TRUE=
-  CONFIG_QAT_FALSE='#'
+	 if test "x$user_libaio" = xyes ; then
+  WANT_MMAP_LIBAIO_TRUE=
+  WANT_MMAP_LIBAIO_FALSE='#'
 else
-  CONFIG_QAT_TRUE='#'
-  CONFIG_QAT_FALSE=
+  WANT_MMAP_LIBAIO_TRUE='#'
+  WANT_MMAP_LIBAIO_FALSE=
 fi
 
 
@@ -41136,12 +41189,16 @@ if test -z "${CONFIG_KERNEL_TRUE}" && test -z "${CONFIG_KERNEL_FALSE}"; then
   as_fn_error $? "conditional \"CONFIG_KERNEL\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${CONFIG_QAT_TRUE}" && test -z "${CONFIG_QAT_FALSE}"; then
+  as_fn_error $? "conditional \"CONFIG_QAT\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 if test -z "${WANT_DEVNAME2DEVID_TRUE}" && test -z "${WANT_DEVNAME2DEVID_FALSE}"; then
   as_fn_error $? "conditional \"WANT_DEVNAME2DEVID\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${CONFIG_QAT_TRUE}" && test -z "${CONFIG_QAT_FALSE}"; then
-  as_fn_error $? "conditional \"CONFIG_QAT\" was never defined.
+if test -z "${WANT_MMAP_LIBAIO_TRUE}" && test -z "${WANT_MMAP_LIBAIO_FALSE}"; then
+  as_fn_error $? "conditional \"WANT_MMAP_LIBAIO\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
 
diff --git a/zfs/include/Makefile.in b/zfs/include/Makefile.in
index ae748a9..acd99dc 100644
--- a/zfs/include/Makefile.in
+++ b/zfs/include/Makefile.in
@@ -187,6 +187,7 @@ am__aclocal_m4_deps = $(top_srcdir)/config/always-arch.m4 \
 	$(top_srcdir)/config/toolchain-simd.m4 \
 	$(top_srcdir)/config/user-dracut.m4 \
 	$(top_srcdir)/config/user-frame-larger-than.m4 \
+	$(top_srcdir)/config/user-libaio.m4 \
 	$(top_srcdir)/config/user-libattr.m4 \
 	$(top_srcdir)/config/user-libblkid.m4 \
 	$(top_srcdir)/config/user-libtirpc.m4 \
@@ -400,6 +401,7 @@ KERNELCPPFLAGS = @KERNELCPPFLAGS@
 KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAIO = @LIBAIO@
 LIBATTR = @LIBATTR@
 LIBBLKID = @LIBBLKID@
 LIBOBJS = @LIBOBJS@
diff --git a/zfs/include/linux/Makefile.in b/zfs/include/linux/Makefile.in
index 0f6c8c3..1002d83 100644
--- a/zfs/include/linux/Makefile.in
+++ b/zfs/include/linux/Makefile.in
@@ -187,6 +187,7 @@ am__aclocal_m4_deps = $(top_srcdir)/config/always-arch.m4 \
 	$(top_srcdir)/config/toolchain-simd.m4 \
 	$(top_srcdir)/config/user-dracut.m4 \
 	$(top_srcdir)/config/user-frame-larger-than.m4 \
+	$(top_srcdir)/config/user-libaio.m4 \
 	$(top_srcdir)/config/user-libattr.m4 \
 	$(top_srcdir)/config/user-libblkid.m4 \
 	$(top_srcdir)/config/user-libtirpc.m4 \
@@ -345,6 +346,7 @@ KERNELCPPFLAGS = @KERNELCPPFLAGS@
 KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAIO = @LIBAIO@
 LIBATTR = @LIBATTR@
 LIBBLKID = @LIBBLKID@
 LIBOBJS = @LIBOBJS@
diff --git a/zfs/include/sys/Makefile.in b/zfs/include/sys/Makefile.in
index 25d1f71..c24010a 100644
--- a/zfs/include/sys/Makefile.in
+++ b/zfs/include/sys/Makefile.in
@@ -187,6 +187,7 @@ am__aclocal_m4_deps = $(top_srcdir)/config/always-arch.m4 \
 	$(top_srcdir)/config/toolchain-simd.m4 \
 	$(top_srcdir)/config/user-dracut.m4 \
 	$(top_srcdir)/config/user-frame-larger-than.m4 \
+	$(top_srcdir)/config/user-libaio.m4 \
 	$(top_srcdir)/config/user-libattr.m4 \
 	$(top_srcdir)/config/user-libblkid.m4 \
 	$(top_srcdir)/config/user-libtirpc.m4 \
@@ -606,6 +607,7 @@ KERNELCPPFLAGS = @KERNELCPPFLAGS@
 KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAIO = @LIBAIO@
 LIBATTR = @LIBATTR@
 LIBBLKID = @LIBBLKID@
 LIBOBJS = @LIBOBJS@
diff --git a/zfs/include/sys/crypto/Makefile.in b/zfs/include/sys/crypto/Makefile.in
index fa2f570..79a03c5 100644
--- a/zfs/include/sys/crypto/Makefile.in
+++ b/zfs/include/sys/crypto/Makefile.in
@@ -187,6 +187,7 @@ am__aclocal_m4_deps = $(top_srcdir)/config/always-arch.m4 \
 	$(top_srcdir)/config/toolchain-simd.m4 \
 	$(top_srcdir)/config/user-dracut.m4 \
 	$(top_srcdir)/config/user-frame-larger-than.m4 \
+	$(top_srcdir)/config/user-libaio.m4 \
 	$(top_srcdir)/config/user-libattr.m4 \
 	$(top_srcdir)/config/user-libblkid.m4 \
 	$(top_srcdir)/config/user-libtirpc.m4 \
@@ -342,6 +343,7 @@ KERNELCPPFLAGS = @KERNELCPPFLAGS@
 KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAIO = @LIBAIO@
 LIBATTR = @LIBATTR@
 LIBBLKID = @LIBBLKID@
 LIBOBJS = @LIBOBJS@
diff --git a/zfs/include/sys/fm/Makefile.in b/zfs/include/sys/fm/Makefile.in
index 85019a1..a73b969 100644
--- a/zfs/include/sys/fm/Makefile.in
+++ b/zfs/include/sys/fm/Makefile.in
@@ -187,6 +187,7 @@ am__aclocal_m4_deps = $(top_srcdir)/config/always-arch.m4 \
 	$(top_srcdir)/config/toolchain-simd.m4 \
 	$(top_srcdir)/config/user-dracut.m4 \
 	$(top_srcdir)/config/user-frame-larger-than.m4 \
+	$(top_srcdir)/config/user-libaio.m4 \
 	$(top_srcdir)/config/user-libattr.m4 \
 	$(top_srcdir)/config/user-libblkid.m4 \
 	$(top_srcdir)/config/user-libtirpc.m4 \
@@ -382,6 +383,7 @@ KERNELCPPFLAGS = @KERNELCPPFLAGS@
 KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAIO = @LIBAIO@
 LIBATTR = @LIBATTR@
 LIBBLKID = @LIBBLKID@
 LIBOBJS = @LIBOBJS@
diff --git a/zfs/include/sys/fm/fs/Makefile.in b/zfs/include/sys/fm/fs/Makefile.in
index 42a85e5..03e3298 100644
--- a/zfs/include/sys/fm/fs/Makefile.in
+++ b/zfs/include/sys/fm/fs/Makefile.in
@@ -187,6 +187,7 @@ am__aclocal_m4_deps = $(top_srcdir)/config/always-arch.m4 \
 	$(top_srcdir)/config/toolchain-simd.m4 \
 	$(top_srcdir)/config/user-dracut.m4 \
 	$(top_srcdir)/config/user-frame-larger-than.m4 \
+	$(top_srcdir)/config/user-libaio.m4 \
 	$(top_srcdir)/config/user-libattr.m4 \
 	$(top_srcdir)/config/user-libblkid.m4 \
 	$(top_srcdir)/config/user-libtirpc.m4 \
@@ -338,6 +339,7 @@ KERNELCPPFLAGS = @KERNELCPPFLAGS@
 KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAIO = @LIBAIO@
 LIBATTR = @LIBATTR@
 LIBBLKID = @LIBBLKID@
 LIBOBJS = @LIBOBJS@
diff --git a/zfs/include/sys/fs/Makefile.in b/zfs/include/sys/fs/Makefile.in
index d22d5fc..8ea51c9 100644
--- a/zfs/include/sys/fs/Makefile.in
+++ b/zfs/include/sys/fs/Makefile.in
@@ -187,6 +187,7 @@ am__aclocal_m4_deps = $(top_srcdir)/config/always-arch.m4 \
 	$(top_srcdir)/config/toolchain-simd.m4 \
 	$(top_srcdir)/config/user-dracut.m4 \
 	$(top_srcdir)/config/user-frame-larger-than.m4 \
+	$(top_srcdir)/config/user-libaio.m4 \
 	$(top_srcdir)/config/user-libattr.m4 \
 	$(top_srcdir)/config/user-libblkid.m4 \
 	$(top_srcdir)/config/user-libtirpc.m4 \
@@ -338,6 +339,7 @@ KERNELCPPFLAGS = @KERNELCPPFLAGS@
 KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAIO = @LIBAIO@
 LIBATTR = @LIBATTR@
 LIBBLKID = @LIBBLKID@
 LIBOBJS = @LIBOBJS@
diff --git a/zfs/include/sys/sysevent/Makefile.in b/zfs/include/sys/sysevent/Makefile.in
index 12c0912..2a9b504 100644
--- a/zfs/include/sys/sysevent/Makefile.in
+++ b/zfs/include/sys/sysevent/Makefile.in
@@ -187,6 +187,7 @@ am__aclocal_m4_deps = $(top_srcdir)/config/always-arch.m4 \
 	$(top_srcdir)/config/toolchain-simd.m4 \
 	$(top_srcdir)/config/user-dracut.m4 \
 	$(top_srcdir)/config/user-frame-larger-than.m4 \
+	$(top_srcdir)/config/user-libaio.m4 \
 	$(top_srcdir)/config/user-libattr.m4 \
 	$(top_srcdir)/config/user-libblkid.m4 \
 	$(top_srcdir)/config/user-libtirpc.m4 \
@@ -342,6 +343,7 @@ KERNELCPPFLAGS = @KERNELCPPFLAGS@
 KERNELMAKE_PARAMS = @KERNELMAKE_PARAMS@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBAIO = @LIBAIO@
 LIBATTR = @LIBATTR@
 LIBBLKID = @LIBBLKID@
 LIBOBJS = @LIBOBJS@
diff --git a/zfs/include/sys/uio_impl.h b/zfs/include/sys/uio_impl.h
index 37e283d..01ca723 100644
--- a/zfs/include/sys/uio_impl.h
+++ b/zfs/include/sys/uio_impl.h
@@ -42,7 +42,7 @@
 #include <sys/uio.h>
 
 extern int uiomove(void *, size_t, enum uio_rw, uio_t *);
-extern void uio_prefaultpages(ssize_t, uio_t *);
+extern int uio_prefaultpages(ssize_t, enum uio_rw, uio_t *);
 extern int uiocopy(void *, size_t, enum uio_rw, uio_t *, size_t *);
 extern void uioskip(uio_t *, size_t);
 
diff --git a/zfs/module/zcommon/zfs_uio.c b/zfs/module/zcommon/zfs_uio.c
index 7b4175b..0001f95 100644
--- a/zfs/module/zcommon/zfs_uio.c
+++ b/zfs/module/zcommon/zfs_uio.c
@@ -148,64 +148,51 @@ uiomove(void *p, size_t n, enum uio_rw rw, struct uio *uio)
 }
 EXPORT_SYMBOL(uiomove);
 
-#define	fuword8(uptr, vptr)	get_user((*vptr), (uptr))
-
 /*
- * Fault in the pages of the first n bytes specified by the uio structure.
- * 1 byte in each page is touched and the uio struct is unmodified. Any
- * error will terminate the process as this is only a best attempt to get
- * the pages resident.
+ * Fault in the user space pages specified by the uio structure.  Note that
+ * when faulting in pages with UIO_READ they may have zeros written to them
+ * which is OK because we know they'll be overwritten.
  */
-void
-uio_prefaultpages(ssize_t n, struct uio *uio)
+int
+uio_prefaultpages(ssize_t n, enum uio_rw rw, struct uio *uio)
 {
-	const struct iovec *iov;
-	ulong_t cnt, incr;
-	caddr_t p;
-	uint8_t tmp;
-	int iovcnt;
-	size_t skip;
+	const struct iovec *iov = uio->uio_iov;
+	size_t skip = uio->uio_skip;
+	int iovcnt = uio->uio_iovcnt;
+	uio_seg_t seg = uio->uio_segflg;
+	char __user *p;
+	ulong_t cnt;
+	int error;
 
-	/* no need to fault in kernel pages */
-	switch (uio->uio_segflg) {
-		case UIO_SYSSPACE:
-		case UIO_BVEC:
-			return;
-		case UIO_USERSPACE:
-		case UIO_USERISPACE:
-			break;
-		default:
-			ASSERT(0);
-	}
+	/* No need to fault in kernel pages */
+	if (seg == UIO_SYSSPACE || seg == UIO_BVEC)
+		return (0);
 
-	iov = uio->uio_iov;
-	iovcnt = uio->uio_iovcnt;
-	skip = uio->uio_skip;
+	ASSERT(seg == UIO_USERSPACE || seg == UIO_USERISPACE);
 
-	for (; n > 0 && iovcnt > 0; iov++, iovcnt--, skip = 0) {
+	while ((n > 0) && (iovcnt > 0)) {
 		cnt = MIN(iov->iov_len - skip, n);
-		/* empty iov */
-		if (cnt == 0)
-			continue;
-		n -= cnt;
-		/*
-		 * touch each page in this segment.
-		 */
 		p = iov->iov_base + skip;
-		while (cnt) {
-			if (fuword8((uint8_t *)p, &tmp))
-				return;
-			incr = MIN(cnt, PAGESIZE);
-			p += incr;
-			cnt -= incr;
+
+		if (rw == UIO_READ)
+			error = -fault_in_pages_writeable(p, cnt);
+		else
+			error = -fault_in_pages_readable(p, cnt);
+
+		if (error)
+			return (error);
+
+		skip += cnt;
+		if (skip == iov->iov_len) {
+			skip = 0;
+			iov++;
+			iovcnt--;
 		}
-		/*
-		 * touch the last byte in case it straddles a page.
-		 */
-		p--;
-		if (fuword8((uint8_t *)p, &tmp))
-			return;
+
+		n -= cnt;
 	}
+
+	return (0);
 }
 EXPORT_SYMBOL(uio_prefaultpages);
 
diff --git a/zfs/module/zfs/zfs_vnops.c b/zfs/module/zfs/zfs_vnops.c
index 6a1dab5..9338bb0 100644
--- a/zfs/module/zfs/zfs_vnops.c
+++ b/zfs/module/zfs/zfs_vnops.c
@@ -390,6 +390,10 @@ mappedread(struct inode *ip, int nbytes, uio_t *uio)
 	int error = 0;
 	void *pb;
 
+	error = uio_prefaultpages(nbytes, UIO_READ, uio);
+	if (error)
+		return (error);
+
 	start = uio->uio_loffset;
 	off = start & (PAGE_SIZE-1);
 	for (start &= PAGE_MASK; len > 0; start += PAGE_SIZE) {
@@ -675,7 +679,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 		xuio = (xuio_t *)uio;
 	else
 #endif
-		uio_prefaultpages(MIN(n, max_blksz), uio);
+		uio_prefaultpages(MIN(n, max_blksz), UIO_WRITE, uio);
 
 	/*
 	 * If in append mode, set the io offset pointer to eof.
@@ -921,7 +925,7 @@ zfs_write(struct inode *ip, uio_t *uio, int ioflag, cred_t *cr)
 		n -= nbytes;
 
 		if (!xuio && n > 0)
-			uio_prefaultpages(MIN(n, max_blksz), uio);
+			uio_prefaultpages(MIN(n, max_blksz), UIO_WRITE, uio);
 	}
 
 	zfs_inode_update(zp);
diff --git a/zfs/zfs_config.h.in b/zfs/zfs_config.h.in
index ac41b5a..a87d6ac 100644
--- a/zfs/zfs_config.h.in
+++ b/zfs/zfs_config.h.in
@@ -312,6 +312,9 @@
 /* kernel has large stacks */
 #undef HAVE_LARGE_STACKS
 
+/* Define if you have libaio */
+#undef HAVE_LIBAIO
+
 /* Define if you have libattr */
 #undef HAVE_LIBATTR
 
-- 
2.7.4





More information about the kernel-team mailing list