aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsfs.c24
-rw-r--r--fs/cifs/cifsglob.h5
-rw-r--r--fs/cifs/cifspdu.h23
-rw-r--r--fs/cifs/file.c2
-rw-r--r--fs/cifs/inode.c6
-rw-r--r--fs/cifs/misc.c7
-rw-r--r--fs/cifs/readdir.c2
-rw-r--r--fs/cifs/smb1ops.c7
-rw-r--r--fs/cifs/smb2maperror.c4
-rw-r--r--fs/cifs/smb2misc.c17
-rw-r--r--fs/cifs/smb2ops.c170
-rw-r--r--fs/cifs/smb2pdu.c16
-rw-r--r--fs/cifs/smb2pdu.h6
-rw-r--r--fs/cifs/smbfsctl.h2
14 files changed, 269 insertions, 22 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index ac4f260155c8..889b98455750 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -207,6 +207,19 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
207 return 0; 207 return 0;
208} 208}
209 209
210static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
211{
212 struct super_block *sb = file->f_path.dentry->d_sb;
213 struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
214 struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
215 struct TCP_Server_Info *server = tcon->ses->server;
216
217 if (server->ops->fallocate)
218 return server->ops->fallocate(file, tcon, mode, off, len);
219
220 return -EOPNOTSUPP;
221}
222
210static int cifs_permission(struct inode *inode, int mask) 223static int cifs_permission(struct inode *inode, int mask)
211{ 224{
212 struct cifs_sb_info *cifs_sb; 225 struct cifs_sb_info *cifs_sb;
@@ -812,8 +825,9 @@ static int cifs_setlease(struct file *file, long arg, struct file_lock **lease)
812 if (!(S_ISREG(inode->i_mode))) 825 if (!(S_ISREG(inode->i_mode)))
813 return -EINVAL; 826 return -EINVAL;
814 827
815 /* check if file is oplocked */ 828 /* Check if file is oplocked if this is request for new lease */
816 if (((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) || 829 if (arg == F_UNLCK ||
830 ((arg == F_RDLCK) && CIFS_CACHE_READ(CIFS_I(inode))) ||
817 ((arg == F_WRLCK) && CIFS_CACHE_WRITE(CIFS_I(inode)))) 831 ((arg == F_WRLCK) && CIFS_CACHE_WRITE(CIFS_I(inode))))
818 return generic_setlease(file, arg, lease); 832 return generic_setlease(file, arg, lease);
819 else if (tlink_tcon(cfile->tlink)->local_lease && 833 else if (tlink_tcon(cfile->tlink)->local_lease &&
@@ -908,6 +922,7 @@ const struct file_operations cifs_file_ops = {
908 .unlocked_ioctl = cifs_ioctl, 922 .unlocked_ioctl = cifs_ioctl,
909#endif /* CONFIG_CIFS_POSIX */ 923#endif /* CONFIG_CIFS_POSIX */
910 .setlease = cifs_setlease, 924 .setlease = cifs_setlease,
925 .fallocate = cifs_fallocate,
911}; 926};
912 927
913const struct file_operations cifs_file_strict_ops = { 928const struct file_operations cifs_file_strict_ops = {
@@ -927,6 +942,7 @@ const struct file_operations cifs_file_strict_ops = {
927 .unlocked_ioctl = cifs_ioctl, 942 .unlocked_ioctl = cifs_ioctl,
928#endif /* CONFIG_CIFS_POSIX */ 943#endif /* CONFIG_CIFS_POSIX */
929 .setlease = cifs_setlease, 944 .setlease = cifs_setlease,
945 .fallocate = cifs_fallocate,
930}; 946};
931 947
932const struct file_operations cifs_file_direct_ops = { 948const struct file_operations cifs_file_direct_ops = {
@@ -947,6 +963,7 @@ const struct file_operations cifs_file_direct_ops = {
947#endif /* CONFIG_CIFS_POSIX */ 963#endif /* CONFIG_CIFS_POSIX */
948 .llseek = cifs_llseek, 964 .llseek = cifs_llseek,
949 .setlease = cifs_setlease, 965 .setlease = cifs_setlease,
966 .fallocate = cifs_fallocate,
950}; 967};
951 968
952const struct file_operations cifs_file_nobrl_ops = { 969const struct file_operations cifs_file_nobrl_ops = {
@@ -965,6 +982,7 @@ const struct file_operations cifs_file_nobrl_ops = {
965 .unlocked_ioctl = cifs_ioctl, 982 .unlocked_ioctl = cifs_ioctl,
966#endif /* CONFIG_CIFS_POSIX */ 983#endif /* CONFIG_CIFS_POSIX */
967 .setlease = cifs_setlease, 984 .setlease = cifs_setlease,
985 .fallocate = cifs_fallocate,
968}; 986};
969 987
970const struct file_operations cifs_file_strict_nobrl_ops = { 988const struct file_operations cifs_file_strict_nobrl_ops = {
@@ -983,6 +1001,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = {
983 .unlocked_ioctl = cifs_ioctl, 1001 .unlocked_ioctl = cifs_ioctl,
984#endif /* CONFIG_CIFS_POSIX */ 1002#endif /* CONFIG_CIFS_POSIX */
985 .setlease = cifs_setlease, 1003 .setlease = cifs_setlease,
1004 .fallocate = cifs_fallocate,
986}; 1005};
987 1006
988const struct file_operations cifs_file_direct_nobrl_ops = { 1007const struct file_operations cifs_file_direct_nobrl_ops = {
@@ -1002,6 +1021,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = {
1002#endif /* CONFIG_CIFS_POSIX */ 1021#endif /* CONFIG_CIFS_POSIX */
1003 .llseek = cifs_llseek, 1022 .llseek = cifs_llseek,
1004 .setlease = cifs_setlease, 1023 .setlease = cifs_setlease,
1024 .fallocate = cifs_fallocate,
1005}; 1025};
1006 1026
1007const struct file_operations cifs_dir_ops = { 1027const struct file_operations cifs_dir_ops = {
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 0012e1e291d4..dfc731b02aa9 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -409,6 +409,10 @@ struct smb_version_operations {
409 /* get mtu credits */ 409 /* get mtu credits */
410 int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int, 410 int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int,
411 unsigned int *, unsigned int *); 411 unsigned int *, unsigned int *);
412 /* check if we need to issue closedir */
413 bool (*dir_needs_close)(struct cifsFileInfo *);
414 long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t,
415 loff_t);
412}; 416};
413 417
414struct smb_version_values { 418struct smb_version_values {
@@ -883,6 +887,7 @@ struct cifs_tcon {
883 for this mount even if server would support */ 887 for this mount even if server would support */
884 bool local_lease:1; /* check leases (only) on local system not remote */ 888 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 */ 889 bool broken_posix_open; /* e.g. Samba server versions < 3.3.2, 3.2.9 */
890 bool broken_sparse_sup; /* if server or share does not support sparse */
886 bool need_reconnect:1; /* connection reset, tid now invalid */ 891 bool need_reconnect:1; /* connection reset, tid now invalid */
887#ifdef CONFIG_CIFS_SMB2 892#ifdef CONFIG_CIFS_SMB2
888 bool print:1; /* set if connection to printer share */ 893 bool print:1; /* set if connection to printer share */
diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
index 33df36ef9d52..5f9822ac0245 100644
--- a/fs/cifs/cifspdu.h
+++ b/fs/cifs/cifspdu.h
@@ -2253,6 +2253,29 @@ typedef struct {
2253/* minimum includes first three fields, and empty FS Name */ 2253/* minimum includes first three fields, and empty FS Name */
2254#define MIN_FS_ATTR_INFO_SIZE 12 2254#define MIN_FS_ATTR_INFO_SIZE 12
2255 2255
2256
2257/* List of FileSystemAttributes - see 2.5.1 of MS-FSCC */
2258#define FILE_SUPPORT_INTEGRITY_STREAMS 0x04000000
2259#define FILE_SUPPORTS_USN_JOURNAL 0x02000000
2260#define FILE_SUPPORTS_OPEN_BY_FILE_ID 0x01000000
2261#define FILE_SUPPORTS_EXTENDED_ATTRIBUTES 0x00800000
2262#define FILE_SUPPORTS_HARD_LINKS 0x00400000
2263#define FILE_SUPPORTS_TRANSACTIONS 0x00200000
2264#define FILE_SEQUENTIAL_WRITE_ONCE 0x00100000
2265#define FILE_READ_ONLY_VOLUME 0x00080000
2266#define FILE_NAMED_STREAMS 0x00040000
2267#define FILE_SUPPORTS_ENCRYPTION 0x00020000
2268#define FILE_SUPPORTS_OBJECT_IDS 0x00010000
2269#define FILE_VOLUME_IS_COMPRESSED 0x00008000
2270#define FILE_SUPPORTS_REMOTE_STORAGE 0x00000100
2271#define FILE_SUPPORTS_REPARSE_POINTS 0x00000080
2272#define FILE_SUPPORTS_SPARSE_FILES 0x00000040
2273#define FILE_VOLUME_QUOTAS 0x00000020
2274#define FILE_FILE_COMPRESSION 0x00000010
2275#define FILE_PERSISTENT_ACLS 0x00000008
2276#define FILE_UNICODE_ON_DISK 0x00000004
2277#define FILE_CASE_PRESERVED_NAMES 0x00000002
2278#define FILE_CASE_SENSITIVE_SEARCH 0x00000001
2256typedef struct { 2279typedef struct {
2257 __le32 Attributes; 2280 __le32 Attributes;
2258 __le32 MaxPathNameComponentLength; 2281 __le32 MaxPathNameComponentLength;
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 4ab2f79ffa7a..d5fec92e0360 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -762,7 +762,7 @@ int cifs_closedir(struct inode *inode, struct file *file)
762 762
763 cifs_dbg(FYI, "Freeing private data in close dir\n"); 763 cifs_dbg(FYI, "Freeing private data in close dir\n");
764 spin_lock(&cifs_file_list_lock); 764 spin_lock(&cifs_file_list_lock);
765 if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { 765 if (server->ops->dir_needs_close(cfile)) {
766 cfile->invalidHandle = true; 766 cfile->invalidHandle = true;
767 spin_unlock(&cifs_file_list_lock); 767 spin_unlock(&cifs_file_list_lock);
768 if (server->ops->close_dir) 768 if (server->ops->close_dir)
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 426d6c6ad8bf..949ec909ec9a 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1727,6 +1727,12 @@ unlink_target:
1727 target_dentry, to_name); 1727 target_dentry, to_name);
1728 } 1728 }
1729 1729
1730 /* force revalidate to go get info when needed */
1731 CIFS_I(source_dir)->time = CIFS_I(target_dir)->time = 0;
1732
1733 source_dir->i_ctime = source_dir->i_mtime = target_dir->i_ctime =
1734 target_dir->i_mtime = current_fs_time(source_dir->i_sb);
1735
1730cifs_rename_exit: 1736cifs_rename_exit:
1731 kfree(info_buf_source); 1737 kfree(info_buf_source);
1732 kfree(from_name); 1738 kfree(from_name);
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index 81340c6253eb..b7415d596dbd 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -574,13 +574,6 @@ void cifs_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
574 cinode->oplock = 0; 574 cinode->oplock = 0;
575} 575}
576 576
577static int
578cifs_oplock_break_wait(void *unused)
579{
580 schedule();
581 return signal_pending(current) ? -ERESTARTSYS : 0;
582}
583
584/* 577/*
585 * We wait for oplock breaks to be processed before we attempt to perform 578 * We wait for oplock breaks to be processed before we attempt to perform
586 * writes. 579 * writes.
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index b15862e0f68c..798c80a41c88 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -593,7 +593,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
593 /* close and restart search */ 593 /* close and restart search */
594 cifs_dbg(FYI, "search backing up - close and restart search\n"); 594 cifs_dbg(FYI, "search backing up - close and restart search\n");
595 spin_lock(&cifs_file_list_lock); 595 spin_lock(&cifs_file_list_lock);
596 if (!cfile->srch_inf.endOfSearch && !cfile->invalidHandle) { 596 if (server->ops->dir_needs_close(cfile)) {
597 cfile->invalidHandle = true; 597 cfile->invalidHandle = true;
598 spin_unlock(&cifs_file_list_lock); 598 spin_unlock(&cifs_file_list_lock);
599 if (server->ops->close) 599 if (server->ops->close)
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c
index 5e8c22d6c7b9..1a6df4b03f67 100644
--- a/fs/cifs/smb1ops.c
+++ b/fs/cifs/smb1ops.c
@@ -1015,6 +1015,12 @@ cifs_wp_retry_size(struct inode *inode)
1015 return CIFS_SB(inode->i_sb)->wsize; 1015 return CIFS_SB(inode->i_sb)->wsize;
1016} 1016}
1017 1017
1018static bool
1019cifs_dir_needs_close(struct cifsFileInfo *cfile)
1020{
1021 return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle;
1022}
1023
1018struct smb_version_operations smb1_operations = { 1024struct smb_version_operations smb1_operations = {
1019 .send_cancel = send_nt_cancel, 1025 .send_cancel = send_nt_cancel,
1020 .compare_fids = cifs_compare_fids, 1026 .compare_fids = cifs_compare_fids,
@@ -1086,6 +1092,7 @@ struct smb_version_operations smb1_operations = {
1086 .create_mf_symlink = cifs_create_mf_symlink, 1092 .create_mf_symlink = cifs_create_mf_symlink,
1087 .is_read_op = cifs_is_read_op, 1093 .is_read_op = cifs_is_read_op,
1088 .wp_retry_size = cifs_wp_retry_size, 1094 .wp_retry_size = cifs_wp_retry_size,
1095 .dir_needs_close = cifs_dir_needs_close,
1089#ifdef CONFIG_CIFS_XATTR 1096#ifdef CONFIG_CIFS_XATTR
1090 .query_all_EAs = CIFSSMBQAllEAs, 1097 .query_all_EAs = CIFSSMBQAllEAs,
1091 .set_EA = CIFSSMBSetEA, 1098 .set_EA = CIFSSMBSetEA,
diff --git a/fs/cifs/smb2maperror.c b/fs/cifs/smb2maperror.c
index e31a9dfdcd39..af59d03db492 100644
--- a/fs/cifs/smb2maperror.c
+++ b/fs/cifs/smb2maperror.c
@@ -214,7 +214,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
214 {STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"}, 214 {STATUS_BREAKPOINT, -EIO, "STATUS_BREAKPOINT"},
215 {STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"}, 215 {STATUS_SINGLE_STEP, -EIO, "STATUS_SINGLE_STEP"},
216 {STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"}, 216 {STATUS_BUFFER_OVERFLOW, -EIO, "STATUS_BUFFER_OVERFLOW"},
217 {STATUS_NO_MORE_FILES, -EIO, "STATUS_NO_MORE_FILES"}, 217 {STATUS_NO_MORE_FILES, -ENODATA, "STATUS_NO_MORE_FILES"},
218 {STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"}, 218 {STATUS_WAKE_SYSTEM_DEBUGGER, -EIO, "STATUS_WAKE_SYSTEM_DEBUGGER"},
219 {STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"}, 219 {STATUS_HANDLES_CLOSED, -EIO, "STATUS_HANDLES_CLOSED"},
220 {STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"}, 220 {STATUS_NO_INHERITANCE, -EIO, "STATUS_NO_INHERITANCE"},
@@ -298,7 +298,7 @@ static const struct status_to_posix_error smb2_error_map_table[] = {
298 {STATUS_INVALID_PARAMETER, -EINVAL, "STATUS_INVALID_PARAMETER"}, 298 {STATUS_INVALID_PARAMETER, -EINVAL, "STATUS_INVALID_PARAMETER"},
299 {STATUS_NO_SUCH_DEVICE, -ENODEV, "STATUS_NO_SUCH_DEVICE"}, 299 {STATUS_NO_SUCH_DEVICE, -ENODEV, "STATUS_NO_SUCH_DEVICE"},
300 {STATUS_NO_SUCH_FILE, -ENOENT, "STATUS_NO_SUCH_FILE"}, 300 {STATUS_NO_SUCH_FILE, -ENOENT, "STATUS_NO_SUCH_FILE"},
301 {STATUS_INVALID_DEVICE_REQUEST, -EIO, "STATUS_INVALID_DEVICE_REQUEST"}, 301 {STATUS_INVALID_DEVICE_REQUEST, -EOPNOTSUPP, "STATUS_INVALID_DEVICE_REQUEST"},
302 {STATUS_END_OF_FILE, -ENODATA, "STATUS_END_OF_FILE"}, 302 {STATUS_END_OF_FILE, -ENODATA, "STATUS_END_OF_FILE"},
303 {STATUS_WRONG_VOLUME, -EIO, "STATUS_WRONG_VOLUME"}, 303 {STATUS_WRONG_VOLUME, -EIO, "STATUS_WRONG_VOLUME"},
304 {STATUS_NO_MEDIA_IN_DEVICE, -EIO, "STATUS_NO_MEDIA_IN_DEVICE"}, 304 {STATUS_NO_MEDIA_IN_DEVICE, -EIO, "STATUS_NO_MEDIA_IN_DEVICE"},
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index f2e6ac29a8d6..4aa7a0f07d6e 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -178,9 +178,24 @@ smb2_check_message(char *buf, unsigned int length)
178 /* Windows 7 server returns 24 bytes more */ 178 /* Windows 7 server returns 24 bytes more */
179 if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE) 179 if (clc_len + 20 == len && command == SMB2_OPLOCK_BREAK_HE)
180 return 0; 180 return 0;
181 /* server can return one byte more */ 181 /* server can return one byte more due to implied bcc[0] */
182 if (clc_len == 4 + len + 1) 182 if (clc_len == 4 + len + 1)
183 return 0; 183 return 0;
184
185 /*
186 * MacOS server pads after SMB2.1 write response with 3 bytes
187 * of junk. Other servers match RFC1001 len to actual
188 * SMB2/SMB3 frame length (header + smb2 response specific data)
189 * Log the server error (once), but allow it and continue
190 * since the frame is parseable.
191 */
192 if (clc_len < 4 /* RFC1001 header size */ + len) {
193 printk_once(KERN_WARNING
194 "SMB2 server sent bad RFC1001 len %d not %d\n",
195 len, clc_len - 4);
196 return 0;
197 }
198
184 return 1; 199 return 1;
185 } 200 }
186 return 0; 201 return 0;
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 77f8aeb9c2fc..5a48aa290dfe 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -731,11 +731,72 @@ smb2_sync_write(const unsigned int xid, struct cifsFileInfo *cfile,
731 return SMB2_write(xid, parms, written, iov, nr_segs); 731 return SMB2_write(xid, parms, written, iov, nr_segs);
732} 732}
733 733
734/* Set or clear the SPARSE_FILE attribute based on value passed in setsparse */
735static bool smb2_set_sparse(const unsigned int xid, struct cifs_tcon *tcon,
736 struct cifsFileInfo *cfile, struct inode *inode, __u8 setsparse)
737{
738 struct cifsInodeInfo *cifsi;
739 int rc;
740
741 cifsi = CIFS_I(inode);
742
743 /* if file already sparse don't bother setting sparse again */
744 if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && setsparse)
745 return true; /* already sparse */
746
747 if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) && !setsparse)
748 return true; /* already not sparse */
749
750 /*
751 * Can't check for sparse support on share the usual way via the
752 * FS attribute info (FILE_SUPPORTS_SPARSE_FILES) on the share
753 * since Samba server doesn't set the flag on the share, yet
754 * supports the set sparse FSCTL and returns sparse correctly
755 * in the file attributes. If we fail setting sparse though we
756 * mark that server does not support sparse files for this share
757 * to avoid repeatedly sending the unsupported fsctl to server
758 * if the file is repeatedly extended.
759 */
760 if (tcon->broken_sparse_sup)
761 return false;
762
763 rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
764 cfile->fid.volatile_fid, FSCTL_SET_SPARSE,
765 true /* is_fctl */, &setsparse, 1, NULL, NULL);
766 if (rc) {
767 tcon->broken_sparse_sup = true;
768 cifs_dbg(FYI, "set sparse rc = %d\n", rc);
769 return false;
770 }
771
772 if (setsparse)
773 cifsi->cifsAttrs |= FILE_ATTRIBUTE_SPARSE_FILE;
774 else
775 cifsi->cifsAttrs &= (~FILE_ATTRIBUTE_SPARSE_FILE);
776
777 return true;
778}
779
734static int 780static int
735smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, 781smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon,
736 struct cifsFileInfo *cfile, __u64 size, bool set_alloc) 782 struct cifsFileInfo *cfile, __u64 size, bool set_alloc)
737{ 783{
738 __le64 eof = cpu_to_le64(size); 784 __le64 eof = cpu_to_le64(size);
785 struct inode *inode;
786
787 /*
788 * If extending file more than one page make sparse. Many Linux fs
789 * make files sparse by default when extending via ftruncate
790 */
791 inode = cfile->dentry->d_inode;
792
793 if (!set_alloc && (size > inode->i_size + 8192)) {
794 __u8 set_sparse = 1;
795
796 /* whether set sparse succeeds or not, extend the file */
797 smb2_set_sparse(xid, tcon, cfile, inode, set_sparse);
798 }
799
739 return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid, 800 return SMB2_set_eof(xid, tcon, cfile->fid.persistent_fid,
740 cfile->fid.volatile_fid, cfile->pid, &eof, false); 801 cfile->fid.volatile_fid, cfile->pid, &eof, false);
741} 802}
@@ -954,6 +1015,105 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
954 return rc; 1015 return rc;
955} 1016}
956 1017
1018static long smb3_zero_range(struct file *file, struct cifs_tcon *tcon,
1019 loff_t offset, loff_t len, bool keep_size)
1020{
1021 struct inode *inode;
1022 struct cifsInodeInfo *cifsi;
1023 struct cifsFileInfo *cfile = file->private_data;
1024 struct file_zero_data_information fsctl_buf;
1025 long rc;
1026 unsigned int xid;
1027
1028 xid = get_xid();
1029
1030 inode = cfile->dentry->d_inode;
1031 cifsi = CIFS_I(inode);
1032
1033 /* if file not oplocked can't be sure whether asking to extend size */
1034 if (!CIFS_CACHE_READ(cifsi))
1035 if (keep_size == false)
1036 return -EOPNOTSUPP;
1037
1038 /*
1039 * Must check if file sparse since fallocate -z (zero range) assumes
1040 * non-sparse allocation
1041 */
1042 if (!(cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE))
1043 return -EOPNOTSUPP;
1044
1045 /*
1046 * need to make sure we are not asked to extend the file since the SMB3
1047 * fsctl does not change the file size. In the future we could change
1048 * this to zero the first part of the range then set the file size
1049 * which for a non sparse file would zero the newly extended range
1050 */
1051 if (keep_size == false)
1052 if (i_size_read(inode) < offset + len)
1053 return -EOPNOTSUPP;
1054
1055 cifs_dbg(FYI, "offset %lld len %lld", offset, len);
1056
1057 fsctl_buf.FileOffset = cpu_to_le64(offset);
1058 fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
1059
1060 rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
1061 cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
1062 true /* is_fctl */, (char *)&fsctl_buf,
1063 sizeof(struct file_zero_data_information), NULL, NULL);
1064 free_xid(xid);
1065 return rc;
1066}
1067
1068static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
1069 loff_t offset, loff_t len)
1070{
1071 struct inode *inode;
1072 struct cifsInodeInfo *cifsi;
1073 struct cifsFileInfo *cfile = file->private_data;
1074 struct file_zero_data_information fsctl_buf;
1075 long rc;
1076 unsigned int xid;
1077 __u8 set_sparse = 1;
1078
1079 xid = get_xid();
1080
1081 inode = cfile->dentry->d_inode;
1082 cifsi = CIFS_I(inode);
1083
1084 /* Need to make file sparse, if not already, before freeing range. */
1085 /* Consider adding equivalent for compressed since it could also work */
1086 if (!smb2_set_sparse(xid, tcon, cfile, inode, set_sparse))
1087 return -EOPNOTSUPP;
1088
1089 cifs_dbg(FYI, "offset %lld len %lld", offset, len);
1090
1091 fsctl_buf.FileOffset = cpu_to_le64(offset);
1092 fsctl_buf.BeyondFinalZero = cpu_to_le64(offset + len);
1093
1094 rc = SMB2_ioctl(xid, tcon, cfile->fid.persistent_fid,
1095 cfile->fid.volatile_fid, FSCTL_SET_ZERO_DATA,
1096 true /* is_fctl */, (char *)&fsctl_buf,
1097 sizeof(struct file_zero_data_information), NULL, NULL);
1098 free_xid(xid);
1099 return rc;
1100}
1101
1102static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
1103 loff_t off, loff_t len)
1104{
1105 /* KEEP_SIZE already checked for by do_fallocate */
1106 if (mode & FALLOC_FL_PUNCH_HOLE)
1107 return smb3_punch_hole(file, tcon, off, len);
1108 else if (mode & FALLOC_FL_ZERO_RANGE) {
1109 if (mode & FALLOC_FL_KEEP_SIZE)
1110 return smb3_zero_range(file, tcon, off, len, true);
1111 return smb3_zero_range(file, tcon, off, len, false);
1112 }
1113
1114 return -EOPNOTSUPP;
1115}
1116
957static void 1117static void
958smb2_downgrade_oplock(struct TCP_Server_Info *server, 1118smb2_downgrade_oplock(struct TCP_Server_Info *server,
959 struct cifsInodeInfo *cinode, bool set_level2) 1119 struct cifsInodeInfo *cinode, bool set_level2)
@@ -1161,6 +1321,12 @@ smb2_wp_retry_size(struct inode *inode)
1161 SMB2_MAX_BUFFER_SIZE); 1321 SMB2_MAX_BUFFER_SIZE);
1162} 1322}
1163 1323
1324static bool
1325smb2_dir_needs_close(struct cifsFileInfo *cfile)
1326{
1327 return !cfile->invalidHandle;
1328}
1329
1164struct smb_version_operations smb20_operations = { 1330struct smb_version_operations smb20_operations = {
1165 .compare_fids = smb2_compare_fids, 1331 .compare_fids = smb2_compare_fids,
1166 .setup_request = smb2_setup_request, 1332 .setup_request = smb2_setup_request,
@@ -1236,6 +1402,7 @@ struct smb_version_operations smb20_operations = {
1236 .parse_lease_buf = smb2_parse_lease_buf, 1402 .parse_lease_buf = smb2_parse_lease_buf,
1237 .clone_range = smb2_clone_range, 1403 .clone_range = smb2_clone_range,
1238 .wp_retry_size = smb2_wp_retry_size, 1404 .wp_retry_size = smb2_wp_retry_size,
1405 .dir_needs_close = smb2_dir_needs_close,
1239}; 1406};
1240 1407
1241struct smb_version_operations smb21_operations = { 1408struct smb_version_operations smb21_operations = {
@@ -1313,6 +1480,7 @@ struct smb_version_operations smb21_operations = {
1313 .parse_lease_buf = smb2_parse_lease_buf, 1480 .parse_lease_buf = smb2_parse_lease_buf,
1314 .clone_range = smb2_clone_range, 1481 .clone_range = smb2_clone_range,
1315 .wp_retry_size = smb2_wp_retry_size, 1482 .wp_retry_size = smb2_wp_retry_size,
1483 .dir_needs_close = smb2_dir_needs_close,
1316}; 1484};
1317 1485
1318struct smb_version_operations smb30_operations = { 1486struct smb_version_operations smb30_operations = {
@@ -1393,6 +1561,8 @@ struct smb_version_operations smb30_operations = {
1393 .clone_range = smb2_clone_range, 1561 .clone_range = smb2_clone_range,
1394 .validate_negotiate = smb3_validate_negotiate, 1562 .validate_negotiate = smb3_validate_negotiate,
1395 .wp_retry_size = smb2_wp_retry_size, 1563 .wp_retry_size = smb2_wp_retry_size,
1564 .dir_needs_close = smb2_dir_needs_close,
1565 .fallocate = smb3_fallocate,
1396}; 1566};
1397 1567
1398struct smb_version_values smb20_values = { 1568struct smb_version_values smb20_values = {
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 42ebc1a8be6c..fa0dd044213b 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -907,7 +907,8 @@ tcon_exit:
907tcon_error_exit: 907tcon_error_exit:
908 if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) { 908 if (rsp->hdr.Status == STATUS_BAD_NETWORK_NAME) {
909 cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree); 909 cifs_dbg(VFS, "BAD_NETWORK_NAME: %s\n", tree);
910 tcon->bad_network_name = true; 910 if (tcon)
911 tcon->bad_network_name = true;
911 } 912 }
912 goto tcon_exit; 913 goto tcon_exit;
913} 914}
@@ -1224,7 +1225,9 @@ SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid,
1224 1225
1225 cifs_dbg(FYI, "SMB2 IOCTL\n"); 1226 cifs_dbg(FYI, "SMB2 IOCTL\n");
1226 1227
1227 *out_data = NULL; 1228 if (out_data != NULL)
1229 *out_data = NULL;
1230
1228 /* zero out returned data len, in case of error */ 1231 /* zero out returned data len, in case of error */
1229 if (plen) 1232 if (plen)
1230 *plen = 0; 1233 *plen = 0;
@@ -2177,6 +2180,10 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
2177 rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base; 2180 rsp = (struct smb2_query_directory_rsp *)iov[0].iov_base;
2178 2181
2179 if (rc) { 2182 if (rc) {
2183 if (rc == -ENODATA && rsp->hdr.Status == STATUS_NO_MORE_FILES) {
2184 srch_inf->endOfSearch = true;
2185 rc = 0;
2186 }
2180 cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); 2187 cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE);
2181 goto qdir_exit; 2188 goto qdir_exit;
2182 } 2189 }
@@ -2214,11 +2221,6 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon,
2214 else 2221 else
2215 cifs_dbg(VFS, "illegal search buffer type\n"); 2222 cifs_dbg(VFS, "illegal search buffer type\n");
2216 2223
2217 if (rsp->hdr.Status == STATUS_NO_MORE_FILES)
2218 srch_inf->endOfSearch = 1;
2219 else
2220 srch_inf->endOfSearch = 0;
2221
2222 return rc; 2224 return rc;
2223 2225
2224qdir_exit: 2226qdir_exit:
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index 69f3595d3952..fbe486c285a9 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -573,6 +573,12 @@ struct copychunk_ioctl {
573 __u32 Reserved2; 573 __u32 Reserved2;
574} __packed; 574} __packed;
575 575
576/* this goes in the ioctl buffer when doing FSCTL_SET_ZERO_DATA */
577struct file_zero_data_information {
578 __le64 FileOffset;
579 __le64 BeyondFinalZero;
580} __packed;
581
576struct copychunk_ioctl_rsp { 582struct copychunk_ioctl_rsp {
577 __le32 ChunksWritten; 583 __le32 ChunksWritten;
578 __le32 ChunkBytesWritten; 584 __le32 ChunkBytesWritten;
diff --git a/fs/cifs/smbfsctl.h b/fs/cifs/smbfsctl.h
index 0e538b5c9622..83efa59535be 100644
--- a/fs/cifs/smbfsctl.h
+++ b/fs/cifs/smbfsctl.h
@@ -63,7 +63,7 @@
63#define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */ 63#define FSCTL_SET_OBJECT_ID_EXTENDED 0x000900BC /* BB add struct */
64#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */ 64#define FSCTL_CREATE_OR_GET_OBJECT_ID 0x000900C0 /* BB add struct */
65#define FSCTL_SET_SPARSE 0x000900C4 /* BB add struct */ 65#define FSCTL_SET_SPARSE 0x000900C4 /* BB add struct */
66#define FSCTL_SET_ZERO_DATA 0x000900C8 /* BB add struct */ 66#define FSCTL_SET_ZERO_DATA 0x000980C8
67#define FSCTL_SET_ENCRYPTION 0x000900D7 /* BB add struct */ 67#define FSCTL_SET_ENCRYPTION 0x000900D7 /* BB add struct */
68#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB /* BB add struct */ 68#define FSCTL_ENCRYPTION_FSCTL_IO 0x000900DB /* BB add struct */
69#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF /* BB add struct */ 69#define FSCTL_WRITE_RAW_ENCRYPTED 0x000900DF /* BB add struct */