diff options
-rw-r--r-- | fs/cifs/cifsfs.c | 24 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 23 | ||||
-rw-r--r-- | fs/cifs/file.c | 2 | ||||
-rw-r--r-- | fs/cifs/inode.c | 6 | ||||
-rw-r--r-- | fs/cifs/misc.c | 7 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 2 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 7 | ||||
-rw-r--r-- | fs/cifs/smb2maperror.c | 4 | ||||
-rw-r--r-- | fs/cifs/smb2misc.c | 17 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 170 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 16 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 6 | ||||
-rw-r--r-- | fs/cifs/smbfsctl.h | 2 |
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 | ||
210 | static 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 | |||
210 | static int cifs_permission(struct inode *inode, int mask) | 223 | static 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 | ||
913 | const struct file_operations cifs_file_strict_ops = { | 928 | const 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 | ||
932 | const struct file_operations cifs_file_direct_ops = { | 948 | const 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 | ||
952 | const struct file_operations cifs_file_nobrl_ops = { | 969 | const 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 | ||
970 | const struct file_operations cifs_file_strict_nobrl_ops = { | 988 | const 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 | ||
988 | const struct file_operations cifs_file_direct_nobrl_ops = { | 1007 | const 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 | ||
1007 | const struct file_operations cifs_dir_ops = { | 1027 | const 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 | ||
414 | struct smb_version_values { | 418 | struct 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 | ||
2256 | typedef struct { | 2279 | typedef 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 | |||
1730 | cifs_rename_exit: | 1736 | cifs_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 | ||
577 | static int | ||
578 | cifs_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 | ||
1018 | static bool | ||
1019 | cifs_dir_needs_close(struct cifsFileInfo *cfile) | ||
1020 | { | ||
1021 | return !cfile->srch_inf.endOfSearch && !cfile->invalidHandle; | ||
1022 | } | ||
1023 | |||
1018 | struct smb_version_operations smb1_operations = { | 1024 | struct 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 */ | ||
735 | static 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 | |||
734 | static int | 780 | static int |
735 | smb2_set_file_size(const unsigned int xid, struct cifs_tcon *tcon, | 781 | smb2_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 | ||
1018 | static 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 | |||
1068 | static 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 | |||
1102 | static 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 | |||
957 | static void | 1117 | static void |
958 | smb2_downgrade_oplock(struct TCP_Server_Info *server, | 1118 | smb2_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 | ||
1324 | static bool | ||
1325 | smb2_dir_needs_close(struct cifsFileInfo *cfile) | ||
1326 | { | ||
1327 | return !cfile->invalidHandle; | ||
1328 | } | ||
1329 | |||
1164 | struct smb_version_operations smb20_operations = { | 1330 | struct 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 | ||
1241 | struct smb_version_operations smb21_operations = { | 1408 | struct 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 | ||
1318 | struct smb_version_operations smb30_operations = { | 1486 | struct 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 | ||
1398 | struct smb_version_values smb20_values = { | 1568 | struct 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: | |||
907 | tcon_error_exit: | 907 | tcon_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 | ||
2224 | qdir_exit: | 2226 | qdir_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 */ | ||
577 | struct file_zero_data_information { | ||
578 | __le64 FileOffset; | ||
579 | __le64 BeyondFinalZero; | ||
580 | } __packed; | ||
581 | |||
576 | struct copychunk_ioctl_rsp { | 582 | struct 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 */ |