diff --git a/config/kernel-fallocate.m4 b/config/kernel-fallocate.m4 index 7a8550f7e7..815602d3e2 100644 --- a/config/kernel-fallocate.m4 +++ b/config/kernel-fallocate.m4 @@ -3,6 +3,10 @@ dnl # Linux 2.6.38 - 3.x API dnl # The fallocate callback was moved from the inode_operations dnl # structure to the file_operations structure. dnl # +dnl # +dnl # Linux 3.15+ +dnl # fallocate learned a new flag, FALLOC_FL_ZERO_RANGE +dnl # AC_DEFUN([ZFS_AC_KERNEL_SRC_FALLOCATE], [ ZFS_LINUX_TEST_SRC([file_fallocate], [ #include @@ -15,12 +19,25 @@ AC_DEFUN([ZFS_AC_KERNEL_SRC_FALLOCATE], [ .fallocate = test_fallocate, }; ], []) + ZFS_LINUX_TEST_SRC([falloc_fl_zero_range], [ + #include + ],[ + int flags __attribute__ ((unused)); + flags = FALLOC_FL_ZERO_RANGE; + ]) ]) AC_DEFUN([ZFS_AC_KERNEL_FALLOCATE], [ AC_MSG_CHECKING([whether fops->fallocate() exists]) ZFS_LINUX_TEST_RESULT([file_fallocate], [ AC_MSG_RESULT(yes) + AC_MSG_CHECKING([whether FALLOC_FL_ZERO_RANGE exists]) + ZFS_LINUX_TEST_RESULT([falloc_fl_zero_range], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_FALLOC_FL_ZERO_RANGE, 1, [FALLOC_FL_ZERO_RANGE is defined]) + ],[ + AC_MSG_RESULT(no) + ]) ],[ ZFS_LINUX_TEST_ERROR([file_fallocate]) ]) diff --git a/module/os/linux/zfs/zpl_file.c b/module/os/linux/zfs/zpl_file.c index 7e88eae337..f1241c4437 100644 --- a/module/os/linux/zfs/zpl_file.c +++ b/module/os/linux/zfs/zpl_file.c @@ -745,7 +745,12 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len) fstrans_cookie_t cookie; int error = 0; - if ((mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) != 0) + int test_mode = FALLOC_FL_PUNCH_HOLE; +#ifdef HAVE_FALLOC_FL_ZERO_RANGE + test_mode |= FALLOC_FL_ZERO_RANGE; +#endif + + if ((mode & ~(FALLOC_FL_KEEP_SIZE | test_mode)) != 0) return (-EOPNOTSUPP); if (offset < 0 || len <= 0) @@ -756,7 +761,7 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len) crhold(cr); cookie = spl_fstrans_mark(); - if (mode & FALLOC_FL_PUNCH_HOLE) { + if (mode & (test_mode)) { flock64_t bf; if (offset > olen)