[SMB3] Enable fallocate -z support for SMB3 mounts
fallocate -z (FALLOC_FL_ZERO_RANGE) can map to SMB3 FSCTL_SET_ZERO_DATA SMB3 FSCTL but FALLOC_FL_ZERO_RANGE when called without the FALLOC_FL_KEEPSIZE flag set could want the file size changed so we can not support that subcase unless the file is cached (and thus we know the file size). Signed-off-by: Steve French <smfrench@gmail.com> Reviewed-by: Pavel Shilovsky <pshilovsky@samba.org>
This commit is contained in:
parent
31742c5a33
commit
30175628bf
|
@ -1015,6 +1015,56 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
|
||||||
|
loff_t offset, loff_t len, bool keep_size)
|
||||||
|
{
|
||||||
|
struct inode *inode;
|
||||||
|
struct cifsInodeInfo *cifsi;
|
||||||
|
struct cifsFileInfo *cfile = file->private_data;
|
||||||
|
struct file_zero_data_information fsctl_buf;
|
||||||
|
long rc;
|
||||||
|
unsigned int xid;
|
||||||
|
|
||||||
|
xid = get_xid();
|
||||||
|
|
||||||
|
inode = cfile->dentry->d_inode;
|
||||||
|
cifsi = CIFS_I(inode);
|
||||||
|
|
||||||
|
/* if file not oplocked can't be sure whether asking to extend size */
|
||||||
|
if (!CIFS_CACHE_READ(cifsi))
|
||||||
|
if (keep_size == false)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Must check if file sparse since fallocate -z (zero range) assumes
|
||||||
|
* non-sparse allocation
|
||||||
|
*/
|
||||||
|
if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* need to make sure we are not asked to extend the file since the SMB3
|
||||||
|
* fsctl does not change the file size. In the future we could change
|
||||||
|
* this to zero the first part of the range then set the file size
|
||||||
|
* which for a non sparse file would zero the newly extended range
|
||||||
|
*/
|
||||||
|
if (keep_size == false)
|
||||||
|
if (i_size_read(inode) < offset + len)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
cifs_dbg(FYI, "offset %lld len %lld", offset, len);
|
||||||
|
|
||||||
|
fsctl_buf.FileOffset = cpu_to_le64(offset);
|
||||||
|
fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
|
||||||
|
|
||||||
|
rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
|
||||||
|
cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
|
||||||
|
true /* is_fctl */, (char *)&fsctl_buf,
|
||||||
|
sizeof(struct file_zero_data_information), NULL, NULL);
|
||||||
|
free_xid(xid);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
|
||||||
loff_t offset, loff_t len)
|
loff_t offset, loff_t len)
|
||||||
{
|
{
|
||||||
|
@ -1055,6 +1105,11 @@ static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
|
||||||
/* KEEP_SIZE already checked for by do_fallocate */
|
/* KEEP_SIZE already checked for by do_fallocate */
|
||||||
if (mode & FALLOC_FL_PUNCH_HOLE)
|
if (mode & FALLOC_FL_PUNCH_HOLE)
|
||||||
return smb3_punch_hole(file, tcon, off, len);
|
return smb3_punch_hole(file, tcon, off, len);
|
||||||
|
else if (mode & FALLOC_FL_ZERO_RANGE) {
|
||||||
|
if (mode & FALLOC_FL_KEEP_SIZE)
|
||||||
|
return smb3_zero_range(file, tcon, off, len, true);
|
||||||
|
return smb3_zero_range(file, tcon, off, len, false);
|
||||||
|
}
|
||||||
|
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue