Message ID | 20210408074630.622927-1-lsahlber@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | cifs: improve fallocate emulation | expand |
Hi Ronnie, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on cifs/for-next] [also build test WARNING on v5.12-rc6 next-20210407] [If your patch is applied to the wrong git tree, kindly drop us a note. And when submitting patch, we suggest to use '--base' as documented in https://git-scm.com/docs/git-format-patch] url: https://github.com/0day-ci/linux/commits/Ronnie-Sahlberg/cifs-improve-fallocate-emulation/20210408-154812 base: git://git.samba.org/sfrench/cifs-2.6.git for-next config: x86_64-randconfig-s032-20210408 (attached as .config) compiler: gcc-9 (Debian 9.3.0-22) 9.3.0 reproduce: # apt-get install sparse # sparse version: v0.6.3-279-g6d5d9b42-dirty # https://github.com/0day-ci/linux/commit/4e8489f4555efd3340016e422828e29ae87d7f0b git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Ronnie-Sahlberg/cifs-improve-fallocate-emulation/20210408-154812 git checkout 4e8489f4555efd3340016e422828e29ae87d7f0b # save the attached .config to linux build tree make W=1 C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=x86_64 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> sparse warnings: (new ones prefixed by >>) >> fs/cifs/smb2ops.c:3639:35: sparse: sparse: restricted __le64 degrades to integer fs/cifs/smb2ops.c:3645:37: sparse: sparse: restricted __le64 degrades to integer >> fs/cifs/smb2ops.c:3662:19: sparse: sparse: incorrect type in assignment (different base types) @@ expected long long [assigned] [usertype] l @@ got restricted __le64 [usertype] length @@ fs/cifs/smb2ops.c:3662:19: sparse: expected long long [assigned] [usertype] l fs/cifs/smb2ops.c:3662:19: sparse: got restricted __le64 [usertype] length vim +3639 fs/cifs/smb2ops.c 3589 3590 static int smb3_simple_fallocate_range(unsigned int xid, 3591 struct cifs_tcon *tcon, 3592 struct cifsFileInfo *cfile, 3593 loff_t off, loff_t len) 3594 { 3595 struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data; 3596 u32 out_data_len; 3597 char *buf = NULL; 3598 loff_t l; 3599 int rc; 3600 3601 in_data.file_offset = cpu_to_le64(off); 3602 in_data.length = cpu_to_le64(len); 3603 rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, 3604 cfile->fid.volatile_fid, 3605 FSCTL_QUERY_ALLOCATED_RANGES, true, 3606 (char *)&in_data, sizeof(in_data), 3607 1024 * sizeof(struct file_allocated_range_buffer), 3608 (char **)&out_data, &out_data_len); 3609 if (rc) 3610 goto out; 3611 /* 3612 * It is already all allocated 3613 */ 3614 if (out_data_len == 0) 3615 goto out; 3616 3617 buf = kzalloc(1024 * 1024, GFP_KERNEL); 3618 if (buf == NULL) { 3619 rc = -ENOMEM; 3620 goto out; 3621 } 3622 3623 tmp_data = out_data; 3624 while (len) { 3625 /* 3626 * The rest of the region is unmapped so write it all. 3627 */ 3628 if (out_data_len == 0) { 3629 rc = smb3_simple_fallocate_write_range(xid, tcon, 3630 cfile, off, len, buf); 3631 goto out; 3632 } 3633 3634 if (out_data_len < sizeof(struct file_allocated_range_buffer)) { 3635 rc = -EINVAL; 3636 goto out; 3637 } 3638 > 3639 if (off < tmp_data->file_offset) { 3640 /* 3641 * We are at a hole. Write until the end of the region 3642 * or until the next allocated data, 3643 * whichever comes next. 3644 */ 3645 l = tmp_data->file_offset - off; 3646 if (len < l) 3647 l = len; 3648 rc = smb3_simple_fallocate_write_range(xid, tcon, 3649 cfile, off, l, buf); 3650 if (rc) 3651 goto out; 3652 off = off + l; 3653 len = len - l; 3654 if (len == 0) 3655 goto out; 3656 } 3657 /* 3658 * We are at a section of allocated data, just skip forward 3659 * until the end of the data or the end of the region 3660 * we are supposed to fallocate, whichever comes first. 3661 */ > 3662 l = tmp_data->length; 3663 if (len < l) 3664 l = len; 3665 off += l; 3666 len -= l; 3667 3668 tmp_data = &tmp_data[1]; 3669 out_data_len -= sizeof(struct file_allocated_range_buffer); 3670 } 3671 3672 out: 3673 kfree(out_data); 3674 kfree(buf); 3675 return rc; 3676 } 3677 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index f703204fb185..2433cc396531 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -3563,6 +3563,119 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon, return rc; } +static int smb3_simple_fallocate_write_range(unsigned int xid, + struct cifs_tcon *tcon, + struct cifsFileInfo *cfile, + loff_t off, loff_t len, + char *buf) +{ + struct cifs_io_parms io_parms = {0}; + int nbytes; + struct kvec iov[2]; + + io_parms.netfid = cfile->fid.netfid; + io_parms.pid = current->tgid; + io_parms.tcon = tcon; + io_parms.persistent_fid = cfile->fid.persistent_fid; + io_parms.volatile_fid = cfile->fid.volatile_fid; + io_parms.offset = off; + io_parms.length = len; + + /* iov[0] is reserved for smb header */ + iov[1].iov_base = buf; + iov[1].iov_len = io_parms.length; + return SMB2_write(xid, &io_parms, &nbytes, iov, 1); +} + +static int smb3_simple_fallocate_range(unsigned int xid, + struct cifs_tcon *tcon, + struct cifsFileInfo *cfile, + loff_t off, loff_t len) +{ + struct file_allocated_range_buffer in_data, *out_data = NULL, *tmp_data; + u32 out_data_len; + char *buf = NULL; + loff_t l; + int rc; + + in_data.file_offset = cpu_to_le64(off); + in_data.length = cpu_to_le64(len); + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, + FSCTL_QUERY_ALLOCATED_RANGES, true, + (char *)&in_data, sizeof(in_data), + 1024 * sizeof(struct file_allocated_range_buffer), + (char **)&out_data, &out_data_len); + if (rc) + goto out; + /* + * It is already all allocated + */ + if (out_data_len == 0) + goto out; + + buf = kzalloc(1024 * 1024, GFP_KERNEL); + if (buf == NULL) { + rc = -ENOMEM; + goto out; + } + + tmp_data = out_data; + while (len) { + /* + * The rest of the region is unmapped so write it all. + */ + if (out_data_len == 0) { + rc = smb3_simple_fallocate_write_range(xid, tcon, + cfile, off, len, buf); + goto out; + } + + if (out_data_len < sizeof(struct file_allocated_range_buffer)) { + rc = -EINVAL; + goto out; + } + + if (off < tmp_data->file_offset) { + /* + * We are at a hole. Write until the end of the region + * or until the next allocated data, + * whichever comes next. + */ + l = tmp_data->file_offset - off; + if (len < l) + l = len; + rc = smb3_simple_fallocate_write_range(xid, tcon, + cfile, off, l, buf); + if (rc) + goto out; + off = off + l; + len = len - l; + if (len == 0) + goto out; + } + /* + * We are at a section of allocated data, just skip forward + * until the end of the data or the end of the region + * we are supposed to fallocate, whichever comes first. + */ + l = tmp_data->length; + if (len < l) + l = len; + off += l; + len -= l; + + tmp_data = &tmp_data[1]; + out_data_len -= sizeof(struct file_allocated_range_buffer); + } + + out: + kfree(out_data); + kfree(buf); + return rc; +} + + static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, loff_t off, loff_t len, bool keep_size) { @@ -3623,6 +3736,26 @@ static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon, } if ((keep_size == true) || (i_size_read(inode) >= off + len)) { + /* + * At this point, we are trying to fallocate an internal + * regions of a sparse file. Since smb2 does not have a + * fallocate command we have two otions on how to emulate this. + * We can either turn the entire file to become non-sparse + * which we only do if the fallocate is for virtually + * the whole file, or we can overwrite the region with zeroes + * using SMB2_write, which could be prohibitevly expensive + * if len is large. + */ + /* + * We are only trying to fallocate a small region so + * just write it with zero. + */ + if (len <= 1024 * 1024) { + rc = smb3_simple_fallocate_range(xid, tcon, cfile, + off, len); + goto out; + } + /* * Check if falloc starts within first few pages of file * and ends within a few pages of the end of file to
RHBZ: 1866684 We don't have a real fallocate in the SMB2 protocol so we used to emulate fallocate by simply switching the file to become non-sparse. But as that could potantially consume a lot more data than we intended to fallocate (large sparse file and fallocating a thin slice in the middle) we would only do this IFF the fallocate request was for virtually the entire file. This patch improves this and starts allowing us to fallocate smaller chunks of a file by overwriting the region with 0, for the parts that are unallocated. The method used is to first query the server for FSCTL_QUERY_ALLOCATED_RANGES to find what is unallocated in teh fallocate range and then to only overwrite-with-zero the unallocated ranges to fill in the holes. As overwriting-with-zero is different from just allocating blocks, and potentially much more expensive, we limit this to only allow fallocate ranges up to 1Mb in size. Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com> --- fs/cifs/smb2ops.c | 133 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+)