diff options
-rw-r--r-- | fs/cifs/Kconfig | 120 | ||||
-rw-r--r-- | fs/cifs/cifs_dfs_ref.c | 4 | ||||
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 1 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 3 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 65 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 8 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 54 | ||||
-rw-r--r-- | fs/cifs/connect.c | 66 | ||||
-rw-r--r-- | fs/cifs/file.c | 269 | ||||
-rw-r--r-- | fs/cifs/inode.c | 2 | ||||
-rw-r--r-- | fs/cifs/link.c | 14 | ||||
-rw-r--r-- | fs/cifs/smb1ops.c | 8 | ||||
-rw-r--r-- | fs/cifs/smb2misc.c | 24 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 115 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 179 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.h | 4 | ||||
-rw-r--r-- | fs/cifs/smb2transport.c | 25 | ||||
-rw-r--r-- | fs/cifs/smbdirect.c | 6 | ||||
-rw-r--r-- | fs/cifs/trace.h | 89 | ||||
-rw-r--r-- | fs/cifs/transport.c | 208 |
21 files changed, 929 insertions, 337 deletions
diff --git a/fs/cifs/Kconfig b/fs/cifs/Kconfig index f1ddc9d03c10..76724efc831c 100644 --- a/fs/cifs/Kconfig +++ b/fs/cifs/Kconfig | |||
@@ -117,25 +117,25 @@ config CIFS_UPCALL | |||
117 | secure Kerberos authentication is required). If unsure, say Y. | 117 | secure Kerberos authentication is required). If unsure, say Y. |
118 | 118 | ||
119 | config CIFS_XATTR | 119 | config CIFS_XATTR |
120 | bool "CIFS extended attributes" | 120 | bool "CIFS extended attributes" |
121 | depends on CIFS | 121 | depends on CIFS |
122 | help | 122 | help |
123 | Extended attributes are name:value pairs associated with inodes by | 123 | Extended attributes are name:value pairs associated with inodes by |
124 | the kernel or by users (see the attr(5) manual page for details). | 124 | the kernel or by users (see the attr(5) manual page for details). |
125 | CIFS maps the name of extended attributes beginning with the user | 125 | CIFS maps the name of extended attributes beginning with the user |
126 | namespace prefix to SMB/CIFS EAs. EAs are stored on Windows | 126 | namespace prefix to SMB/CIFS EAs. EAs are stored on Windows |
127 | servers without the user namespace prefix, but their names are | 127 | servers without the user namespace prefix, but their names are |
128 | seen by Linux cifs clients prefaced by the user namespace prefix. | 128 | seen by Linux cifs clients prefaced by the user namespace prefix. |
129 | The system namespace (used by some filesystems to store ACLs) is | 129 | The system namespace (used by some filesystems to store ACLs) is |
130 | not supported at this time. | 130 | not supported at this time. |
131 | 131 | ||
132 | If unsure, say Y. | 132 | If unsure, say Y. |
133 | 133 | ||
134 | config CIFS_POSIX | 134 | config CIFS_POSIX |
135 | bool "CIFS POSIX Extensions" | 135 | bool "CIFS POSIX Extensions" |
136 | depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY && CIFS_XATTR | 136 | depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY && CIFS_XATTR |
137 | help | 137 | help |
138 | Enabling this option will cause the cifs client to attempt to | 138 | Enabling this option will cause the cifs client to attempt to |
139 | negotiate a newer dialect with servers, such as Samba 3.0.5 | 139 | negotiate a newer dialect with servers, such as Samba 3.0.5 |
140 | or later, that optionally can handle more POSIX like (rather | 140 | or later, that optionally can handle more POSIX like (rather |
141 | than Windows like) file behavior. It also enables | 141 | than Windows like) file behavior. It also enables |
@@ -144,61 +144,62 @@ config CIFS_POSIX | |||
144 | CIFS POSIX ACL support. If unsure, say N. | 144 | CIFS POSIX ACL support. If unsure, say N. |
145 | 145 | ||
146 | config CIFS_ACL | 146 | config CIFS_ACL |
147 | bool "Provide CIFS ACL support" | 147 | bool "Provide CIFS ACL support" |
148 | depends on CIFS_XATTR && KEYS | 148 | depends on CIFS_XATTR && KEYS |
149 | help | 149 | help |
150 | Allows fetching CIFS/NTFS ACL from the server. The DACL blob | 150 | Allows fetching CIFS/NTFS ACL from the server. The DACL blob |
151 | is handed over to the application/caller. See the man | 151 | is handed over to the application/caller. See the man |
152 | page for getcifsacl for more information. If unsure, say Y. | 152 | page for getcifsacl for more information. If unsure, say Y. |
153 | 153 | ||
154 | config CIFS_DEBUG | 154 | config CIFS_DEBUG |
155 | bool "Enable CIFS debugging routines" | 155 | bool "Enable CIFS debugging routines" |
156 | default y | 156 | default y |
157 | depends on CIFS | 157 | depends on CIFS |
158 | help | 158 | help |
159 | Enabling this option adds helpful debugging messages to | 159 | Enabling this option adds helpful debugging messages to |
160 | the cifs code which increases the size of the cifs module. | 160 | the cifs code which increases the size of the cifs module. |
161 | If unsure, say Y. | 161 | If unsure, say Y. |
162 | |||
162 | config CIFS_DEBUG2 | 163 | config CIFS_DEBUG2 |
163 | bool "Enable additional CIFS debugging routines" | 164 | bool "Enable additional CIFS debugging routines" |
164 | depends on CIFS_DEBUG | 165 | depends on CIFS_DEBUG |
165 | help | 166 | help |
166 | Enabling this option adds a few more debugging routines | 167 | Enabling this option adds a few more debugging routines |
167 | to the cifs code which slightly increases the size of | 168 | to the cifs code which slightly increases the size of |
168 | the cifs module and can cause additional logging of debug | 169 | the cifs module and can cause additional logging of debug |
169 | messages in some error paths, slowing performance. This | 170 | messages in some error paths, slowing performance. This |
170 | option can be turned off unless you are debugging | 171 | option can be turned off unless you are debugging |
171 | cifs problems. If unsure, say N. | 172 | cifs problems. If unsure, say N. |
172 | 173 | ||
173 | config CIFS_DEBUG_DUMP_KEYS | 174 | config CIFS_DEBUG_DUMP_KEYS |
174 | bool "Dump encryption keys for offline decryption (Unsafe)" | 175 | bool "Dump encryption keys for offline decryption (Unsafe)" |
175 | depends on CIFS_DEBUG | 176 | depends on CIFS_DEBUG |
176 | help | 177 | help |
177 | Enabling this will dump the encryption and decryption keys | 178 | Enabling this will dump the encryption and decryption keys |
178 | used to communicate on an encrypted share connection on the | 179 | used to communicate on an encrypted share connection on the |
179 | console. This allows Wireshark to decrypt and dissect | 180 | console. This allows Wireshark to decrypt and dissect |
180 | encrypted network captures. Enable this carefully. | 181 | encrypted network captures. Enable this carefully. |
181 | If unsure, say N. | 182 | If unsure, say N. |
182 | 183 | ||
183 | config CIFS_DFS_UPCALL | 184 | config CIFS_DFS_UPCALL |
184 | bool "DFS feature support" | 185 | bool "DFS feature support" |
185 | depends on CIFS && KEYS | 186 | depends on CIFS && KEYS |
186 | select DNS_RESOLVER | 187 | select DNS_RESOLVER |
187 | help | 188 | help |
188 | Distributed File System (DFS) support is used to access shares | 189 | Distributed File System (DFS) support is used to access shares |
189 | transparently in an enterprise name space, even if the share | 190 | transparently in an enterprise name space, even if the share |
190 | moves to a different server. This feature also enables | 191 | moves to a different server. This feature also enables |
191 | an upcall mechanism for CIFS which contacts userspace helper | 192 | an upcall mechanism for CIFS which contacts userspace helper |
192 | utilities to provide server name resolution (host names to | 193 | utilities to provide server name resolution (host names to |
193 | IP addresses) which is needed in order to reconnect to | 194 | IP addresses) which is needed in order to reconnect to |
194 | servers if their addresses change or for implicit mounts of | 195 | servers if their addresses change or for implicit mounts of |
195 | DFS junction points. If unsure, say Y. | 196 | DFS junction points. If unsure, say Y. |
196 | 197 | ||
197 | config CIFS_NFSD_EXPORT | 198 | config CIFS_NFSD_EXPORT |
198 | bool "Allow nfsd to export CIFS file system" | 199 | bool "Allow nfsd to export CIFS file system" |
199 | depends on CIFS && BROKEN | 200 | depends on CIFS && BROKEN |
200 | help | 201 | help |
201 | Allows NFS server to export a CIFS mounted share (nfsd over cifs) | 202 | Allows NFS server to export a CIFS mounted share (nfsd over cifs) |
202 | 203 | ||
203 | config CIFS_SMB_DIRECT | 204 | config CIFS_SMB_DIRECT |
204 | bool "SMB Direct support (Experimental)" | 205 | bool "SMB Direct support (Experimental)" |
@@ -209,10 +210,9 @@ config CIFS_SMB_DIRECT | |||
209 | say N. | 210 | say N. |
210 | 211 | ||
211 | config CIFS_FSCACHE | 212 | config CIFS_FSCACHE |
212 | bool "Provide CIFS client caching support" | 213 | bool "Provide CIFS client caching support" |
213 | depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y | 214 | depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y |
214 | help | 215 | help |
215 | Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data | 216 | Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data |
216 | to be cached locally on disk through the general filesystem cache | 217 | to be cached locally on disk through the general filesystem cache |
217 | manager. If unsure, say N. | 218 | manager. If unsure, say N. |
218 | |||
diff --git a/fs/cifs/cifs_dfs_ref.c b/fs/cifs/cifs_dfs_ref.c index d9b99abe1243..5d83c924cc47 100644 --- a/fs/cifs/cifs_dfs_ref.c +++ b/fs/cifs/cifs_dfs_ref.c | |||
@@ -285,9 +285,9 @@ static void dump_referral(const struct dfs_info3_param *ref) | |||
285 | { | 285 | { |
286 | cifs_dbg(FYI, "DFS: ref path: %s\n", ref->path_name); | 286 | cifs_dbg(FYI, "DFS: ref path: %s\n", ref->path_name); |
287 | cifs_dbg(FYI, "DFS: node path: %s\n", ref->node_name); | 287 | cifs_dbg(FYI, "DFS: node path: %s\n", ref->node_name); |
288 | cifs_dbg(FYI, "DFS: fl: %hd, srv_type: %hd\n", | 288 | cifs_dbg(FYI, "DFS: fl: %d, srv_type: %d\n", |
289 | ref->flags, ref->server_type); | 289 | ref->flags, ref->server_type); |
290 | cifs_dbg(FYI, "DFS: ref_flags: %hd, path_consumed: %hd\n", | 290 | cifs_dbg(FYI, "DFS: ref_flags: %d, path_consumed: %d\n", |
291 | ref->ref_flag, ref->path_consumed); | 291 | ref->ref_flag, ref->path_consumed); |
292 | } | 292 | } |
293 | 293 | ||
diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index 42f0d67f1054..ed49222abecb 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h | |||
@@ -58,6 +58,7 @@ struct cifs_sb_info { | |||
58 | spinlock_t tlink_tree_lock; | 58 | spinlock_t tlink_tree_lock; |
59 | struct tcon_link *master_tlink; | 59 | struct tcon_link *master_tlink; |
60 | struct nls_table *local_nls; | 60 | struct nls_table *local_nls; |
61 | unsigned int bsize; | ||
61 | unsigned int rsize; | 62 | unsigned int rsize; |
62 | unsigned int wsize; | 63 | unsigned int wsize; |
63 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ | 64 | unsigned long actimeo; /* attribute cache timeout (jiffies) */ |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 62d48d486d8f..217276b8b942 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -381,7 +381,7 @@ cifs_show_security(struct seq_file *s, struct cifs_ses *ses) | |||
381 | seq_puts(s, "ntlm"); | 381 | seq_puts(s, "ntlm"); |
382 | break; | 382 | break; |
383 | case Kerberos: | 383 | case Kerberos: |
384 | seq_puts(s, "krb5"); | 384 | seq_printf(s, "krb5,cruid=%u", from_kuid_munged(&init_user_ns,ses->cred_uid)); |
385 | break; | 385 | break; |
386 | case RawNTLMSSP: | 386 | case RawNTLMSSP: |
387 | seq_puts(s, "ntlmssp"); | 387 | seq_puts(s, "ntlmssp"); |
@@ -554,6 +554,7 @@ cifs_show_options(struct seq_file *s, struct dentry *root) | |||
554 | 554 | ||
555 | seq_printf(s, ",rsize=%u", cifs_sb->rsize); | 555 | seq_printf(s, ",rsize=%u", cifs_sb->rsize); |
556 | seq_printf(s, ",wsize=%u", cifs_sb->wsize); | 556 | seq_printf(s, ",wsize=%u", cifs_sb->wsize); |
557 | seq_printf(s, ",bsize=%u", cifs_sb->bsize); | ||
557 | seq_printf(s, ",echo_interval=%lu", | 558 | seq_printf(s, ",echo_interval=%lu", |
558 | tcon->ses->server->echo_interval / HZ); | 559 | tcon->ses->server->echo_interval / HZ); |
559 | if (tcon->snapshot_time) | 560 | if (tcon->snapshot_time) |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 7652551a1fc4..142164ef1f05 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -150,5 +150,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | |||
150 | extern const struct export_operations cifs_export_ops; | 150 | extern const struct export_operations cifs_export_ops; |
151 | #endif /* CONFIG_CIFS_NFSD_EXPORT */ | 151 | #endif /* CONFIG_CIFS_NFSD_EXPORT */ |
152 | 152 | ||
153 | #define CIFS_VERSION "2.17" | 153 | #define CIFS_VERSION "2.18" |
154 | #endif /* _CIFSFS_H */ | 154 | #endif /* _CIFSFS_H */ |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 94dbdbe5be34..f293e052e351 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -216,6 +216,7 @@ struct cifs_io_parms; | |||
216 | struct cifs_search_info; | 216 | struct cifs_search_info; |
217 | struct cifsInodeInfo; | 217 | struct cifsInodeInfo; |
218 | struct cifs_open_parms; | 218 | struct cifs_open_parms; |
219 | struct cifs_credits; | ||
219 | 220 | ||
220 | struct smb_version_operations { | 221 | struct smb_version_operations { |
221 | int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *, | 222 | int (*send_cancel)(struct TCP_Server_Info *, struct smb_rqst *, |
@@ -230,12 +231,15 @@ struct smb_version_operations { | |||
230 | /* check response: verify signature, map error */ | 231 | /* check response: verify signature, map error */ |
231 | int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *, | 232 | int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *, |
232 | bool); | 233 | bool); |
233 | void (*add_credits)(struct TCP_Server_Info *, const unsigned int, | 234 | void (*add_credits)(struct TCP_Server_Info *server, |
234 | const int); | 235 | const struct cifs_credits *credits, |
236 | const int optype); | ||
235 | void (*set_credits)(struct TCP_Server_Info *, const int); | 237 | void (*set_credits)(struct TCP_Server_Info *, const int); |
236 | int * (*get_credits_field)(struct TCP_Server_Info *, const int); | 238 | int * (*get_credits_field)(struct TCP_Server_Info *, const int); |
237 | unsigned int (*get_credits)(struct mid_q_entry *); | 239 | unsigned int (*get_credits)(struct mid_q_entry *); |
238 | __u64 (*get_next_mid)(struct TCP_Server_Info *); | 240 | __u64 (*get_next_mid)(struct TCP_Server_Info *); |
241 | void (*revert_current_mid)(struct TCP_Server_Info *server, | ||
242 | const unsigned int val); | ||
239 | /* data offset from read response message */ | 243 | /* data offset from read response message */ |
240 | unsigned int (*read_data_offset)(char *); | 244 | unsigned int (*read_data_offset)(char *); |
241 | /* | 245 | /* |
@@ -383,8 +387,8 @@ struct smb_version_operations { | |||
383 | struct cifs_fid *); | 387 | struct cifs_fid *); |
384 | /* calculate a size of SMB message */ | 388 | /* calculate a size of SMB message */ |
385 | unsigned int (*calc_smb_size)(void *buf, struct TCP_Server_Info *ptcpi); | 389 | unsigned int (*calc_smb_size)(void *buf, struct TCP_Server_Info *ptcpi); |
386 | /* check for STATUS_PENDING and process it in a positive case */ | 390 | /* check for STATUS_PENDING and process the response if yes */ |
387 | bool (*is_status_pending)(char *, struct TCP_Server_Info *, int); | 391 | bool (*is_status_pending)(char *buf, struct TCP_Server_Info *server); |
388 | /* check for STATUS_NETWORK_SESSION_EXPIRED */ | 392 | /* check for STATUS_NETWORK_SESSION_EXPIRED */ |
389 | bool (*is_session_expired)(char *); | 393 | bool (*is_session_expired)(char *); |
390 | /* send oplock break response */ | 394 | /* send oplock break response */ |
@@ -452,7 +456,11 @@ struct smb_version_operations { | |||
452 | unsigned int (*wp_retry_size)(struct inode *); | 456 | unsigned int (*wp_retry_size)(struct inode *); |
453 | /* get mtu credits */ | 457 | /* get mtu credits */ |
454 | int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int, | 458 | int (*wait_mtu_credits)(struct TCP_Server_Info *, unsigned int, |
455 | unsigned int *, unsigned int *); | 459 | unsigned int *, struct cifs_credits *); |
460 | /* adjust previously taken mtu credits to request size */ | ||
461 | int (*adjust_credits)(struct TCP_Server_Info *server, | ||
462 | struct cifs_credits *credits, | ||
463 | const unsigned int payload_size); | ||
456 | /* check if we need to issue closedir */ | 464 | /* check if we need to issue closedir */ |
457 | bool (*dir_needs_close)(struct cifsFileInfo *); | 465 | bool (*dir_needs_close)(struct cifsFileInfo *); |
458 | long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t, | 466 | long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t, |
@@ -557,6 +565,7 @@ struct smb_vol { | |||
557 | bool resilient:1; /* noresilient not required since not fored for CA */ | 565 | bool resilient:1; /* noresilient not required since not fored for CA */ |
558 | bool domainauto:1; | 566 | bool domainauto:1; |
559 | bool rdma:1; | 567 | bool rdma:1; |
568 | unsigned int bsize; | ||
560 | unsigned int rsize; | 569 | unsigned int rsize; |
561 | unsigned int wsize; | 570 | unsigned int wsize; |
562 | bool sockopt_tcp_nodelay:1; | 571 | bool sockopt_tcp_nodelay:1; |
@@ -710,6 +719,11 @@ struct TCP_Server_Info { | |||
710 | int nr_targets; | 719 | int nr_targets; |
711 | }; | 720 | }; |
712 | 721 | ||
722 | struct cifs_credits { | ||
723 | unsigned int value; | ||
724 | unsigned int instance; | ||
725 | }; | ||
726 | |||
713 | static inline unsigned int | 727 | static inline unsigned int |
714 | in_flight(struct TCP_Server_Info *server) | 728 | in_flight(struct TCP_Server_Info *server) |
715 | { | 729 | { |
@@ -731,18 +745,18 @@ has_credits(struct TCP_Server_Info *server, int *credits) | |||
731 | } | 745 | } |
732 | 746 | ||
733 | static inline void | 747 | static inline void |
734 | add_credits(struct TCP_Server_Info *server, const unsigned int add, | 748 | add_credits(struct TCP_Server_Info *server, const struct cifs_credits *credits, |
735 | const int optype) | 749 | const int optype) |
736 | { | 750 | { |
737 | server->ops->add_credits(server, add, optype); | 751 | server->ops->add_credits(server, credits, optype); |
738 | } | 752 | } |
739 | 753 | ||
740 | static inline void | 754 | static inline void |
741 | add_credits_and_wake_if(struct TCP_Server_Info *server, const unsigned int add, | 755 | add_credits_and_wake_if(struct TCP_Server_Info *server, |
742 | const int optype) | 756 | const struct cifs_credits *credits, const int optype) |
743 | { | 757 | { |
744 | if (add) { | 758 | if (credits->value) { |
745 | server->ops->add_credits(server, add, optype); | 759 | server->ops->add_credits(server, credits, optype); |
746 | wake_up(&server->request_q); | 760 | wake_up(&server->request_q); |
747 | } | 761 | } |
748 | } | 762 | } |
@@ -753,6 +767,14 @@ set_credits(struct TCP_Server_Info *server, const int val) | |||
753 | server->ops->set_credits(server, val); | 767 | server->ops->set_credits(server, val); |
754 | } | 768 | } |
755 | 769 | ||
770 | static inline int | ||
771 | adjust_credits(struct TCP_Server_Info *server, struct cifs_credits *credits, | ||
772 | const unsigned int payload_size) | ||
773 | { | ||
774 | return server->ops->adjust_credits ? | ||
775 | server->ops->adjust_credits(server, credits, payload_size) : 0; | ||
776 | } | ||
777 | |||
756 | static inline __le64 | 778 | static inline __le64 |
757 | get_next_mid64(struct TCP_Server_Info *server) | 779 | get_next_mid64(struct TCP_Server_Info *server) |
758 | { | 780 | { |
@@ -770,6 +792,22 @@ get_next_mid(struct TCP_Server_Info *server) | |||
770 | return cpu_to_le16(mid); | 792 | return cpu_to_le16(mid); |
771 | } | 793 | } |
772 | 794 | ||
795 | static inline void | ||
796 | revert_current_mid(struct TCP_Server_Info *server, const unsigned int val) | ||
797 | { | ||
798 | if (server->ops->revert_current_mid) | ||
799 | server->ops->revert_current_mid(server, val); | ||
800 | } | ||
801 | |||
802 | static inline void | ||
803 | revert_current_mid_from_hdr(struct TCP_Server_Info *server, | ||
804 | const struct smb2_sync_hdr *shdr) | ||
805 | { | ||
806 | unsigned int num = le16_to_cpu(shdr->CreditCharge); | ||
807 | |||
808 | return revert_current_mid(server, num > 0 ? num : 1); | ||
809 | } | ||
810 | |||
773 | static inline __u16 | 811 | static inline __u16 |
774 | get_mid(const struct smb_hdr *smb) | 812 | get_mid(const struct smb_hdr *smb) |
775 | { | 813 | { |
@@ -1234,7 +1272,7 @@ struct cifs_readdata { | |||
1234 | unsigned int pagesz; | 1272 | unsigned int pagesz; |
1235 | unsigned int page_offset; | 1273 | unsigned int page_offset; |
1236 | unsigned int tailsz; | 1274 | unsigned int tailsz; |
1237 | unsigned int credits; | 1275 | struct cifs_credits credits; |
1238 | unsigned int nr_pages; | 1276 | unsigned int nr_pages; |
1239 | struct page **pages; | 1277 | struct page **pages; |
1240 | }; | 1278 | }; |
@@ -1260,7 +1298,7 @@ struct cifs_writedata { | |||
1260 | unsigned int pagesz; | 1298 | unsigned int pagesz; |
1261 | unsigned int page_offset; | 1299 | unsigned int page_offset; |
1262 | unsigned int tailsz; | 1300 | unsigned int tailsz; |
1263 | unsigned int credits; | 1301 | struct cifs_credits credits; |
1264 | unsigned int nr_pages; | 1302 | unsigned int nr_pages; |
1265 | struct page **pages; | 1303 | struct page **pages; |
1266 | }; | 1304 | }; |
@@ -1422,6 +1460,7 @@ struct mid_q_entry { | |||
1422 | struct kref refcount; | 1460 | struct kref refcount; |
1423 | struct TCP_Server_Info *server; /* server corresponding to this mid */ | 1461 | struct TCP_Server_Info *server; /* server corresponding to this mid */ |
1424 | __u64 mid; /* multiplex id */ | 1462 | __u64 mid; /* multiplex id */ |
1463 | __u16 credits; /* number of credits consumed by this mid */ | ||
1425 | __u32 pid; /* process id */ | 1464 | __u32 pid; /* process id */ |
1426 | __u32 sequence_number; /* for CIFS signing */ | 1465 | __u32 sequence_number; /* for CIFS signing */ |
1427 | unsigned long when_alloc; /* when mid was created */ | 1466 | unsigned long when_alloc; /* when mid was created */ |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 336c116995d7..4f96b3b00a7a 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -93,7 +93,8 @@ extern int cifs_discard_remaining_data(struct TCP_Server_Info *server); | |||
93 | extern int cifs_call_async(struct TCP_Server_Info *server, | 93 | extern int cifs_call_async(struct TCP_Server_Info *server, |
94 | struct smb_rqst *rqst, | 94 | struct smb_rqst *rqst, |
95 | mid_receive_t *receive, mid_callback_t *callback, | 95 | mid_receive_t *receive, mid_callback_t *callback, |
96 | mid_handle_t *handle, void *cbdata, const int flags); | 96 | mid_handle_t *handle, void *cbdata, const int flags, |
97 | const struct cifs_credits *exist_credits); | ||
97 | extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, | 98 | extern int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, |
98 | struct smb_rqst *rqst, int *resp_buf_type, | 99 | struct smb_rqst *rqst, int *resp_buf_type, |
99 | const int flags, struct kvec *resp_iov); | 100 | const int flags, struct kvec *resp_iov); |
@@ -115,7 +116,7 @@ extern int cifs_check_receive(struct mid_q_entry *mid, | |||
115 | struct TCP_Server_Info *server, bool log_error); | 116 | struct TCP_Server_Info *server, bool log_error); |
116 | extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server, | 117 | extern int cifs_wait_mtu_credits(struct TCP_Server_Info *server, |
117 | unsigned int size, unsigned int *num, | 118 | unsigned int size, unsigned int *num, |
118 | unsigned int *credits); | 119 | struct cifs_credits *credits); |
119 | extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, | 120 | extern int SendReceive2(const unsigned int /* xid */ , struct cifs_ses *, |
120 | struct kvec *, int /* nvec to send */, | 121 | struct kvec *, int /* nvec to send */, |
121 | int * /* type of buf returned */, const int flags, | 122 | int * /* type of buf returned */, const int flags, |
@@ -133,6 +134,9 @@ extern bool is_size_safe_to_change(struct cifsInodeInfo *, __u64 eof); | |||
133 | extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, | 134 | extern void cifs_update_eof(struct cifsInodeInfo *cifsi, loff_t offset, |
134 | unsigned int bytes_written); | 135 | unsigned int bytes_written); |
135 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); | 136 | extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *, bool); |
137 | extern int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, | ||
138 | bool fsuid_only, | ||
139 | struct cifsFileInfo **ret_file); | ||
136 | extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); | 140 | extern struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *, bool); |
137 | extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server); | 141 | extern unsigned int smbCalcSize(void *buf, struct TCP_Server_Info *server); |
138 | extern int decode_negTokenInit(unsigned char *security_blob, int length, | 142 | extern int decode_negTokenInit(unsigned char *security_blob, int length, |
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index bb54ccf8481c..f43747c062a7 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -139,8 +139,8 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc, | |||
139 | return -ENOMEM; | 139 | return -ENOMEM; |
140 | 140 | ||
141 | if (tcon->ipc) { | 141 | if (tcon->ipc) { |
142 | snprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", | 142 | scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", |
143 | tcon->ses->server->hostname); | 143 | tcon->ses->server->hostname); |
144 | rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc); | 144 | rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc); |
145 | goto out; | 145 | goto out; |
146 | } | 146 | } |
@@ -172,7 +172,7 @@ static int __cifs_reconnect_tcon(const struct nls_table *nlsc, | |||
172 | continue; | 172 | continue; |
173 | } | 173 | } |
174 | 174 | ||
175 | snprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); | 175 | scnprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); |
176 | 176 | ||
177 | rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc); | 177 | rc = CIFSTCon(0, tcon->ses, tree, tcon, nlsc); |
178 | if (!rc) | 178 | if (!rc) |
@@ -822,9 +822,10 @@ static void | |||
822 | cifs_echo_callback(struct mid_q_entry *mid) | 822 | cifs_echo_callback(struct mid_q_entry *mid) |
823 | { | 823 | { |
824 | struct TCP_Server_Info *server = mid->callback_data; | 824 | struct TCP_Server_Info *server = mid->callback_data; |
825 | struct cifs_credits credits = { .value = 1, .instance = 0 }; | ||
825 | 826 | ||
826 | DeleteMidQEntry(mid); | 827 | DeleteMidQEntry(mid); |
827 | add_credits(server, 1, CIFS_ECHO_OP); | 828 | add_credits(server, &credits, CIFS_ECHO_OP); |
828 | } | 829 | } |
829 | 830 | ||
830 | int | 831 | int |
@@ -859,7 +860,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) | |||
859 | iov[1].iov_base = (char *)smb + 4; | 860 | iov[1].iov_base = (char *)smb + 4; |
860 | 861 | ||
861 | rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL, | 862 | rc = cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL, |
862 | server, CIFS_ASYNC_OP | CIFS_ECHO_OP); | 863 | server, CIFS_ASYNC_OP | CIFS_ECHO_OP, NULL); |
863 | if (rc) | 864 | if (rc) |
864 | cifs_dbg(FYI, "Echo request failed: %d\n", rc); | 865 | cifs_dbg(FYI, "Echo request failed: %d\n", rc); |
865 | 866 | ||
@@ -1605,16 +1606,17 @@ cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1605 | } | 1606 | } |
1606 | 1607 | ||
1607 | if (server->ops->is_status_pending && | 1608 | if (server->ops->is_status_pending && |
1608 | server->ops->is_status_pending(buf, server, 0)) { | 1609 | server->ops->is_status_pending(buf, server)) { |
1609 | cifs_discard_remaining_data(server); | 1610 | cifs_discard_remaining_data(server); |
1610 | return -1; | 1611 | return -1; |
1611 | } | 1612 | } |
1612 | 1613 | ||
1613 | /* set up first two iov for signature check and to get credits */ | 1614 | /* set up first two iov for signature check and to get credits */ |
1614 | rdata->iov[0].iov_base = buf; | 1615 | rdata->iov[0].iov_base = buf; |
1615 | rdata->iov[0].iov_len = 4; | 1616 | rdata->iov[0].iov_len = server->vals->header_preamble_size; |
1616 | rdata->iov[1].iov_base = buf + 4; | 1617 | rdata->iov[1].iov_base = buf + server->vals->header_preamble_size; |
1617 | rdata->iov[1].iov_len = server->total_read - 4; | 1618 | rdata->iov[1].iov_len = |
1619 | server->total_read - server->vals->header_preamble_size; | ||
1618 | cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", | 1620 | cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", |
1619 | rdata->iov[0].iov_base, rdata->iov[0].iov_len); | 1621 | rdata->iov[0].iov_base, rdata->iov[0].iov_len); |
1620 | cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n", | 1622 | cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n", |
@@ -1713,6 +1715,7 @@ cifs_readv_callback(struct mid_q_entry *mid) | |||
1713 | .rq_npages = rdata->nr_pages, | 1715 | .rq_npages = rdata->nr_pages, |
1714 | .rq_pagesz = rdata->pagesz, | 1716 | .rq_pagesz = rdata->pagesz, |
1715 | .rq_tailsz = rdata->tailsz }; | 1717 | .rq_tailsz = rdata->tailsz }; |
1718 | struct cifs_credits credits = { .value = 1, .instance = 0 }; | ||
1716 | 1719 | ||
1717 | cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n", | 1720 | cifs_dbg(FYI, "%s: mid=%llu state=%d result=%d bytes=%u\n", |
1718 | __func__, mid->mid, mid->mid_state, rdata->result, | 1721 | __func__, mid->mid, mid->mid_state, rdata->result, |
@@ -1750,7 +1753,7 @@ cifs_readv_callback(struct mid_q_entry *mid) | |||
1750 | 1753 | ||
1751 | queue_work(cifsiod_wq, &rdata->work); | 1754 | queue_work(cifsiod_wq, &rdata->work); |
1752 | DeleteMidQEntry(mid); | 1755 | DeleteMidQEntry(mid); |
1753 | add_credits(server, 1, 0); | 1756 | add_credits(server, &credits, 0); |
1754 | } | 1757 | } |
1755 | 1758 | ||
1756 | /* cifs_async_readv - send an async write, and set up mid to handle result */ | 1759 | /* cifs_async_readv - send an async write, and set up mid to handle result */ |
@@ -1809,7 +1812,7 @@ cifs_async_readv(struct cifs_readdata *rdata) | |||
1809 | 1812 | ||
1810 | kref_get(&rdata->refcount); | 1813 | kref_get(&rdata->refcount); |
1811 | rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, | 1814 | rc = cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, |
1812 | cifs_readv_callback, NULL, rdata, 0); | 1815 | cifs_readv_callback, NULL, rdata, 0, NULL); |
1813 | 1816 | ||
1814 | if (rc == 0) | 1817 | if (rc == 0) |
1815 | cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); | 1818 | cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); |
@@ -2123,14 +2126,18 @@ cifs_writev_requeue(struct cifs_writedata *wdata) | |||
2123 | wdata2->tailsz = tailsz; | 2126 | wdata2->tailsz = tailsz; |
2124 | wdata2->bytes = cur_len; | 2127 | wdata2->bytes = cur_len; |
2125 | 2128 | ||
2126 | wdata2->cfile = find_writable_file(CIFS_I(inode), false); | 2129 | rc = cifs_get_writable_file(CIFS_I(inode), false, |
2130 | &wdata2->cfile); | ||
2127 | if (!wdata2->cfile) { | 2131 | if (!wdata2->cfile) { |
2128 | cifs_dbg(VFS, "No writable handles for inode\n"); | 2132 | cifs_dbg(VFS, "No writable handle to retry writepages rc=%d\n", |
2129 | rc = -EBADF; | 2133 | rc); |
2130 | break; | 2134 | if (!is_retryable_error(rc)) |
2135 | rc = -EBADF; | ||
2136 | } else { | ||
2137 | wdata2->pid = wdata2->cfile->pid; | ||
2138 | rc = server->ops->async_writev(wdata2, | ||
2139 | cifs_writedata_release); | ||
2131 | } | 2140 | } |
2132 | wdata2->pid = wdata2->cfile->pid; | ||
2133 | rc = server->ops->async_writev(wdata2, cifs_writedata_release); | ||
2134 | 2141 | ||
2135 | for (j = 0; j < nr_pages; j++) { | 2142 | for (j = 0; j < nr_pages; j++) { |
2136 | unlock_page(wdata2->pages[j]); | 2143 | unlock_page(wdata2->pages[j]); |
@@ -2145,6 +2152,7 @@ cifs_writev_requeue(struct cifs_writedata *wdata) | |||
2145 | kref_put(&wdata2->refcount, cifs_writedata_release); | 2152 | kref_put(&wdata2->refcount, cifs_writedata_release); |
2146 | if (is_retryable_error(rc)) | 2153 | if (is_retryable_error(rc)) |
2147 | continue; | 2154 | continue; |
2155 | i += nr_pages; | ||
2148 | break; | 2156 | break; |
2149 | } | 2157 | } |
2150 | 2158 | ||
@@ -2152,6 +2160,13 @@ cifs_writev_requeue(struct cifs_writedata *wdata) | |||
2152 | i += nr_pages; | 2160 | i += nr_pages; |
2153 | } while (i < wdata->nr_pages); | 2161 | } while (i < wdata->nr_pages); |
2154 | 2162 | ||
2163 | /* cleanup remaining pages from the original wdata */ | ||
2164 | for (; i < wdata->nr_pages; i++) { | ||
2165 | SetPageError(wdata->pages[i]); | ||
2166 | end_page_writeback(wdata->pages[i]); | ||
2167 | put_page(wdata->pages[i]); | ||
2168 | } | ||
2169 | |||
2155 | if (rc != 0 && !is_retryable_error(rc)) | 2170 | if (rc != 0 && !is_retryable_error(rc)) |
2156 | mapping_set_error(inode->i_mapping, rc); | 2171 | mapping_set_error(inode->i_mapping, rc); |
2157 | kref_put(&wdata->refcount, cifs_writedata_release); | 2172 | kref_put(&wdata->refcount, cifs_writedata_release); |
@@ -2226,6 +2241,7 @@ cifs_writev_callback(struct mid_q_entry *mid) | |||
2226 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); | 2241 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); |
2227 | unsigned int written; | 2242 | unsigned int written; |
2228 | WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; | 2243 | WRITE_RSP *smb = (WRITE_RSP *)mid->resp_buf; |
2244 | struct cifs_credits credits = { .value = 1, .instance = 0 }; | ||
2229 | 2245 | ||
2230 | switch (mid->mid_state) { | 2246 | switch (mid->mid_state) { |
2231 | case MID_RESPONSE_RECEIVED: | 2247 | case MID_RESPONSE_RECEIVED: |
@@ -2261,7 +2277,7 @@ cifs_writev_callback(struct mid_q_entry *mid) | |||
2261 | 2277 | ||
2262 | queue_work(cifsiod_wq, &wdata->work); | 2278 | queue_work(cifsiod_wq, &wdata->work); |
2263 | DeleteMidQEntry(mid); | 2279 | DeleteMidQEntry(mid); |
2264 | add_credits(tcon->ses->server, 1, 0); | 2280 | add_credits(tcon->ses->server, &credits, 0); |
2265 | } | 2281 | } |
2266 | 2282 | ||
2267 | /* cifs_async_writev - send an async write, and set up mid to handle result */ | 2283 | /* cifs_async_writev - send an async write, and set up mid to handle result */ |
@@ -2339,7 +2355,7 @@ cifs_async_writev(struct cifs_writedata *wdata, | |||
2339 | 2355 | ||
2340 | kref_get(&wdata->refcount); | 2356 | kref_get(&wdata->refcount); |
2341 | rc = cifs_call_async(tcon->ses->server, &rqst, NULL, | 2357 | rc = cifs_call_async(tcon->ses->server, &rqst, NULL, |
2342 | cifs_writev_callback, NULL, wdata, 0); | 2358 | cifs_writev_callback, NULL, wdata, 0, NULL); |
2343 | 2359 | ||
2344 | if (rc == 0) | 2360 | if (rc == 0) |
2345 | cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); | 2361 | cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8463c940e0e5..b95db2b593cb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -102,7 +102,7 @@ enum { | |||
102 | Opt_backupuid, Opt_backupgid, Opt_uid, | 102 | Opt_backupuid, Opt_backupgid, Opt_uid, |
103 | Opt_cruid, Opt_gid, Opt_file_mode, | 103 | Opt_cruid, Opt_gid, Opt_file_mode, |
104 | Opt_dirmode, Opt_port, | 104 | Opt_dirmode, Opt_port, |
105 | Opt_rsize, Opt_wsize, Opt_actimeo, | 105 | Opt_blocksize, Opt_rsize, Opt_wsize, Opt_actimeo, |
106 | Opt_echo_interval, Opt_max_credits, | 106 | Opt_echo_interval, Opt_max_credits, |
107 | Opt_snapshot, | 107 | Opt_snapshot, |
108 | 108 | ||
@@ -204,6 +204,7 @@ static const match_table_t cifs_mount_option_tokens = { | |||
204 | { Opt_dirmode, "dirmode=%s" }, | 204 | { Opt_dirmode, "dirmode=%s" }, |
205 | { Opt_dirmode, "dir_mode=%s" }, | 205 | { Opt_dirmode, "dir_mode=%s" }, |
206 | { Opt_port, "port=%s" }, | 206 | { Opt_port, "port=%s" }, |
207 | { Opt_blocksize, "bsize=%s" }, | ||
207 | { Opt_rsize, "rsize=%s" }, | 208 | { Opt_rsize, "rsize=%s" }, |
208 | { Opt_wsize, "wsize=%s" }, | 209 | { Opt_wsize, "wsize=%s" }, |
209 | { Opt_actimeo, "actimeo=%s" }, | 210 | { Opt_actimeo, "actimeo=%s" }, |
@@ -348,7 +349,7 @@ static int reconn_set_ipaddr(struct TCP_Server_Info *server) | |||
348 | cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__); | 349 | cifs_dbg(FYI, "%s: failed to create UNC path\n", __func__); |
349 | return -ENOMEM; | 350 | return -ENOMEM; |
350 | } | 351 | } |
351 | snprintf(unc, len, "\\\\%s", server->hostname); | 352 | scnprintf(unc, len, "\\\\%s", server->hostname); |
352 | 353 | ||
353 | rc = dns_resolve_server_name_to_ip(unc, &ipaddr); | 354 | rc = dns_resolve_server_name_to_ip(unc, &ipaddr); |
354 | kfree(unc); | 355 | kfree(unc); |
@@ -592,6 +593,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
592 | msleep(3000); | 593 | msleep(3000); |
593 | } else { | 594 | } else { |
594 | atomic_inc(&tcpSesReconnectCount); | 595 | atomic_inc(&tcpSesReconnectCount); |
596 | set_credits(server, 1); | ||
595 | spin_lock(&GlobalMid_Lock); | 597 | spin_lock(&GlobalMid_Lock); |
596 | if (server->tcpStatus != CifsExiting) | 598 | if (server->tcpStatus != CifsExiting) |
597 | server->tcpStatus = CifsNeedNegotiate; | 599 | server->tcpStatus = CifsNeedNegotiate; |
@@ -1053,7 +1055,7 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1053 | } | 1055 | } |
1054 | 1056 | ||
1055 | if (server->ops->is_status_pending && | 1057 | if (server->ops->is_status_pending && |
1056 | server->ops->is_status_pending(buf, server, length)) | 1058 | server->ops->is_status_pending(buf, server)) |
1057 | return -1; | 1059 | return -1; |
1058 | 1060 | ||
1059 | if (!mid) | 1061 | if (!mid) |
@@ -1063,6 +1065,26 @@ cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *mid) | |||
1063 | return 0; | 1065 | return 0; |
1064 | } | 1066 | } |
1065 | 1067 | ||
1068 | static void | ||
1069 | smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) | ||
1070 | { | ||
1071 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buffer; | ||
1072 | |||
1073 | /* | ||
1074 | * SMB1 does not use credits. | ||
1075 | */ | ||
1076 | if (server->vals->header_preamble_size) | ||
1077 | return; | ||
1078 | |||
1079 | if (shdr->CreditRequest) { | ||
1080 | spin_lock(&server->req_lock); | ||
1081 | server->credits += le16_to_cpu(shdr->CreditRequest); | ||
1082 | spin_unlock(&server->req_lock); | ||
1083 | wake_up(&server->request_q); | ||
1084 | } | ||
1085 | } | ||
1086 | |||
1087 | |||
1066 | static int | 1088 | static int |
1067 | cifs_demultiplex_thread(void *p) | 1089 | cifs_demultiplex_thread(void *p) |
1068 | { | 1090 | { |
@@ -1192,6 +1214,7 @@ next_pdu: | |||
1192 | } else if (server->ops->is_oplock_break && | 1214 | } else if (server->ops->is_oplock_break && |
1193 | server->ops->is_oplock_break(bufs[i], | 1215 | server->ops->is_oplock_break(bufs[i], |
1194 | server)) { | 1216 | server)) { |
1217 | smb2_add_credits_from_hdr(bufs[i], server); | ||
1195 | cifs_dbg(FYI, "Received oplock break\n"); | 1218 | cifs_dbg(FYI, "Received oplock break\n"); |
1196 | } else { | 1219 | } else { |
1197 | cifs_dbg(VFS, "No task to wake, unknown frame " | 1220 | cifs_dbg(VFS, "No task to wake, unknown frame " |
@@ -1203,6 +1226,7 @@ next_pdu: | |||
1203 | if (server->ops->dump_detail) | 1226 | if (server->ops->dump_detail) |
1204 | server->ops->dump_detail(bufs[i], | 1227 | server->ops->dump_detail(bufs[i], |
1205 | server); | 1228 | server); |
1229 | smb2_add_credits_from_hdr(bufs[i], server); | ||
1206 | cifs_dump_mids(server); | 1230 | cifs_dump_mids(server); |
1207 | #endif /* CIFS_DEBUG2 */ | 1231 | #endif /* CIFS_DEBUG2 */ |
1208 | } | 1232 | } |
@@ -1486,6 +1510,11 @@ cifs_parse_devname(const char *devname, struct smb_vol *vol) | |||
1486 | const char *delims = "/\\"; | 1510 | const char *delims = "/\\"; |
1487 | size_t len; | 1511 | size_t len; |
1488 | 1512 | ||
1513 | if (unlikely(!devname || !*devname)) { | ||
1514 | cifs_dbg(VFS, "Device name not specified.\n"); | ||
1515 | return -EINVAL; | ||
1516 | } | ||
1517 | |||
1489 | /* make sure we have a valid UNC double delimiter prefix */ | 1518 | /* make sure we have a valid UNC double delimiter prefix */ |
1490 | len = strspn(devname, delims); | 1519 | len = strspn(devname, delims); |
1491 | if (len != 2) | 1520 | if (len != 2) |
@@ -1571,7 +1600,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1571 | vol->cred_uid = current_uid(); | 1600 | vol->cred_uid = current_uid(); |
1572 | vol->linux_uid = current_uid(); | 1601 | vol->linux_uid = current_uid(); |
1573 | vol->linux_gid = current_gid(); | 1602 | vol->linux_gid = current_gid(); |
1574 | 1603 | vol->bsize = 1024 * 1024; /* can improve cp performance significantly */ | |
1575 | /* | 1604 | /* |
1576 | * default to SFM style remapping of seven reserved characters | 1605 | * default to SFM style remapping of seven reserved characters |
1577 | * unless user overrides it or we negotiate CIFS POSIX where | 1606 | * unless user overrides it or we negotiate CIFS POSIX where |
@@ -1944,6 +1973,26 @@ cifs_parse_mount_options(const char *mountdata, const char *devname, | |||
1944 | } | 1973 | } |
1945 | port = (unsigned short)option; | 1974 | port = (unsigned short)option; |
1946 | break; | 1975 | break; |
1976 | case Opt_blocksize: | ||
1977 | if (get_option_ul(args, &option)) { | ||
1978 | cifs_dbg(VFS, "%s: Invalid blocksize value\n", | ||
1979 | __func__); | ||
1980 | goto cifs_parse_mount_err; | ||
1981 | } | ||
1982 | /* | ||
1983 | * inode blocksize realistically should never need to be | ||
1984 | * less than 16K or greater than 16M and default is 1MB. | ||
1985 | * Note that small inode block sizes (e.g. 64K) can lead | ||
1986 | * to very poor performance of common tools like cp and scp | ||
1987 | */ | ||
1988 | if ((option < CIFS_MAX_MSGSIZE) || | ||
1989 | (option > (4 * SMB3_DEFAULT_IOSIZE))) { | ||
1990 | cifs_dbg(VFS, "%s: Invalid blocksize\n", | ||
1991 | __func__); | ||
1992 | goto cifs_parse_mount_err; | ||
1993 | } | ||
1994 | vol->bsize = option; | ||
1995 | break; | ||
1947 | case Opt_rsize: | 1996 | case Opt_rsize: |
1948 | if (get_option_ul(args, &option)) { | 1997 | if (get_option_ul(args, &option)) { |
1949 | cifs_dbg(VFS, "%s: Invalid rsize value\n", | 1998 | cifs_dbg(VFS, "%s: Invalid rsize value\n", |
@@ -2609,7 +2658,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
2609 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | 2658 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
2610 | tcp_ses->session_estab = false; | 2659 | tcp_ses->session_estab = false; |
2611 | tcp_ses->sequence_number = 0; | 2660 | tcp_ses->sequence_number = 0; |
2612 | tcp_ses->reconnect_instance = 0; | 2661 | tcp_ses->reconnect_instance = 1; |
2613 | tcp_ses->lstrp = jiffies; | 2662 | tcp_ses->lstrp = jiffies; |
2614 | spin_lock_init(&tcp_ses->req_lock); | 2663 | spin_lock_init(&tcp_ses->req_lock); |
2615 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); | 2664 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); |
@@ -2770,7 +2819,7 @@ cifs_setup_ipc(struct cifs_ses *ses, struct smb_vol *volume_info) | |||
2770 | if (tcon == NULL) | 2819 | if (tcon == NULL) |
2771 | return -ENOMEM; | 2820 | return -ENOMEM; |
2772 | 2821 | ||
2773 | snprintf(unc, sizeof(unc), "\\\\%s\\IPC$", ses->server->hostname); | 2822 | scnprintf(unc, sizeof(unc), "\\\\%s\\IPC$", ses->server->hostname); |
2774 | 2823 | ||
2775 | /* cannot fail */ | 2824 | /* cannot fail */ |
2776 | nls_codepage = load_nls_default(); | 2825 | nls_codepage = load_nls_default(); |
@@ -3839,6 +3888,7 @@ int cifs_setup_cifs_sb(struct smb_vol *pvolume_info, | |||
3839 | spin_lock_init(&cifs_sb->tlink_tree_lock); | 3888 | spin_lock_init(&cifs_sb->tlink_tree_lock); |
3840 | cifs_sb->tlink_tree = RB_ROOT; | 3889 | cifs_sb->tlink_tree = RB_ROOT; |
3841 | 3890 | ||
3891 | cifs_sb->bsize = pvolume_info->bsize; | ||
3842 | /* | 3892 | /* |
3843 | * Temporarily set r/wsize for matching superblock. If we end up using | 3893 | * Temporarily set r/wsize for matching superblock. If we end up using |
3844 | * new sb then client will later negotiate it downward if needed. | 3894 | * new sb then client will later negotiate it downward if needed. |
@@ -4198,7 +4248,7 @@ static int update_vol_info(const struct dfs_cache_tgt_iterator *tgt_it, | |||
4198 | new_unc = kmalloc(len, GFP_KERNEL); | 4248 | new_unc = kmalloc(len, GFP_KERNEL); |
4199 | if (!new_unc) | 4249 | if (!new_unc) |
4200 | return -ENOMEM; | 4250 | return -ENOMEM; |
4201 | snprintf(new_unc, len, "\\%s", tgt); | 4251 | scnprintf(new_unc, len, "\\%s", tgt); |
4202 | 4252 | ||
4203 | kfree(vol->UNC); | 4253 | kfree(vol->UNC); |
4204 | vol->UNC = new_unc; | 4254 | vol->UNC = new_unc; |
@@ -4902,8 +4952,6 @@ cifs_negotiate_protocol(const unsigned int xid, struct cifs_ses *ses) | |||
4902 | if (!server->ops->need_neg(server)) | 4952 | if (!server->ops->need_neg(server)) |
4903 | return 0; | 4953 | return 0; |
4904 | 4954 | ||
4905 | set_credits(server, 1); | ||
4906 | |||
4907 | rc = server->ops->negotiate(xid, ses); | 4955 | rc = server->ops->negotiate(xid, ses); |
4908 | if (rc == 0) { | 4956 | if (rc == 0) { |
4909 | spin_lock(&GlobalMid_Lock); | 4957 | spin_lock(&GlobalMid_Lock); |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 659ce1b92c44..4c144c1f50eb 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -1842,24 +1842,30 @@ struct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode, | |||
1842 | return NULL; | 1842 | return NULL; |
1843 | } | 1843 | } |
1844 | 1844 | ||
1845 | struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | 1845 | /* Return -EBADF if no handle is found and general rc otherwise */ |
1846 | bool fsuid_only) | 1846 | int |
1847 | cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only, | ||
1848 | struct cifsFileInfo **ret_file) | ||
1847 | { | 1849 | { |
1848 | struct cifsFileInfo *open_file, *inv_file = NULL; | 1850 | struct cifsFileInfo *open_file, *inv_file = NULL; |
1849 | struct cifs_sb_info *cifs_sb; | 1851 | struct cifs_sb_info *cifs_sb; |
1850 | struct cifs_tcon *tcon; | 1852 | struct cifs_tcon *tcon; |
1851 | bool any_available = false; | 1853 | bool any_available = false; |
1852 | int rc; | 1854 | int rc = -EBADF; |
1853 | unsigned int refind = 0; | 1855 | unsigned int refind = 0; |
1854 | 1856 | ||
1855 | /* Having a null inode here (because mapping->host was set to zero by | 1857 | *ret_file = NULL; |
1856 | the VFS or MM) should not happen but we had reports of on oops (due to | 1858 | |
1857 | it being zero) during stress testcases so we need to check for it */ | 1859 | /* |
1860 | * Having a null inode here (because mapping->host was set to zero by | ||
1861 | * the VFS or MM) should not happen but we had reports of on oops (due | ||
1862 | * to it being zero) during stress testcases so we need to check for it | ||
1863 | */ | ||
1858 | 1864 | ||
1859 | if (cifs_inode == NULL) { | 1865 | if (cifs_inode == NULL) { |
1860 | cifs_dbg(VFS, "Null inode passed to cifs_writeable_file\n"); | 1866 | cifs_dbg(VFS, "Null inode passed to cifs_writeable_file\n"); |
1861 | dump_stack(); | 1867 | dump_stack(); |
1862 | return NULL; | 1868 | return rc; |
1863 | } | 1869 | } |
1864 | 1870 | ||
1865 | cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); | 1871 | cifs_sb = CIFS_SB(cifs_inode->vfs_inode.i_sb); |
@@ -1873,7 +1879,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode, | |||
1873 | refind_writable: | 1879 | refind_writable: |
1874 | if (refind > MAX_REOPEN_ATT) { | 1880 | if (refind > MAX_REOPEN_ATT) { |
1875 | spin_unlock(&tcon->open_file_lock); | 1881 | spin_unlock(&tcon->open_file_lock); |
1876 | return NULL; | 1882 | return rc; |
1877 | } | 1883 | } |
1878 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { | 1884 | list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { |
1879 | if (!any_available && open_file->pid != current->tgid) | 1885 | if (!any_available && open_file->pid != current->tgid) |
@@ -1885,7 +1891,8 @@ refind_writable: | |||
1885 | /* found a good writable file */ | 1891 | /* found a good writable file */ |
1886 | cifsFileInfo_get(open_file); | 1892 | cifsFileInfo_get(open_file); |
1887 | spin_unlock(&tcon->open_file_lock); | 1893 | spin_unlock(&tcon->open_file_lock); |
1888 | return open_file; | 1894 | *ret_file = open_file; |
1895 | return 0; | ||
1889 | } else { | 1896 | } else { |
1890 | if (!inv_file) | 1897 | if (!inv_file) |
1891 | inv_file = open_file; | 1898 | inv_file = open_file; |
@@ -1907,22 +1914,35 @@ refind_writable: | |||
1907 | 1914 | ||
1908 | if (inv_file) { | 1915 | if (inv_file) { |
1909 | rc = cifs_reopen_file(inv_file, false); | 1916 | rc = cifs_reopen_file(inv_file, false); |
1910 | if (!rc) | 1917 | if (!rc) { |
1911 | return inv_file; | 1918 | *ret_file = inv_file; |
1912 | else { | 1919 | return 0; |
1913 | spin_lock(&tcon->open_file_lock); | ||
1914 | list_move_tail(&inv_file->flist, | ||
1915 | &cifs_inode->openFileList); | ||
1916 | spin_unlock(&tcon->open_file_lock); | ||
1917 | cifsFileInfo_put(inv_file); | ||
1918 | ++refind; | ||
1919 | inv_file = NULL; | ||
1920 | spin_lock(&tcon->open_file_lock); | ||
1921 | goto refind_writable; | ||
1922 | } | 1920 | } |
1921 | |||
1922 | spin_lock(&tcon->open_file_lock); | ||
1923 | list_move_tail(&inv_file->flist, &cifs_inode->openFileList); | ||
1924 | spin_unlock(&tcon->open_file_lock); | ||
1925 | cifsFileInfo_put(inv_file); | ||
1926 | ++refind; | ||
1927 | inv_file = NULL; | ||
1928 | spin_lock(&tcon->open_file_lock); | ||
1929 | goto refind_writable; | ||
1923 | } | 1930 | } |
1924 | 1931 | ||
1925 | return NULL; | 1932 | return rc; |
1933 | } | ||
1934 | |||
1935 | struct cifsFileInfo * | ||
1936 | find_writable_file(struct cifsInodeInfo *cifs_inode, bool fsuid_only) | ||
1937 | { | ||
1938 | struct cifsFileInfo *cfile; | ||
1939 | int rc; | ||
1940 | |||
1941 | rc = cifs_get_writable_file(cifs_inode, fsuid_only, &cfile); | ||
1942 | if (rc) | ||
1943 | cifs_dbg(FYI, "couldn't find writable handle rc=%d", rc); | ||
1944 | |||
1945 | return cfile; | ||
1926 | } | 1946 | } |
1927 | 1947 | ||
1928 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | 1948 | static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) |
@@ -1959,8 +1979,8 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1959 | if (mapping->host->i_size - offset < (loff_t)to) | 1979 | if (mapping->host->i_size - offset < (loff_t)to) |
1960 | to = (unsigned)(mapping->host->i_size - offset); | 1980 | to = (unsigned)(mapping->host->i_size - offset); |
1961 | 1981 | ||
1962 | open_file = find_writable_file(CIFS_I(mapping->host), false); | 1982 | rc = cifs_get_writable_file(CIFS_I(mapping->host), false, &open_file); |
1963 | if (open_file) { | 1983 | if (!rc) { |
1964 | bytes_written = cifs_write(open_file, open_file->pid, | 1984 | bytes_written = cifs_write(open_file, open_file->pid, |
1965 | write_data, to - from, &offset); | 1985 | write_data, to - from, &offset); |
1966 | cifsFileInfo_put(open_file); | 1986 | cifsFileInfo_put(open_file); |
@@ -1970,9 +1990,12 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) | |||
1970 | rc = 0; | 1990 | rc = 0; |
1971 | else if (bytes_written < 0) | 1991 | else if (bytes_written < 0) |
1972 | rc = bytes_written; | 1992 | rc = bytes_written; |
1993 | else | ||
1994 | rc = -EFAULT; | ||
1973 | } else { | 1995 | } else { |
1974 | cifs_dbg(FYI, "No writeable filehandles for inode\n"); | 1996 | cifs_dbg(FYI, "No writable handle for write page rc=%d\n", rc); |
1975 | rc = -EIO; | 1997 | if (!is_retryable_error(rc)) |
1998 | rc = -EIO; | ||
1976 | } | 1999 | } |
1977 | 2000 | ||
1978 | kunmap(page); | 2001 | kunmap(page); |
@@ -2079,9 +2102,9 @@ static int | |||
2079 | wdata_send_pages(struct cifs_writedata *wdata, unsigned int nr_pages, | 2102 | wdata_send_pages(struct cifs_writedata *wdata, unsigned int nr_pages, |
2080 | struct address_space *mapping, struct writeback_control *wbc) | 2103 | struct address_space *mapping, struct writeback_control *wbc) |
2081 | { | 2104 | { |
2082 | int rc = 0; | 2105 | int rc; |
2083 | struct TCP_Server_Info *server; | 2106 | struct TCP_Server_Info *server = |
2084 | unsigned int i; | 2107 | tlink_tcon(wdata->cfile->tlink)->ses->server; |
2085 | 2108 | ||
2086 | wdata->sync_mode = wbc->sync_mode; | 2109 | wdata->sync_mode = wbc->sync_mode; |
2087 | wdata->nr_pages = nr_pages; | 2110 | wdata->nr_pages = nr_pages; |
@@ -2091,21 +2114,16 @@ wdata_send_pages(struct cifs_writedata *wdata, unsigned int nr_pages, | |||
2091 | page_offset(wdata->pages[nr_pages - 1]), | 2114 | page_offset(wdata->pages[nr_pages - 1]), |
2092 | (loff_t)PAGE_SIZE); | 2115 | (loff_t)PAGE_SIZE); |
2093 | wdata->bytes = ((nr_pages - 1) * PAGE_SIZE) + wdata->tailsz; | 2116 | wdata->bytes = ((nr_pages - 1) * PAGE_SIZE) + wdata->tailsz; |
2117 | wdata->pid = wdata->cfile->pid; | ||
2094 | 2118 | ||
2095 | if (wdata->cfile != NULL) | 2119 | rc = adjust_credits(server, &wdata->credits, wdata->bytes); |
2096 | cifsFileInfo_put(wdata->cfile); | 2120 | if (rc) |
2097 | wdata->cfile = find_writable_file(CIFS_I(mapping->host), false); | 2121 | return rc; |
2098 | if (!wdata->cfile) { | ||
2099 | cifs_dbg(VFS, "No writable handles for inode\n"); | ||
2100 | rc = -EBADF; | ||
2101 | } else { | ||
2102 | wdata->pid = wdata->cfile->pid; | ||
2103 | server = tlink_tcon(wdata->cfile->tlink)->ses->server; | ||
2104 | rc = server->ops->async_writev(wdata, cifs_writedata_release); | ||
2105 | } | ||
2106 | 2122 | ||
2107 | for (i = 0; i < nr_pages; ++i) | 2123 | if (wdata->cfile->invalidHandle) |
2108 | unlock_page(wdata->pages[i]); | 2124 | rc = -EAGAIN; |
2125 | else | ||
2126 | rc = server->ops->async_writev(wdata, cifs_writedata_release); | ||
2109 | 2127 | ||
2110 | return rc; | 2128 | return rc; |
2111 | } | 2129 | } |
@@ -2113,11 +2131,13 @@ wdata_send_pages(struct cifs_writedata *wdata, unsigned int nr_pages, | |||
2113 | static int cifs_writepages(struct address_space *mapping, | 2131 | static int cifs_writepages(struct address_space *mapping, |
2114 | struct writeback_control *wbc) | 2132 | struct writeback_control *wbc) |
2115 | { | 2133 | { |
2116 | struct cifs_sb_info *cifs_sb = CIFS_SB(mapping->host->i_sb); | 2134 | struct inode *inode = mapping->host; |
2135 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | ||
2117 | struct TCP_Server_Info *server; | 2136 | struct TCP_Server_Info *server; |
2118 | bool done = false, scanned = false, range_whole = false; | 2137 | bool done = false, scanned = false, range_whole = false; |
2119 | pgoff_t end, index; | 2138 | pgoff_t end, index; |
2120 | struct cifs_writedata *wdata; | 2139 | struct cifs_writedata *wdata; |
2140 | struct cifsFileInfo *cfile = NULL; | ||
2121 | int rc = 0; | 2141 | int rc = 0; |
2122 | int saved_rc = 0; | 2142 | int saved_rc = 0; |
2123 | unsigned int xid; | 2143 | unsigned int xid; |
@@ -2143,11 +2163,23 @@ static int cifs_writepages(struct address_space *mapping, | |||
2143 | server = cifs_sb_master_tcon(cifs_sb)->ses->server; | 2163 | server = cifs_sb_master_tcon(cifs_sb)->ses->server; |
2144 | retry: | 2164 | retry: |
2145 | while (!done && index <= end) { | 2165 | while (!done && index <= end) { |
2146 | unsigned int i, nr_pages, found_pages, wsize, credits; | 2166 | unsigned int i, nr_pages, found_pages, wsize; |
2147 | pgoff_t next = 0, tofind, saved_index = index; | 2167 | pgoff_t next = 0, tofind, saved_index = index; |
2168 | struct cifs_credits credits_on_stack; | ||
2169 | struct cifs_credits *credits = &credits_on_stack; | ||
2170 | int get_file_rc = 0; | ||
2171 | |||
2172 | if (cfile) | ||
2173 | cifsFileInfo_put(cfile); | ||
2174 | |||
2175 | rc = cifs_get_writable_file(CIFS_I(inode), false, &cfile); | ||
2176 | |||
2177 | /* in case of an error store it to return later */ | ||
2178 | if (rc) | ||
2179 | get_file_rc = rc; | ||
2148 | 2180 | ||
2149 | rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, | 2181 | rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, |
2150 | &wsize, &credits); | 2182 | &wsize, credits); |
2151 | if (rc != 0) { | 2183 | if (rc != 0) { |
2152 | done = true; | 2184 | done = true; |
2153 | break; | 2185 | break; |
@@ -2180,13 +2212,26 @@ retry: | |||
2180 | continue; | 2212 | continue; |
2181 | } | 2213 | } |
2182 | 2214 | ||
2183 | wdata->credits = credits; | 2215 | wdata->credits = credits_on_stack; |
2216 | wdata->cfile = cfile; | ||
2217 | cfile = NULL; | ||
2184 | 2218 | ||
2185 | rc = wdata_send_pages(wdata, nr_pages, mapping, wbc); | 2219 | if (!wdata->cfile) { |
2220 | cifs_dbg(VFS, "No writable handle in writepages rc=%d\n", | ||
2221 | get_file_rc); | ||
2222 | if (is_retryable_error(get_file_rc)) | ||
2223 | rc = get_file_rc; | ||
2224 | else | ||
2225 | rc = -EBADF; | ||
2226 | } else | ||
2227 | rc = wdata_send_pages(wdata, nr_pages, mapping, wbc); | ||
2228 | |||
2229 | for (i = 0; i < nr_pages; ++i) | ||
2230 | unlock_page(wdata->pages[i]); | ||
2186 | 2231 | ||
2187 | /* send failure -- clean up the mess */ | 2232 | /* send failure -- clean up the mess */ |
2188 | if (rc != 0) { | 2233 | if (rc != 0) { |
2189 | add_credits_and_wake_if(server, wdata->credits, 0); | 2234 | add_credits_and_wake_if(server, &wdata->credits, 0); |
2190 | for (i = 0; i < nr_pages; ++i) { | 2235 | for (i = 0; i < nr_pages; ++i) { |
2191 | if (is_retryable_error(rc)) | 2236 | if (is_retryable_error(rc)) |
2192 | redirty_page_for_writepage(wbc, | 2237 | redirty_page_for_writepage(wbc, |
@@ -2238,6 +2283,8 @@ retry: | |||
2238 | if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) | 2283 | if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) |
2239 | mapping->writeback_index = index; | 2284 | mapping->writeback_index = index; |
2240 | 2285 | ||
2286 | if (cfile) | ||
2287 | cifsFileInfo_put(cfile); | ||
2241 | free_xid(xid); | 2288 | free_xid(xid); |
2242 | return rc; | 2289 | return rc; |
2243 | } | 2290 | } |
@@ -2567,7 +2614,8 @@ static int | |||
2567 | cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, | 2614 | cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, |
2568 | struct cifs_aio_ctx *ctx) | 2615 | struct cifs_aio_ctx *ctx) |
2569 | { | 2616 | { |
2570 | unsigned int wsize, credits; | 2617 | unsigned int wsize; |
2618 | struct cifs_credits credits; | ||
2571 | int rc; | 2619 | int rc; |
2572 | struct TCP_Server_Info *server = | 2620 | struct TCP_Server_Info *server = |
2573 | tlink_tcon(wdata->cfile->tlink)->ses->server; | 2621 | tlink_tcon(wdata->cfile->tlink)->ses->server; |
@@ -2577,18 +2625,19 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, | |||
2577 | * Note: we are attempting to resend the whole wdata not in segments | 2625 | * Note: we are attempting to resend the whole wdata not in segments |
2578 | */ | 2626 | */ |
2579 | do { | 2627 | do { |
2580 | rc = server->ops->wait_mtu_credits( | 2628 | rc = server->ops->wait_mtu_credits(server, wdata->bytes, &wsize, |
2581 | server, wdata->bytes, &wsize, &credits); | 2629 | &credits); |
2582 | 2630 | ||
2583 | if (rc) | 2631 | if (rc) |
2584 | goto out; | 2632 | goto out; |
2585 | 2633 | ||
2586 | if (wsize < wdata->bytes) { | 2634 | if (wsize < wdata->bytes) { |
2587 | add_credits_and_wake_if(server, credits, 0); | 2635 | add_credits_and_wake_if(server, &credits, 0); |
2588 | msleep(1000); | 2636 | msleep(1000); |
2589 | } | 2637 | } |
2590 | } while (wsize < wdata->bytes); | 2638 | } while (wsize < wdata->bytes); |
2591 | 2639 | ||
2640 | wdata->credits = credits; | ||
2592 | rc = -EAGAIN; | 2641 | rc = -EAGAIN; |
2593 | while (rc == -EAGAIN) { | 2642 | while (rc == -EAGAIN) { |
2594 | rc = 0; | 2643 | rc = 0; |
@@ -2604,7 +2653,7 @@ cifs_resend_wdata(struct cifs_writedata *wdata, struct list_head *wdata_list, | |||
2604 | return 0; | 2653 | return 0; |
2605 | } | 2654 | } |
2606 | 2655 | ||
2607 | add_credits_and_wake_if(server, wdata->credits, 0); | 2656 | add_credits_and_wake_if(server, &wdata->credits, 0); |
2608 | out: | 2657 | out: |
2609 | kref_put(&wdata->refcount, cifs_uncached_writedata_release); | 2658 | kref_put(&wdata->refcount, cifs_uncached_writedata_release); |
2610 | 2659 | ||
@@ -2627,6 +2676,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, | |||
2627 | struct TCP_Server_Info *server; | 2676 | struct TCP_Server_Info *server; |
2628 | struct page **pagevec; | 2677 | struct page **pagevec; |
2629 | size_t start; | 2678 | size_t start; |
2679 | unsigned int xid; | ||
2630 | 2680 | ||
2631 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) | 2681 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_RWPIDFORWARD) |
2632 | pid = open_file->pid; | 2682 | pid = open_file->pid; |
@@ -2634,12 +2684,23 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, | |||
2634 | pid = current->tgid; | 2684 | pid = current->tgid; |
2635 | 2685 | ||
2636 | server = tlink_tcon(open_file->tlink)->ses->server; | 2686 | server = tlink_tcon(open_file->tlink)->ses->server; |
2687 | xid = get_xid(); | ||
2637 | 2688 | ||
2638 | do { | 2689 | do { |
2639 | unsigned int wsize, credits; | 2690 | unsigned int wsize; |
2691 | struct cifs_credits credits_on_stack; | ||
2692 | struct cifs_credits *credits = &credits_on_stack; | ||
2693 | |||
2694 | if (open_file->invalidHandle) { | ||
2695 | rc = cifs_reopen_file(open_file, false); | ||
2696 | if (rc == -EAGAIN) | ||
2697 | continue; | ||
2698 | else if (rc) | ||
2699 | break; | ||
2700 | } | ||
2640 | 2701 | ||
2641 | rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, | 2702 | rc = server->ops->wait_mtu_credits(server, cifs_sb->wsize, |
2642 | &wsize, &credits); | 2703 | &wsize, credits); |
2643 | if (rc) | 2704 | if (rc) |
2644 | break; | 2705 | break; |
2645 | 2706 | ||
@@ -2731,16 +2792,22 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, | |||
2731 | wdata->pid = pid; | 2792 | wdata->pid = pid; |
2732 | wdata->bytes = cur_len; | 2793 | wdata->bytes = cur_len; |
2733 | wdata->pagesz = PAGE_SIZE; | 2794 | wdata->pagesz = PAGE_SIZE; |
2734 | wdata->credits = credits; | 2795 | wdata->credits = credits_on_stack; |
2735 | wdata->ctx = ctx; | 2796 | wdata->ctx = ctx; |
2736 | kref_get(&ctx->refcount); | 2797 | kref_get(&ctx->refcount); |
2737 | 2798 | ||
2738 | if (!wdata->cfile->invalidHandle || | 2799 | rc = adjust_credits(server, &wdata->credits, wdata->bytes); |
2739 | !(rc = cifs_reopen_file(wdata->cfile, false))) | 2800 | |
2740 | rc = server->ops->async_writev(wdata, | 2801 | if (!rc) { |
2802 | if (wdata->cfile->invalidHandle) | ||
2803 | rc = -EAGAIN; | ||
2804 | else | ||
2805 | rc = server->ops->async_writev(wdata, | ||
2741 | cifs_uncached_writedata_release); | 2806 | cifs_uncached_writedata_release); |
2807 | } | ||
2808 | |||
2742 | if (rc) { | 2809 | if (rc) { |
2743 | add_credits_and_wake_if(server, wdata->credits, 0); | 2810 | add_credits_and_wake_if(server, &wdata->credits, 0); |
2744 | kref_put(&wdata->refcount, | 2811 | kref_put(&wdata->refcount, |
2745 | cifs_uncached_writedata_release); | 2812 | cifs_uncached_writedata_release); |
2746 | if (rc == -EAGAIN) { | 2813 | if (rc == -EAGAIN) { |
@@ -2756,6 +2823,7 @@ cifs_write_from_iter(loff_t offset, size_t len, struct iov_iter *from, | |||
2756 | len -= cur_len; | 2823 | len -= cur_len; |
2757 | } while (len > 0); | 2824 | } while (len > 0); |
2758 | 2825 | ||
2826 | free_xid(xid); | ||
2759 | return rc; | 2827 | return rc; |
2760 | } | 2828 | } |
2761 | 2829 | ||
@@ -3028,14 +3096,16 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from) | |||
3028 | * these pages but not on the region from pos to ppos+len-1. | 3096 | * these pages but not on the region from pos to ppos+len-1. |
3029 | */ | 3097 | */ |
3030 | written = cifs_user_writev(iocb, from); | 3098 | written = cifs_user_writev(iocb, from); |
3031 | if (written > 0 && CIFS_CACHE_READ(cinode)) { | 3099 | if (CIFS_CACHE_READ(cinode)) { |
3032 | /* | 3100 | /* |
3033 | * Windows 7 server can delay breaking level2 oplock if a write | 3101 | * We have read level caching and we have just sent a write |
3034 | * request comes - break it on the client to prevent reading | 3102 | * request to the server thus making data in the cache stale. |
3035 | * an old data. | 3103 | * Zap the cache and set oplock/lease level to NONE to avoid |
3104 | * reading stale data from the cache. All subsequent read | ||
3105 | * operations will read new data from the server. | ||
3036 | */ | 3106 | */ |
3037 | cifs_zap_mapping(inode); | 3107 | cifs_zap_mapping(inode); |
3038 | cifs_dbg(FYI, "Set no oplock for inode=%p after a write operation\n", | 3108 | cifs_dbg(FYI, "Set Oplock/Lease to NONE for inode=%p after write\n", |
3039 | inode); | 3109 | inode); |
3040 | cinode->oplock = 0; | 3110 | cinode->oplock = 0; |
3041 | } | 3111 | } |
@@ -3260,7 +3330,8 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata, | |||
3260 | struct list_head *rdata_list, | 3330 | struct list_head *rdata_list, |
3261 | struct cifs_aio_ctx *ctx) | 3331 | struct cifs_aio_ctx *ctx) |
3262 | { | 3332 | { |
3263 | unsigned int rsize, credits; | 3333 | unsigned int rsize; |
3334 | struct cifs_credits credits; | ||
3264 | int rc; | 3335 | int rc; |
3265 | struct TCP_Server_Info *server = | 3336 | struct TCP_Server_Info *server = |
3266 | tlink_tcon(rdata->cfile->tlink)->ses->server; | 3337 | tlink_tcon(rdata->cfile->tlink)->ses->server; |
@@ -3277,11 +3348,12 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata, | |||
3277 | goto out; | 3348 | goto out; |
3278 | 3349 | ||
3279 | if (rsize < rdata->bytes) { | 3350 | if (rsize < rdata->bytes) { |
3280 | add_credits_and_wake_if(server, credits, 0); | 3351 | add_credits_and_wake_if(server, &credits, 0); |
3281 | msleep(1000); | 3352 | msleep(1000); |
3282 | } | 3353 | } |
3283 | } while (rsize < rdata->bytes); | 3354 | } while (rsize < rdata->bytes); |
3284 | 3355 | ||
3356 | rdata->credits = credits; | ||
3285 | rc = -EAGAIN; | 3357 | rc = -EAGAIN; |
3286 | while (rc == -EAGAIN) { | 3358 | while (rc == -EAGAIN) { |
3287 | rc = 0; | 3359 | rc = 0; |
@@ -3297,7 +3369,7 @@ static int cifs_resend_rdata(struct cifs_readdata *rdata, | |||
3297 | return 0; | 3369 | return 0; |
3298 | } | 3370 | } |
3299 | 3371 | ||
3300 | add_credits_and_wake_if(server, rdata->credits, 0); | 3372 | add_credits_and_wake_if(server, &rdata->credits, 0); |
3301 | out: | 3373 | out: |
3302 | kref_put(&rdata->refcount, | 3374 | kref_put(&rdata->refcount, |
3303 | cifs_uncached_readdata_release); | 3375 | cifs_uncached_readdata_release); |
@@ -3311,7 +3383,9 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, | |||
3311 | struct cifs_aio_ctx *ctx) | 3383 | struct cifs_aio_ctx *ctx) |
3312 | { | 3384 | { |
3313 | struct cifs_readdata *rdata; | 3385 | struct cifs_readdata *rdata; |
3314 | unsigned int npages, rsize, credits; | 3386 | unsigned int npages, rsize; |
3387 | struct cifs_credits credits_on_stack; | ||
3388 | struct cifs_credits *credits = &credits_on_stack; | ||
3315 | size_t cur_len; | 3389 | size_t cur_len; |
3316 | int rc; | 3390 | int rc; |
3317 | pid_t pid; | 3391 | pid_t pid; |
@@ -3331,8 +3405,16 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, | |||
3331 | iov_iter_advance(&direct_iov, offset - ctx->pos); | 3405 | iov_iter_advance(&direct_iov, offset - ctx->pos); |
3332 | 3406 | ||
3333 | do { | 3407 | do { |
3408 | if (open_file->invalidHandle) { | ||
3409 | rc = cifs_reopen_file(open_file, true); | ||
3410 | if (rc == -EAGAIN) | ||
3411 | continue; | ||
3412 | else if (rc) | ||
3413 | break; | ||
3414 | } | ||
3415 | |||
3334 | rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, | 3416 | rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, |
3335 | &rsize, &credits); | 3417 | &rsize, credits); |
3336 | if (rc) | 3418 | if (rc) |
3337 | break; | 3419 | break; |
3338 | 3420 | ||
@@ -3406,15 +3488,21 @@ cifs_send_async_read(loff_t offset, size_t len, struct cifsFileInfo *open_file, | |||
3406 | rdata->pagesz = PAGE_SIZE; | 3488 | rdata->pagesz = PAGE_SIZE; |
3407 | rdata->read_into_pages = cifs_uncached_read_into_pages; | 3489 | rdata->read_into_pages = cifs_uncached_read_into_pages; |
3408 | rdata->copy_into_pages = cifs_uncached_copy_into_pages; | 3490 | rdata->copy_into_pages = cifs_uncached_copy_into_pages; |
3409 | rdata->credits = credits; | 3491 | rdata->credits = credits_on_stack; |
3410 | rdata->ctx = ctx; | 3492 | rdata->ctx = ctx; |
3411 | kref_get(&ctx->refcount); | 3493 | kref_get(&ctx->refcount); |
3412 | 3494 | ||
3413 | if (!rdata->cfile->invalidHandle || | 3495 | rc = adjust_credits(server, &rdata->credits, rdata->bytes); |
3414 | !(rc = cifs_reopen_file(rdata->cfile, true))) | 3496 | |
3415 | rc = server->ops->async_readv(rdata); | 3497 | if (!rc) { |
3498 | if (rdata->cfile->invalidHandle) | ||
3499 | rc = -EAGAIN; | ||
3500 | else | ||
3501 | rc = server->ops->async_readv(rdata); | ||
3502 | } | ||
3503 | |||
3416 | if (rc) { | 3504 | if (rc) { |
3417 | add_credits_and_wake_if(server, rdata->credits, 0); | 3505 | add_credits_and_wake_if(server, &rdata->credits, 0); |
3418 | kref_put(&rdata->refcount, | 3506 | kref_put(&rdata->refcount, |
3419 | cifs_uncached_readdata_release); | 3507 | cifs_uncached_readdata_release); |
3420 | if (rc == -EAGAIN) { | 3508 | if (rc == -EAGAIN) { |
@@ -3533,8 +3621,6 @@ again: | |||
3533 | ctx->total_len = ctx->len - iov_iter_count(to); | 3621 | ctx->total_len = ctx->len - iov_iter_count(to); |
3534 | } | 3622 | } |
3535 | 3623 | ||
3536 | cifs_stats_bytes_read(tcon, ctx->total_len); | ||
3537 | |||
3538 | /* mask nodata case */ | 3624 | /* mask nodata case */ |
3539 | if (rc == -ENODATA) | 3625 | if (rc == -ENODATA) |
3540 | rc = 0; | 3626 | rc = 0; |
@@ -4095,10 +4181,19 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
4095 | loff_t offset; | 4181 | loff_t offset; |
4096 | struct page *page, *tpage; | 4182 | struct page *page, *tpage; |
4097 | struct cifs_readdata *rdata; | 4183 | struct cifs_readdata *rdata; |
4098 | unsigned credits; | 4184 | struct cifs_credits credits_on_stack; |
4185 | struct cifs_credits *credits = &credits_on_stack; | ||
4186 | |||
4187 | if (open_file->invalidHandle) { | ||
4188 | rc = cifs_reopen_file(open_file, true); | ||
4189 | if (rc == -EAGAIN) | ||
4190 | continue; | ||
4191 | else if (rc) | ||
4192 | break; | ||
4193 | } | ||
4099 | 4194 | ||
4100 | rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, | 4195 | rc = server->ops->wait_mtu_credits(server, cifs_sb->rsize, |
4101 | &rsize, &credits); | 4196 | &rsize, credits); |
4102 | if (rc) | 4197 | if (rc) |
4103 | break; | 4198 | break; |
4104 | 4199 | ||
@@ -4144,18 +4239,24 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, | |||
4144 | rdata->tailsz = PAGE_SIZE; | 4239 | rdata->tailsz = PAGE_SIZE; |
4145 | rdata->read_into_pages = cifs_readpages_read_into_pages; | 4240 | rdata->read_into_pages = cifs_readpages_read_into_pages; |
4146 | rdata->copy_into_pages = cifs_readpages_copy_into_pages; | 4241 | rdata->copy_into_pages = cifs_readpages_copy_into_pages; |
4147 | rdata->credits = credits; | 4242 | rdata->credits = credits_on_stack; |
4148 | 4243 | ||
4149 | list_for_each_entry_safe(page, tpage, &tmplist, lru) { | 4244 | list_for_each_entry_safe(page, tpage, &tmplist, lru) { |
4150 | list_del(&page->lru); | 4245 | list_del(&page->lru); |
4151 | rdata->pages[rdata->nr_pages++] = page; | 4246 | rdata->pages[rdata->nr_pages++] = page; |
4152 | } | 4247 | } |
4153 | 4248 | ||
4154 | if (!rdata->cfile->invalidHandle || | 4249 | rc = adjust_credits(server, &rdata->credits, rdata->bytes); |
4155 | !(rc = cifs_reopen_file(rdata->cfile, true))) | 4250 | |
4156 | rc = server->ops->async_readv(rdata); | 4251 | if (!rc) { |
4252 | if (rdata->cfile->invalidHandle) | ||
4253 | rc = -EAGAIN; | ||
4254 | else | ||
4255 | rc = server->ops->async_readv(rdata); | ||
4256 | } | ||
4257 | |||
4157 | if (rc) { | 4258 | if (rc) { |
4158 | add_credits_and_wake_if(server, rdata->credits, 0); | 4259 | add_credits_and_wake_if(server, &rdata->credits, 0); |
4159 | for (i = 0; i < rdata->nr_pages; i++) { | 4260 | for (i = 0; i < rdata->nr_pages; i++) { |
4160 | page = rdata->pages[i]; | 4261 | page = rdata->pages[i]; |
4161 | lru_cache_add_file(page); | 4262 | lru_cache_add_file(page); |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 478003644916..53fdb5df0d2e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
@@ -2080,7 +2080,7 @@ int cifs_getattr(const struct path *path, struct kstat *stat, | |||
2080 | return rc; | 2080 | return rc; |
2081 | 2081 | ||
2082 | generic_fillattr(inode, stat); | 2082 | generic_fillattr(inode, stat); |
2083 | stat->blksize = CIFS_MAX_MSGSIZE; | 2083 | stat->blksize = cifs_sb->bsize; |
2084 | stat->ino = CIFS_I(inode)->uniqueid; | 2084 | stat->ino = CIFS_I(inode)->uniqueid; |
2085 | 2085 | ||
2086 | /* old CIFS Unix Extensions doesn't return create time */ | 2086 | /* old CIFS Unix Extensions doesn't return create time */ |
diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 2148b0f60e5e..62216dc8f9f5 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c | |||
@@ -103,9 +103,9 @@ parse_mf_symlink(const u8 *buf, unsigned int buf_len, unsigned int *_link_len, | |||
103 | return rc; | 103 | return rc; |
104 | } | 104 | } |
105 | 105 | ||
106 | snprintf(md5_str2, sizeof(md5_str2), | 106 | scnprintf(md5_str2, sizeof(md5_str2), |
107 | CIFS_MF_SYMLINK_MD5_FORMAT, | 107 | CIFS_MF_SYMLINK_MD5_FORMAT, |
108 | CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); | 108 | CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); |
109 | 109 | ||
110 | if (strncmp(md5_str1, md5_str2, 17) != 0) | 110 | if (strncmp(md5_str1, md5_str2, 17) != 0) |
111 | return -EINVAL; | 111 | return -EINVAL; |
@@ -142,10 +142,10 @@ format_mf_symlink(u8 *buf, unsigned int buf_len, const char *link_str) | |||
142 | return rc; | 142 | return rc; |
143 | } | 143 | } |
144 | 144 | ||
145 | snprintf(buf, buf_len, | 145 | scnprintf(buf, buf_len, |
146 | CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT, | 146 | CIFS_MF_SYMLINK_LEN_FORMAT CIFS_MF_SYMLINK_MD5_FORMAT, |
147 | link_len, | 147 | link_len, |
148 | CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); | 148 | CIFS_MF_SYMLINK_MD5_ARGS(md5_hash)); |
149 | 149 | ||
150 | ofs = CIFS_MF_SYMLINK_LINK_OFFSET; | 150 | ofs = CIFS_MF_SYMLINK_LINK_OFFSET; |
151 | memcpy(buf + ofs, link_str, link_len); | 151 | memcpy(buf + ofs, link_str, link_len); |
diff --git a/fs/cifs/smb1ops.c b/fs/cifs/smb1ops.c index 32a6c020478f..f0ce27c3c6e4 100644 --- a/fs/cifs/smb1ops.c +++ b/fs/cifs/smb1ops.c | |||
@@ -117,11 +117,11 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buffer) | |||
117 | } | 117 | } |
118 | 118 | ||
119 | static void | 119 | static void |
120 | cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add, | 120 | cifs_add_credits(struct TCP_Server_Info *server, |
121 | const int optype) | 121 | const struct cifs_credits *credits, const int optype) |
122 | { | 122 | { |
123 | spin_lock(&server->req_lock); | 123 | spin_lock(&server->req_lock); |
124 | server->credits += add; | 124 | server->credits += credits->value; |
125 | server->in_flight--; | 125 | server->in_flight--; |
126 | spin_unlock(&server->req_lock); | 126 | spin_unlock(&server->req_lock); |
127 | wake_up(&server->request_q); | 127 | wake_up(&server->request_q); |
@@ -308,7 +308,7 @@ coalesce_t2(char *second_buf, struct smb_hdr *target_hdr) | |||
308 | remaining = tgt_total_cnt - total_in_tgt; | 308 | remaining = tgt_total_cnt - total_in_tgt; |
309 | 309 | ||
310 | if (remaining < 0) { | 310 | if (remaining < 0) { |
311 | cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%hu\n", | 311 | cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=%hu total_in_tgt=%u\n", |
312 | tgt_total_cnt, total_in_tgt); | 312 | tgt_total_cnt, total_in_tgt); |
313 | return -EPROTO; | 313 | return -EPROTO; |
314 | } | 314 | } |
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c index 7b8b58fb4d3f..0e3570e40ff8 100644 --- a/fs/cifs/smb2misc.c +++ b/fs/cifs/smb2misc.c | |||
@@ -517,7 +517,6 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, | |||
517 | __u8 lease_state; | 517 | __u8 lease_state; |
518 | struct list_head *tmp; | 518 | struct list_head *tmp; |
519 | struct cifsFileInfo *cfile; | 519 | struct cifsFileInfo *cfile; |
520 | struct TCP_Server_Info *server = tcon->ses->server; | ||
521 | struct cifs_pending_open *open; | 520 | struct cifs_pending_open *open; |
522 | struct cifsInodeInfo *cinode; | 521 | struct cifsInodeInfo *cinode; |
523 | int ack_req = le32_to_cpu(rsp->Flags & | 522 | int ack_req = le32_to_cpu(rsp->Flags & |
@@ -537,13 +536,25 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, | |||
537 | cifs_dbg(FYI, "lease key match, lease break 0x%x\n", | 536 | cifs_dbg(FYI, "lease key match, lease break 0x%x\n", |
538 | le32_to_cpu(rsp->NewLeaseState)); | 537 | le32_to_cpu(rsp->NewLeaseState)); |
539 | 538 | ||
540 | server->ops->set_oplock_level(cinode, lease_state, 0, NULL); | ||
541 | |||
542 | if (ack_req) | 539 | if (ack_req) |
543 | cfile->oplock_break_cancelled = false; | 540 | cfile->oplock_break_cancelled = false; |
544 | else | 541 | else |
545 | cfile->oplock_break_cancelled = true; | 542 | cfile->oplock_break_cancelled = true; |
546 | 543 | ||
544 | set_bit(CIFS_INODE_PENDING_OPLOCK_BREAK, &cinode->flags); | ||
545 | |||
546 | /* | ||
547 | * Set or clear flags depending on the lease state being READ. | ||
548 | * HANDLE caching flag should be added when the client starts | ||
549 | * to defer closing remote file handles with HANDLE leases. | ||
550 | */ | ||
551 | if (lease_state & SMB2_LEASE_READ_CACHING_HE) | ||
552 | set_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, | ||
553 | &cinode->flags); | ||
554 | else | ||
555 | clear_bit(CIFS_INODE_DOWNGRADE_OPLOCK_TO_L2, | ||
556 | &cinode->flags); | ||
557 | |||
547 | queue_work(cifsoplockd_wq, &cfile->oplock_break); | 558 | queue_work(cifsoplockd_wq, &cfile->oplock_break); |
548 | kfree(lw); | 559 | kfree(lw); |
549 | return true; | 560 | return true; |
@@ -648,13 +659,6 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) | |||
648 | if (rsp->sync_hdr.Command != SMB2_OPLOCK_BREAK) | 659 | if (rsp->sync_hdr.Command != SMB2_OPLOCK_BREAK) |
649 | return false; | 660 | return false; |
650 | 661 | ||
651 | if (rsp->sync_hdr.CreditRequest) { | ||
652 | spin_lock(&server->req_lock); | ||
653 | server->credits += le16_to_cpu(rsp->sync_hdr.CreditRequest); | ||
654 | spin_unlock(&server->req_lock); | ||
655 | wake_up(&server->request_q); | ||
656 | } | ||
657 | |||
658 | if (rsp->StructureSize != | 662 | if (rsp->StructureSize != |
659 | smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) { | 663 | smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) { |
660 | if (le16_to_cpu(rsp->StructureSize) == 44) | 664 | if (le16_to_cpu(rsp->StructureSize) == 44) |
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c index 6f96e2292856..085e91436da7 100644 --- a/fs/cifs/smb2ops.c +++ b/fs/cifs/smb2ops.c | |||
@@ -67,10 +67,13 @@ change_conf(struct TCP_Server_Info *server) | |||
67 | } | 67 | } |
68 | 68 | ||
69 | static void | 69 | static void |
70 | smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, | 70 | smb2_add_credits(struct TCP_Server_Info *server, |
71 | const int optype) | 71 | const struct cifs_credits *credits, const int optype) |
72 | { | 72 | { |
73 | int *val, rc = -1; | 73 | int *val, rc = -1; |
74 | unsigned int add = credits->value; | ||
75 | unsigned int instance = credits->instance; | ||
76 | bool reconnect_detected = false; | ||
74 | 77 | ||
75 | spin_lock(&server->req_lock); | 78 | spin_lock(&server->req_lock); |
76 | val = server->ops->get_credits_field(server, optype); | 79 | val = server->ops->get_credits_field(server, optype); |
@@ -79,8 +82,11 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, | |||
79 | if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0)) | 82 | if (((optype & CIFS_OP_MASK) == CIFS_NEG_OP) && (*val != 0)) |
80 | trace_smb3_reconnect_with_invalid_credits(server->CurrentMid, | 83 | trace_smb3_reconnect_with_invalid_credits(server->CurrentMid, |
81 | server->hostname, *val); | 84 | server->hostname, *val); |
85 | if ((instance == 0) || (instance == server->reconnect_instance)) | ||
86 | *val += add; | ||
87 | else | ||
88 | reconnect_detected = true; | ||
82 | 89 | ||
83 | *val += add; | ||
84 | if (*val > 65000) { | 90 | if (*val > 65000) { |
85 | *val = 65000; /* Don't get near 64K credits, avoid srv bugs */ | 91 | *val = 65000; /* Don't get near 64K credits, avoid srv bugs */ |
86 | printk_once(KERN_WARNING "server overflowed SMB3 credits\n"); | 92 | printk_once(KERN_WARNING "server overflowed SMB3 credits\n"); |
@@ -102,7 +108,12 @@ smb2_add_credits(struct TCP_Server_Info *server, const unsigned int add, | |||
102 | spin_unlock(&server->req_lock); | 108 | spin_unlock(&server->req_lock); |
103 | wake_up(&server->request_q); | 109 | wake_up(&server->request_q); |
104 | 110 | ||
105 | if (server->tcpStatus == CifsNeedReconnect) | 111 | if (reconnect_detected) |
112 | cifs_dbg(FYI, "trying to put %d credits from the old server instance %d\n", | ||
113 | add, instance); | ||
114 | |||
115 | if (server->tcpStatus == CifsNeedReconnect | ||
116 | || server->tcpStatus == CifsExiting) | ||
106 | return; | 117 | return; |
107 | 118 | ||
108 | switch (rc) { | 119 | switch (rc) { |
@@ -163,7 +174,7 @@ smb2_get_credits(struct mid_q_entry *mid) | |||
163 | 174 | ||
164 | static int | 175 | static int |
165 | smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, | 176 | smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, |
166 | unsigned int *num, unsigned int *credits) | 177 | unsigned int *num, struct cifs_credits *credits) |
167 | { | 178 | { |
168 | int rc = 0; | 179 | int rc = 0; |
169 | unsigned int scredits; | 180 | unsigned int scredits; |
@@ -189,7 +200,8 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, | |||
189 | /* can deadlock with reopen */ | 200 | /* can deadlock with reopen */ |
190 | if (scredits <= 8) { | 201 | if (scredits <= 8) { |
191 | *num = SMB2_MAX_BUFFER_SIZE; | 202 | *num = SMB2_MAX_BUFFER_SIZE; |
192 | *credits = 0; | 203 | credits->value = 0; |
204 | credits->instance = 0; | ||
193 | break; | 205 | break; |
194 | } | 206 | } |
195 | 207 | ||
@@ -198,8 +210,10 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, | |||
198 | *num = min_t(unsigned int, size, | 210 | *num = min_t(unsigned int, size, |
199 | scredits * SMB2_MAX_BUFFER_SIZE); | 211 | scredits * SMB2_MAX_BUFFER_SIZE); |
200 | 212 | ||
201 | *credits = DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); | 213 | credits->value = |
202 | server->credits -= *credits; | 214 | DIV_ROUND_UP(*num, SMB2_MAX_BUFFER_SIZE); |
215 | credits->instance = server->reconnect_instance; | ||
216 | server->credits -= credits->value; | ||
203 | server->in_flight++; | 217 | server->in_flight++; |
204 | break; | 218 | break; |
205 | } | 219 | } |
@@ -208,6 +222,38 @@ smb2_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, | |||
208 | return rc; | 222 | return rc; |
209 | } | 223 | } |
210 | 224 | ||
225 | static int | ||
226 | smb2_adjust_credits(struct TCP_Server_Info *server, | ||
227 | struct cifs_credits *credits, | ||
228 | const unsigned int payload_size) | ||
229 | { | ||
230 | int new_val = DIV_ROUND_UP(payload_size, SMB2_MAX_BUFFER_SIZE); | ||
231 | |||
232 | if (!credits->value || credits->value == new_val) | ||
233 | return 0; | ||
234 | |||
235 | if (credits->value < new_val) { | ||
236 | WARN_ONCE(1, "request has less credits (%d) than required (%d)", | ||
237 | credits->value, new_val); | ||
238 | return -ENOTSUPP; | ||
239 | } | ||
240 | |||
241 | spin_lock(&server->req_lock); | ||
242 | |||
243 | if (server->reconnect_instance != credits->instance) { | ||
244 | spin_unlock(&server->req_lock); | ||
245 | cifs_dbg(VFS, "trying to return %d credits to old session\n", | ||
246 | credits->value - new_val); | ||
247 | return -EAGAIN; | ||
248 | } | ||
249 | |||
250 | server->credits += credits->value - new_val; | ||
251 | spin_unlock(&server->req_lock); | ||
252 | wake_up(&server->request_q); | ||
253 | credits->value = new_val; | ||
254 | return 0; | ||
255 | } | ||
256 | |||
211 | static __u64 | 257 | static __u64 |
212 | smb2_get_next_mid(struct TCP_Server_Info *server) | 258 | smb2_get_next_mid(struct TCP_Server_Info *server) |
213 | { | 259 | { |
@@ -219,6 +265,15 @@ smb2_get_next_mid(struct TCP_Server_Info *server) | |||
219 | return mid; | 265 | return mid; |
220 | } | 266 | } |
221 | 267 | ||
268 | static void | ||
269 | smb2_revert_current_mid(struct TCP_Server_Info *server, const unsigned int val) | ||
270 | { | ||
271 | spin_lock(&GlobalMid_Lock); | ||
272 | if (server->CurrentMid >= val) | ||
273 | server->CurrentMid -= val; | ||
274 | spin_unlock(&GlobalMid_Lock); | ||
275 | } | ||
276 | |||
222 | static struct mid_q_entry * | 277 | static struct mid_q_entry * |
223 | smb2_find_mid(struct TCP_Server_Info *server, char *buf) | 278 | smb2_find_mid(struct TCP_Server_Info *server, char *buf) |
224 | { | 279 | { |
@@ -940,6 +995,16 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, | |||
940 | resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; | 995 | resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER; |
941 | memset(rsp_iov, 0, sizeof(rsp_iov)); | 996 | memset(rsp_iov, 0, sizeof(rsp_iov)); |
942 | 997 | ||
998 | if (ses->server->ops->query_all_EAs) { | ||
999 | if (!ea_value) { | ||
1000 | rc = ses->server->ops->query_all_EAs(xid, tcon, path, | ||
1001 | ea_name, NULL, 0, | ||
1002 | cifs_sb); | ||
1003 | if (rc == -ENODATA) | ||
1004 | goto sea_exit; | ||
1005 | } | ||
1006 | } | ||
1007 | |||
943 | /* Open */ | 1008 | /* Open */ |
944 | memset(&open_iov, 0, sizeof(open_iov)); | 1009 | memset(&open_iov, 0, sizeof(open_iov)); |
945 | rqst[0].rq_iov = open_iov; | 1010 | rqst[0].rq_iov = open_iov; |
@@ -1753,14 +1818,14 @@ smb2_close_dir(const unsigned int xid, struct cifs_tcon *tcon, | |||
1753 | * the number of credits and return true. Otherwise - return false. | 1818 | * the number of credits and return true. Otherwise - return false. |
1754 | */ | 1819 | */ |
1755 | static bool | 1820 | static bool |
1756 | smb2_is_status_pending(char *buf, struct TCP_Server_Info *server, int length) | 1821 | smb2_is_status_pending(char *buf, struct TCP_Server_Info *server) |
1757 | { | 1822 | { |
1758 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; | 1823 | struct smb2_sync_hdr *shdr = (struct smb2_sync_hdr *)buf; |
1759 | 1824 | ||
1760 | if (shdr->Status != STATUS_PENDING) | 1825 | if (shdr->Status != STATUS_PENDING) |
1761 | return false; | 1826 | return false; |
1762 | 1827 | ||
1763 | if (!length) { | 1828 | if (shdr->CreditRequest) { |
1764 | spin_lock(&server->req_lock); | 1829 | spin_lock(&server->req_lock); |
1765 | server->credits += le16_to_cpu(shdr->CreditRequest); | 1830 | server->credits += le16_to_cpu(shdr->CreditRequest); |
1766 | spin_unlock(&server->req_lock); | 1831 | spin_unlock(&server->req_lock); |
@@ -2595,6 +2660,15 @@ smb2_downgrade_oplock(struct TCP_Server_Info *server, | |||
2595 | } | 2660 | } |
2596 | 2661 | ||
2597 | static void | 2662 | static void |
2663 | smb21_downgrade_oplock(struct TCP_Server_Info *server, | ||
2664 | struct cifsInodeInfo *cinode, bool set_level2) | ||
2665 | { | ||
2666 | server->ops->set_oplock_level(cinode, | ||
2667 | set_level2 ? SMB2_LEASE_READ_CACHING_HE : | ||
2668 | 0, 0, NULL); | ||
2669 | } | ||
2670 | |||
2671 | static void | ||
2598 | smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, | 2672 | smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, |
2599 | unsigned int epoch, bool *purge_cache) | 2673 | unsigned int epoch, bool *purge_cache) |
2600 | { | 2674 | { |
@@ -3210,15 +3284,15 @@ handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, | |||
3210 | } | 3284 | } |
3211 | 3285 | ||
3212 | if (server->ops->is_status_pending && | 3286 | if (server->ops->is_status_pending && |
3213 | server->ops->is_status_pending(buf, server, 0)) | 3287 | server->ops->is_status_pending(buf, server)) |
3214 | return -1; | 3288 | return -1; |
3215 | 3289 | ||
3216 | /* set up first two iov to get credits */ | 3290 | /* set up first two iov to get credits */ |
3217 | rdata->iov[0].iov_base = buf; | 3291 | rdata->iov[0].iov_base = buf; |
3218 | rdata->iov[0].iov_len = 4; | 3292 | rdata->iov[0].iov_len = 0; |
3219 | rdata->iov[1].iov_base = buf + 4; | 3293 | rdata->iov[1].iov_base = buf; |
3220 | rdata->iov[1].iov_len = | 3294 | rdata->iov[1].iov_len = |
3221 | min_t(unsigned int, buf_len, server->vals->read_rsp_size) - 4; | 3295 | min_t(unsigned int, buf_len, server->vals->read_rsp_size); |
3222 | cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", | 3296 | cifs_dbg(FYI, "0: iov_base=%p iov_len=%zu\n", |
3223 | rdata->iov[0].iov_base, rdata->iov[0].iov_len); | 3297 | rdata->iov[0].iov_base, rdata->iov[0].iov_len); |
3224 | cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n", | 3298 | cifs_dbg(FYI, "1: iov_base=%p iov_len=%zu\n", |
@@ -3541,6 +3615,7 @@ struct smb_version_operations smb20_operations = { | |||
3541 | .get_credits = smb2_get_credits, | 3615 | .get_credits = smb2_get_credits, |
3542 | .wait_mtu_credits = cifs_wait_mtu_credits, | 3616 | .wait_mtu_credits = cifs_wait_mtu_credits, |
3543 | .get_next_mid = smb2_get_next_mid, | 3617 | .get_next_mid = smb2_get_next_mid, |
3618 | .revert_current_mid = smb2_revert_current_mid, | ||
3544 | .read_data_offset = smb2_read_data_offset, | 3619 | .read_data_offset = smb2_read_data_offset, |
3545 | .read_data_length = smb2_read_data_length, | 3620 | .read_data_length = smb2_read_data_length, |
3546 | .map_error = map_smb2_to_linux_error, | 3621 | .map_error = map_smb2_to_linux_error, |
@@ -3635,7 +3710,9 @@ struct smb_version_operations smb21_operations = { | |||
3635 | .get_credits_field = smb2_get_credits_field, | 3710 | .get_credits_field = smb2_get_credits_field, |
3636 | .get_credits = smb2_get_credits, | 3711 | .get_credits = smb2_get_credits, |
3637 | .wait_mtu_credits = smb2_wait_mtu_credits, | 3712 | .wait_mtu_credits = smb2_wait_mtu_credits, |
3713 | .adjust_credits = smb2_adjust_credits, | ||
3638 | .get_next_mid = smb2_get_next_mid, | 3714 | .get_next_mid = smb2_get_next_mid, |
3715 | .revert_current_mid = smb2_revert_current_mid, | ||
3639 | .read_data_offset = smb2_read_data_offset, | 3716 | .read_data_offset = smb2_read_data_offset, |
3640 | .read_data_length = smb2_read_data_length, | 3717 | .read_data_length = smb2_read_data_length, |
3641 | .map_error = map_smb2_to_linux_error, | 3718 | .map_error = map_smb2_to_linux_error, |
@@ -3646,7 +3723,7 @@ struct smb_version_operations smb21_operations = { | |||
3646 | .print_stats = smb2_print_stats, | 3723 | .print_stats = smb2_print_stats, |
3647 | .is_oplock_break = smb2_is_valid_oplock_break, | 3724 | .is_oplock_break = smb2_is_valid_oplock_break, |
3648 | .handle_cancelled_mid = smb2_handle_cancelled_mid, | 3725 | .handle_cancelled_mid = smb2_handle_cancelled_mid, |
3649 | .downgrade_oplock = smb2_downgrade_oplock, | 3726 | .downgrade_oplock = smb21_downgrade_oplock, |
3650 | .need_neg = smb2_need_neg, | 3727 | .need_neg = smb2_need_neg, |
3651 | .negotiate = smb2_negotiate, | 3728 | .negotiate = smb2_negotiate, |
3652 | .negotiate_wsize = smb2_negotiate_wsize, | 3729 | .negotiate_wsize = smb2_negotiate_wsize, |
@@ -3731,7 +3808,9 @@ struct smb_version_operations smb30_operations = { | |||
3731 | .get_credits_field = smb2_get_credits_field, | 3808 | .get_credits_field = smb2_get_credits_field, |
3732 | .get_credits = smb2_get_credits, | 3809 | .get_credits = smb2_get_credits, |
3733 | .wait_mtu_credits = smb2_wait_mtu_credits, | 3810 | .wait_mtu_credits = smb2_wait_mtu_credits, |
3811 | .adjust_credits = smb2_adjust_credits, | ||
3734 | .get_next_mid = smb2_get_next_mid, | 3812 | .get_next_mid = smb2_get_next_mid, |
3813 | .revert_current_mid = smb2_revert_current_mid, | ||
3735 | .read_data_offset = smb2_read_data_offset, | 3814 | .read_data_offset = smb2_read_data_offset, |
3736 | .read_data_length = smb2_read_data_length, | 3815 | .read_data_length = smb2_read_data_length, |
3737 | .map_error = map_smb2_to_linux_error, | 3816 | .map_error = map_smb2_to_linux_error, |
@@ -3743,7 +3822,7 @@ struct smb_version_operations smb30_operations = { | |||
3743 | .dump_share_caps = smb2_dump_share_caps, | 3822 | .dump_share_caps = smb2_dump_share_caps, |
3744 | .is_oplock_break = smb2_is_valid_oplock_break, | 3823 | .is_oplock_break = smb2_is_valid_oplock_break, |
3745 | .handle_cancelled_mid = smb2_handle_cancelled_mid, | 3824 | .handle_cancelled_mid = smb2_handle_cancelled_mid, |
3746 | .downgrade_oplock = smb2_downgrade_oplock, | 3825 | .downgrade_oplock = smb21_downgrade_oplock, |
3747 | .need_neg = smb2_need_neg, | 3826 | .need_neg = smb2_need_neg, |
3748 | .negotiate = smb2_negotiate, | 3827 | .negotiate = smb2_negotiate, |
3749 | .negotiate_wsize = smb3_negotiate_wsize, | 3828 | .negotiate_wsize = smb3_negotiate_wsize, |
@@ -3836,7 +3915,9 @@ struct smb_version_operations smb311_operations = { | |||
3836 | .get_credits_field = smb2_get_credits_field, | 3915 | .get_credits_field = smb2_get_credits_field, |
3837 | .get_credits = smb2_get_credits, | 3916 | .get_credits = smb2_get_credits, |
3838 | .wait_mtu_credits = smb2_wait_mtu_credits, | 3917 | .wait_mtu_credits = smb2_wait_mtu_credits, |
3918 | .adjust_credits = smb2_adjust_credits, | ||
3839 | .get_next_mid = smb2_get_next_mid, | 3919 | .get_next_mid = smb2_get_next_mid, |
3920 | .revert_current_mid = smb2_revert_current_mid, | ||
3840 | .read_data_offset = smb2_read_data_offset, | 3921 | .read_data_offset = smb2_read_data_offset, |
3841 | .read_data_length = smb2_read_data_length, | 3922 | .read_data_length = smb2_read_data_length, |
3842 | .map_error = map_smb2_to_linux_error, | 3923 | .map_error = map_smb2_to_linux_error, |
@@ -3848,7 +3929,7 @@ struct smb_version_operations smb311_operations = { | |||
3848 | .dump_share_caps = smb2_dump_share_caps, | 3929 | .dump_share_caps = smb2_dump_share_caps, |
3849 | .is_oplock_break = smb2_is_valid_oplock_break, | 3930 | .is_oplock_break = smb2_is_valid_oplock_break, |
3850 | .handle_cancelled_mid = smb2_handle_cancelled_mid, | 3931 | .handle_cancelled_mid = smb2_handle_cancelled_mid, |
3851 | .downgrade_oplock = smb2_downgrade_oplock, | 3932 | .downgrade_oplock = smb21_downgrade_oplock, |
3852 | .need_neg = smb2_need_neg, | 3933 | .need_neg = smb2_need_neg, |
3853 | .negotiate = smb2_negotiate, | 3934 | .negotiate = smb2_negotiate, |
3854 | .negotiate_wsize = smb3_negotiate_wsize, | 3935 | .negotiate_wsize = smb3_negotiate_wsize, |
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c index 77b3aaa39b35..60fbe306f604 100644 --- a/fs/cifs/smb2pdu.c +++ b/fs/cifs/smb2pdu.c | |||
@@ -107,13 +107,13 @@ smb2_hdr_assemble(struct smb2_sync_hdr *shdr, __le16 smb2_cmd, | |||
107 | struct TCP_Server_Info *server = tcon->ses->server; | 107 | struct TCP_Server_Info *server = tcon->ses->server; |
108 | 108 | ||
109 | spin_lock(&server->req_lock); | 109 | spin_lock(&server->req_lock); |
110 | /* Request up to 2 credits but don't go over the limit. */ | 110 | /* Request up to 10 credits but don't go over the limit. */ |
111 | if (server->credits >= server->max_credits) | 111 | if (server->credits >= server->max_credits) |
112 | shdr->CreditRequest = cpu_to_le16(0); | 112 | shdr->CreditRequest = cpu_to_le16(0); |
113 | else | 113 | else |
114 | shdr->CreditRequest = cpu_to_le16( | 114 | shdr->CreditRequest = cpu_to_le16( |
115 | min_t(int, server->max_credits - | 115 | min_t(int, server->max_credits - |
116 | server->credits, 2)); | 116 | server->credits, 10)); |
117 | spin_unlock(&server->req_lock); | 117 | spin_unlock(&server->req_lock); |
118 | } else { | 118 | } else { |
119 | shdr->CreditRequest = cpu_to_le16(2); | 119 | shdr->CreditRequest = cpu_to_le16(2); |
@@ -173,8 +173,8 @@ static int __smb2_reconnect(const struct nls_table *nlsc, | |||
173 | return -ENOMEM; | 173 | return -ENOMEM; |
174 | 174 | ||
175 | if (tcon->ipc) { | 175 | if (tcon->ipc) { |
176 | snprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", | 176 | scnprintf(tree, MAX_TREE_SIZE, "\\\\%s\\IPC$", |
177 | tcon->ses->server->hostname); | 177 | tcon->ses->server->hostname); |
178 | rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); | 178 | rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); |
179 | goto out; | 179 | goto out; |
180 | } | 180 | } |
@@ -206,7 +206,7 @@ static int __smb2_reconnect(const struct nls_table *nlsc, | |||
206 | continue; | 206 | continue; |
207 | } | 207 | } |
208 | 208 | ||
209 | snprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); | 209 | scnprintf(tree, MAX_TREE_SIZE, "\\%s", tgt); |
210 | 210 | ||
211 | rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); | 211 | rc = SMB2_tcon(0, tcon->ses, tree, tcon, nlsc); |
212 | if (!rc) | 212 | if (!rc) |
@@ -490,6 +490,23 @@ build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt) | |||
490 | { | 490 | { |
491 | pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE; | 491 | pneg_ctxt->ContextType = SMB2_POSIX_EXTENSIONS_AVAILABLE; |
492 | pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN); | 492 | pneg_ctxt->DataLength = cpu_to_le16(POSIX_CTXT_DATA_LEN); |
493 | /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */ | ||
494 | pneg_ctxt->Name[0] = 0x93; | ||
495 | pneg_ctxt->Name[1] = 0xAD; | ||
496 | pneg_ctxt->Name[2] = 0x25; | ||
497 | pneg_ctxt->Name[3] = 0x50; | ||
498 | pneg_ctxt->Name[4] = 0x9C; | ||
499 | pneg_ctxt->Name[5] = 0xB4; | ||
500 | pneg_ctxt->Name[6] = 0x11; | ||
501 | pneg_ctxt->Name[7] = 0xE7; | ||
502 | pneg_ctxt->Name[8] = 0xB4; | ||
503 | pneg_ctxt->Name[9] = 0x23; | ||
504 | pneg_ctxt->Name[10] = 0x83; | ||
505 | pneg_ctxt->Name[11] = 0xDE; | ||
506 | pneg_ctxt->Name[12] = 0x96; | ||
507 | pneg_ctxt->Name[13] = 0x8B; | ||
508 | pneg_ctxt->Name[14] = 0xCD; | ||
509 | pneg_ctxt->Name[15] = 0x7C; | ||
493 | } | 510 | } |
494 | 511 | ||
495 | static void | 512 | static void |
@@ -986,8 +1003,14 @@ int smb3_validate_negotiate(const unsigned int xid, struct cifs_tcon *tcon) | |||
986 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, | 1003 | rc = SMB2_ioctl(xid, tcon, NO_FILE_ID, NO_FILE_ID, |
987 | FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, | 1004 | FSCTL_VALIDATE_NEGOTIATE_INFO, true /* is_fsctl */, |
988 | (char *)pneg_inbuf, inbuflen, (char **)&pneg_rsp, &rsplen); | 1005 | (char *)pneg_inbuf, inbuflen, (char **)&pneg_rsp, &rsplen); |
989 | 1006 | if (rc == -EOPNOTSUPP) { | |
990 | if (rc != 0) { | 1007 | /* |
1008 | * Old Windows versions or Netapp SMB server can return | ||
1009 | * not supported error. Client should accept it. | ||
1010 | */ | ||
1011 | cifs_dbg(VFS, "Server does not support validate negotiate\n"); | ||
1012 | return 0; | ||
1013 | } else if (rc != 0) { | ||
991 | cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc); | 1014 | cifs_dbg(VFS, "validate protocol negotiate failed: %d\n", rc); |
992 | rc = -EIO; | 1015 | rc = -EIO; |
993 | goto out_free_inbuf; | 1016 | goto out_free_inbuf; |
@@ -1614,6 +1637,9 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, | |||
1614 | rqst.rq_iov = iov; | 1637 | rqst.rq_iov = iov; |
1615 | rqst.rq_nvec = 2; | 1638 | rqst.rq_nvec = 2; |
1616 | 1639 | ||
1640 | /* Need 64 for max size write so ask for more in case not there yet */ | ||
1641 | req->sync_hdr.CreditRequest = cpu_to_le16(64); | ||
1642 | |||
1617 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); | 1643 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
1618 | cifs_small_buf_release(req); | 1644 | cifs_small_buf_release(req); |
1619 | rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base; | 1645 | rsp = (struct smb2_tree_connect_rsp *)rsp_iov.iov_base; |
@@ -2170,6 +2196,8 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, | |||
2170 | rqst.rq_iov = iov; | 2196 | rqst.rq_iov = iov; |
2171 | rqst.rq_nvec = n_iov; | 2197 | rqst.rq_nvec = n_iov; |
2172 | 2198 | ||
2199 | trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, CREATE_NOT_FILE, | ||
2200 | FILE_WRITE_ATTRIBUTES); | ||
2173 | /* resource #4: response buffer */ | 2201 | /* resource #4: response buffer */ |
2174 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); | 2202 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
2175 | if (rc) { | 2203 | if (rc) { |
@@ -2388,6 +2416,9 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path, | |||
2388 | if (rc) | 2416 | if (rc) |
2389 | goto creat_exit; | 2417 | goto creat_exit; |
2390 | 2418 | ||
2419 | trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, | ||
2420 | oparms->create_options, oparms->desired_access); | ||
2421 | |||
2391 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, | 2422 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, |
2392 | &rsp_iov); | 2423 | &rsp_iov); |
2393 | rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; | 2424 | rsp = (struct smb2_create_rsp *)rsp_iov.iov_base; |
@@ -2837,6 +2868,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, | |||
2837 | if (rc) | 2868 | if (rc) |
2838 | goto qinf_exit; | 2869 | goto qinf_exit; |
2839 | 2870 | ||
2871 | trace_smb3_query_info_enter(xid, persistent_fid, tcon->tid, | ||
2872 | ses->Suid, info_class, (__u32)info_type); | ||
2873 | |||
2840 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); | 2874 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
2841 | rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; | 2875 | rsp = (struct smb2_query_info_rsp *)rsp_iov.iov_base; |
2842 | 2876 | ||
@@ -2847,6 +2881,9 @@ query_info(const unsigned int xid, struct cifs_tcon *tcon, | |||
2847 | goto qinf_exit; | 2881 | goto qinf_exit; |
2848 | } | 2882 | } |
2849 | 2883 | ||
2884 | trace_smb3_query_info_done(xid, persistent_fid, tcon->tid, | ||
2885 | ses->Suid, info_class, (__u32)info_type); | ||
2886 | |||
2850 | if (dlen) { | 2887 | if (dlen) { |
2851 | *dlen = le32_to_cpu(rsp->OutputBufferLength); | 2888 | *dlen = le32_to_cpu(rsp->OutputBufferLength); |
2852 | if (!*data) { | 2889 | if (!*data) { |
@@ -2924,14 +2961,16 @@ smb2_echo_callback(struct mid_q_entry *mid) | |||
2924 | { | 2961 | { |
2925 | struct TCP_Server_Info *server = mid->callback_data; | 2962 | struct TCP_Server_Info *server = mid->callback_data; |
2926 | struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf; | 2963 | struct smb2_echo_rsp *rsp = (struct smb2_echo_rsp *)mid->resp_buf; |
2927 | unsigned int credits_received = 0; | 2964 | struct cifs_credits credits = { .value = 0, .instance = 0 }; |
2928 | 2965 | ||
2929 | if (mid->mid_state == MID_RESPONSE_RECEIVED | 2966 | if (mid->mid_state == MID_RESPONSE_RECEIVED |
2930 | || mid->mid_state == MID_RESPONSE_MALFORMED) | 2967 | || mid->mid_state == MID_RESPONSE_MALFORMED) { |
2931 | credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); | 2968 | credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
2969 | credits.instance = server->reconnect_instance; | ||
2970 | } | ||
2932 | 2971 | ||
2933 | DeleteMidQEntry(mid); | 2972 | DeleteMidQEntry(mid); |
2934 | add_credits(server, credits_received, CIFS_ECHO_OP); | 2973 | add_credits(server, &credits, CIFS_ECHO_OP); |
2935 | } | 2974 | } |
2936 | 2975 | ||
2937 | void smb2_reconnect_server(struct work_struct *work) | 2976 | void smb2_reconnect_server(struct work_struct *work) |
@@ -3023,7 +3062,7 @@ SMB2_echo(struct TCP_Server_Info *server) | |||
3023 | iov[0].iov_base = (char *)req; | 3062 | iov[0].iov_base = (char *)req; |
3024 | 3063 | ||
3025 | rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL, | 3064 | rc = cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL, |
3026 | server, CIFS_ECHO_OP); | 3065 | server, CIFS_ECHO_OP, NULL); |
3027 | if (rc) | 3066 | if (rc) |
3028 | cifs_dbg(FYI, "Echo request failed: %d\n", rc); | 3067 | cifs_dbg(FYI, "Echo request failed: %d\n", rc); |
3029 | 3068 | ||
@@ -3114,6 +3153,11 @@ smb2_new_read_req(void **buf, unsigned int *total_len, | |||
3114 | req->MinimumCount = 0; | 3153 | req->MinimumCount = 0; |
3115 | req->Length = cpu_to_le32(io_parms->length); | 3154 | req->Length = cpu_to_le32(io_parms->length); |
3116 | req->Offset = cpu_to_le64(io_parms->offset); | 3155 | req->Offset = cpu_to_le64(io_parms->offset); |
3156 | |||
3157 | trace_smb3_read_enter(0 /* xid */, | ||
3158 | io_parms->persistent_fid, | ||
3159 | io_parms->tcon->tid, io_parms->tcon->ses->Suid, | ||
3160 | io_parms->offset, io_parms->length); | ||
3117 | #ifdef CONFIG_CIFS_SMB_DIRECT | 3161 | #ifdef CONFIG_CIFS_SMB_DIRECT |
3118 | /* | 3162 | /* |
3119 | * If we want to do a RDMA write, fill in and append | 3163 | * If we want to do a RDMA write, fill in and append |
@@ -3184,7 +3228,7 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
3184 | struct TCP_Server_Info *server = tcon->ses->server; | 3228 | struct TCP_Server_Info *server = tcon->ses->server; |
3185 | struct smb2_sync_hdr *shdr = | 3229 | struct smb2_sync_hdr *shdr = |
3186 | (struct smb2_sync_hdr *)rdata->iov[0].iov_base; | 3230 | (struct smb2_sync_hdr *)rdata->iov[0].iov_base; |
3187 | unsigned int credits_received = 0; | 3231 | struct cifs_credits credits = { .value = 0, .instance = 0 }; |
3188 | struct smb_rqst rqst = { .rq_iov = rdata->iov, | 3232 | struct smb_rqst rqst = { .rq_iov = rdata->iov, |
3189 | .rq_nvec = 2, | 3233 | .rq_nvec = 2, |
3190 | .rq_pages = rdata->pages, | 3234 | .rq_pages = rdata->pages, |
@@ -3199,7 +3243,8 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
3199 | 3243 | ||
3200 | switch (mid->mid_state) { | 3244 | switch (mid->mid_state) { |
3201 | case MID_RESPONSE_RECEIVED: | 3245 | case MID_RESPONSE_RECEIVED: |
3202 | credits_received = le16_to_cpu(shdr->CreditRequest); | 3246 | credits.value = le16_to_cpu(shdr->CreditRequest); |
3247 | credits.instance = server->reconnect_instance; | ||
3203 | /* result already set, check signature */ | 3248 | /* result already set, check signature */ |
3204 | if (server->sign && !mid->decrypted) { | 3249 | if (server->sign && !mid->decrypted) { |
3205 | int rc; | 3250 | int rc; |
@@ -3224,11 +3269,11 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
3224 | cifs_stats_bytes_read(tcon, rdata->got_bytes); | 3269 | cifs_stats_bytes_read(tcon, rdata->got_bytes); |
3225 | break; | 3270 | break; |
3226 | case MID_RESPONSE_MALFORMED: | 3271 | case MID_RESPONSE_MALFORMED: |
3227 | credits_received = le16_to_cpu(shdr->CreditRequest); | 3272 | credits.value = le16_to_cpu(shdr->CreditRequest); |
3273 | credits.instance = server->reconnect_instance; | ||
3228 | /* fall through */ | 3274 | /* fall through */ |
3229 | default: | 3275 | default: |
3230 | if (rdata->result != -ENODATA) | 3276 | rdata->result = -EIO; |
3231 | rdata->result = -EIO; | ||
3232 | } | 3277 | } |
3233 | #ifdef CONFIG_CIFS_SMB_DIRECT | 3278 | #ifdef CONFIG_CIFS_SMB_DIRECT |
3234 | /* | 3279 | /* |
@@ -3255,7 +3300,7 @@ smb2_readv_callback(struct mid_q_entry *mid) | |||
3255 | 3300 | ||
3256 | queue_work(cifsiod_wq, &rdata->work); | 3301 | queue_work(cifsiod_wq, &rdata->work); |
3257 | DeleteMidQEntry(mid); | 3302 | DeleteMidQEntry(mid); |
3258 | add_credits(server, credits_received, 0); | 3303 | add_credits(server, &credits, 0); |
3259 | } | 3304 | } |
3260 | 3305 | ||
3261 | /* smb2_async_readv - send an async read, and set up mid to handle result */ | 3306 | /* smb2_async_readv - send an async read, and set up mid to handle result */ |
@@ -3285,17 +3330,8 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
3285 | 3330 | ||
3286 | rc = smb2_new_read_req( | 3331 | rc = smb2_new_read_req( |
3287 | (void **) &buf, &total_len, &io_parms, rdata, 0, 0); | 3332 | (void **) &buf, &total_len, &io_parms, rdata, 0, 0); |
3288 | if (rc) { | 3333 | if (rc) |
3289 | if (rc == -EAGAIN && rdata->credits) { | ||
3290 | /* credits was reset by reconnect */ | ||
3291 | rdata->credits = 0; | ||
3292 | /* reduce in_flight value since we won't send the req */ | ||
3293 | spin_lock(&server->req_lock); | ||
3294 | server->in_flight--; | ||
3295 | spin_unlock(&server->req_lock); | ||
3296 | } | ||
3297 | return rc; | 3334 | return rc; |
3298 | } | ||
3299 | 3335 | ||
3300 | if (smb3_encryption_required(io_parms.tcon)) | 3336 | if (smb3_encryption_required(io_parms.tcon)) |
3301 | flags |= CIFS_TRANSFORM_REQ; | 3337 | flags |= CIFS_TRANSFORM_REQ; |
@@ -3305,24 +3341,24 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
3305 | 3341 | ||
3306 | shdr = (struct smb2_sync_hdr *)buf; | 3342 | shdr = (struct smb2_sync_hdr *)buf; |
3307 | 3343 | ||
3308 | if (rdata->credits) { | 3344 | if (rdata->credits.value > 0) { |
3309 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, | 3345 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(rdata->bytes, |
3310 | SMB2_MAX_BUFFER_SIZE)); | 3346 | SMB2_MAX_BUFFER_SIZE)); |
3311 | shdr->CreditRequest = | 3347 | shdr->CreditRequest = |
3312 | cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); | 3348 | cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); |
3313 | spin_lock(&server->req_lock); | 3349 | |
3314 | server->credits += rdata->credits - | 3350 | rc = adjust_credits(server, &rdata->credits, rdata->bytes); |
3315 | le16_to_cpu(shdr->CreditCharge); | 3351 | if (rc) |
3316 | spin_unlock(&server->req_lock); | 3352 | goto async_readv_out; |
3317 | wake_up(&server->request_q); | 3353 | |
3318 | rdata->credits = le16_to_cpu(shdr->CreditCharge); | ||
3319 | flags |= CIFS_HAS_CREDITS; | 3354 | flags |= CIFS_HAS_CREDITS; |
3320 | } | 3355 | } |
3321 | 3356 | ||
3322 | kref_get(&rdata->refcount); | 3357 | kref_get(&rdata->refcount); |
3323 | rc = cifs_call_async(io_parms.tcon->ses->server, &rqst, | 3358 | rc = cifs_call_async(io_parms.tcon->ses->server, &rqst, |
3324 | cifs_readv_receive, smb2_readv_callback, | 3359 | cifs_readv_receive, smb2_readv_callback, |
3325 | smb3_handle_read_data, rdata, flags); | 3360 | smb3_handle_read_data, rdata, flags, |
3361 | &rdata->credits); | ||
3326 | if (rc) { | 3362 | if (rc) { |
3327 | kref_put(&rdata->refcount, cifs_readdata_release); | 3363 | kref_put(&rdata->refcount, cifs_readdata_release); |
3328 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); | 3364 | cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); |
@@ -3332,6 +3368,7 @@ smb2_async_readv(struct cifs_readdata *rdata) | |||
3332 | io_parms.offset, io_parms.length, rc); | 3368 | io_parms.offset, io_parms.length, rc); |
3333 | } | 3369 | } |
3334 | 3370 | ||
3371 | async_readv_out: | ||
3335 | cifs_small_buf_release(buf); | 3372 | cifs_small_buf_release(buf); |
3336 | return rc; | 3373 | return rc; |
3337 | } | 3374 | } |
@@ -3378,7 +3415,10 @@ SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
3378 | io_parms->tcon->tid, ses->Suid, | 3415 | io_parms->tcon->tid, ses->Suid, |
3379 | io_parms->offset, io_parms->length, | 3416 | io_parms->offset, io_parms->length, |
3380 | rc); | 3417 | rc); |
3381 | } | 3418 | } else |
3419 | trace_smb3_read_done(xid, req->PersistentFileId, | ||
3420 | io_parms->tcon->tid, ses->Suid, | ||
3421 | io_parms->offset, 0); | ||
3382 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); | 3422 | free_rsp_buf(resp_buftype, rsp_iov.iov_base); |
3383 | return rc == -ENODATA ? 0 : rc; | 3423 | return rc == -ENODATA ? 0 : rc; |
3384 | } else | 3424 | } else |
@@ -3417,14 +3457,16 @@ smb2_writev_callback(struct mid_q_entry *mid) | |||
3417 | { | 3457 | { |
3418 | struct cifs_writedata *wdata = mid->callback_data; | 3458 | struct cifs_writedata *wdata = mid->callback_data; |
3419 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); | 3459 | struct cifs_tcon *tcon = tlink_tcon(wdata->cfile->tlink); |
3460 | struct TCP_Server_Info *server = tcon->ses->server; | ||
3420 | unsigned int written; | 3461 | unsigned int written; |
3421 | struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; | 3462 | struct smb2_write_rsp *rsp = (struct smb2_write_rsp *)mid->resp_buf; |
3422 | unsigned int credits_received = 0; | 3463 | struct cifs_credits credits = { .value = 0, .instance = 0 }; |
3423 | 3464 | ||
3424 | switch (mid->mid_state) { | 3465 | switch (mid->mid_state) { |
3425 | case MID_RESPONSE_RECEIVED: | 3466 | case MID_RESPONSE_RECEIVED: |
3426 | credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); | 3467 | credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
3427 | wdata->result = smb2_check_receive(mid, tcon->ses->server, 0); | 3468 | credits.instance = server->reconnect_instance; |
3469 | wdata->result = smb2_check_receive(mid, server, 0); | ||
3428 | if (wdata->result != 0) | 3470 | if (wdata->result != 0) |
3429 | break; | 3471 | break; |
3430 | 3472 | ||
@@ -3448,7 +3490,8 @@ smb2_writev_callback(struct mid_q_entry *mid) | |||
3448 | wdata->result = -EAGAIN; | 3490 | wdata->result = -EAGAIN; |
3449 | break; | 3491 | break; |
3450 | case MID_RESPONSE_MALFORMED: | 3492 | case MID_RESPONSE_MALFORMED: |
3451 | credits_received = le16_to_cpu(rsp->sync_hdr.CreditRequest); | 3493 | credits.value = le16_to_cpu(rsp->sync_hdr.CreditRequest); |
3494 | credits.instance = server->reconnect_instance; | ||
3452 | /* fall through */ | 3495 | /* fall through */ |
3453 | default: | 3496 | default: |
3454 | wdata->result = -EIO; | 3497 | wdata->result = -EIO; |
@@ -3481,7 +3524,7 @@ smb2_writev_callback(struct mid_q_entry *mid) | |||
3481 | 3524 | ||
3482 | queue_work(cifsiod_wq, &wdata->work); | 3525 | queue_work(cifsiod_wq, &wdata->work); |
3483 | DeleteMidQEntry(mid); | 3526 | DeleteMidQEntry(mid); |
3484 | add_credits(tcon->ses->server, credits_received, 0); | 3527 | add_credits(server, &credits, 0); |
3485 | } | 3528 | } |
3486 | 3529 | ||
3487 | /* smb2_async_writev - send an async write, and set up mid to handle result */ | 3530 | /* smb2_async_writev - send an async write, and set up mid to handle result */ |
@@ -3499,17 +3542,8 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
3499 | unsigned int total_len; | 3542 | unsigned int total_len; |
3500 | 3543 | ||
3501 | rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len); | 3544 | rc = smb2_plain_req_init(SMB2_WRITE, tcon, (void **) &req, &total_len); |
3502 | if (rc) { | 3545 | if (rc) |
3503 | if (rc == -EAGAIN && wdata->credits) { | 3546 | return rc; |
3504 | /* credits was reset by reconnect */ | ||
3505 | wdata->credits = 0; | ||
3506 | /* reduce in_flight value since we won't send the req */ | ||
3507 | spin_lock(&server->req_lock); | ||
3508 | server->in_flight--; | ||
3509 | spin_unlock(&server->req_lock); | ||
3510 | } | ||
3511 | goto async_writev_out; | ||
3512 | } | ||
3513 | 3547 | ||
3514 | if (smb3_encryption_required(tcon)) | 3548 | if (smb3_encryption_required(tcon)) |
3515 | flags |= CIFS_TRANSFORM_REQ; | 3549 | flags |= CIFS_TRANSFORM_REQ; |
@@ -3526,6 +3560,9 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
3526 | req->DataOffset = cpu_to_le16( | 3560 | req->DataOffset = cpu_to_le16( |
3527 | offsetof(struct smb2_write_req, Buffer)); | 3561 | offsetof(struct smb2_write_req, Buffer)); |
3528 | req->RemainingBytes = 0; | 3562 | req->RemainingBytes = 0; |
3563 | |||
3564 | trace_smb3_write_enter(0 /* xid */, wdata->cfile->fid.persistent_fid, | ||
3565 | tcon->tid, tcon->ses->Suid, wdata->offset, wdata->bytes); | ||
3529 | #ifdef CONFIG_CIFS_SMB_DIRECT | 3566 | #ifdef CONFIG_CIFS_SMB_DIRECT |
3530 | /* | 3567 | /* |
3531 | * If we want to do a server RDMA read, fill in and append | 3568 | * If we want to do a server RDMA read, fill in and append |
@@ -3595,23 +3632,22 @@ smb2_async_writev(struct cifs_writedata *wdata, | |||
3595 | req->Length = cpu_to_le32(wdata->bytes); | 3632 | req->Length = cpu_to_le32(wdata->bytes); |
3596 | #endif | 3633 | #endif |
3597 | 3634 | ||
3598 | if (wdata->credits) { | 3635 | if (wdata->credits.value > 0) { |
3599 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, | 3636 | shdr->CreditCharge = cpu_to_le16(DIV_ROUND_UP(wdata->bytes, |
3600 | SMB2_MAX_BUFFER_SIZE)); | 3637 | SMB2_MAX_BUFFER_SIZE)); |
3601 | shdr->CreditRequest = | 3638 | shdr->CreditRequest = |
3602 | cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); | 3639 | cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 1); |
3603 | spin_lock(&server->req_lock); | 3640 | |
3604 | server->credits += wdata->credits - | 3641 | rc = adjust_credits(server, &wdata->credits, wdata->bytes); |
3605 | le16_to_cpu(shdr->CreditCharge); | 3642 | if (rc) |
3606 | spin_unlock(&server->req_lock); | 3643 | goto async_writev_out; |
3607 | wake_up(&server->request_q); | 3644 | |
3608 | wdata->credits = le16_to_cpu(shdr->CreditCharge); | ||
3609 | flags |= CIFS_HAS_CREDITS; | 3645 | flags |= CIFS_HAS_CREDITS; |
3610 | } | 3646 | } |
3611 | 3647 | ||
3612 | kref_get(&wdata->refcount); | 3648 | kref_get(&wdata->refcount); |
3613 | rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL, | 3649 | rc = cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL, |
3614 | wdata, flags); | 3650 | wdata, flags, &wdata->credits); |
3615 | 3651 | ||
3616 | if (rc) { | 3652 | if (rc) { |
3617 | trace_smb3_write_err(0 /* no xid */, req->PersistentFileId, | 3653 | trace_smb3_write_err(0 /* no xid */, req->PersistentFileId, |
@@ -3674,6 +3710,10 @@ SMB2_write(const unsigned int xid, struct cifs_io_parms *io_parms, | |||
3674 | offsetof(struct smb2_write_req, Buffer)); | 3710 | offsetof(struct smb2_write_req, Buffer)); |
3675 | req->RemainingBytes = 0; | 3711 | req->RemainingBytes = 0; |
3676 | 3712 | ||
3713 | trace_smb3_write_enter(xid, io_parms->persistent_fid, | ||
3714 | io_parms->tcon->tid, io_parms->tcon->ses->Suid, | ||
3715 | io_parms->offset, io_parms->length); | ||
3716 | |||
3677 | iov[0].iov_base = (char *)req; | 3717 | iov[0].iov_base = (char *)req; |
3678 | /* 1 for Buffer */ | 3718 | /* 1 for Buffer */ |
3679 | iov[0].iov_len = total_len - 1; | 3719 | iov[0].iov_len = total_len - 1; |
@@ -3836,6 +3876,9 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, | |||
3836 | rqst.rq_iov = iov; | 3876 | rqst.rq_iov = iov; |
3837 | rqst.rq_nvec = 2; | 3877 | rqst.rq_nvec = 2; |
3838 | 3878 | ||
3879 | trace_smb3_query_dir_enter(xid, persistent_fid, tcon->tid, | ||
3880 | tcon->ses->Suid, index, output_size); | ||
3881 | |||
3839 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); | 3882 | rc = cifs_send_recv(xid, ses, &rqst, &resp_buftype, flags, &rsp_iov); |
3840 | cifs_small_buf_release(req); | 3883 | cifs_small_buf_release(req); |
3841 | rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base; | 3884 | rsp = (struct smb2_query_directory_rsp *)rsp_iov.iov_base; |
@@ -3843,18 +3886,26 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, | |||
3843 | if (rc) { | 3886 | if (rc) { |
3844 | if (rc == -ENODATA && | 3887 | if (rc == -ENODATA && |
3845 | rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) { | 3888 | rsp->sync_hdr.Status == STATUS_NO_MORE_FILES) { |
3889 | trace_smb3_query_dir_done(xid, persistent_fid, | ||
3890 | tcon->tid, tcon->ses->Suid, index, 0); | ||
3846 | srch_inf->endOfSearch = true; | 3891 | srch_inf->endOfSearch = true; |
3847 | rc = 0; | 3892 | rc = 0; |
3848 | } else | 3893 | } else { |
3894 | trace_smb3_query_dir_err(xid, persistent_fid, tcon->tid, | ||
3895 | tcon->ses->Suid, index, 0, rc); | ||
3849 | cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); | 3896 | cifs_stats_fail_inc(tcon, SMB2_QUERY_DIRECTORY_HE); |
3897 | } | ||
3850 | goto qdir_exit; | 3898 | goto qdir_exit; |
3851 | } | 3899 | } |
3852 | 3900 | ||
3853 | rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), | 3901 | rc = smb2_validate_iov(le16_to_cpu(rsp->OutputBufferOffset), |
3854 | le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, | 3902 | le32_to_cpu(rsp->OutputBufferLength), &rsp_iov, |
3855 | info_buf_size); | 3903 | info_buf_size); |
3856 | if (rc) | 3904 | if (rc) { |
3905 | trace_smb3_query_dir_err(xid, persistent_fid, tcon->tid, | ||
3906 | tcon->ses->Suid, index, 0, rc); | ||
3857 | goto qdir_exit; | 3907 | goto qdir_exit; |
3908 | } | ||
3858 | 3909 | ||
3859 | srch_inf->unicode = true; | 3910 | srch_inf->unicode = true; |
3860 | 3911 | ||
@@ -3882,6 +3933,8 @@ SMB2_query_directory(const unsigned int xid, struct cifs_tcon *tcon, | |||
3882 | else | 3933 | else |
3883 | cifs_dbg(VFS, "illegal search buffer type\n"); | 3934 | cifs_dbg(VFS, "illegal search buffer type\n"); |
3884 | 3935 | ||
3936 | trace_smb3_query_dir_done(xid, persistent_fid, tcon->tid, | ||
3937 | tcon->ses->Suid, index, srch_inf->entries_in_buffer); | ||
3885 | return rc; | 3938 | return rc; |
3886 | 3939 | ||
3887 | qdir_exit: | 3940 | qdir_exit: |
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h index 538e2299805f..0bd4d4802701 100644 --- a/fs/cifs/smb2pdu.h +++ b/fs/cifs/smb2pdu.h | |||
@@ -288,12 +288,12 @@ struct smb2_encryption_neg_context { | |||
288 | __le16 Ciphers[1]; /* Ciphers[0] since only one used now */ | 288 | __le16 Ciphers[1]; /* Ciphers[0] since only one used now */ |
289 | } __packed; | 289 | } __packed; |
290 | 290 | ||
291 | #define POSIX_CTXT_DATA_LEN 8 | 291 | #define POSIX_CTXT_DATA_LEN 16 |
292 | struct smb2_posix_neg_context { | 292 | struct smb2_posix_neg_context { |
293 | __le16 ContextType; /* 0x100 */ | 293 | __le16 ContextType; /* 0x100 */ |
294 | __le16 DataLength; | 294 | __le16 DataLength; |
295 | __le32 Reserved; | 295 | __le32 Reserved; |
296 | __le64 Reserved1; /* In case needed for future (eg version or caps) */ | 296 | __u8 Name[16]; /* POSIX ctxt GUID 93AD25509CB411E7B42383DE968BCD7C */ |
297 | } __packed; | 297 | } __packed; |
298 | 298 | ||
299 | struct smb2_negotiate_rsp { | 299 | struct smb2_negotiate_rsp { |
diff --git a/fs/cifs/smb2transport.c b/fs/cifs/smb2transport.c index 7b351c65ee46..d1181572758b 100644 --- a/fs/cifs/smb2transport.c +++ b/fs/cifs/smb2transport.c | |||
@@ -576,6 +576,7 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, | |||
576 | struct TCP_Server_Info *server) | 576 | struct TCP_Server_Info *server) |
577 | { | 577 | { |
578 | struct mid_q_entry *temp; | 578 | struct mid_q_entry *temp; |
579 | unsigned int credits = le16_to_cpu(shdr->CreditCharge); | ||
579 | 580 | ||
580 | if (server == NULL) { | 581 | if (server == NULL) { |
581 | cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n"); | 582 | cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n"); |
@@ -586,6 +587,7 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, | |||
586 | memset(temp, 0, sizeof(struct mid_q_entry)); | 587 | memset(temp, 0, sizeof(struct mid_q_entry)); |
587 | kref_init(&temp->refcount); | 588 | kref_init(&temp->refcount); |
588 | temp->mid = le64_to_cpu(shdr->MessageId); | 589 | temp->mid = le64_to_cpu(shdr->MessageId); |
590 | temp->credits = credits > 0 ? credits : 1; | ||
589 | temp->pid = current->pid; | 591 | temp->pid = current->pid; |
590 | temp->command = shdr->Command; /* Always LE */ | 592 | temp->command = shdr->Command; /* Always LE */ |
591 | temp->when_alloc = jiffies; | 593 | temp->when_alloc = jiffies; |
@@ -600,6 +602,8 @@ smb2_mid_entry_alloc(const struct smb2_sync_hdr *shdr, | |||
600 | 602 | ||
601 | atomic_inc(&midCount); | 603 | atomic_inc(&midCount); |
602 | temp->mid_state = MID_REQUEST_ALLOCATED; | 604 | temp->mid_state = MID_REQUEST_ALLOCATED; |
605 | trace_smb3_cmd_enter(shdr->TreeId, shdr->SessionId, | ||
606 | le16_to_cpu(shdr->Command), temp->mid); | ||
603 | return temp; | 607 | return temp; |
604 | } | 608 | } |
605 | 609 | ||
@@ -615,6 +619,10 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr, | |||
615 | return -EAGAIN; | 619 | return -EAGAIN; |
616 | } | 620 | } |
617 | 621 | ||
622 | if (ses->server->tcpStatus == CifsNeedNegotiate && | ||
623 | shdr->Command != SMB2_NEGOTIATE) | ||
624 | return -EAGAIN; | ||
625 | |||
618 | if (ses->status == CifsNew) { | 626 | if (ses->status == CifsNew) { |
619 | if ((shdr->Command != SMB2_SESSION_SETUP) && | 627 | if ((shdr->Command != SMB2_SESSION_SETUP) && |
620 | (shdr->Command != SMB2_NEGOTIATE)) | 628 | (shdr->Command != SMB2_NEGOTIATE)) |
@@ -634,6 +642,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct smb2_sync_hdr *shdr, | |||
634 | spin_lock(&GlobalMid_Lock); | 642 | spin_lock(&GlobalMid_Lock); |
635 | list_add_tail(&(*mid)->qhead, &ses->server->pending_mid_q); | 643 | list_add_tail(&(*mid)->qhead, &ses->server->pending_mid_q); |
636 | spin_unlock(&GlobalMid_Lock); | 644 | spin_unlock(&GlobalMid_Lock); |
645 | |||
637 | return 0; | 646 | return 0; |
638 | } | 647 | } |
639 | 648 | ||
@@ -674,13 +683,18 @@ smb2_setup_request(struct cifs_ses *ses, struct smb_rqst *rqst) | |||
674 | smb2_seq_num_into_buf(ses->server, shdr); | 683 | smb2_seq_num_into_buf(ses->server, shdr); |
675 | 684 | ||
676 | rc = smb2_get_mid_entry(ses, shdr, &mid); | 685 | rc = smb2_get_mid_entry(ses, shdr, &mid); |
677 | if (rc) | 686 | if (rc) { |
687 | revert_current_mid_from_hdr(ses->server, shdr); | ||
678 | return ERR_PTR(rc); | 688 | return ERR_PTR(rc); |
689 | } | ||
690 | |||
679 | rc = smb2_sign_rqst(rqst, ses->server); | 691 | rc = smb2_sign_rqst(rqst, ses->server); |
680 | if (rc) { | 692 | if (rc) { |
693 | revert_current_mid_from_hdr(ses->server, shdr); | ||
681 | cifs_delete_mid(mid); | 694 | cifs_delete_mid(mid); |
682 | return ERR_PTR(rc); | 695 | return ERR_PTR(rc); |
683 | } | 696 | } |
697 | |||
684 | return mid; | 698 | return mid; |
685 | } | 699 | } |
686 | 700 | ||
@@ -692,14 +706,21 @@ smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
692 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; | 706 | (struct smb2_sync_hdr *)rqst->rq_iov[0].iov_base; |
693 | struct mid_q_entry *mid; | 707 | struct mid_q_entry *mid; |
694 | 708 | ||
709 | if (server->tcpStatus == CifsNeedNegotiate && | ||
710 | shdr->Command != SMB2_NEGOTIATE) | ||
711 | return ERR_PTR(-EAGAIN); | ||
712 | |||
695 | smb2_seq_num_into_buf(server, shdr); | 713 | smb2_seq_num_into_buf(server, shdr); |
696 | 714 | ||
697 | mid = smb2_mid_entry_alloc(shdr, server); | 715 | mid = smb2_mid_entry_alloc(shdr, server); |
698 | if (mid == NULL) | 716 | if (mid == NULL) { |
717 | revert_current_mid_from_hdr(server, shdr); | ||
699 | return ERR_PTR(-ENOMEM); | 718 | return ERR_PTR(-ENOMEM); |
719 | } | ||
700 | 720 | ||
701 | rc = smb2_sign_rqst(rqst, server); | 721 | rc = smb2_sign_rqst(rqst, server); |
702 | if (rc) { | 722 | if (rc) { |
723 | revert_current_mid_from_hdr(server, shdr); | ||
703 | DeleteMidQEntry(mid); | 724 | DeleteMidQEntry(mid); |
704 | return ERR_PTR(rc); | 725 | return ERR_PTR(rc); |
705 | } | 726 | } |
diff --git a/fs/cifs/smbdirect.c b/fs/cifs/smbdirect.c index a568dac7b3a1..b943b74cd246 100644 --- a/fs/cifs/smbdirect.c +++ b/fs/cifs/smbdirect.c | |||
@@ -1550,7 +1550,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) | |||
1550 | char name[MAX_NAME_LEN]; | 1550 | char name[MAX_NAME_LEN]; |
1551 | int rc; | 1551 | int rc; |
1552 | 1552 | ||
1553 | snprintf(name, MAX_NAME_LEN, "smbd_request_%p", info); | 1553 | scnprintf(name, MAX_NAME_LEN, "smbd_request_%p", info); |
1554 | info->request_cache = | 1554 | info->request_cache = |
1555 | kmem_cache_create( | 1555 | kmem_cache_create( |
1556 | name, | 1556 | name, |
@@ -1566,7 +1566,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) | |||
1566 | if (!info->request_mempool) | 1566 | if (!info->request_mempool) |
1567 | goto out1; | 1567 | goto out1; |
1568 | 1568 | ||
1569 | snprintf(name, MAX_NAME_LEN, "smbd_response_%p", info); | 1569 | scnprintf(name, MAX_NAME_LEN, "smbd_response_%p", info); |
1570 | info->response_cache = | 1570 | info->response_cache = |
1571 | kmem_cache_create( | 1571 | kmem_cache_create( |
1572 | name, | 1572 | name, |
@@ -1582,7 +1582,7 @@ static int allocate_caches_and_workqueue(struct smbd_connection *info) | |||
1582 | if (!info->response_mempool) | 1582 | if (!info->response_mempool) |
1583 | goto out3; | 1583 | goto out3; |
1584 | 1584 | ||
1585 | snprintf(name, MAX_NAME_LEN, "smbd_%p", info); | 1585 | scnprintf(name, MAX_NAME_LEN, "smbd_%p", info); |
1586 | info->workqueue = create_workqueue(name); | 1586 | info->workqueue = create_workqueue(name); |
1587 | if (!info->workqueue) | 1587 | if (!info->workqueue) |
1588 | goto out4; | 1588 | goto out4; |
diff --git a/fs/cifs/trace.h b/fs/cifs/trace.h index 59be48206932..d8b049afa606 100644 --- a/fs/cifs/trace.h +++ b/fs/cifs/trace.h | |||
@@ -58,6 +58,7 @@ DEFINE_EVENT(smb3_rw_err_class, smb3_##name, \ | |||
58 | 58 | ||
59 | DEFINE_SMB3_RW_ERR_EVENT(write_err); | 59 | DEFINE_SMB3_RW_ERR_EVENT(write_err); |
60 | DEFINE_SMB3_RW_ERR_EVENT(read_err); | 60 | DEFINE_SMB3_RW_ERR_EVENT(read_err); |
61 | DEFINE_SMB3_RW_ERR_EVENT(query_dir_err); | ||
61 | 62 | ||
62 | 63 | ||
63 | /* For logging successful read or write */ | 64 | /* For logging successful read or write */ |
@@ -100,8 +101,12 @@ DEFINE_EVENT(smb3_rw_done_class, smb3_##name, \ | |||
100 | __u32 len), \ | 101 | __u32 len), \ |
101 | TP_ARGS(xid, fid, tid, sesid, offset, len)) | 102 | TP_ARGS(xid, fid, tid, sesid, offset, len)) |
102 | 103 | ||
104 | DEFINE_SMB3_RW_DONE_EVENT(write_enter); | ||
105 | DEFINE_SMB3_RW_DONE_EVENT(read_enter); | ||
106 | DEFINE_SMB3_RW_DONE_EVENT(query_dir_enter); | ||
103 | DEFINE_SMB3_RW_DONE_EVENT(write_done); | 107 | DEFINE_SMB3_RW_DONE_EVENT(write_done); |
104 | DEFINE_SMB3_RW_DONE_EVENT(read_done); | 108 | DEFINE_SMB3_RW_DONE_EVENT(read_done); |
109 | DEFINE_SMB3_RW_DONE_EVENT(query_dir_done); | ||
105 | 110 | ||
106 | /* | 111 | /* |
107 | * For handle based calls other than read and write, and get/set info | 112 | * For handle based calls other than read and write, and get/set info |
@@ -148,6 +153,48 @@ DEFINE_SMB3_FD_ERR_EVENT(close_err); | |||
148 | /* | 153 | /* |
149 | * For handle based query/set info calls | 154 | * For handle based query/set info calls |
150 | */ | 155 | */ |
156 | DECLARE_EVENT_CLASS(smb3_inf_enter_class, | ||
157 | TP_PROTO(unsigned int xid, | ||
158 | __u64 fid, | ||
159 | __u32 tid, | ||
160 | __u64 sesid, | ||
161 | __u8 infclass, | ||
162 | __u32 type), | ||
163 | TP_ARGS(xid, fid, tid, sesid, infclass, type), | ||
164 | TP_STRUCT__entry( | ||
165 | __field(unsigned int, xid) | ||
166 | __field(__u64, fid) | ||
167 | __field(__u32, tid) | ||
168 | __field(__u64, sesid) | ||
169 | __field(__u8, infclass) | ||
170 | __field(__u32, type) | ||
171 | ), | ||
172 | TP_fast_assign( | ||
173 | __entry->xid = xid; | ||
174 | __entry->fid = fid; | ||
175 | __entry->tid = tid; | ||
176 | __entry->sesid = sesid; | ||
177 | __entry->infclass = infclass; | ||
178 | __entry->type = type; | ||
179 | ), | ||
180 | TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx class=%u type=0x%x", | ||
181 | __entry->xid, __entry->sesid, __entry->tid, __entry->fid, | ||
182 | __entry->infclass, __entry->type) | ||
183 | ) | ||
184 | |||
185 | #define DEFINE_SMB3_INF_ENTER_EVENT(name) \ | ||
186 | DEFINE_EVENT(smb3_inf_enter_class, smb3_##name, \ | ||
187 | TP_PROTO(unsigned int xid, \ | ||
188 | __u64 fid, \ | ||
189 | __u32 tid, \ | ||
190 | __u64 sesid, \ | ||
191 | __u8 infclass, \ | ||
192 | __u32 type), \ | ||
193 | TP_ARGS(xid, fid, tid, sesid, infclass, type)) | ||
194 | |||
195 | DEFINE_SMB3_INF_ENTER_EVENT(query_info_enter); | ||
196 | DEFINE_SMB3_INF_ENTER_EVENT(query_info_done); | ||
197 | |||
151 | DECLARE_EVENT_CLASS(smb3_inf_err_class, | 198 | DECLARE_EVENT_CLASS(smb3_inf_err_class, |
152 | TP_PROTO(unsigned int xid, | 199 | TP_PROTO(unsigned int xid, |
153 | __u64 fid, | 200 | __u64 fid, |
@@ -270,6 +317,7 @@ DEFINE_EVENT(smb3_cmd_done_class, smb3_##name, \ | |||
270 | __u64 mid), \ | 317 | __u64 mid), \ |
271 | TP_ARGS(tid, sesid, cmd, mid)) | 318 | TP_ARGS(tid, sesid, cmd, mid)) |
272 | 319 | ||
320 | DEFINE_SMB3_CMD_DONE_EVENT(cmd_enter); | ||
273 | DEFINE_SMB3_CMD_DONE_EVENT(cmd_done); | 321 | DEFINE_SMB3_CMD_DONE_EVENT(cmd_done); |
274 | DEFINE_SMB3_CMD_DONE_EVENT(ses_expired); | 322 | DEFINE_SMB3_CMD_DONE_EVENT(ses_expired); |
275 | 323 | ||
@@ -406,8 +454,47 @@ DEFINE_SMB3_TCON_EVENT(tcon); | |||
406 | 454 | ||
407 | 455 | ||
408 | /* | 456 | /* |
409 | * For smb2/smb3 open call | 457 | * For smb2/smb3 open (including create and mkdir) calls |
410 | */ | 458 | */ |
459 | |||
460 | DECLARE_EVENT_CLASS(smb3_open_enter_class, | ||
461 | TP_PROTO(unsigned int xid, | ||
462 | __u32 tid, | ||
463 | __u64 sesid, | ||
464 | int create_options, | ||
465 | int desired_access), | ||
466 | TP_ARGS(xid, tid, sesid, create_options, desired_access), | ||
467 | TP_STRUCT__entry( | ||
468 | __field(unsigned int, xid) | ||
469 | __field(__u32, tid) | ||
470 | __field(__u64, sesid) | ||
471 | __field(int, create_options) | ||
472 | __field(int, desired_access) | ||
473 | ), | ||
474 | TP_fast_assign( | ||
475 | __entry->xid = xid; | ||
476 | __entry->tid = tid; | ||
477 | __entry->sesid = sesid; | ||
478 | __entry->create_options = create_options; | ||
479 | __entry->desired_access = desired_access; | ||
480 | ), | ||
481 | TP_printk("xid=%u sid=0x%llx tid=0x%x cr_opts=0x%x des_access=0x%x", | ||
482 | __entry->xid, __entry->sesid, __entry->tid, | ||
483 | __entry->create_options, __entry->desired_access) | ||
484 | ) | ||
485 | |||
486 | #define DEFINE_SMB3_OPEN_ENTER_EVENT(name) \ | ||
487 | DEFINE_EVENT(smb3_open_enter_class, smb3_##name, \ | ||
488 | TP_PROTO(unsigned int xid, \ | ||
489 | __u32 tid, \ | ||
490 | __u64 sesid, \ | ||
491 | int create_options, \ | ||
492 | int desired_access), \ | ||
493 | TP_ARGS(xid, tid, sesid, create_options, desired_access)) | ||
494 | |||
495 | DEFINE_SMB3_OPEN_ENTER_EVENT(open_enter); | ||
496 | DEFINE_SMB3_OPEN_ENTER_EVENT(posix_mkdir_enter); | ||
497 | |||
411 | DECLARE_EVENT_CLASS(smb3_open_err_class, | 498 | DECLARE_EVENT_CLASS(smb3_open_err_class, |
412 | TP_PROTO(unsigned int xid, | 499 | TP_PROTO(unsigned int xid, |
413 | __u32 tid, | 500 | __u32 tid, |
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 53532bd3f50d..7ce8a585abd6 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
34 | #include <asm/processor.h> | 34 | #include <asm/processor.h> |
35 | #include <linux/mempool.h> | 35 | #include <linux/mempool.h> |
36 | #include <linux/signal.h> | ||
36 | #include "cifspdu.h" | 37 | #include "cifspdu.h" |
37 | #include "cifsglob.h" | 38 | #include "cifsglob.h" |
38 | #include "cifsproto.h" | 39 | #include "cifsproto.h" |
@@ -291,6 +292,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, | |||
291 | int n_vec; | 292 | int n_vec; |
292 | unsigned int send_length = 0; | 293 | unsigned int send_length = 0; |
293 | unsigned int i, j; | 294 | unsigned int i, j; |
295 | sigset_t mask, oldmask; | ||
294 | size_t total_len = 0, sent, size; | 296 | size_t total_len = 0, sent, size; |
295 | struct socket *ssocket = server->ssocket; | 297 | struct socket *ssocket = server->ssocket; |
296 | struct msghdr smb_msg; | 298 | struct msghdr smb_msg; |
@@ -301,8 +303,14 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, | |||
301 | rc = smbd_send(server, rqst); | 303 | rc = smbd_send(server, rqst); |
302 | goto smbd_done; | 304 | goto smbd_done; |
303 | } | 305 | } |
306 | |||
304 | if (ssocket == NULL) | 307 | if (ssocket == NULL) |
305 | return -ENOTSOCK; | 308 | return -EAGAIN; |
309 | |||
310 | if (signal_pending(current)) { | ||
311 | cifs_dbg(FYI, "signal is pending before sending any data\n"); | ||
312 | return -EINTR; | ||
313 | } | ||
306 | 314 | ||
307 | /* cork the socket */ | 315 | /* cork the socket */ |
308 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, | 316 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, |
@@ -312,6 +320,16 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, | |||
312 | send_length += smb_rqst_len(server, &rqst[j]); | 320 | send_length += smb_rqst_len(server, &rqst[j]); |
313 | rfc1002_marker = cpu_to_be32(send_length); | 321 | rfc1002_marker = cpu_to_be32(send_length); |
314 | 322 | ||
323 | /* | ||
324 | * We should not allow signals to interrupt the network send because | ||
325 | * any partial send will cause session reconnects thus increasing | ||
326 | * latency of system calls and overload a server with unnecessary | ||
327 | * requests. | ||
328 | */ | ||
329 | |||
330 | sigfillset(&mask); | ||
331 | sigprocmask(SIG_BLOCK, &mask, &oldmask); | ||
332 | |||
315 | /* Generate a rfc1002 marker for SMB2+ */ | 333 | /* Generate a rfc1002 marker for SMB2+ */ |
316 | if (server->vals->header_preamble_size == 0) { | 334 | if (server->vals->header_preamble_size == 0) { |
317 | struct kvec hiov = { | 335 | struct kvec hiov = { |
@@ -321,7 +339,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, | |||
321 | iov_iter_kvec(&smb_msg.msg_iter, WRITE, &hiov, 1, 4); | 339 | iov_iter_kvec(&smb_msg.msg_iter, WRITE, &hiov, 1, 4); |
322 | rc = smb_send_kvec(server, &smb_msg, &sent); | 340 | rc = smb_send_kvec(server, &smb_msg, &sent); |
323 | if (rc < 0) | 341 | if (rc < 0) |
324 | goto uncork; | 342 | goto unmask; |
325 | 343 | ||
326 | total_len += sent; | 344 | total_len += sent; |
327 | send_length += 4; | 345 | send_length += 4; |
@@ -343,7 +361,7 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, | |||
343 | 361 | ||
344 | rc = smb_send_kvec(server, &smb_msg, &sent); | 362 | rc = smb_send_kvec(server, &smb_msg, &sent); |
345 | if (rc < 0) | 363 | if (rc < 0) |
346 | goto uncork; | 364 | goto unmask; |
347 | 365 | ||
348 | total_len += sent; | 366 | total_len += sent; |
349 | 367 | ||
@@ -365,7 +383,25 @@ __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, | |||
365 | } | 383 | } |
366 | } | 384 | } |
367 | 385 | ||
368 | uncork: | 386 | unmask: |
387 | sigprocmask(SIG_SETMASK, &oldmask, NULL); | ||
388 | |||
389 | /* | ||
390 | * If signal is pending but we have already sent the whole packet to | ||
391 | * the server we need to return success status to allow a corresponding | ||
392 | * mid entry to be kept in the pending requests queue thus allowing | ||
393 | * to handle responses from the server by the client. | ||
394 | * | ||
395 | * If only part of the packet has been sent there is no need to hide | ||
396 | * interrupt because the session will be reconnected anyway, so there | ||
397 | * won't be any response from the server to handle. | ||
398 | */ | ||
399 | |||
400 | if (signal_pending(current) && (total_len != send_length)) { | ||
401 | cifs_dbg(FYI, "signal is pending after attempt to send\n"); | ||
402 | rc = -EINTR; | ||
403 | } | ||
404 | |||
369 | /* uncork it */ | 405 | /* uncork it */ |
370 | val = 0; | 406 | val = 0; |
371 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, | 407 | kernel_setsockopt(ssocket, SOL_TCP, TCP_CORK, |
@@ -451,15 +487,18 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, | |||
451 | 487 | ||
452 | static int | 488 | static int |
453 | wait_for_free_credits(struct TCP_Server_Info *server, const int timeout, | 489 | wait_for_free_credits(struct TCP_Server_Info *server, const int timeout, |
454 | int *credits) | 490 | int *credits, unsigned int *instance) |
455 | { | 491 | { |
456 | int rc; | 492 | int rc; |
457 | 493 | ||
494 | *instance = 0; | ||
495 | |||
458 | spin_lock(&server->req_lock); | 496 | spin_lock(&server->req_lock); |
459 | if (timeout == CIFS_ASYNC_OP) { | 497 | if (timeout == CIFS_ASYNC_OP) { |
460 | /* oplock breaks must not be held up */ | 498 | /* oplock breaks must not be held up */ |
461 | server->in_flight++; | 499 | server->in_flight++; |
462 | *credits -= 1; | 500 | *credits -= 1; |
501 | *instance = server->reconnect_instance; | ||
463 | spin_unlock(&server->req_lock); | 502 | spin_unlock(&server->req_lock); |
464 | return 0; | 503 | return 0; |
465 | } | 504 | } |
@@ -489,6 +528,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int timeout, | |||
489 | if (timeout != CIFS_BLOCKING_OP) { | 528 | if (timeout != CIFS_BLOCKING_OP) { |
490 | *credits -= 1; | 529 | *credits -= 1; |
491 | server->in_flight++; | 530 | server->in_flight++; |
531 | *instance = server->reconnect_instance; | ||
492 | } | 532 | } |
493 | spin_unlock(&server->req_lock); | 533 | spin_unlock(&server->req_lock); |
494 | break; | 534 | break; |
@@ -499,7 +539,7 @@ wait_for_free_credits(struct TCP_Server_Info *server, const int timeout, | |||
499 | 539 | ||
500 | static int | 540 | static int |
501 | wait_for_free_request(struct TCP_Server_Info *server, const int timeout, | 541 | wait_for_free_request(struct TCP_Server_Info *server, const int timeout, |
502 | const int optype) | 542 | const int optype, unsigned int *instance) |
503 | { | 543 | { |
504 | int *val; | 544 | int *val; |
505 | 545 | ||
@@ -507,15 +547,16 @@ wait_for_free_request(struct TCP_Server_Info *server, const int timeout, | |||
507 | /* Since an echo is already inflight, no need to wait to send another */ | 547 | /* Since an echo is already inflight, no need to wait to send another */ |
508 | if (*val <= 0 && optype == CIFS_ECHO_OP) | 548 | if (*val <= 0 && optype == CIFS_ECHO_OP) |
509 | return -EAGAIN; | 549 | return -EAGAIN; |
510 | return wait_for_free_credits(server, timeout, val); | 550 | return wait_for_free_credits(server, timeout, val, instance); |
511 | } | 551 | } |
512 | 552 | ||
513 | int | 553 | int |
514 | cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, | 554 | cifs_wait_mtu_credits(struct TCP_Server_Info *server, unsigned int size, |
515 | unsigned int *num, unsigned int *credits) | 555 | unsigned int *num, struct cifs_credits *credits) |
516 | { | 556 | { |
517 | *num = size; | 557 | *num = size; |
518 | *credits = 0; | 558 | credits->value = 0; |
559 | credits->instance = server->reconnect_instance; | ||
519 | return 0; | 560 | return 0; |
520 | } | 561 | } |
521 | 562 | ||
@@ -602,27 +643,43 @@ cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst) | |||
602 | int | 643 | int |
603 | cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, | 644 | cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, |
604 | mid_receive_t *receive, mid_callback_t *callback, | 645 | mid_receive_t *receive, mid_callback_t *callback, |
605 | mid_handle_t *handle, void *cbdata, const int flags) | 646 | mid_handle_t *handle, void *cbdata, const int flags, |
647 | const struct cifs_credits *exist_credits) | ||
606 | { | 648 | { |
607 | int rc, timeout, optype; | 649 | int rc, timeout, optype; |
608 | struct mid_q_entry *mid; | 650 | struct mid_q_entry *mid; |
609 | unsigned int credits = 0; | 651 | struct cifs_credits credits = { .value = 0, .instance = 0 }; |
652 | unsigned int instance; | ||
610 | 653 | ||
611 | timeout = flags & CIFS_TIMEOUT_MASK; | 654 | timeout = flags & CIFS_TIMEOUT_MASK; |
612 | optype = flags & CIFS_OP_MASK; | 655 | optype = flags & CIFS_OP_MASK; |
613 | 656 | ||
614 | if ((flags & CIFS_HAS_CREDITS) == 0) { | 657 | if ((flags & CIFS_HAS_CREDITS) == 0) { |
615 | rc = wait_for_free_request(server, timeout, optype); | 658 | rc = wait_for_free_request(server, timeout, optype, &instance); |
616 | if (rc) | 659 | if (rc) |
617 | return rc; | 660 | return rc; |
618 | credits = 1; | 661 | credits.value = 1; |
619 | } | 662 | credits.instance = instance; |
663 | } else | ||
664 | instance = exist_credits->instance; | ||
620 | 665 | ||
621 | mutex_lock(&server->srv_mutex); | 666 | mutex_lock(&server->srv_mutex); |
667 | |||
668 | /* | ||
669 | * We can't use credits obtained from the previous session to send this | ||
670 | * request. Check if there were reconnects after we obtained credits and | ||
671 | * return -EAGAIN in such cases to let callers handle it. | ||
672 | */ | ||
673 | if (instance != server->reconnect_instance) { | ||
674 | mutex_unlock(&server->srv_mutex); | ||
675 | add_credits_and_wake_if(server, &credits, optype); | ||
676 | return -EAGAIN; | ||
677 | } | ||
678 | |||
622 | mid = server->ops->setup_async_request(server, rqst); | 679 | mid = server->ops->setup_async_request(server, rqst); |
623 | if (IS_ERR(mid)) { | 680 | if (IS_ERR(mid)) { |
624 | mutex_unlock(&server->srv_mutex); | 681 | mutex_unlock(&server->srv_mutex); |
625 | add_credits_and_wake_if(server, credits, optype); | 682 | add_credits_and_wake_if(server, &credits, optype); |
626 | return PTR_ERR(mid); | 683 | return PTR_ERR(mid); |
627 | } | 684 | } |
628 | 685 | ||
@@ -647,6 +704,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, | |||
647 | cifs_in_send_dec(server); | 704 | cifs_in_send_dec(server); |
648 | 705 | ||
649 | if (rc < 0) { | 706 | if (rc < 0) { |
707 | revert_current_mid(server, mid->credits); | ||
650 | server->sequence_number -= 2; | 708 | server->sequence_number -= 2; |
651 | cifs_delete_mid(mid); | 709 | cifs_delete_mid(mid); |
652 | } | 710 | } |
@@ -656,7 +714,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, | |||
656 | if (rc == 0) | 714 | if (rc == 0) |
657 | return 0; | 715 | return 0; |
658 | 716 | ||
659 | add_credits_and_wake_if(server, credits, optype); | 717 | add_credits_and_wake_if(server, &credits, optype); |
660 | return rc; | 718 | return rc; |
661 | } | 719 | } |
662 | 720 | ||
@@ -786,8 +844,12 @@ static void | |||
786 | cifs_compound_callback(struct mid_q_entry *mid) | 844 | cifs_compound_callback(struct mid_q_entry *mid) |
787 | { | 845 | { |
788 | struct TCP_Server_Info *server = mid->server; | 846 | struct TCP_Server_Info *server = mid->server; |
847 | struct cifs_credits credits; | ||
848 | |||
849 | credits.value = server->ops->get_credits(mid); | ||
850 | credits.instance = server->reconnect_instance; | ||
789 | 851 | ||
790 | add_credits(server, server->ops->get_credits(mid), mid->optype); | 852 | add_credits(server, &credits, mid->optype); |
791 | } | 853 | } |
792 | 854 | ||
793 | static void | 855 | static void |
@@ -813,7 +875,11 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, | |||
813 | int timeout, optype; | 875 | int timeout, optype; |
814 | struct mid_q_entry *midQ[MAX_COMPOUND]; | 876 | struct mid_q_entry *midQ[MAX_COMPOUND]; |
815 | bool cancelled_mid[MAX_COMPOUND] = {false}; | 877 | bool cancelled_mid[MAX_COMPOUND] = {false}; |
816 | unsigned int credits[MAX_COMPOUND] = {0}; | 878 | struct cifs_credits credits[MAX_COMPOUND] = { |
879 | { .value = 0, .instance = 0 } | ||
880 | }; | ||
881 | unsigned int instance; | ||
882 | unsigned int first_instance = 0; | ||
817 | char *buf; | 883 | char *buf; |
818 | 884 | ||
819 | timeout = flags & CIFS_TIMEOUT_MASK; | 885 | timeout = flags & CIFS_TIMEOUT_MASK; |
@@ -830,16 +896,64 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, | |||
830 | if (ses->server->tcpStatus == CifsExiting) | 896 | if (ses->server->tcpStatus == CifsExiting) |
831 | return -ENOENT; | 897 | return -ENOENT; |
832 | 898 | ||
899 | spin_lock(&ses->server->req_lock); | ||
900 | if (ses->server->credits < num_rqst) { | ||
901 | /* | ||
902 | * Return immediately if not too many requests in flight since | ||
903 | * we will likely be stuck on waiting for credits. | ||
904 | */ | ||
905 | if (ses->server->in_flight < num_rqst - ses->server->credits) { | ||
906 | spin_unlock(&ses->server->req_lock); | ||
907 | return -ENOTSUPP; | ||
908 | } | ||
909 | } else { | ||
910 | /* enough credits to send the whole compounded request */ | ||
911 | ses->server->credits -= num_rqst; | ||
912 | ses->server->in_flight += num_rqst; | ||
913 | first_instance = ses->server->reconnect_instance; | ||
914 | } | ||
915 | spin_unlock(&ses->server->req_lock); | ||
916 | |||
917 | if (first_instance) { | ||
918 | cifs_dbg(FYI, "Acquired %d credits at once\n", num_rqst); | ||
919 | for (i = 0; i < num_rqst; i++) { | ||
920 | credits[i].value = 1; | ||
921 | credits[i].instance = first_instance; | ||
922 | } | ||
923 | goto setup_rqsts; | ||
924 | } | ||
925 | |||
833 | /* | 926 | /* |
927 | * There are not enough credits to send the whole compound request but | ||
928 | * there are requests in flight that may bring credits from the server. | ||
929 | * This approach still leaves the possibility to be stuck waiting for | ||
930 | * credits if the server doesn't grant credits to the outstanding | ||
931 | * requests. This should be fixed by returning immediately and letting | ||
932 | * a caller fallback to sequential commands instead of compounding. | ||
834 | * Ensure we obtain 1 credit per request in the compound chain. | 933 | * Ensure we obtain 1 credit per request in the compound chain. |
835 | * It can be optimized further by waiting for all the credits | ||
836 | * at once but this can wait long enough if we don't have enough | ||
837 | * credits due to some heavy operations in progress or the server | ||
838 | * not granting us much, so a fallback to the current approach is | ||
839 | * needed anyway. | ||
840 | */ | 934 | */ |
841 | for (i = 0; i < num_rqst; i++) { | 935 | for (i = 0; i < num_rqst; i++) { |
842 | rc = wait_for_free_request(ses->server, timeout, optype); | 936 | rc = wait_for_free_request(ses->server, timeout, optype, |
937 | &instance); | ||
938 | |||
939 | if (rc == 0) { | ||
940 | credits[i].value = 1; | ||
941 | credits[i].instance = instance; | ||
942 | /* | ||
943 | * All parts of the compound chain must get credits from | ||
944 | * the same session, otherwise we may end up using more | ||
945 | * credits than the server granted. If there were | ||
946 | * reconnects in between, return -EAGAIN and let callers | ||
947 | * handle it. | ||
948 | */ | ||
949 | if (i == 0) | ||
950 | first_instance = instance; | ||
951 | else if (first_instance != instance) { | ||
952 | i++; | ||
953 | rc = -EAGAIN; | ||
954 | } | ||
955 | } | ||
956 | |||
843 | if (rc) { | 957 | if (rc) { |
844 | /* | 958 | /* |
845 | * We haven't sent an SMB packet to the server yet but | 959 | * We haven't sent an SMB packet to the server yet but |
@@ -851,12 +965,12 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, | |||
851 | * requests correctly. | 965 | * requests correctly. |
852 | */ | 966 | */ |
853 | for (j = 0; j < i; j++) | 967 | for (j = 0; j < i; j++) |
854 | add_credits(ses->server, 1, optype); | 968 | add_credits(ses->server, &credits[j], optype); |
855 | return rc; | 969 | return rc; |
856 | } | 970 | } |
857 | credits[i] = 1; | ||
858 | } | 971 | } |
859 | 972 | ||
973 | setup_rqsts: | ||
860 | /* | 974 | /* |
861 | * Make sure that we sign in the same order that we send on this socket | 975 | * Make sure that we sign in the same order that we send on this socket |
862 | * and avoid races inside tcp sendmsg code that could cause corruption | 976 | * and avoid races inside tcp sendmsg code that could cause corruption |
@@ -865,16 +979,33 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, | |||
865 | 979 | ||
866 | mutex_lock(&ses->server->srv_mutex); | 980 | mutex_lock(&ses->server->srv_mutex); |
867 | 981 | ||
982 | /* | ||
983 | * All the parts of the compound chain belong obtained credits from the | ||
984 | * same session (see the appropriate checks above). In the same time | ||
985 | * there might be reconnects after those checks but before we acquired | ||
986 | * the srv_mutex. We can not use credits obtained from the previous | ||
987 | * session to send this request. Check if there were reconnects after | ||
988 | * we obtained credits and return -EAGAIN in such cases to let callers | ||
989 | * handle it. | ||
990 | */ | ||
991 | if (first_instance != ses->server->reconnect_instance) { | ||
992 | mutex_unlock(&ses->server->srv_mutex); | ||
993 | for (j = 0; j < num_rqst; j++) | ||
994 | add_credits(ses->server, &credits[j], optype); | ||
995 | return -EAGAIN; | ||
996 | } | ||
997 | |||
868 | for (i = 0; i < num_rqst; i++) { | 998 | for (i = 0; i < num_rqst; i++) { |
869 | midQ[i] = ses->server->ops->setup_request(ses, &rqst[i]); | 999 | midQ[i] = ses->server->ops->setup_request(ses, &rqst[i]); |
870 | if (IS_ERR(midQ[i])) { | 1000 | if (IS_ERR(midQ[i])) { |
1001 | revert_current_mid(ses->server, i); | ||
871 | for (j = 0; j < i; j++) | 1002 | for (j = 0; j < i; j++) |
872 | cifs_delete_mid(midQ[j]); | 1003 | cifs_delete_mid(midQ[j]); |
873 | mutex_unlock(&ses->server->srv_mutex); | 1004 | mutex_unlock(&ses->server->srv_mutex); |
874 | 1005 | ||
875 | /* Update # of requests on wire to server */ | 1006 | /* Update # of requests on wire to server */ |
876 | for (j = 0; j < num_rqst; j++) | 1007 | for (j = 0; j < num_rqst; j++) |
877 | add_credits(ses->server, credits[j], optype); | 1008 | add_credits(ses->server, &credits[j], optype); |
878 | return PTR_ERR(midQ[i]); | 1009 | return PTR_ERR(midQ[i]); |
879 | } | 1010 | } |
880 | 1011 | ||
@@ -897,15 +1028,17 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, | |||
897 | for (i = 0; i < num_rqst; i++) | 1028 | for (i = 0; i < num_rqst; i++) |
898 | cifs_save_when_sent(midQ[i]); | 1029 | cifs_save_when_sent(midQ[i]); |
899 | 1030 | ||
900 | if (rc < 0) | 1031 | if (rc < 0) { |
1032 | revert_current_mid(ses->server, num_rqst); | ||
901 | ses->server->sequence_number -= 2; | 1033 | ses->server->sequence_number -= 2; |
1034 | } | ||
902 | 1035 | ||
903 | mutex_unlock(&ses->server->srv_mutex); | 1036 | mutex_unlock(&ses->server->srv_mutex); |
904 | 1037 | ||
905 | if (rc < 0) { | 1038 | if (rc < 0) { |
906 | /* Sending failed for some reason - return credits back */ | 1039 | /* Sending failed for some reason - return credits back */ |
907 | for (i = 0; i < num_rqst; i++) | 1040 | for (i = 0; i < num_rqst; i++) |
908 | add_credits(ses->server, credits[i], optype); | 1041 | add_credits(ses->server, &credits[i], optype); |
909 | goto out; | 1042 | goto out; |
910 | } | 1043 | } |
911 | 1044 | ||
@@ -942,7 +1075,7 @@ compound_send_recv(const unsigned int xid, struct cifs_ses *ses, | |||
942 | midQ[i]->mid_flags |= MID_WAIT_CANCELLED; | 1075 | midQ[i]->mid_flags |= MID_WAIT_CANCELLED; |
943 | midQ[i]->callback = cifs_cancelled_callback; | 1076 | midQ[i]->callback = cifs_cancelled_callback; |
944 | cancelled_mid[i] = true; | 1077 | cancelled_mid[i] = true; |
945 | credits[i] = 0; | 1078 | credits[i].value = 0; |
946 | } | 1079 | } |
947 | spin_unlock(&GlobalMid_Lock); | 1080 | spin_unlock(&GlobalMid_Lock); |
948 | } | 1081 | } |
@@ -1068,6 +1201,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
1068 | unsigned int len = be32_to_cpu(in_buf->smb_buf_length); | 1201 | unsigned int len = be32_to_cpu(in_buf->smb_buf_length); |
1069 | struct kvec iov = { .iov_base = in_buf, .iov_len = len }; | 1202 | struct kvec iov = { .iov_base = in_buf, .iov_len = len }; |
1070 | struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 }; | 1203 | struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 }; |
1204 | struct cifs_credits credits = { .value = 1, .instance = 0 }; | ||
1071 | 1205 | ||
1072 | if (ses == NULL) { | 1206 | if (ses == NULL) { |
1073 | cifs_dbg(VFS, "Null smb session\n"); | 1207 | cifs_dbg(VFS, "Null smb session\n"); |
@@ -1091,7 +1225,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
1091 | return -EIO; | 1225 | return -EIO; |
1092 | } | 1226 | } |
1093 | 1227 | ||
1094 | rc = wait_for_free_request(ses->server, timeout, 0); | 1228 | rc = wait_for_free_request(ses->server, timeout, 0, &credits.instance); |
1095 | if (rc) | 1229 | if (rc) |
1096 | return rc; | 1230 | return rc; |
1097 | 1231 | ||
@@ -1105,7 +1239,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
1105 | if (rc) { | 1239 | if (rc) { |
1106 | mutex_unlock(&ses->server->srv_mutex); | 1240 | mutex_unlock(&ses->server->srv_mutex); |
1107 | /* Update # of requests on wire to server */ | 1241 | /* Update # of requests on wire to server */ |
1108 | add_credits(ses->server, 1, 0); | 1242 | add_credits(ses->server, &credits, 0); |
1109 | return rc; | 1243 | return rc; |
1110 | } | 1244 | } |
1111 | 1245 | ||
@@ -1141,7 +1275,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
1141 | /* no longer considered to be "in-flight" */ | 1275 | /* no longer considered to be "in-flight" */ |
1142 | midQ->callback = DeleteMidQEntry; | 1276 | midQ->callback = DeleteMidQEntry; |
1143 | spin_unlock(&GlobalMid_Lock); | 1277 | spin_unlock(&GlobalMid_Lock); |
1144 | add_credits(ses->server, 1, 0); | 1278 | add_credits(ses->server, &credits, 0); |
1145 | return rc; | 1279 | return rc; |
1146 | } | 1280 | } |
1147 | spin_unlock(&GlobalMid_Lock); | 1281 | spin_unlock(&GlobalMid_Lock); |
@@ -1149,7 +1283,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
1149 | 1283 | ||
1150 | rc = cifs_sync_mid_result(midQ, ses->server); | 1284 | rc = cifs_sync_mid_result(midQ, ses->server); |
1151 | if (rc != 0) { | 1285 | if (rc != 0) { |
1152 | add_credits(ses->server, 1, 0); | 1286 | add_credits(ses->server, &credits, 0); |
1153 | return rc; | 1287 | return rc; |
1154 | } | 1288 | } |
1155 | 1289 | ||
@@ -1165,7 +1299,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
1165 | rc = cifs_check_receive(midQ, ses->server, 0); | 1299 | rc = cifs_check_receive(midQ, ses->server, 0); |
1166 | out: | 1300 | out: |
1167 | cifs_delete_mid(midQ); | 1301 | cifs_delete_mid(midQ); |
1168 | add_credits(ses->server, 1, 0); | 1302 | add_credits(ses->server, &credits, 0); |
1169 | 1303 | ||
1170 | return rc; | 1304 | return rc; |
1171 | } | 1305 | } |
@@ -1207,6 +1341,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, | |||
1207 | unsigned int len = be32_to_cpu(in_buf->smb_buf_length); | 1341 | unsigned int len = be32_to_cpu(in_buf->smb_buf_length); |
1208 | struct kvec iov = { .iov_base = in_buf, .iov_len = len }; | 1342 | struct kvec iov = { .iov_base = in_buf, .iov_len = len }; |
1209 | struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 }; | 1343 | struct smb_rqst rqst = { .rq_iov = &iov, .rq_nvec = 1 }; |
1344 | unsigned int instance; | ||
1210 | 1345 | ||
1211 | if (tcon == NULL || tcon->ses == NULL) { | 1346 | if (tcon == NULL || tcon->ses == NULL) { |
1212 | cifs_dbg(VFS, "Null smb session\n"); | 1347 | cifs_dbg(VFS, "Null smb session\n"); |
@@ -1232,7 +1367,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifs_tcon *tcon, | |||
1232 | return -EIO; | 1367 | return -EIO; |
1233 | } | 1368 | } |
1234 | 1369 | ||
1235 | rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP, 0); | 1370 | rc = wait_for_free_request(ses->server, CIFS_BLOCKING_OP, 0, |
1371 | &instance); | ||
1236 | if (rc) | 1372 | if (rc) |
1237 | return rc; | 1373 | return rc; |
1238 | 1374 | ||