summaryrefslogtreecommitdiffstats
path: root/module
diff options
context:
space:
mode:
authorEtienne Dechamps <[email protected]>2012-09-03 14:56:26 +0200
committerBrian Behlendorf <[email protected]>2012-10-04 16:22:07 -0700
commitbbdc6ae49518a4be7230ab673370e9231e2f72e7 (patch)
treef1e0522a75b9272b1da8a6f5382e0a3b9fbdffe4 /module
parenta6c6839a88b7dc344f3cd8e875a01802b34645cd (diff)
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 <[email protected]> Closes #168
Diffstat (limited to 'module')
-rw-r--r--module/spl/spl-vnode.c53
1 files changed, 53 insertions, 0 deletions
diff --git a/module/spl/spl-vnode.c b/module/spl/spl-vnode.c
index 2e55b007b..f5fc65d26 100644
--- a/module/spl/spl-vnode.c
+++ b/module/spl/spl-vnode.c
@@ -25,6 +25,7 @@
\*****************************************************************************/
#include <sys/vnode.h>
+#include <linux/falloc.h>
#include <spl-debug.h>
#ifdef SS_DEBUG_SUBSYS
@@ -510,6 +511,58 @@ int vn_fsync(vnode_t *vp, int flags, void *x3, void *x4)
} /* 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 */
static file_t *
file_find(int fd)