Skip to content

Commit

Permalink
Linux semantics for fallocate()
Browse files Browse the repository at this point in the history
According to the Linux documentation, the FALLOC_FL_KEEP_SIZE flag must be
set in conjunction with the FALLOC_FL_PUNCH_HOLE flag.  The previous
logic caused a failure whenever FALLOC_FL_KEEP_SIZE was present.

Also, mimic the behavior of other native file systems such as ext4 in
cases where the file might be extended.  If the offset is beyond the end
of the file, return success without changing the file. If the extent of
the punched hole would extend the file, only the existing tail of the
file is punched.

References:
	https://git.kernel.org/cgit/docs/man-pages/man-pages.git/tree/man2/fallocate.2#n102
  • Loading branch information
dweeezil committed Jul 18, 2014
1 parent 61e99a7 commit c348433
Showing 1 changed file with 13 additions and 0 deletions.
13 changes: 13 additions & 0 deletions module/zfs/zpl_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,22 +486,35 @@ zpl_fallocate_common(struct inode *ip, int mode, loff_t offset, loff_t len)
cred_t *cr = CRED();
int error = -EOPNOTSUPP;

#ifdef FALLOC_FL_PUNCH_HOLE
if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
#else
if (mode & FALLOC_FL_KEEP_SIZE)
#endif
return (-EOPNOTSUPP);

crhold(cr);

#ifdef FALLOC_FL_PUNCH_HOLE
if (mode & FALLOC_FL_PUNCH_HOLE) {
flock64_t bf;
loff_t olen;

olen = i_size_read(ip);
if (offset > olen)
return (0);
if (offset + len > olen)
len = olen - offset;
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);
if (!error)
truncate_inode_pages_range(ip->i_mapping, offset,
offset + len - 1);
}
#endif /* FALLOC_FL_PUNCH_HOLE */

Expand Down

0 comments on commit c348433

Please sign in to comment.