diff --git a/config/kernel-vfs-direct_IO.m4 b/config/kernel-vfs-direct_IO.m4 new file mode 100644 index 000000000000..87797f4fc8fa --- /dev/null +++ b/config/kernel-vfs-direct_IO.m4 @@ -0,0 +1,72 @@ +dnl # +dnl # Linux 4.1.x API change +dnl # +AC_DEFUN([ZFS_AC_KERNEL_VFS_DIRECT_IO], + [AC_MSG_CHECKING([whether fops->direct_IO() uses iov_iter without rw]) + ZFS_LINUX_TRY_COMPILE([ + #include + + ssize_t test_direct_IO(struct kiocb *kiocb, + struct iov_iter *iter, loff_t offset) + { return 0; } + + static const struct address_space_operations + fops __attribute__ ((unused)) = { + .direct_IO = test_direct_IO, + }; + ],[ + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_VFS_DIRECT_IO_ITER, 1, + [fops->direct_IO() uses iov_iter without rw]) + ],[ + AC_MSG_RESULT(no) + dnl # + dnl # Linux 3.16.x API change + dnl # + [AC_MSG_CHECKING([whether fops->direct_IO() uses iov_iter with rw]) + ZFS_LINUX_TRY_COMPILE([ + #include + + ssize_t test_direct_IO(int rw, struct kiocb *kiocb, + struct iov_iter *iter, loff_t offset) + { return 0; } + + static const struct address_space_operations + fops __attribute__ ((unused)) = { + .direct_IO = test_direct_IO, + }; + ],[ + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_VFS_DIRECT_IO_ITER_RW, 1, + [fops->direct_IO() uses iov_iter with rw]) + ],[ + AC_MSG_RESULT(no) + dnl # + dnl # Ancient Linux API (predates git) + dnl # + [AC_MSG_CHECKING([whether fops->direct_IO() uses iovec]) + ZFS_LINUX_TRY_COMPILE([ + #include + ssize_t test_direct_IO(int rw, + struct kiocb *kiocb, + const struct iovec *iov, loff_t offset, + unsigned long nr_segs) + { return 0; } + + static const struct address_space_operations + fops __attribute__ ((unused)) = { + .direct_IO = test_direct_IO, + }; + ],[ + ],[ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_VFS_DIRECT_IO_IOVEC, 1, + [fops->direct_IO() uses iovec]) + ],[ + AC_MSG_ERROR(no) + ]) + ]) + ]) +]) diff --git a/config/kernel.m4 b/config/kernel.m4 index 8e8922ec7b88..f4eb7c01fec6 100644 --- a/config/kernel.m4 +++ b/config/kernel.m4 @@ -100,6 +100,7 @@ AC_DEFUN([ZFS_AC_CONFIG_KERNEL], [ ZFS_AC_KERNEL_LSEEK_EXECUTE ZFS_AC_KERNEL_VFS_ITERATE ZFS_AC_KERNEL_VFS_RW_ITERATE + ZFS_AC_KERNEL_VFS_DIRECT_IO AS_IF([test "$LINUX_OBJ" != "$LINUX"], [ KERNELMAKE_PARAMS="$KERNELMAKE_PARAMS O=$LINUX_OBJ" diff --git a/module/zfs/zpl_file.c b/module/zfs/zpl_file.c index 5471140122ac..e91ede5c8346 100644 --- a/module/zfs/zpl_file.c +++ b/module/zfs/zpl_file.c @@ -396,6 +396,32 @@ zpl_aio_write(struct kiocb *kiocb, const struct iovec *iovp, } #endif /* HAVE_VFS_RW_ITERATE */ +static size_t +#ifdef HAVE_VFS_DIRECT_IO_IOVEC +zpl_direct_IO(int rw, struct kiocb *kiocb, const struct iovec *iovp, + loff_t pos, unsigned long nr_segs) +{ +#elif defined(HAVE_VFS_DIRECT_IO_ITER_RW) +zpl_direct_IO(int rw, struct kiocb *kiocb, struct iov_iter *from, + loff_t pos) +{ +#elif (defined HAVE_VFS_DIRECT_IO_ITER) +zpl_direct_IO(struct kiocb *kiocb, struct iov_iter *from, + loff_t pos) +{ + int rw = iov_iter_rw(iter); +#else +#error "No function prototype found for DirectIO" +#endif + const struct iovec *iovp = from->iov; + loff_t pos = from->nr_segs; +#endif + if (rw == WRITE) + return (zpl_iter_write_common(kiocb, iovp, nr_segs, kiocb->ki_nbytes)); + else + return (zpl_iter_read_common(kiocb, iovp, nr_segs, kiocb->ki_nbytes)); +} + static loff_t zpl_llseek(struct file *filp, loff_t offset, int whence) { @@ -799,6 +825,7 @@ const struct address_space_operations zpl_address_space_operations = { .readpage = zpl_readpage, .writepage = zpl_writepage, .writepages = zpl_writepages, + .direct_IO = zpl_direct_IO, }; const struct file_operations zpl_file_operations = {