diff options
author | Etienne Dechamps <[email protected]> | 2011-09-02 09:42:07 +0200 |
---|---|---|
committer | Brian Behlendorf <[email protected]> | 2012-02-09 16:19:32 -0800 |
commit | cb2d19010d8fbcf6c22585cd8763fad3ba7db724 (patch) | |
tree | b4fe64638a19856107953dc1a814c2e3f787c989 /module | |
parent | aec69371a6a2e94534809c5e9ba22e7b0e276937 (diff) |
Support the fallocate() file operation.
Currently only the (FALLOC_FL_PUNCH_HOLE) flag combination is
supported, since it's the only one that matches the behavior of
zfs_space(). This makes it pretty much useless in its current
form, but it's a start.
To support other flag combinations we would need to modify
zfs_space() to make it more flexible, or emulate the desired
functionality in zpl_fallocate().
Signed-off-by: Brian Behlendorf <[email protected]>
Issue #334
Diffstat (limited to 'module')
-rw-r--r-- | module/zfs/zpl_file.c | 47 | ||||
-rw-r--r-- | module/zfs/zpl_inode.c | 12 |
2 files changed, 59 insertions, 0 deletions
diff --git a/module/zfs/zpl_file.c b/module/zfs/zpl_file.c index 0ef2c1558..5ac41c9d2 100644 --- a/module/zfs/zpl_file.c +++ b/module/zfs/zpl_file.c @@ -394,6 +394,50 @@ zpl_writepage(struct page *pp, struct writeback_control *wbc) return zpl_putpage(pp, wbc, pp->mapping); } +/* + * The only flag combination which matches the behavior of zfs_space() + * is FALLOC_FL_PUNCH_HOLE. This flag was introduced in the 2.6.38 kernel. + */ +long +zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len) +{ + cred_t *cr = CRED(); + int error = -EOPNOTSUPP; + + if (mode & FALLOC_FL_KEEP_SIZE) + return (-EOPNOTSUPP); + + crhold(cr); + +#ifdef FALLOC_FL_PUNCH_HOLE + if (mode & FALLOC_FL_PUNCH_HOLE) { + flock64_t bf; + + bf.l_type = F_WRLCK; + bf.l_whence = 0; + bf.l_start = offset; + bf.l_len = len; + bf.l_pid = 0; + + error = -zfs_space(ip, F_FREESP, &bf, FWRITE, offset, cr); + } +#endif /* FALLOC_FL_PUNCH_HOLE */ + + crfree(cr); + + ASSERT3S(error, <=, 0); + return (error); +} + +#ifdef HAVE_FILE_FALLOCATE +static long +zpl_fallocate(struct file *filp, int mode, loff_t offset, loff_t len) +{ + return zpl_fallocate_common(filp->f_path.dentry->d_inode, + mode, offset, len); +} +#endif /* HAVE_FILE_FALLOCATE */ + const struct address_space_operations zpl_address_space_operations = { .readpages = zpl_readpages, .readpage = zpl_readpage, @@ -410,6 +454,9 @@ const struct file_operations zpl_file_operations = { .readdir = zpl_readdir, .mmap = zpl_mmap, .fsync = zpl_fsync, +#ifdef HAVE_FILE_FALLOCATE + .fallocate = zpl_fallocate, +#endif /* HAVE_FILE_FALLOCATE */ }; const struct file_operations zpl_dir_file_operations = { diff --git a/module/zfs/zpl_inode.c b/module/zfs/zpl_inode.c index 2d197a488..9b5533755 100644 --- a/module/zfs/zpl_inode.c +++ b/module/zfs/zpl_inode.c @@ -342,6 +342,15 @@ zpl_truncate_range(struct inode* ip, loff_t start, loff_t end) crfree(cr); } +#ifdef HAVE_INODE_FALLOCATE +static long +zpl_fallocate(struct inode *ip, int mode, loff_t offset, loff_t len) +{ + return zpl_fallocate_common(ip, mode, offset, len); +} +#endif /* HAVE_INODE_FALLOCATE */ + + const struct inode_operations zpl_inode_operations = { .create = zpl_create, .link = zpl_link, @@ -358,6 +367,9 @@ const struct inode_operations zpl_inode_operations = { .removexattr = generic_removexattr, .listxattr = zpl_xattr_list, .truncate_range = zpl_truncate_range, +#ifdef HAVE_INODE_FALLOCATE + .fallocate = zpl_fallocate, +#endif /* HAVE_INODE_FALLOCATE */ }; const struct inode_operations zpl_dir_inode_operations = { |