Implement the truncate_range() inode operation.
authorEtienne Dechamps <etienne.dechamps@ovh.net>
Thu, 1 Sep 2011 11:59:41 +0000 (13:59 +0200)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 9 Feb 2012 23:20:32 +0000 (15:20 -0800)
This operation allows "hole punching" in ZFS files. On Solaris this
is done via the vop_space() system call, which maps to the zfs_space()
function. So we just need to write zpl_truncate_range() as a wrapper
around zfs_space().

Note that this only works for regular files, not ZVOLs.

This is currently an insecure implementation without permission
checking, although this isn't that big of a deal since truncate_range()
isn't even callable from userspace.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Issue #334

module/zfs/zpl_inode.c

index 46b77c9..2d197a4 100644 (file)
@@ -315,6 +315,33 @@ out:
        return (error);
 }
 
+static void
+zpl_truncate_range(struct inode* ip, loff_t start, loff_t end)
+{
+       cred_t *cr = CRED();
+       flock64_t bf;
+
+       ASSERT3S(start, <=, end);
+
+       /*
+        * zfs_freesp() will interpret (len == 0) as meaning "truncate until
+        * the end of the file". We don't want that.
+        */
+       if (start == end)
+               return;
+
+       crhold(cr);
+
+       bf.l_type = F_WRLCK;
+       bf.l_whence = 0;
+       bf.l_start = start;
+       bf.l_len = end - start;
+       bf.l_pid = 0;
+       zfs_space(ip, F_FREESP, &bf, FWRITE, start, cr);
+
+       crfree(cr);
+}
+
 const struct inode_operations zpl_inode_operations = {
        .create         = zpl_create,
        .link           = zpl_link,
@@ -330,6 +357,7 @@ const struct inode_operations zpl_inode_operations = {
        .getxattr       = generic_getxattr,
        .removexattr    = generic_removexattr,
        .listxattr      = zpl_xattr_list,
+       .truncate_range = zpl_truncate_range,
 };
 
 const struct inode_operations zpl_dir_inode_operations = {