diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-04-09 12:10:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-04-09 12:10:02 -0400 |
commit | 84ced7fd06dac98aa630dcfd5f008e3f3c323737 (patch) | |
tree | fed61af0037cdc8065f40e58d23158b6a187d236 | |
parent | 462e9a355e7488fde3712c3b2585fc2f2a2c263d (diff) | |
parent | 806a28efe9b78ffae5e2757e1ee924b8e50c08ab (diff) |
Merge branch 'for-next' of git://git.samba.org/sfrench/cifs-2.6
Pull CIFS fixes from Steve French:
"This is a set of CIFS/SMB3 fixes for stable.
There is another set of four SMB3 reconnect fixes for stable in
progress but they are still being reviewed/tested, so didn't want to
wait any longer to send these five below"
* 'for-next' of git://git.samba.org/sfrench/cifs-2.6:
Reset TreeId to zero on SMB2 TREE_CONNECT
CIFS: Fix build failure with smb2
Introduce cifs_copy_file_range()
SMB3: Rename clone_range to copychunk_range
Handle mismatched open calls
-rw-r--r-- | fs/cifs/cifsfs.c | 87 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 18 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 3 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 11 | ||||
-rw-r--r-- | fs/cifs/connect.c | 13 | ||||
-rw-r--r-- | fs/cifs/ioctl.c | 66 | ||||
-rw-r--r-- | fs/cifs/smb2misc.c | 46 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 41 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 4 | ||||
-rw-r--r-- | fs/cifs/smb2proto.h | 7 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 55 | ||||
-rw-r--r-- | fs/cifs/transport.c | 2 |
13 files changed, 268 insertions, 90 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 15e1db8738ae..dd3f5fabfdf6 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -972,6 +972,86 @@ out: | |||
972 | return rc; | 972 | return rc; |
973 | } | 973 | } |
974 | 974 | ||
975 | ssize_t cifs_file_copychunk_range(unsigned int xid, | ||
976 | struct file *src_file, loff_t off, | ||
977 | struct file *dst_file, loff_t destoff, | ||
978 | size_t len, unsigned int flags) | ||
979 | { | ||
980 | struct inode *src_inode = file_inode(src_file); | ||
981 | struct inode *target_inode = file_inode(dst_file); | ||
982 | struct cifsFileInfo *smb_file_src; | ||
983 | struct cifsFileInfo *smb_file_target; | ||
984 | struct cifs_tcon *src_tcon; | ||
985 | struct cifs_tcon *target_tcon; | ||
986 | ssize_t rc; | ||
987 | |||
988 | cifs_dbg(FYI, "copychunk range\n"); | ||
989 | |||
990 | if (src_inode == target_inode) { | ||
991 | rc = -EINVAL; | ||
992 | goto out; | ||
993 | } | ||
994 | |||
995 | if (!src_file->private_data || !dst_file->private_data) { | ||
996 | rc = -EBADF; | ||
997 | cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); | ||
998 | goto out; | ||
999 | } | ||
1000 | |||
1001 | rc = -EXDEV; | ||
1002 | smb_file_target = dst_file->private_data; | ||
1003 | smb_file_src = src_file->private_data; | ||
1004 | src_tcon = tlink_tcon(smb_file_src->tlink); | ||
1005 | target_tcon = tlink_tcon(smb_file_target->tlink); | ||
1006 | |||
1007 | if (src_tcon->ses != target_tcon->ses) { | ||
1008 | cifs_dbg(VFS, "source and target of copy not on same server\n"); | ||
1009 | goto out; | ||
1010 | } | ||
1011 | |||
1012 | /* | ||
1013 | * Note: cifs case is easier than btrfs since server responsible for | ||
1014 | * checks for proper open modes and file type and if it wants | ||
1015 | * server could even support copy of range where source = target | ||
1016 | */ | ||
1017 | lock_two_nondirectories(target_inode, src_inode); | ||
1018 | |||
1019 | cifs_dbg(FYI, "about to flush pages\n"); | ||
1020 | /* should we flush first and last page first */ | ||
1021 | truncate_inode_pages(&target_inode->i_data, 0); | ||
1022 | |||
1023 | if (target_tcon->ses->server->ops->copychunk_range) | ||
1024 | rc = target_tcon->ses->server->ops->copychunk_range(xid, | ||
1025 | smb_file_src, smb_file_target, off, len, destoff); | ||
1026 | else | ||
1027 | rc = -EOPNOTSUPP; | ||
1028 | |||
1029 | /* force revalidate of size and timestamps of target file now | ||
1030 | * that target is updated on the server | ||
1031 | */ | ||
1032 | CIFS_I(target_inode)->time = 0; | ||
1033 | /* although unlocking in the reverse order from locking is not | ||
1034 | * strictly necessary here it is a little cleaner to be consistent | ||
1035 | */ | ||
1036 | unlock_two_nondirectories(src_inode, target_inode); | ||
1037 | |||
1038 | out: | ||
1039 | return rc; | ||
1040 | } | ||
1041 | |||
1042 | static ssize_t cifs_copy_file_range(struct file *src_file, loff_t off, | ||
1043 | struct file *dst_file, loff_t destoff, | ||
1044 | size_t len, unsigned int flags) | ||
1045 | { | ||
1046 | unsigned int xid = get_xid(); | ||
1047 | ssize_t rc; | ||
1048 | |||
1049 | rc = cifs_file_copychunk_range(xid, src_file, off, dst_file, destoff, | ||
1050 | len, flags); | ||
1051 | free_xid(xid); | ||
1052 | return rc; | ||
1053 | } | ||
1054 | |||
975 | const struct file_operations cifs_file_ops = { | 1055 | const struct file_operations cifs_file_ops = { |
976 | .read_iter = cifs_loose_read_iter, | 1056 | .read_iter = cifs_loose_read_iter, |
977 | .write_iter = cifs_file_write_iter, | 1057 | .write_iter = cifs_file_write_iter, |
@@ -984,6 +1064,7 @@ const struct file_operations cifs_file_ops = { | |||
984 | .splice_read = generic_file_splice_read, | 1064 | .splice_read = generic_file_splice_read, |
985 | .llseek = cifs_llseek, | 1065 | .llseek = cifs_llseek, |
986 | .unlocked_ioctl = cifs_ioctl, | 1066 | .unlocked_ioctl = cifs_ioctl, |
1067 | .copy_file_range = cifs_copy_file_range, | ||
987 | .clone_file_range = cifs_clone_file_range, | 1068 | .clone_file_range = cifs_clone_file_range, |
988 | .setlease = cifs_setlease, | 1069 | .setlease = cifs_setlease, |
989 | .fallocate = cifs_fallocate, | 1070 | .fallocate = cifs_fallocate, |
@@ -1001,6 +1082,7 @@ const struct file_operations cifs_file_strict_ops = { | |||
1001 | .splice_read = generic_file_splice_read, | 1082 | .splice_read = generic_file_splice_read, |
1002 | .llseek = cifs_llseek, | 1083 | .llseek = cifs_llseek, |
1003 | .unlocked_ioctl = cifs_ioctl, | 1084 | .unlocked_ioctl = cifs_ioctl, |
1085 | .copy_file_range = cifs_copy_file_range, | ||
1004 | .clone_file_range = cifs_clone_file_range, | 1086 | .clone_file_range = cifs_clone_file_range, |
1005 | .setlease = cifs_setlease, | 1087 | .setlease = cifs_setlease, |
1006 | .fallocate = cifs_fallocate, | 1088 | .fallocate = cifs_fallocate, |
@@ -1018,6 +1100,7 @@ const struct file_operations cifs_file_direct_ops = { | |||
1018 | .mmap = cifs_file_mmap, | 1100 | .mmap = cifs_file_mmap, |
1019 | .splice_read = generic_file_splice_read, | 1101 | .splice_read = generic_file_splice_read, |
1020 | .unlocked_ioctl = cifs_ioctl, | 1102 | .unlocked_ioctl = cifs_ioctl, |
1103 | .copy_file_range = cifs_copy_file_range, | ||
1021 | .clone_file_range = cifs_clone_file_range, | 1104 | .clone_file_range = cifs_clone_file_range, |
1022 | .llseek = cifs_llseek, | 1105 | .llseek = cifs_llseek, |
1023 | .setlease = cifs_setlease, | 1106 | .setlease = cifs_setlease, |
@@ -1035,6 +1118,7 @@ const struct file_operations cifs_file_nobrl_ops = { | |||
1035 | .splice_read = generic_file_splice_read, | 1118 | .splice_read = generic_file_splice_read, |
1036 | .llseek = cifs_llseek, | 1119 | .llseek = cifs_llseek, |
1037 | .unlocked_ioctl = cifs_ioctl, | 1120 | .unlocked_ioctl = cifs_ioctl, |
1121 | .copy_file_range = cifs_copy_file_range, | ||
1038 | .clone_file_range = cifs_clone_file_range, | 1122 | .clone_file_range = cifs_clone_file_range, |
1039 | .setlease = cifs_setlease, | 1123 | .setlease = cifs_setlease, |
1040 | .fallocate = cifs_fallocate, | 1124 | .fallocate = cifs_fallocate, |
@@ -1051,6 +1135,7 @@ const struct file_operations cifs_file_strict_nobrl_ops = { | |||
1051 | .splice_read = generic_file_splice_read, | 1135 | .splice_read = generic_file_splice_read, |
1052 | .llseek = cifs_llseek, | 1136 | .llseek = cifs_llseek, |
1053 | .unlocked_ioctl = cifs_ioctl, | 1137 | .unlocked_ioctl = cifs_ioctl, |
1138 | .copy_file_range = cifs_copy_file_range, | ||
1054 | .clone_file_range = cifs_clone_file_range, | 1139 | .clone_file_range = cifs_clone_file_range, |
1055 | .setlease = cifs_setlease, | 1140 | .setlease = cifs_setlease, |
1056 | .fallocate = cifs_fallocate, | 1141 | .fallocate = cifs_fallocate, |
@@ -1067,6 +1152,7 @@ const struct file_operations cifs_file_direct_nobrl_ops = { | |||
1067 | .mmap = cifs_file_mmap, | 1152 | .mmap = cifs_file_mmap, |
1068 | .splice_read = generic_file_splice_read, | 1153 | .splice_read = generic_file_splice_read, |
1069 | .unlocked_ioctl = cifs_ioctl, | 1154 | .unlocked_ioctl = cifs_ioctl, |
1155 | .copy_file_range = cifs_copy_file_range, | ||
1070 | .clone_file_range = cifs_clone_file_range, | 1156 | .clone_file_range = cifs_clone_file_range, |
1071 | .llseek = cifs_llseek, | 1157 | .llseek = cifs_llseek, |
1072 | .setlease = cifs_setlease, | 1158 | .setlease = cifs_setlease, |
@@ -1078,6 +1164,7 @@ const struct file_operations cifs_dir_ops = { | |||
1078 | .release = cifs_closedir, | 1164 | .release = cifs_closedir, |
1079 | .read = generic_read_dir, | 1165 | .read = generic_read_dir, |
1080 | .unlocked_ioctl = cifs_ioctl, | 1166 | .unlocked_ioctl = cifs_ioctl, |
1167 | .copy_file_range = cifs_copy_file_range, | ||
1081 | .clone_file_range = cifs_clone_file_range, | 1168 | .clone_file_range = cifs_clone_file_range, |
1082 | .llseek = generic_file_llseek, | 1169 | .llseek = generic_file_llseek, |
1083 | }; | 1170 | }; |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index da717fee3026..30bf89b1fd9a 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -139,6 +139,11 @@ extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | |||
139 | # define cifs_listxattr NULL | 139 | # define cifs_listxattr NULL |
140 | #endif | 140 | #endif |
141 | 141 | ||
142 | extern ssize_t cifs_file_copychunk_range(unsigned int xid, | ||
143 | struct file *src_file, loff_t off, | ||
144 | struct file *dst_file, loff_t destoff, | ||
145 | size_t len, unsigned int flags); | ||
146 | |||
142 | extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | 147 | extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); |
143 | #ifdef CONFIG_CIFS_NFSD_EXPORT | 148 | #ifdef CONFIG_CIFS_NFSD_EXPORT |
144 | extern const struct export_operations cifs_export_ops; | 149 | extern const struct export_operations cifs_export_ops; |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index d42dd3288647..d07f13a63369 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -243,6 +243,7 @@ struct smb_version_operations { | |||
243 | /* verify the message */ | 243 | /* verify the message */ |
244 | int (*check_message)(char *, unsigned int, struct TCP_Server_Info *); | 244 | int (*check_message)(char *, unsigned int, struct TCP_Server_Info *); |
245 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); | 245 | bool (*is_oplock_break)(char *, struct TCP_Server_Info *); |
246 | int (*handle_cancelled_mid)(char *, struct TCP_Server_Info *); | ||
246 | void (*downgrade_oplock)(struct TCP_Server_Info *, | 247 | void (*downgrade_oplock)(struct TCP_Server_Info *, |
247 | struct cifsInodeInfo *, bool); | 248 | struct cifsInodeInfo *, bool); |
248 | /* process transaction2 response */ | 249 | /* process transaction2 response */ |
@@ -407,9 +408,10 @@ struct smb_version_operations { | |||
407 | char * (*create_lease_buf)(u8 *, u8); | 408 | char * (*create_lease_buf)(u8 *, u8); |
408 | /* parse lease context buffer and return oplock/epoch info */ | 409 | /* parse lease context buffer and return oplock/epoch info */ |
409 | __u8 (*parse_lease_buf)(void *, unsigned int *); | 410 | __u8 (*parse_lease_buf)(void *, unsigned int *); |
410 | int (*clone_range)(const unsigned int, struct cifsFileInfo *src_file, | 411 | ssize_t (*copychunk_range)(const unsigned int, |
411 | struct cifsFileInfo *target_file, u64 src_off, u64 len, | 412 | struct cifsFileInfo *src_file, |
412 | u64 dest_off); | 413 | struct cifsFileInfo *target_file, |
414 | u64 src_off, u64 len, u64 dest_off); | ||
413 | int (*duplicate_extents)(const unsigned int, struct cifsFileInfo *src, | 415 | int (*duplicate_extents)(const unsigned int, struct cifsFileInfo *src, |
414 | struct cifsFileInfo *target_file, u64 src_off, u64 len, | 416 | struct cifsFileInfo *target_file, u64 src_off, u64 len, |
415 | u64 dest_off); | 417 | u64 dest_off); |
@@ -1343,6 +1345,7 @@ struct mid_q_entry { | |||
1343 | void *callback_data; /* general purpose pointer for callback */ | 1345 | void *callback_data; /* general purpose pointer for callback */ |
1344 | void *resp_buf; /* pointer to received SMB header */ | 1346 | void *resp_buf; /* pointer to received SMB header */ |
1345 | int mid_state; /* wish this were enum but can not pass to wait_event */ | 1347 | int mid_state; /* wish this were enum but can not pass to wait_event */ |
1348 | unsigned int mid_flags; | ||
1346 | __le16 command; /* smb command code */ | 1349 | __le16 command; /* smb command code */ |
1347 | bool large_buf:1; /* if valid response, is pointer to large buf */ | 1350 | bool large_buf:1; /* if valid response, is pointer to large buf */ |
1348 | bool multiRsp:1; /* multiple trans2 responses for one request */ | 1351 | bool multiRsp:1; /* multiple trans2 responses for one request */ |
@@ -1350,6 +1353,12 @@ struct mid_q_entry { | |||
1350 | bool decrypted:1; /* decrypted entry */ | 1353 | bool decrypted:1; /* decrypted entry */ |
1351 | }; | 1354 | }; |
1352 | 1355 | ||
1356 | struct close_cancelled_open { | ||
1357 | struct cifs_fid fid; | ||
1358 | struct cifs_tcon *tcon; | ||
1359 | struct work_struct work; | ||
1360 | }; | ||
1361 | |||
1353 | /* Make code in transport.c a little cleaner by moving | 1362 | /* Make code in transport.c a little cleaner by moving |
1354 | update of optional stats into function below */ | 1363 | update of optional stats into function below */ |
1355 | #ifdef CONFIG_CIFS_STATS2 | 1364 | #ifdef CONFIG_CIFS_STATS2 |
@@ -1481,6 +1490,9 @@ static inline void free_dfs_info_array(struct dfs_info3_param *param, | |||
1481 | #define MID_RESPONSE_MALFORMED 0x10 | 1490 | #define MID_RESPONSE_MALFORMED 0x10 |
1482 | #define MID_SHUTDOWN 0x20 | 1491 | #define MID_SHUTDOWN 0x20 |
1483 | 1492 | ||
1493 | /* Flags */ | ||
1494 | #define MID_WAIT_CANCELLED 1 /* Cancelled while waiting for response */ | ||
1495 | |||
1484 | /* Types of response buffer returned from SendReceive2 */ | 1496 | /* Types of response buffer returned from SendReceive2 */ |
1485 | #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ | 1497 | #define CIFS_NO_BUFFER 0 /* Response buffer not returned */ |
1486 | #define CIFS_SMALL_BUFFER 1 | 1498 | #define CIFS_SMALL_BUFFER 1 |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 97e5d236d265..ec5e5e514fdd 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -79,7 +79,8 @@ extern void cifs_delete_mid(struct mid_q_entry *mid); | |||
79 | extern void cifs_wake_up_task(struct mid_q_entry *mid); | 79 | extern void cifs_wake_up_task(struct mid_q_entry *mid); |
80 | extern int cifs_handle_standard(struct TCP_Server_Info *server, | 80 | extern int cifs_handle_standard(struct TCP_Server_Info *server, |
81 | struct mid_q_entry *mid); | 81 | struct mid_q_entry *mid); |
82 | extern int cifs_discard_remaining_data(struct TCP_Server_Info *server); | 82 | extern int cifs_discard_remaining_data(struct TCP_Server_Info *server, |
83 | char *buf); | ||
83 | extern int cifs_call_async(struct TCP_Server_Info *server, | 84 | extern int cifs_call_async(struct TCP_Server_Info *server, |
84 | struct smb_rqst *rqst, | 85 | struct smb_rqst *rqst, |
85 | mid_receive_t *receive, mid_callback_t *callback, | 86 | mid_receive_t *receive, mid_callback_t *callback, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 066950671929..967b92631807 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -1400,9 +1400,9 @@ openRetry: | |||
1400 | * current bigbuf. | 1400 | * current bigbuf. |
1401 | */ | 1401 | */ |
1402 | int | 1402 | int |
1403 | cifs_discard_remaining_data(struct TCP_Server_Info *server) | 1403 | cifs_discard_remaining_data(struct TCP_Server_Info *server, char *buf) |
1404 | { | 1404 | { |
1405 | unsigned int rfclen = get_rfc1002_length(server->smallbuf); | 1405 | unsigned int rfclen = get_rfc1002_length(buf); |
1406 | int remaining = rfclen + 4 - server->total_read; | 1406 | int remaining = rfclen + 4 - server->total_read; |
1407 | 1407 | ||
1408 | while (remaining > 0) { | 1408 | while (remaining > 0) { |
@@ -1426,7 +1426,7 @@ cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1426 | int length; | 1426 | int length; |
1427 | struct cifs_readdata *rdata = mid->callback_data; | 1427 | struct cifs_readdata *rdata = mid->callback_data; |
1428 | 1428 | ||
1429 | length = cifs_discard_remaining_data(server); | 1429 | length = cifs_discard_remaining_data(server, mid->resp_buf); |
1430 | dequeue_mid(mid, rdata->result); | 1430 | dequeue_mid(mid, rdata->result); |
1431 | return length; | 1431 | return length; |
1432 | } | 1432 | } |
@@ -1459,7 +1459,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1459 | 1459 | ||
1460 | if (server->ops->is_status_pending && | 1460 | if (server->ops->is_status_pending && |
1461 | server->ops->is_status_pending(buf, server, 0)) { | 1461 | server->ops->is_status_pending(buf, server, 0)) { |
1462 | cifs_discard_remaining_data(server); | 1462 | cifs_discard_remaining_data(server, buf); |
1463 | return -1; | 1463 | return -1; |
1464 | } | 1464 | } |
1465 | 1465 | ||
@@ -1519,6 +1519,9 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1519 | cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n", | 1519 | cifs_dbg(FYI, "0: iov_base=%p iov_len=%u\n", |
1520 | rdata->iov[0].iov_base, server->total_read); | 1520 | rdata->iov[0].iov_base, server->total_read); |
1521 | 1521 | ||
1522 | mid->resp_buf = server->smallbuf; | ||
1523 | server->smallbuf = NULL; | ||
1524 | |||
1522 | /* how much data is in the response? */ | 1525 | /* how much data is in the response? */ |
1523 | data_len = server->ops->read_data_length(buf); | 1526 | data_len = server->ops->read_data_length(buf); |
1524 | if (data_offset + data_len > buflen) { | 1527 | if (data_offset + data_len > buflen) { |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 9ae695ae3ed7..0c7596cef4b8 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -904,10 +904,19 @@ cifs_demultiplex_thread(void *p) | |||
904 | 904 | ||
905 | server->lstrp = jiffies; | 905 | server->lstrp = jiffies; |
906 | if (mid_entry != NULL) { | 906 | if (mid_entry != NULL) { |
907 | if ((mid_entry->mid_flags & MID_WAIT_CANCELLED) && | ||
908 | mid_entry->mid_state == MID_RESPONSE_RECEIVED && | ||
909 | server->ops->handle_cancelled_mid) | ||
910 | server->ops->handle_cancelled_mid( | ||
911 | mid_entry->resp_buf, | ||
912 | server); | ||
913 | |||
907 | if (!mid_entry->multiRsp || mid_entry->multiEnd) | 914 | if (!mid_entry->multiRsp || mid_entry->multiEnd) |
908 | mid_entry->callback(mid_entry); | 915 | mid_entry->callback(mid_entry); |
909 | } else if (!server->ops->is_oplock_break || | 916 | } else if (server->ops->is_oplock_break && |
910 | !server->ops->is_oplock_break(buf, server)) { | 917 | server->ops->is_oplock_break(buf, server)) { |
918 | cifs_dbg(FYI, "Received oplock break\n"); | ||
919 | } else { | ||
911 | cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", | 920 | cifs_dbg(VFS, "No task to wake, unknown frame received! NumMids %d\n", |
912 | atomic_read(&midCount)); | 921 | atomic_read(&midCount)); |
913 | cifs_dump_mem("Received Data is: ", buf, | 922 | cifs_dump_mem("Received Data is: ", buf, |
diff --git a/fs/cifs/ioctl.c b/fs/cifs/ioctl.c index 001528781b6b..265c45fe4ea5 100644 --- a/fs/cifs/ioctl.c +++ b/fs/cifs/ioctl.c | |||
@@ -34,71 +34,14 @@ | |||
34 | #include "cifs_ioctl.h" | 34 | #include "cifs_ioctl.h" |
35 | #include <linux/btrfs.h> | 35 | #include <linux/btrfs.h> |
36 | 36 | ||
37 | static int cifs_file_clone_range(unsigned int xid, struct file *src_file, | 37 | static long cifs_ioctl_copychunk(unsigned int xid, struct file *dst_file, |
38 | struct file *dst_file) | ||
39 | { | ||
40 | struct inode *src_inode = file_inode(src_file); | ||
41 | struct inode *target_inode = file_inode(dst_file); | ||
42 | struct cifsFileInfo *smb_file_src; | ||
43 | struct cifsFileInfo *smb_file_target; | ||
44 | struct cifs_tcon *src_tcon; | ||
45 | struct cifs_tcon *target_tcon; | ||
46 | int rc; | ||
47 | |||
48 | cifs_dbg(FYI, "ioctl clone range\n"); | ||
49 | |||
50 | if (!src_file->private_data || !dst_file->private_data) { | ||
51 | rc = -EBADF; | ||
52 | cifs_dbg(VFS, "missing cifsFileInfo on copy range src file\n"); | ||
53 | goto out; | ||
54 | } | ||
55 | |||
56 | rc = -EXDEV; | ||
57 | smb_file_target = dst_file->private_data; | ||
58 | smb_file_src = src_file->private_data; | ||
59 | src_tcon = tlink_tcon(smb_file_src->tlink); | ||
60 | target_tcon = tlink_tcon(smb_file_target->tlink); | ||
61 | |||
62 | if (src_tcon->ses != target_tcon->ses) { | ||
63 | cifs_dbg(VFS, "source and target of copy not on same server\n"); | ||
64 | goto out; | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * Note: cifs case is easier than btrfs since server responsible for | ||
69 | * checks for proper open modes and file type and if it wants | ||
70 | * server could even support copy of range where source = target | ||
71 | */ | ||
72 | lock_two_nondirectories(target_inode, src_inode); | ||
73 | |||
74 | cifs_dbg(FYI, "about to flush pages\n"); | ||
75 | /* should we flush first and last page first */ | ||
76 | truncate_inode_pages(&target_inode->i_data, 0); | ||
77 | |||
78 | if (target_tcon->ses->server->ops->clone_range) | ||
79 | rc = target_tcon->ses->server->ops->clone_range(xid, | ||
80 | smb_file_src, smb_file_target, 0, src_inode->i_size, 0); | ||
81 | else | ||
82 | rc = -EOPNOTSUPP; | ||
83 | |||
84 | /* force revalidate of size and timestamps of target file now | ||
85 | that target is updated on the server */ | ||
86 | CIFS_I(target_inode)->time = 0; | ||
87 | /* although unlocking in the reverse order from locking is not | ||
88 | strictly necessary here it is a little cleaner to be consistent */ | ||
89 | unlock_two_nondirectories(src_inode, target_inode); | ||
90 | out: | ||
91 | return rc; | ||
92 | } | ||
93 | |||
94 | static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, | ||
95 | unsigned long srcfd) | 38 | unsigned long srcfd) |
96 | { | 39 | { |
97 | int rc; | 40 | int rc; |
98 | struct fd src_file; | 41 | struct fd src_file; |
99 | struct inode *src_inode; | 42 | struct inode *src_inode; |
100 | 43 | ||
101 | cifs_dbg(FYI, "ioctl clone range\n"); | 44 | cifs_dbg(FYI, "ioctl copychunk range\n"); |
102 | /* the destination must be opened for writing */ | 45 | /* the destination must be opened for writing */ |
103 | if (!(dst_file->f_mode & FMODE_WRITE)) { | 46 | if (!(dst_file->f_mode & FMODE_WRITE)) { |
104 | cifs_dbg(FYI, "file target not open for write\n"); | 47 | cifs_dbg(FYI, "file target not open for write\n"); |
@@ -129,7 +72,8 @@ static long cifs_ioctl_clone(unsigned int xid, struct file *dst_file, | |||
129 | if (S_ISDIR(src_inode->i_mode)) | 72 | if (S_ISDIR(src_inode->i_mode)) |
130 | goto out_fput; | 73 | goto out_fput; |
131 | 74 | ||
132 | rc = cifs_file_clone_range(xid, src_file.file, dst_file); | 75 | rc = cifs_file_copychunk_range(xid, src_file.file, 0, dst_file, 0, |
76 | src_inode->i_size, 0); | ||
133 | 77 | ||
134 | out_fput: | 78 | out_fput: |
135 | fdput(src_file); | 79 | fdput(src_file); |
@@ -251,7 +195,7 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) | |||
251 | } | 195 | } |
252 | break; | 196 | break; |
253 | case CIFS_IOC_COPYCHUNK_FILE: | 197 | case CIFS_IOC_COPYCHUNK_FILE: |
254 | rc = cifs_ioctl_clone(xid, filep, arg); | 198 | rc = cifs_ioctl_copychunk(xid, filep, arg); |
255 | break; | 199 | break; |
256 | case CIFS_IOC_SET_INTEGRITY: | 200 | case CIFS_IOC_SET_INTEGRITY: |
257 | if (pSMBFile == NULL) | 201 | if (pSMBFile == NULL) |
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index fd516ea8b8f8..1a04b3a5beb1 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c | |||
@@ -659,3 +659,49 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) | |||
659 | cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n"); | 659 | cifs_dbg(FYI, "Can not process oplock break for non-existent connection\n"); |
660 | return false; | 660 | return false; |
661 | } | 661 | } |
662 | |||
663 | void | ||
664 | smb2_cancelled_close_fid(struct work_struct *work) | ||
665 | { | ||
666 | struct close_cancelled_open *cancelled = container_of(work, | ||
667 | struct close_cancelled_open, work); | ||
668 | |||
669 | cifs_dbg(VFS, "Close unmatched open\n"); | ||
670 | |||
671 | SMB2_close(0, cancelled->tcon, cancelled->fid.persistent_fid, | ||
672 | cancelled->fid.volatile_fid); | ||
673 | cifs_put_tcon(cancelled->tcon); | ||
674 | kfree(cancelled); | ||
675 | } | ||
676 | |||
677 | int | ||
678 | smb2_handle_cancelled_mid(char *buffer, struct TCP_Server_Info *server) | ||
679 | { | ||
680 | struct smb2_sync_hdr *sync_hdr = get_sync_hdr(buffer); | ||
681 | struct smb2_create_rsp *rsp = (struct smb2_create_rsp *)buffer; | ||
682 | struct cifs_tcon *tcon; | ||
683 | struct close_cancelled_open *cancelled; | ||
684 | |||
685 | if (sync_hdr->Command != SMB2_CREATE || | ||
686 | sync_hdr->Status != STATUS_SUCCESS) | ||
687 | return 0; | ||
688 | |||
689 | cancelled = kzalloc(sizeof(*cancelled), GFP_KERNEL); | ||
690 | if (!cancelled) | ||
691 | return -ENOMEM; | ||
692 | |||
693 | tcon = smb2_find_smb_tcon(server, sync_hdr->SessionId, | ||
694 | sync_hdr->TreeId); | ||
695 | if (!tcon) { | ||
696 | kfree(cancelled); | ||
697 | return -ENOENT; | ||
698 | } | ||
699 | |||
700 | cancelled->fid.persistent_fid = rsp->PersistentFileId; | ||
701 | cancelled->fid.volatile_fid = rsp->VolatileFileId; | ||
702 | cancelled->tcon = tcon; | ||
703 | INIT_WORK(&cancelled->work, smb2_cancelled_close_fid); | ||
704 | queue_work(cifsiod_wq, &cancelled->work); | ||
705 | |||
706 | return 0; | ||
707 | } | ||
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 0231108d9387..7b12a727947e 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/vfs.h> | 21 | #include <linux/vfs.h> |
22 | #include <linux/falloc.h> | 22 | #include <linux/falloc.h> |
23 | #include <linux/scatterlist.h> | 23 | #include <linux/scatterlist.h> |
24 | #include <linux/uuid.h> | ||
24 | #include <crypto/aead.h> | 25 | #include <crypto/aead.h> |
25 | #include "cifsglob.h" | 26 | #include "cifsglob.h" |
26 | #include "smb2pdu.h" | 27 | #include "smb2pdu.h" |
@@ -592,8 +593,8 @@ req_res_key_exit: | |||
592 | return rc; | 593 | return rc; |
593 | } | 594 | } |
594 | 595 | ||
595 | static int | 596 | static ssize_t |
596 | smb2_clone_range(const unsigned int xid, | 597 | smb2_copychunk_range(const unsigned int xid, |
597 | struct cifsFileInfo *srcfile, | 598 | struct cifsFileInfo *srcfile, |
598 | struct cifsFileInfo *trgtfile, u64 src_off, | 599 | struct cifsFileInfo *trgtfile, u64 src_off, |
599 | u64 len, u64 dest_off) | 600 | u64 len, u64 dest_off) |
@@ -605,13 +606,14 @@ smb2_clone_range(const unsigned int xid, | |||
605 | struct cifs_tcon *tcon; | 606 | struct cifs_tcon *tcon; |
606 | int chunks_copied = 0; | 607 | int chunks_copied = 0; |
607 | bool chunk_sizes_updated = false; | 608 | bool chunk_sizes_updated = false; |
609 | ssize_t bytes_written, total_bytes_written = 0; | ||
608 | 610 | ||
609 | pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL); | 611 | pcchunk = kmalloc(sizeof(struct copychunk_ioctl), GFP_KERNEL); |
610 | 612 | ||
611 | if (pcchunk == NULL) | 613 | if (pcchunk == NULL) |
612 | return -ENOMEM; | 614 | return -ENOMEM; |
613 | 615 | ||
614 | cifs_dbg(FYI, "in smb2_clone_range - about to call request res key\n"); | 616 | cifs_dbg(FYI, "in smb2_copychunk_range - about to call request res key\n"); |
615 | /* Request a key from the server to identify the source of the copy */ | 617 | /* Request a key from the server to identify the source of the copy */ |
616 | rc = SMB2_request_res_key(xid, tlink_tcon(srcfile->tlink), | 618 | rc = SMB2_request_res_key(xid, tlink_tcon(srcfile->tlink), |
617 | srcfile->fid.persistent_fid, | 619 | srcfile->fid.persistent_fid, |
@@ -669,14 +671,16 @@ smb2_clone_range(const unsigned int xid, | |||
669 | } | 671 | } |
670 | chunks_copied++; | 672 | chunks_copied++; |
671 | 673 | ||
672 | src_off += le32_to_cpu(retbuf->TotalBytesWritten); | 674 | bytes_written = le32_to_cpu(retbuf->TotalBytesWritten); |
673 | dest_off += le32_to_cpu(retbuf->TotalBytesWritten); | 675 | src_off += bytes_written; |
674 | len -= le32_to_cpu(retbuf->TotalBytesWritten); | 676 | dest_off += bytes_written; |
677 | len -= bytes_written; | ||
678 | total_bytes_written += bytes_written; | ||
675 | 679 | ||
676 | cifs_dbg(FYI, "Chunks %d PartialChunk %d Total %d\n", | 680 | cifs_dbg(FYI, "Chunks %d PartialChunk %d Total %zu\n", |
677 | le32_to_cpu(retbuf->ChunksWritten), | 681 | le32_to_cpu(retbuf->ChunksWritten), |
678 | le32_to_cpu(retbuf->ChunkBytesWritten), | 682 | le32_to_cpu(retbuf->ChunkBytesWritten), |
679 | le32_to_cpu(retbuf->TotalBytesWritten)); | 683 | bytes_written); |
680 | } else if (rc == -EINVAL) { | 684 | } else if (rc == -EINVAL) { |
681 | if (ret_data_len != sizeof(struct copychunk_ioctl_rsp)) | 685 | if (ret_data_len != sizeof(struct copychunk_ioctl_rsp)) |
682 | goto cchunk_out; | 686 | goto cchunk_out; |
@@ -713,7 +717,10 @@ smb2_clone_range(const unsigned int xid, | |||
713 | cchunk_out: | 717 | cchunk_out: |
714 | kfree(pcchunk); | 718 | kfree(pcchunk); |
715 | kfree(retbuf); | 719 | kfree(retbuf); |
716 | return rc; | 720 | if (rc) |
721 | return rc; | ||
722 | else | ||
723 | return total_bytes_written; | ||
717 | } | 724 | } |
718 | 725 | ||
719 | static int | 726 | static int |
@@ -2188,7 +2195,7 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid) | |||
2188 | if (rc) | 2195 | if (rc) |
2189 | goto free_pages; | 2196 | goto free_pages; |
2190 | 2197 | ||
2191 | rc = cifs_discard_remaining_data(server); | 2198 | rc = cifs_discard_remaining_data(server, buf); |
2192 | if (rc) | 2199 | if (rc) |
2193 | goto free_pages; | 2200 | goto free_pages; |
2194 | 2201 | ||
@@ -2214,7 +2221,7 @@ free_pages: | |||
2214 | kfree(pages); | 2221 | kfree(pages); |
2215 | return rc; | 2222 | return rc; |
2216 | discard_data: | 2223 | discard_data: |
2217 | cifs_discard_remaining_data(server); | 2224 | cifs_discard_remaining_data(server, buf); |
2218 | goto free_pages; | 2225 | goto free_pages; |
2219 | } | 2226 | } |
2220 | 2227 | ||
@@ -2322,6 +2329,7 @@ struct smb_version_operations smb20_operations = { | |||
2322 | .clear_stats = smb2_clear_stats, | 2329 | .clear_stats = smb2_clear_stats, |
2323 | .print_stats = smb2_print_stats, | 2330 | .print_stats = smb2_print_stats, |
2324 | .is_oplock_break = smb2_is_valid_oplock_break, | 2331 | .is_oplock_break = smb2_is_valid_oplock_break, |
2332 | .handle_cancelled_mid = smb2_handle_cancelled_mid, | ||
2325 | .downgrade_oplock = smb2_downgrade_oplock, | 2333 | .downgrade_oplock = smb2_downgrade_oplock, |
2326 | .need_neg = smb2_need_neg, | 2334 | .need_neg = smb2_need_neg, |
2327 | .negotiate = smb2_negotiate, | 2335 | .negotiate = smb2_negotiate, |
@@ -2377,7 +2385,7 @@ struct smb_version_operations smb20_operations = { | |||
2377 | .set_oplock_level = smb2_set_oplock_level, | 2385 | .set_oplock_level = smb2_set_oplock_level, |
2378 | .create_lease_buf = smb2_create_lease_buf, | 2386 | .create_lease_buf = smb2_create_lease_buf, |
2379 | .parse_lease_buf = smb2_parse_lease_buf, | 2387 | .parse_lease_buf = smb2_parse_lease_buf, |
2380 | .clone_range = smb2_clone_range, | 2388 | .copychunk_range = smb2_copychunk_range, |
2381 | .wp_retry_size = smb2_wp_retry_size, | 2389 | .wp_retry_size = smb2_wp_retry_size, |
2382 | .dir_needs_close = smb2_dir_needs_close, | 2390 | .dir_needs_close = smb2_dir_needs_close, |
2383 | .get_dfs_refer = smb2_get_dfs_refer, | 2391 | .get_dfs_refer = smb2_get_dfs_refer, |
@@ -2404,6 +2412,7 @@ struct smb_version_operations smb21_operations = { | |||
2404 | .clear_stats = smb2_clear_stats, | 2412 | .clear_stats = smb2_clear_stats, |
2405 | .print_stats = smb2_print_stats, | 2413 | .print_stats = smb2_print_stats, |
2406 | .is_oplock_break = smb2_is_valid_oplock_break, | 2414 | .is_oplock_break = smb2_is_valid_oplock_break, |
2415 | .handle_cancelled_mid = smb2_handle_cancelled_mid, | ||
2407 | .downgrade_oplock = smb2_downgrade_oplock, | 2416 | .downgrade_oplock = smb2_downgrade_oplock, |
2408 | .need_neg = smb2_need_neg, | 2417 | .need_neg = smb2_need_neg, |
2409 | .negotiate = smb2_negotiate, | 2418 | .negotiate = smb2_negotiate, |
@@ -2459,7 +2468,7 @@ struct smb_version_operations smb21_operations = { | |||
2459 | .set_oplock_level = smb21_set_oplock_level, | 2468 | .set_oplock_level = smb21_set_oplock_level, |
2460 | .create_lease_buf = smb2_create_lease_buf, | 2469 | .create_lease_buf = smb2_create_lease_buf, |
2461 | .parse_lease_buf = smb2_parse_lease_buf, | 2470 | .parse_lease_buf = smb2_parse_lease_buf, |
2462 | .clone_range = smb2_clone_range, | 2471 | .copychunk_range = smb2_copychunk_range, |
2463 | .wp_retry_size = smb2_wp_retry_size, | 2472 | .wp_retry_size = smb2_wp_retry_size, |
2464 | .dir_needs_close = smb2_dir_needs_close, | 2473 | .dir_needs_close = smb2_dir_needs_close, |
2465 | .enum_snapshots = smb3_enum_snapshots, | 2474 | .enum_snapshots = smb3_enum_snapshots, |
@@ -2488,6 +2497,7 @@ struct smb_version_operations smb30_operations = { | |||
2488 | .print_stats = smb2_print_stats, | 2497 | .print_stats = smb2_print_stats, |
2489 | .dump_share_caps = smb2_dump_share_caps, | 2498 | .dump_share_caps = smb2_dump_share_caps, |
2490 | .is_oplock_break = smb2_is_valid_oplock_break, | 2499 | .is_oplock_break = smb2_is_valid_oplock_break, |
2500 | .handle_cancelled_mid = smb2_handle_cancelled_mid, | ||
2491 | .downgrade_oplock = smb2_downgrade_oplock, | 2501 | .downgrade_oplock = smb2_downgrade_oplock, |
2492 | .need_neg = smb2_need_neg, | 2502 | .need_neg = smb2_need_neg, |
2493 | .negotiate = smb2_negotiate, | 2503 | .negotiate = smb2_negotiate, |
@@ -2545,7 +2555,7 @@ struct smb_version_operations smb30_operations = { | |||
2545 | .set_oplock_level = smb3_set_oplock_level, | 2555 | .set_oplock_level = smb3_set_oplock_level, |
2546 | .create_lease_buf = smb3_create_lease_buf, | 2556 | .create_lease_buf = smb3_create_lease_buf, |
2547 | .parse_lease_buf = smb3_parse_lease_buf, | 2557 | .parse_lease_buf = smb3_parse_lease_buf, |
2548 | .clone_range = smb2_clone_range, | 2558 | .copychunk_range = smb2_copychunk_range, |
2549 | .duplicate_extents = smb2_duplicate_extents, | 2559 | .duplicate_extents = smb2_duplicate_extents, |
2550 | .validate_negotiate = smb3_validate_negotiate, | 2560 | .validate_negotiate = smb3_validate_negotiate, |
2551 | .wp_retry_size = smb2_wp_retry_size, | 2561 | .wp_retry_size = smb2_wp_retry_size, |
@@ -2582,6 +2592,7 @@ struct smb_version_operations smb311_operations = { | |||
2582 | .print_stats = smb2_print_stats, | 2592 | .print_stats = smb2_print_stats, |
2583 | .dump_share_caps = smb2_dump_share_caps, | 2593 | .dump_share_caps = smb2_dump_share_caps, |
2584 | .is_oplock_break = smb2_is_valid_oplock_break, | 2594 | .is_oplock_break = smb2_is_valid_oplock_break, |
2595 | .handle_cancelled_mid = smb2_handle_cancelled_mid, | ||
2585 | .downgrade_oplock = smb2_downgrade_oplock, | 2596 | .downgrade_oplock = smb2_downgrade_oplock, |
2586 | .need_neg = smb2_need_neg, | 2597 | .need_neg = smb2_need_neg, |
2587 | .negotiate = smb2_negotiate, | 2598 | .negotiate = smb2_negotiate, |
@@ -2639,7 +2650,7 @@ struct smb_version_operations smb311_operations = { | |||
2639 | .set_oplock_level = smb3_set_oplock_level, | 2650 | .set_oplock_level = smb3_set_oplock_level, |
2640 | .create_lease_buf = smb3_create_lease_buf, | 2651 | .create_lease_buf = smb3_create_lease_buf, |
2641 | .parse_lease_buf = smb3_parse_lease_buf, | 2652 | .parse_lease_buf = smb3_parse_lease_buf, |
2642 | .clone_range = smb2_clone_range, | 2653 | .copychunk_range = smb2_copychunk_range, |
2643 | .duplicate_extents = smb2_duplicate_extents, | 2654 | .duplicate_extents = smb2_duplicate_extents, |
2644 | /* .validate_negotiate = smb3_validate_negotiate, */ /* not used in 3.11 */ | 2655 | /* .validate_negotiate = smb3_validate_negotiate, */ /* not used in 3.11 */ |
2645 | .wp_retry_size = smb2_wp_retry_size, | 2656 | .wp_retry_size = smb2_wp_retry_size, |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 7446496850a3..66fa1b941cdf 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -1185,6 +1185,10 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, | |||
1185 | return -EINVAL; | 1185 | return -EINVAL; |
1186 | } | 1186 | } |
1187 | 1187 | ||
1188 | /* SMB2 TREE_CONNECT request must be called with TreeId == 0 */ | ||
1189 | if (tcon) | ||
1190 | tcon->tid = 0; | ||
1191 | |||
1188 | rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req); | 1192 | rc = small_smb2_init(SMB2_TREE_CONNECT, tcon, (void **) &req); |
1189 | if (rc) { | 1193 | if (rc) { |
1190 | kfree(unc_path); | 1194 | kfree(unc_path); |
diff --git a/fs/cifs/smb2proto.h b/fs/cifs/smb2proto.h index 69e35873b1de..6853454fc871 100644 --- a/fs/cifs/smb2proto.h +++ b/fs/cifs/smb2proto.h | |||
@@ -48,6 +48,10 @@ extern struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses, | |||
48 | struct smb_rqst *rqst); | 48 | struct smb_rqst *rqst); |
49 | extern struct mid_q_entry *smb2_setup_async_request( | 49 | extern struct mid_q_entry *smb2_setup_async_request( |
50 | struct TCP_Server_Info *server, struct smb_rqst *rqst); | 50 | struct TCP_Server_Info *server, struct smb_rqst *rqst); |
51 | extern struct cifs_ses *smb2_find_smb_ses(struct TCP_Server_Info *server, | ||
52 | __u64 ses_id); | ||
53 | extern struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, | ||
54 | __u64 ses_id, __u32 tid); | ||
51 | extern int smb2_calc_signature(struct smb_rqst *rqst, | 55 | extern int smb2_calc_signature(struct smb_rqst *rqst, |
52 | struct TCP_Server_Info *server); | 56 | struct TCP_Server_Info *server); |
53 | extern int smb3_calc_signature(struct smb_rqst *rqst, | 57 | extern int smb3_calc_signature(struct smb_rqst *rqst, |
@@ -164,6 +168,9 @@ extern int SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon, | |||
164 | extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, | 168 | extern int SMB2_oplock_break(const unsigned int xid, struct cifs_tcon *tcon, |
165 | const u64 persistent_fid, const u64 volatile_fid, | 169 | const u64 persistent_fid, const u64 volatile_fid, |
166 | const __u8 oplock_level); | 170 | const __u8 oplock_level); |
171 | extern int smb2_handle_cancelled_mid(char *buffer, | ||
172 | struct TCP_Server_Info *server); | ||
173 | void smb2_cancelled_close_fid(struct work_struct *work); | ||
167 | extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, | 174 | extern int SMB2_QFS_info(const unsigned int xid, struct cifs_tcon *tcon, |
168 | u64 persistent_file_id, u64 volatile_file_id, | 175 | u64 persistent_file_id, u64 volatile_file_id, |
169 | struct kstatfs *FSData); | 176 | struct kstatfs *FSData); |
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 7c3bb1bd7eed..506b67fc93d9 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
@@ -115,23 +115,70 @@ smb3_crypto_shash_allocate(struct TCP_Server_Info *server) | |||
115 | return 0; | 115 | return 0; |
116 | } | 116 | } |
117 | 117 | ||
118 | struct cifs_ses * | 118 | static struct cifs_ses * |
119 | smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) | 119 | smb2_find_smb_ses_unlocked(struct TCP_Server_Info *server, __u64 ses_id) |
120 | { | 120 | { |
121 | struct cifs_ses *ses; | 121 | struct cifs_ses *ses; |
122 | 122 | ||
123 | spin_lock(&cifs_tcp_ses_lock); | ||
124 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { | 123 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
125 | if (ses->Suid != ses_id) | 124 | if (ses->Suid != ses_id) |
126 | continue; | 125 | continue; |
127 | spin_unlock(&cifs_tcp_ses_lock); | ||
128 | return ses; | 126 | return ses; |
129 | } | 127 | } |
128 | |||
129 | return NULL; | ||
130 | } | ||
131 | |||
132 | struct cifs_ses * | ||
133 | smb2_find_smb_ses(struct TCP_Server_Info *server, __u64 ses_id) | ||
134 | { | ||
135 | struct cifs_ses *ses; | ||
136 | |||
137 | spin_lock(&cifs_tcp_ses_lock); | ||
138 | ses = smb2_find_smb_ses_unlocked(server, ses_id); | ||
130 | spin_unlock(&cifs_tcp_ses_lock); | 139 | spin_unlock(&cifs_tcp_ses_lock); |
131 | 140 | ||
141 | return ses; | ||
142 | } | ||
143 | |||
144 | static struct cifs_tcon * | ||
145 | smb2_find_smb_sess_tcon_unlocked(struct cifs_ses *ses, __u32 tid) | ||
146 | { | ||
147 | struct cifs_tcon *tcon; | ||
148 | |||
149 | list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { | ||
150 | if (tcon->tid != tid) | ||
151 | continue; | ||
152 | ++tcon->tc_count; | ||
153 | return tcon; | ||
154 | } | ||
155 | |||
132 | return NULL; | 156 | return NULL; |
133 | } | 157 | } |
134 | 158 | ||
159 | /* | ||
160 | * Obtain tcon corresponding to the tid in the given | ||
161 | * cifs_ses | ||
162 | */ | ||
163 | |||
164 | struct cifs_tcon * | ||
165 | smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid) | ||
166 | { | ||
167 | struct cifs_ses *ses; | ||
168 | struct cifs_tcon *tcon; | ||
169 | |||
170 | spin_lock(&cifs_tcp_ses_lock); | ||
171 | ses = smb2_find_smb_ses_unlocked(server, ses_id); | ||
172 | if (!ses) { | ||
173 | spin_unlock(&cifs_tcp_ses_lock); | ||
174 | return NULL; | ||
175 | } | ||
176 | tcon = smb2_find_smb_sess_tcon_unlocked(ses, tid); | ||
177 | spin_unlock(&cifs_tcp_ses_lock); | ||
178 | |||
179 | return tcon; | ||
180 | } | ||
181 | |||
135 | int | 182 | int |
136 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) | 183 | smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) |
137 | { | 184 | { |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 526f0533cb4e..f6e13a977fc8 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -752,9 +752,11 @@ cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, | |||
752 | 752 | ||
753 | rc = wait_for_response(ses->server, midQ); | 753 | rc = wait_for_response(ses->server, midQ); |
754 | if (rc != 0) { | 754 | if (rc != 0) { |
755 | cifs_dbg(FYI, "Cancelling wait for mid %llu\n", midQ->mid); | ||
755 | send_cancel(ses->server, rqst, midQ); | 756 | send_cancel(ses->server, rqst, midQ); |
756 | spin_lock(&GlobalMid_Lock); | 757 | spin_lock(&GlobalMid_Lock); |
757 | if (midQ->mid_state == MID_REQUEST_SUBMITTED) { | 758 | if (midQ->mid_state == MID_REQUEST_SUBMITTED) { |
759 | midQ->mid_flags |= MID_WAIT_CANCELLED; | ||
758 | midQ->callback = DeleteMidQEntry; | 760 | midQ->callback = DeleteMidQEntry; |
759 | spin_unlock(&GlobalMid_Lock); | 761 | spin_unlock(&GlobalMid_Lock); |
760 | add_credits(ses->server, 1, optype); | 762 | add_credits(ses->server, 1, optype); |