aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <smfrench@gmail.com>2014-08-11 22:05:25 -0400
committerSteve French <smfrench@gmail.com>2014-08-13 14:18:35 -0400
commit3d1a3745d8ca7ccdf00905b01fd5ab42ff523a94 (patch)
tree17ba01e56cbf7238e5ce59967f1e073da95b885b
parent8ae31240ccc8ff339101e2d023b82cb7c93dd002 (diff)
Add sparse file support to SMB2/SMB3 mounts
Many Linux filesystes 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@gmail.com> Reviewed-by: Shirish Pargaonkar <spargaonkar@suse.com>
-rw-r--r--fs/cifs/cifsglob.h1
-rw-r--r--fs/cifs/smb2ops.c43
-rw-r--r--fs/cifs/smb2pdu.c4
3 files changed, 47 insertions, 1 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 0012e1e291d4..bc20a6ea6754 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -883,6 +883,7 @@ struct cifs_tcon {
883 for this mount even if server would support */ 883 for this mount even if server would support */
884 bool local_lease:1; /* check leases (only) on local system not remote */ 884 bool local_lease:1; /* check leases (only) on local system not remote */
885 bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */ 885 bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
886 bool broken_sparse_sup; /* if server or share does not support sparse */
886 bool need_reconnect:1; /* connection reset, tid now invalid */ 887 bool need_reconnect:1; /* connection reset, tid now invalid */
887#ifdef CONFIG_CIFS_SMB2 888#ifdef CONFIG_CIFS_SMB2
888 bool print:1; /* set if connection to printer share */ 889 bool print:1; /* set if connection to printer share */
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 77f8aeb9c2fc..74634369c21e 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,
736 struct cifsFileInfo *cfile, __u64 size, bool set_alloc) 736 struct cifsFileInfo *cfile, __u64 size, bool set_alloc)
737{ 737{
738 __le64 eof = cpu_to_le64(size); 738 __le64 eof = cpu_to_le64(size);
739 struct inode *inode;
740
741 /*
742 * If extending file more than one page make sparse. Many Linux fs
743 * make files sparse by default when extending via ftruncate
744 */
745 inode = cfile->dentry->d_inode;
746
747 if (!set_alloc && (size > inode->i_size + 8192)) {
748 struct cifsInodeInfo *cifsi;
749 __u8 set_sparse = 1;
750 int rc;
751
752 cifsi = CIFS_I(inode);
753
754 /* if file already sparse or no server support don't bother */
755 if (cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE)
756 goto smb2_set_eof;
757
758 /*
759 * Can't check for sparse support on share the usual way via the
760 * FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share
761 * since Samba server doesn't set the flag on the share, yet
762 * supports the set sparse FSCTL and returns sparse correctly
763 * in the file attributes. If we fail setting sparse though we
764 * mark that server does not support sparse files for this share
765 * to avoid repeatedly sending the unsupported fsctl to server
766 * if the file is repeatedly extended.
767 */
768 if (tcon->broken_sparse_sup)
769 goto smb2_set_eof;
770
771 rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
772 cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
773 true /* is_fctl */, &set_sparse, 1, NULL, NULL);
774 if (rc) {
775 tcon->broken_sparse_sup = true;
776 cifs_dbg(FYI, "set sparse rc = %d\n", rc);
777 } else
778 cifsi->cifsAttrs |= FILE_ATTRIBUTE_SPARSE_FILE;
779 }
780
781smb2_set_eof:
739 return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, 782 return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
740 cfile->fid.volatile_fid, cfile->pid, &eof, false); 783 cfile->fid.volatile_fid, cfile->pid, &eof, false);
741} 784}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 42ebc1a8be6c..74440af59f35 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -1224,7 +1224,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
1224 1224
1225 cifs_dbg(FYI, "SMB2 IOCTL\n"); 1225 cifs_dbg(FYI, "SMB2 IOCTL\n");
1226 1226
1227 *out_data = NULL; 1227 if (out_data != NULL)
1228 *out_data = NULL;
1229
1228 /* zero out returned data len, in case of error */ 1230 /* zero out returned data len, in case of error */
1229 if (plen) 1231 if (plen)
1230 *plen = 0; 1232 *plen = 0;