[PATCH] [CIFS] Add sparse file support to SMB2/SMB3 mounts
Shirish Pargaonkar
shirishpargaonkar at gmail.com
Wed Aug 13 15:25:13 MDT 2014
Reviewed-by: Shirish Pargaonkar <spargaonkar at suse.com>
On Wed, Aug 13, 2014 at 12:11 AM, Steve French <smfrench at gmail.com> wrote:
> On Tue, Aug 12, 2014 at 11:34 PM, Shirish Pargaonkar
> <shirishpargaonkar at gmail.com> wrote:
>> On Tue, Aug 12, 2014 at 9:13 AM, Steve French <smfrench at gmail.com> wrote:
>>> Many Linux filesystems make a file "sparse" when extending
>>> a file with ftruncate. This does work for CIFS to Samba
>>> (only) but not for SMB2/SMB3 (to Samba or Windows) since
>>> there is a "set sparse" fsctl which is supposed to be
>>> sent to mark a file as sparse.
>>>
>>> This patch marks a file as sparse by sending this simple
>>> set sparse fsctl if it is extended more than 2 pages.
>>> It has been tested to Windows 8.1, Samba and various
>>> SMB2/SMB3 servers which do support setting sparse (and
>>> MacOS which does not appear to support the fsctl yet).
>>> If a server share does not support setting a file
>>> as sparse, then we do not retry setting sparse on that
>>> share.
>>>
>>> The disk space savings for sparse files can be quite
>>> large (even more significant on Windows servers than Samba).
>>>
>>> Signed-off-by: Steve French <smfrench at gmail.com>
>>> ---
>>> fs/cifs/cifsglob.h | 1 +
>>> fs/cifs/smb2ops.c | 43 +++++++++++++++++++++++++++++++++++++++++++
>>> fs/cifs/smb2pdu.c | 4 +++-
>>> 3 files changed, 47 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
>>> index 0012e1e..bc20a6e 100644
>>> --- a/fs/cifs/cifsglob.h
>>> +++ b/fs/cifs/cifsglob.h
>>> @@ -883,6 +883,7 @@ struct cifs_tcon {
>>> for this mount even if server would support */
>>> bool local_lease:1; /* check leases (only) on local system not remote */
>>> bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
>>> + bool broken_sparse_sup; /* if server or share does not support sparse */
>>> bool need_reconnect:1; /* connection reset, tid now invalid */
>>> #ifdef CONFIG_CIFS_SMB2
>>> bool print:1; /* set if connection to printer share */
>>> diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
>>> index 77f8aeb..7463436 100644
>>> --- a/fs/cifs/smb2ops.c
>>> +++ b/fs/cifs/smb2ops.c
>>> @@ -736,6 +736,49 @@ smb2_set_file_size(const unsigned int xid, struct
>>> cifs_tcon *tcon,
>>> struct cifsFileInfo *cfile, __u64 size, bool set_alloc)
>>> {
>>> __le64 eof = cpu_to_le64(size);
>>> + struct inode *inode;
>>> +
>>> + /*
>>> + * If extending file more than one page make sparse. Many Linux fs
>>> + * make files sparse by default when extending via ftruncate
>>> + */
>>> + inode = cfile->dentry->d_inode;
>>> +
>>> + if (!set_alloc && (size > inode->i_size + 8192)) {
>>> + struct cifsInodeInfo *cifsi;
>>> + __u8 set_sparse = 1;
>>> + int rc;
>>> +
>>> + cifsi = CIFS_I(inode);
>>> +
>>> + /* if file already sparse or no server support don't bother */
>>> + if (cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)
>>> + goto smb2_set_eof;
>>
>> Is this check always valid? Is it possible that the file is not
>> sparse anymore at the server?
>
> If someone unsparsed the file that is fine. The ftruncate to
> extend the file will still work fine as it did before this patch
> (it just will take up more disk space than it would
> if the file were sparse). When the actimeo (1 second) expires,
> and we next refresh the inode attributes from the server
> we will notice the file is not sparse and and future
> ftruncate/extends will mark the file sparse.
>
>>
>>> +
>>> + /*
>>> + * Can't check for sparse support on share the usual way via the
>>> + * FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share
>>> + * since Samba server doesn't set the flag on the share, yet
>>> + * supports the set sparse FSCTL and returns sparse correctly
>>> + * in the file attributes. If we fail setting sparse though we
>>> + * mark that server does not support sparse files for this share
>>> + * to avoid repeatedly sending the unsupported fsctl to server
>>> + * if the file is repeatedly extended.
>>> + */
>>> + if (tcon->broken_sparse_sup)
>>> + goto smb2_set_eof;
>>> +
>>> + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
>>> + cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
>>> + true /* is_fctl */, &set_sparse, 1, NULL, NULL);
>>> + if (rc) {
>>> + tcon->broken_sparse_sup = true;
>>> + cifs_dbg(FYI, "set sparse rc = %d\n", rc);
>>> + } else
>>> + cifsi->cifsAttrs |= FILE_ATTRIBUTE_SPARSE_FILE;
>>> + }
>>> +
>>> +smb2_set_eof:
>>> return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
>>> cfile->fid.volatile_fid, cfile->pid, &eof, false);
>>> }
>
>
>
>
> --
> Thanks,
>
> Steve
More information about the samba-technical
mailing list