mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-11-17 18:11:00 +03:00
Add interface for file hole punching.
This adds an interface to "punch holes" (deallocate space) in VFS files. The interface is identical to the Solaris VOP_SPACE interface. This interface is necessary for TRIM support on file vdevs. This is implemented using Linux fallocate(FALLOC_FL_PUNCH_HOLE), which was introduced in 2.6.38. For a brief time before 2.6.38 this was done using the truncate_range inode operation, which was quickly deprecated. This patch only supports FALLOC_FL_PUNCH_HOLE. This adds support for the truncate_range() inode operation to VOP_SPACE() for file hole punching. This API is deprecated and removed in 3.5, so it's only useful for old kernels. On tmpfs, the truncate_range() inode operation translates to shmem_truncate_range(). Unfortunately, this function expects the end offset to be inclusive and aligned to the end of a page. If it is not, the kernel will stop with a BUG_ON(). This patch fixes the issue by adapting to the constraints set forth by shmem_truncate_range(). Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #168
This commit is contained in:
parent
a6c6839a88
commit
bbdc6ae495
@ -72,6 +72,7 @@ AC_DEFUN([SPL_AC_CONFIG_KERNEL], [
|
|||||||
SPL_AC_4ARGS_VFS_RENAME
|
SPL_AC_4ARGS_VFS_RENAME
|
||||||
SPL_AC_VFS_FSYNC
|
SPL_AC_VFS_FSYNC
|
||||||
SPL_AC_2ARGS_VFS_FSYNC
|
SPL_AC_2ARGS_VFS_FSYNC
|
||||||
|
SPL_AC_INODE_TRUNCATE_RANGE
|
||||||
SPL_AC_FS_STRUCT_SPINLOCK
|
SPL_AC_FS_STRUCT_SPINLOCK
|
||||||
SPL_AC_CRED_STRUCT
|
SPL_AC_CRED_STRUCT
|
||||||
SPL_AC_GROUPS_SEARCH
|
SPL_AC_GROUPS_SEARCH
|
||||||
@ -1992,6 +1993,27 @@ 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])
|
||||||
|
SPL_LINUX_TRY_COMPILE([
|
||||||
|
#include <linux/fs.h>
|
||||||
|
],[
|
||||||
|
struct inode_operations ops;
|
||||||
|
ops.truncate_range = NULL;
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
AC_DEFINE(HAVE_INODE_TRUNCATE_RANGE, 1,
|
||||||
|
[truncate_range() inode operation is available])
|
||||||
|
],[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
])
|
||||||
|
]))
|
||||||
|
|
||||||
dnl #
|
dnl #
|
||||||
dnl # 2.6.33 API change. Also backported in RHEL5 as of 2.6.18-190.el5.
|
dnl # 2.6.33 API change. Also backported in RHEL5 as of 2.6.18-190.el5.
|
||||||
dnl # Earlier versions of rwsem_is_locked() were inline and had a race
|
dnl # Earlier versions of rwsem_is_locked() were inline and had a race
|
||||||
|
@ -66,6 +66,9 @@
|
|||||||
#define FNODSYNC 0x10000 /* fsync pseudo flag */
|
#define FNODSYNC 0x10000 /* fsync pseudo flag */
|
||||||
#define FNOFOLLOW 0x20000 /* don't follow symlinks */
|
#define FNOFOLLOW 0x20000 /* don't follow symlinks */
|
||||||
|
|
||||||
|
#define F_FREESP 11 /* Free file space */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The vnode AT_ flags are mapped to the Linux ATTR_* flags.
|
* The vnode AT_ flags are mapped to the Linux ATTR_* flags.
|
||||||
* This allows them to be used safely with an iattr structure.
|
* This allows them to be used safely with an iattr structure.
|
||||||
@ -185,6 +188,8 @@ extern int vn_remove(const char *path, uio_seg_t seg, int flags);
|
|||||||
extern int vn_rename(const char *path1, const char *path2, int x1);
|
extern int vn_rename(const char *path1, const char *path2, int x1);
|
||||||
extern int vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4);
|
extern int vn_getattr(vnode_t *vp, vattr_t *vap, int flags, void *x3, void *x4);
|
||||||
extern int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4);
|
extern int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4);
|
||||||
|
extern int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
|
||||||
|
offset_t offset, void *x6, void *x7);
|
||||||
extern file_t *vn_getf(int fd);
|
extern file_t *vn_getf(int fd);
|
||||||
extern void vn_releasef(int fd);
|
extern void vn_releasef(int fd);
|
||||||
extern int vn_set_pwd(const char *filename);
|
extern int vn_set_pwd(const char *filename);
|
||||||
@ -197,6 +202,7 @@ void spl_vn_fini(void);
|
|||||||
#define VOP_SEEK vn_seek
|
#define VOP_SEEK vn_seek
|
||||||
#define VOP_GETATTR vn_getattr
|
#define VOP_GETATTR vn_getattr
|
||||||
#define VOP_FSYNC vn_fsync
|
#define VOP_FSYNC vn_fsync
|
||||||
|
#define VOP_SPACE vn_space
|
||||||
#define VOP_PUTPAGE(vp, o, s, f, x1, x2) ((void)0)
|
#define VOP_PUTPAGE(vp, o, s, f, x1, x2) ((void)0)
|
||||||
#define vn_is_readonly(vp) 0
|
#define vn_is_readonly(vp) 0
|
||||||
#define getf vn_getf
|
#define getf vn_getf
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
\*****************************************************************************/
|
\*****************************************************************************/
|
||||||
|
|
||||||
#include <sys/vnode.h>
|
#include <sys/vnode.h>
|
||||||
|
#include <linux/falloc.h>
|
||||||
#include <spl-debug.h>
|
#include <spl-debug.h>
|
||||||
|
|
||||||
#ifdef SS_DEBUG_SUBSYS
|
#ifdef SS_DEBUG_SUBSYS
|
||||||
@ -510,6 +511,58 @@ int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4)
|
|||||||
} /* vn_fsync() */
|
} /* vn_fsync() */
|
||||||
EXPORT_SYMBOL(vn_fsync);
|
EXPORT_SYMBOL(vn_fsync);
|
||||||
|
|
||||||
|
int vn_space(vnode_t *vp, int cmd, struct flock *bfp, int flag,
|
||||||
|
offset_t offset, void *x6, void *x7)
|
||||||
|
{
|
||||||
|
int error = EOPNOTSUPP;
|
||||||
|
SENTRY;
|
||||||
|
|
||||||
|
if (cmd != F_FREESP || bfp->l_whence != 0)
|
||||||
|
SRETURN(EOPNOTSUPP);
|
||||||
|
|
||||||
|
ASSERT(vp);
|
||||||
|
ASSERT(vp->v_file);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_INODE_TRUNCATE_RANGE
|
||||||
|
if (vp->v_file->f_dentry && vp->v_file->f_dentry->d_inode &&
|
||||||
|
vp->v_file->f_dentry->d_inode->i_op &&
|
||||||
|
vp->v_file->f_dentry->d_inode->i_op->truncate_range) {
|
||||||
|
off_t end = bfp->l_start + bfp->l_len;
|
||||||
|
/*
|
||||||
|
* Judging from the code in shmem_truncate_range(),
|
||||||
|
* it seems the kernel expects the end offset to be
|
||||||
|
* inclusive and aligned to the end of a page.
|
||||||
|
*/
|
||||||
|
if (end % PAGE_SIZE != 0) {
|
||||||
|
end &= ~(off_t)(PAGE_SIZE - 1);
|
||||||
|
if (end <= bfp->l_start)
|
||||||
|
SRETURN(0);
|
||||||
|
}
|
||||||
|
--end;
|
||||||
|
|
||||||
|
vp->v_file->f_dentry->d_inode->i_op->truncate_range(
|
||||||
|
vp->v_file->f_dentry->d_inode,
|
||||||
|
bfp->l_start, end
|
||||||
|
);
|
||||||
|
SRETURN(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SRETURN(error);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(vn_space);
|
||||||
|
|
||||||
/* Function must be called while holding the vn_file_lock */
|
/* Function must be called while holding the vn_file_lock */
|
||||||
static file_t *
|
static file_t *
|
||||||
file_find(int fd)
|
file_find(int fd)
|
||||||
|
Loading…
Reference in New Issue
Block a user