summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2013-01-08 09:42:49 -0800
committerBrian Behlendorf <[email protected]>2013-01-08 09:53:13 -0800
commit1c7b3eaf87492e875d7ad05f183e98fa306e48c2 (patch)
tree363ffca3d6ce6c1ca4e09d44fd60d04cdc22667c
parent46a75aadb7c08085a4ad2e55dcf5b6fb387c1253 (diff)
RHEL 6.4 compat, fallocate()
In the upstream kernel the FALLOC_FL_PUNCH_HOLE #define was introduced after the fallocate() function was moved from the inode_operations to the file_operations structure. Therefore, the SPL code assumed that if FALLOC_FL_PUNCH_HOLE was defined it was safe to use f_ops->fallocate(). Unfortunately, the RHEL6.4 kernel has only backported the FALLOC_FL_PUNCH_HOLE #define and not the fallocate() change. To address this compatibility issue the spl_filp_fallocate() helper function was added to properly detect which interface is available. Signed-off-by: Brian Behlendorf <[email protected]>
-rw-r--r--config/spl-build.m474
-rw-r--r--include/linux/file_compat.h20
-rw-r--r--module/spl/spl-vnode.c16
3 files changed, 101 insertions, 9 deletions
diff --git a/config/spl-build.m4 b/config/spl-build.m4
index ea25e206f..f710d8e95 100644
--- a/config/spl-build.m4
+++ b/config/spl-build.m4
@@ -78,6 +78,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
SPL_AC_EXPORTED_RWSEM_IS_LOCKED
SPL_AC_KERNEL_INVALIDATE_INODES
SPL_AC_KERNEL_2ARGS_INVALIDATE_INODES
+ SPL_AC_KERNEL_FALLOCATE
SPL_AC_SHRINK_DCACHE_MEMORY
SPL_AC_SHRINK_ICACHE_MEMORY
SPL_AC_KERN_PATH_PARENT_HEADER
@@ -1922,7 +1923,6 @@ AC_DEFUN([SPL_AC_2ARGS_VFS_FSYNC], [
dnl #
dnl # 3.5 API change,
dnl # inode_operations.truncate_range removed
-dnl # (deprecated in favor of FALLOC_FL_PUNCH_HOLE)
dnl #
AC_DEFUN([SPL_AC_INODE_TRUNCATE_RANGE], [
AC_MSG_CHECKING([whether truncate_range() inode operation is available])
@@ -1938,7 +1938,77 @@ AC_DEFUN([SPL_AC_INODE_TRUNCATE_RANGE], [
],[
AC_MSG_RESULT(no)
])
-]))
+])
+
+dnl #
+dnl # Linux 2.6.38 - 3.x API
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_FILE_FALLOCATE], [
+ AC_MSG_CHECKING([whether fops->fallocate() exists])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+ ],[
+ long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
+ struct file_operations fops __attribute__ ((unused)) = {
+ .fallocate = fallocate,
+ };
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_FILE_FALLOCATE, 1, [fops->fallocate() exists])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # Linux 2.6.x - 2.6.37 API
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_INODE_FALLOCATE], [
+ AC_MSG_CHECKING([whether iops->fallocate() exists])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+ ],[
+ long (*fallocate) (struct inode *, int, loff_t, loff_t) = NULL;
+ struct inode_operations fops __attribute__ ((unused)) = {
+ .fallocate = fallocate,
+ };
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_INODE_FALLOCATE, 1, [fops->fallocate() exists])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # PaX Linux 2.6.38 - 3.x API
+dnl #
+AC_DEFUN([SPL_AC_PAX_KERNEL_FILE_FALLOCATE], [
+ AC_MSG_CHECKING([whether fops->fallocate() exists])
+ SPL_LINUX_TRY_COMPILE([
+ #include <linux/fs.h>
+ ],[
+ long (*fallocate) (struct file *, int, loff_t, loff_t) = NULL;
+ struct file_operations_no_const fops __attribute__ ((unused)) = {
+ .fallocate = fallocate,
+ };
+ ],[
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_FILE_FALLOCATE, 1, [fops->fallocate() exists])
+ ],[
+ AC_MSG_RESULT(no)
+ ])
+])
+
+dnl #
+dnl # The fallocate callback was moved from the inode_operations
+dnl # structure to the file_operations structure.
+dnl #
+AC_DEFUN([SPL_AC_KERNEL_FALLOCATE], [
+ SPL_AC_KERNEL_FILE_FALLOCATE
+ SPL_AC_KERNEL_INODE_FALLOCATE
+ SPL_AC_PAX_KERNEL_FILE_FALLOCATE
+])
dnl #
dnl # 2.6.33 API change. Also backported in RHEL5 as of 2.6.18-190.el5.
diff --git a/include/linux/file_compat.h b/include/linux/file_compat.h
index 8664df672..3dc33278f 100644
--- a/include/linux/file_compat.h
+++ b/include/linux/file_compat.h
@@ -50,6 +50,26 @@ spl_filp_open(const char *name, int flags, int mode, int *err)
#define spl_filp_poff(f) (&(f)->f_pos)
#define spl_filp_write(fp, b, s, p) (fp)->f_op->write((fp), (b), (s), p)
+static inline int
+spl_filp_fallocate(struct file *fp, int mode, loff_t offset, loff_t len)
+{
+ int error = -EOPNOTSUPP;
+
+#ifdef HAVE_FILE_FALLOCATE
+ if (fp->f_op->fallocate)
+ error = fp->f_op->fallocate(fp, mode, offset, len);
+#else
+# ifdef HAVE_INODE_FALLOCATE
+ if (fp->f_dentry && fp->f_dentry->d_inode &&
+ fp->f_dentry->d_inode->i_op->fallocate)
+ error = fp->f_dentry->d_inode->i_op->fallocate(
+ fp->f_dentry->d_inode, mode, offset, len);
+# endif /* HAVE_INODE_FALLOCATE */
+#endif /*HAVE_FILE_FALLOCATE */
+
+ return (error);
+}
+
#ifdef HAVE_VFS_FSYNC
# ifdef HAVE_2ARGS_VFS_FSYNC
# define spl_filp_fsync(fp, sync) vfs_fsync(fp, sync)
diff --git a/module/spl/spl-vnode.c b/module/spl/spl-vnode.c
index 0ecd9addf..d8da9814b 100644
--- a/module/spl/spl-vnode.c
+++ b/module/spl/spl-vnode.c
@@ -654,13 +654,15 @@ int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
ASSERT(bfp->l_start >= 0 && bfp->l_len > 0);
#ifdef FALLOC_FL_PUNCH_HOLE
- if (vp->v_file->f_op->fallocate) {
- error = -vp->v_file->f_op->fallocate(vp->v_file,
- FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
- bfp->l_start, bfp->l_len);
- if (!error)
- SRETURN(0);
- }
+ /*
+ * When supported by the underlying file system preferentially
+ * use the fallocate() callback to preallocate the space.
+ */
+ error = -spl_filp_fallocate(vp->v_file,
+ FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE,
+ bfp->l_start, bfp->l_len);
+ if (error == 0)
+ SRETURN(0);
#endif
#ifdef HAVE_INODE_TRUNCATE_RANGE