diff options
author | Brian Behlendorf <[email protected]> | 2013-01-08 09:42:49 -0800 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2013-01-08 09:53:13 -0800 |
commit | 1c7b3eaf87492e875d7ad05f183e98fa306e48c2 (patch) | |
tree | 363ffca3d6ce6c1ca4e09d44fd60d04cdc22667c | |
parent | 46a75aadb7c08085a4ad2e55dcf5b6fb387c1253 (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.m4 | 74 | ||||
-rw-r--r-- | include/linux/file_compat.h | 20 | ||||
-rw-r--r-- | module/spl/spl-vnode.c | 16 |
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 |