diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 74634369c21ea9b8c0321211cc004c2e8f68e63c..85be34ad8d7637c0ad75885a36924e3d82abf54b 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c @@ -731,6 +731,52 @@ smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile, return SMB2_write(xid, parms, written, iov, nr_segs); } +/* Set or clear the SPARSE_FILE attribute based on value passed in setsparse */ +static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon, + struct cifsFileInfo *cfile, struct inode *inode, __u8 setsparse) +{ + struct cifsInodeInfo *cifsi; + int rc; + + cifsi = CIFS_I(inode); + + /* if file already sparse don't bother setting sparse again */ + if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && setsparse) + return true; /* already sparse */ + + if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && !setsparse) + return true; /* already not 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) + return false; + + rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid, + cfile->fid.volatile_fid, FSCTL_SET_SPARSE, + true /* is_fctl */, &setsparse, 1, NULL, NULL); + if (rc) { + tcon->broken_sparse_sup = true; + cifs_dbg(FYI, "set sparse rc = %d\n", rc); + return false; + } + + if (setsparse) + cifsi->cifsAttrs |= FILE_ATTRIBUTE_SPARSE_FILE; + else + cifsi->cifsAttrs &= (~FILE_ATTRIBUTE_SPARSE_FILE); + + return true; +} + static int smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, struct cifsFileInfo *cfile, __u64 size, bool set_alloc) @@ -745,40 +791,12 @@ smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, 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; - - /* - * 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; + + /* whether set sparse succeeds or not, extend the file */ + smb2_set_sparse(xid, tcon, cfile, inode, set_sparse); } -smb2_set_eof: return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, cfile->fid.volatile_fid, cfile->pid, &eof, false); }