diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/cifs/README | 6 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.c | 3 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 25 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 47 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 9 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 18 | ||||
-rw-r--r-- | fs/cifs/connect.c | 44 | ||||
-rw-r--r-- | fs/cifs/dir.c | 6 | ||||
-rw-r--r-- | fs/cifs/file.c | 23 | ||||
-rw-r--r-- | fs/cifs/misc.c | 19 | ||||
-rw-r--r-- | fs/cifs/transport.c | 78 |
11 files changed, 169 insertions, 109 deletions
diff --git a/fs/cifs/README b/fs/cifs/README index 895da1dc1550..b7d782bab797 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
@@ -753,10 +753,6 @@ module loading or during the runtime by using the interface | |||
753 | 753 | ||
754 | i.e. echo "value" > /sys/module/cifs/parameters/<param> | 754 | i.e. echo "value" > /sys/module/cifs/parameters/<param> |
755 | 755 | ||
756 | 1. echo_retries - The number of echo attempts before giving up and | 756 | 1. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default. |
757 | reconnecting to the server. The default is 5. The value 0 | ||
758 | means never reconnect. | ||
759 | |||
760 | 2. enable_oplocks - Enable or disable oplocks. Oplocks are enabled by default. | ||
761 | [Y/y/1]. To disable use any of [N/n/0]. | 757 | [Y/y/1]. To disable use any of [N/n/0]. |
762 | 758 | ||
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 24b3dfc05282..573b899b5a5d 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c | |||
@@ -171,8 +171,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
171 | seq_printf(m, "TCP status: %d\n\tLocal Users To " | 171 | seq_printf(m, "TCP status: %d\n\tLocal Users To " |
172 | "Server: %d SecMode: 0x%x Req On Wire: %d", | 172 | "Server: %d SecMode: 0x%x Req On Wire: %d", |
173 | server->tcpStatus, server->srv_count, | 173 | server->tcpStatus, server->srv_count, |
174 | server->sec_mode, | 174 | server->sec_mode, in_flight(server)); |
175 | atomic_read(&server->inFlight)); | ||
176 | 175 | ||
177 | #ifdef CONFIG_CIFS_STATS2 | 176 | #ifdef CONFIG_CIFS_STATS2 |
178 | seq_printf(m, " In Send: %d In MaxReq Wait: %d", | 177 | seq_printf(m, " In Send: %d In MaxReq Wait: %d", |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 418fc42fb8b2..eee522c56ef0 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -76,12 +76,7 @@ MODULE_PARM_DESC(cifs_min_small, "Small network buffers in pool. Default: 30 " | |||
76 | unsigned int cifs_max_pending = CIFS_MAX_REQ; | 76 | unsigned int cifs_max_pending = CIFS_MAX_REQ; |
77 | module_param(cifs_max_pending, int, 0444); | 77 | module_param(cifs_max_pending, int, 0444); |
78 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " | 78 | MODULE_PARM_DESC(cifs_max_pending, "Simultaneous requests to server. " |
79 | "Default: 50 Range: 2 to 256"); | 79 | "Default: 32767 Range: 2 to 32767."); |
80 | unsigned short echo_retries = 5; | ||
81 | module_param(echo_retries, ushort, 0644); | ||
82 | MODULE_PARM_DESC(echo_retries, "Number of echo attempts before giving up and " | ||
83 | "reconnecting server. Default: 5. 0 means " | ||
84 | "never reconnect."); | ||
85 | module_param(enable_oplocks, bool, 0644); | 80 | module_param(enable_oplocks, bool, 0644); |
86 | MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:" | 81 | MODULE_PARM_DESC(enable_oplocks, "Enable or disable oplocks (bool). Default:" |
87 | "y/Y/1"); | 82 | "y/Y/1"); |
@@ -1111,9 +1106,9 @@ init_cifs(void) | |||
1111 | if (cifs_max_pending < 2) { | 1106 | if (cifs_max_pending < 2) { |
1112 | cifs_max_pending = 2; | 1107 | cifs_max_pending = 2; |
1113 | cFYI(1, "cifs_max_pending set to min of 2"); | 1108 | cFYI(1, "cifs_max_pending set to min of 2"); |
1114 | } else if (cifs_max_pending > 256) { | 1109 | } else if (cifs_max_pending > CIFS_MAX_REQ) { |
1115 | cifs_max_pending = 256; | 1110 | cifs_max_pending = CIFS_MAX_REQ; |
1116 | cFYI(1, "cifs_max_pending set to max of 256"); | 1111 | cFYI(1, "cifs_max_pending set to max of %u", CIFS_MAX_REQ); |
1117 | } | 1112 | } |
1118 | 1113 | ||
1119 | rc = cifs_fscache_register(); | 1114 | rc = cifs_fscache_register(); |
@@ -1175,11 +1170,8 @@ static void __exit | |||
1175 | exit_cifs(void) | 1170 | exit_cifs(void) |
1176 | { | 1171 | { |
1177 | cFYI(DBG2, "exit_cifs"); | 1172 | cFYI(DBG2, "exit_cifs"); |
1178 | cifs_proc_clean(); | 1173 | unregister_filesystem(&cifs_fs_type); |
1179 | cifs_fscache_unregister(); | ||
1180 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
1181 | cifs_dfs_release_automount_timer(); | 1174 | cifs_dfs_release_automount_timer(); |
1182 | #endif | ||
1183 | #ifdef CONFIG_CIFS_ACL | 1175 | #ifdef CONFIG_CIFS_ACL |
1184 | cifs_destroy_idmaptrees(); | 1176 | cifs_destroy_idmaptrees(); |
1185 | exit_cifs_idmap(); | 1177 | exit_cifs_idmap(); |
@@ -1187,10 +1179,11 @@ exit_cifs(void) | |||
1187 | #ifdef CONFIG_CIFS_UPCALL | 1179 | #ifdef CONFIG_CIFS_UPCALL |
1188 | unregister_key_type(&cifs_spnego_key_type); | 1180 | unregister_key_type(&cifs_spnego_key_type); |
1189 | #endif | 1181 | #endif |
1190 | unregister_filesystem(&cifs_fs_type); | ||
1191 | cifs_destroy_inodecache(); | ||
1192 | cifs_destroy_mids(); | ||
1193 | cifs_destroy_request_bufs(); | 1182 | cifs_destroy_request_bufs(); |
1183 | cifs_destroy_mids(); | ||
1184 | cifs_destroy_inodecache(); | ||
1185 | cifs_fscache_unregister(); | ||
1186 | cifs_proc_clean(); | ||
1194 | } | 1187 | } |
1195 | 1188 | ||
1196 | MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); | 1189 | MODULE_AUTHOR("Steve French <sfrench@us.ibm.com>"); |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 76e7d8b6da17..339ebe3ebc0d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -55,14 +55,9 @@ | |||
55 | 55 | ||
56 | /* | 56 | /* |
57 | * MAX_REQ is the maximum number of requests that WE will send | 57 | * MAX_REQ is the maximum number of requests that WE will send |
58 | * on one socket concurrently. It also matches the most common | 58 | * on one socket concurrently. |
59 | * value of max multiplex returned by servers. We may | ||
60 | * eventually want to use the negotiated value (in case | ||
61 | * future servers can handle more) when we are more confident that | ||
62 | * we will not have problems oveloading the socket with pending | ||
63 | * write data. | ||
64 | */ | 59 | */ |
65 | #define CIFS_MAX_REQ 50 | 60 | #define CIFS_MAX_REQ 32767 |
66 | 61 | ||
67 | #define RFC1001_NAME_LEN 15 | 62 | #define RFC1001_NAME_LEN 15 |
68 | #define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1) | 63 | #define RFC1001_NAME_LEN_WITH_NULL (RFC1001_NAME_LEN + 1) |
@@ -255,7 +250,9 @@ struct TCP_Server_Info { | |||
255 | bool noblocksnd; /* use blocking sendmsg */ | 250 | bool noblocksnd; /* use blocking sendmsg */ |
256 | bool noautotune; /* do not autotune send buf sizes */ | 251 | bool noautotune; /* do not autotune send buf sizes */ |
257 | bool tcp_nodelay; | 252 | bool tcp_nodelay; |
258 | atomic_t inFlight; /* number of requests on the wire to server */ | 253 | int credits; /* send no more requests at once */ |
254 | unsigned int in_flight; /* number of requests on the wire to server */ | ||
255 | spinlock_t req_lock; /* protect the two values above */ | ||
259 | struct mutex srv_mutex; | 256 | struct mutex srv_mutex; |
260 | struct task_struct *tsk; | 257 | struct task_struct *tsk; |
261 | char server_GUID[16]; | 258 | char server_GUID[16]; |
@@ -263,6 +260,7 @@ struct TCP_Server_Info { | |||
263 | bool session_estab; /* mark when very first sess is established */ | 260 | bool session_estab; /* mark when very first sess is established */ |
264 | u16 dialect; /* dialect index that server chose */ | 261 | u16 dialect; /* dialect index that server chose */ |
265 | enum securityEnum secType; | 262 | enum securityEnum secType; |
263 | bool oplocks:1; /* enable oplocks */ | ||
266 | unsigned int maxReq; /* Clients should submit no more */ | 264 | unsigned int maxReq; /* Clients should submit no more */ |
267 | /* than maxReq distinct unanswered SMBs to the server when using */ | 265 | /* than maxReq distinct unanswered SMBs to the server when using */ |
268 | /* multiplexed reads or writes */ | 266 | /* multiplexed reads or writes */ |
@@ -307,6 +305,36 @@ struct TCP_Server_Info { | |||
307 | #endif | 305 | #endif |
308 | }; | 306 | }; |
309 | 307 | ||
308 | static inline unsigned int | ||
309 | in_flight(struct TCP_Server_Info *server) | ||
310 | { | ||
311 | unsigned int num; | ||
312 | spin_lock(&server->req_lock); | ||
313 | num = server->in_flight; | ||
314 | spin_unlock(&server->req_lock); | ||
315 | return num; | ||
316 | } | ||
317 | |||
318 | static inline int* | ||
319 | get_credits_field(struct TCP_Server_Info *server) | ||
320 | { | ||
321 | /* | ||
322 | * This will change to switch statement when we reserve slots for echos | ||
323 | * and oplock breaks. | ||
324 | */ | ||
325 | return &server->credits; | ||
326 | } | ||
327 | |||
328 | static inline bool | ||
329 | has_credits(struct TCP_Server_Info *server, int *credits) | ||
330 | { | ||
331 | int num; | ||
332 | spin_lock(&server->req_lock); | ||
333 | num = *credits; | ||
334 | spin_unlock(&server->req_lock); | ||
335 | return num > 0; | ||
336 | } | ||
337 | |||
310 | /* | 338 | /* |
311 | * Macros to allow the TCP_Server_Info->net field and related code to drop out | 339 | * Macros to allow the TCP_Server_Info->net field and related code to drop out |
312 | * when CONFIG_NET_NS isn't set. | 340 | * when CONFIG_NET_NS isn't set. |
@@ -1010,9 +1038,6 @@ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ | |||
1010 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ | 1038 | GLOBAL_EXTERN unsigned int cifs_min_small; /* min size of small buf pool */ |
1011 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ | 1039 | GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/ |
1012 | 1040 | ||
1013 | /* reconnect after this many failed echo attempts */ | ||
1014 | GLOBAL_EXTERN unsigned short echo_retries; | ||
1015 | |||
1016 | #ifdef CONFIG_CIFS_ACL | 1041 | #ifdef CONFIG_CIFS_ACL |
1017 | GLOBAL_EXTERN struct rb_root uidtree; | 1042 | GLOBAL_EXTERN struct rb_root uidtree; |
1018 | GLOBAL_EXTERN struct rb_root gidtree; | 1043 | GLOBAL_EXTERN struct rb_root gidtree; |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 6f4e243e0f62..503e73d8bdb7 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -88,6 +88,9 @@ extern int SendReceiveBlockingLock(const unsigned int xid, | |||
88 | struct smb_hdr *in_buf , | 88 | struct smb_hdr *in_buf , |
89 | struct smb_hdr *out_buf, | 89 | struct smb_hdr *out_buf, |
90 | int *bytes_returned); | 90 | int *bytes_returned); |
91 | extern void cifs_add_credits(struct TCP_Server_Info *server, | ||
92 | const unsigned int add); | ||
93 | extern void cifs_set_credits(struct TCP_Server_Info *server, const int val); | ||
91 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); | 94 | extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); |
92 | extern bool is_valid_oplock_break(struct smb_hdr *smb, | 95 | extern bool is_valid_oplock_break(struct smb_hdr *smb, |
93 | struct TCP_Server_Info *); | 96 | struct TCP_Server_Info *); |
@@ -168,7 +171,13 @@ extern struct smb_vol *cifs_get_volume_info(char *mount_data, | |||
168 | const char *devname); | 171 | const char *devname); |
169 | extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); | 172 | extern int cifs_mount(struct cifs_sb_info *, struct smb_vol *); |
170 | extern void cifs_umount(struct cifs_sb_info *); | 173 | extern void cifs_umount(struct cifs_sb_info *); |
174 | |||
175 | #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) | ||
171 | extern void cifs_dfs_release_automount_timer(void); | 176 | extern void cifs_dfs_release_automount_timer(void); |
177 | #else /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */ | ||
178 | #define cifs_dfs_release_automount_timer() do { } while (0) | ||
179 | #endif /* ! IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) */ | ||
180 | |||
172 | void cifs_proc_init(void); | 181 | void cifs_proc_init(void); |
173 | void cifs_proc_clean(void); | 182 | void cifs_proc_clean(void); |
174 | 183 | ||
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 8b7794c31591..70aac35c398f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
@@ -458,7 +458,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) | |||
458 | goto neg_err_exit; | 458 | goto neg_err_exit; |
459 | } | 459 | } |
460 | server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode); | 460 | server->sec_mode = (__u8)le16_to_cpu(rsp->SecurityMode); |
461 | server->maxReq = le16_to_cpu(rsp->MaxMpxCount); | 461 | server->maxReq = min_t(unsigned int, |
462 | le16_to_cpu(rsp->MaxMpxCount), | ||
463 | cifs_max_pending); | ||
464 | cifs_set_credits(server, server->maxReq); | ||
462 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); | 465 | server->maxBuf = le16_to_cpu(rsp->MaxBufSize); |
463 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); | 466 | server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs); |
464 | /* even though we do not use raw we might as well set this | 467 | /* even though we do not use raw we might as well set this |
@@ -564,7 +567,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifs_ses *ses) | |||
564 | 567 | ||
565 | /* one byte, so no need to convert this or EncryptionKeyLen from | 568 | /* one byte, so no need to convert this or EncryptionKeyLen from |
566 | little endian */ | 569 | little endian */ |
567 | server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); | 570 | server->maxReq = min_t(unsigned int, le16_to_cpu(pSMBr->MaxMpxCount), |
571 | cifs_max_pending); | ||
572 | cifs_set_credits(server, server->maxReq); | ||
568 | /* probably no need to store and check maxvcs */ | 573 | /* probably no need to store and check maxvcs */ |
569 | server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); | 574 | server->maxBuf = le32_to_cpu(pSMBr->MaxBufferSize); |
570 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); | 575 | server->max_rw = le32_to_cpu(pSMBr->MaxRawSize); |
@@ -716,8 +721,7 @@ cifs_echo_callback(struct mid_q_entry *mid) | |||
716 | struct TCP_Server_Info *server = mid->callback_data; | 721 | struct TCP_Server_Info *server = mid->callback_data; |
717 | 722 | ||
718 | DeleteMidQEntry(mid); | 723 | DeleteMidQEntry(mid); |
719 | atomic_dec(&server->inFlight); | 724 | cifs_add_credits(server, 1); |
720 | wake_up(&server->request_q); | ||
721 | } | 725 | } |
722 | 726 | ||
723 | int | 727 | int |
@@ -1669,8 +1673,7 @@ cifs_readv_callback(struct mid_q_entry *mid) | |||
1669 | 1673 | ||
1670 | queue_work(system_nrt_wq, &rdata->work); | 1674 | queue_work(system_nrt_wq, &rdata->work); |
1671 | DeleteMidQEntry(mid); | 1675 | DeleteMidQEntry(mid); |
1672 | atomic_dec(&server->inFlight); | 1676 | cifs_add_credits(server, 1); |
1673 | wake_up(&server->request_q); | ||
1674 | } | 1677 | } |
1675 | 1678 | ||
1676 | /* cifs_async_readv - send an async write, and set up mid to handle result */ | 1679 | /* cifs_async_readv - send an async write, and set up mid to handle result */ |
@@ -2110,8 +2113,7 @@ cifs_writev_callback(struct mid_q_entry *mid) | |||
2110 | 2113 | ||
2111 | queue_work(system_nrt_wq, &wdata->work); | 2114 | queue_work(system_nrt_wq, &wdata->work); |
2112 | DeleteMidQEntry(mid); | 2115 | DeleteMidQEntry(mid); |
2113 | atomic_dec(&tcon->ses->server->inFlight); | 2116 | cifs_add_credits(tcon->ses->server, 1); |
2114 | wake_up(&tcon->ses->server->request_q); | ||
2115 | } | 2117 | } |
2116 | 2118 | ||
2117 | /* cifs_async_writev - send an async write, and set up mid to handle result */ | 2119 | /* cifs_async_writev - send an async write, and set up mid to handle result */ |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 602f77c304c9..5560e1d5e54b 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -373,12 +373,22 @@ allocate_buffers(struct TCP_Server_Info *server) | |||
373 | static bool | 373 | static bool |
374 | server_unresponsive(struct TCP_Server_Info *server) | 374 | server_unresponsive(struct TCP_Server_Info *server) |
375 | { | 375 | { |
376 | if (echo_retries > 0 && server->tcpStatus == CifsGood && | 376 | /* |
377 | time_after(jiffies, server->lstrp + | 377 | * We need to wait 2 echo intervals to make sure we handle such |
378 | (echo_retries * SMB_ECHO_INTERVAL))) { | 378 | * situations right: |
379 | * 1s client sends a normal SMB request | ||
380 | * 2s client gets a response | ||
381 | * 30s echo workqueue job pops, and decides we got a response recently | ||
382 | * and don't need to send another | ||
383 | * ... | ||
384 | * 65s kernel_recvmsg times out, and we see that we haven't gotten | ||
385 | * a response in >60s. | ||
386 | */ | ||
387 | if (server->tcpStatus == CifsGood && | ||
388 | time_after(jiffies, server->lstrp + 2 * SMB_ECHO_INTERVAL)) { | ||
379 | cERROR(1, "Server %s has not responded in %d seconds. " | 389 | cERROR(1, "Server %s has not responded in %d seconds. " |
380 | "Reconnecting...", server->hostname, | 390 | "Reconnecting...", server->hostname, |
381 | (echo_retries * SMB_ECHO_INTERVAL / HZ)); | 391 | (2 * SMB_ECHO_INTERVAL) / HZ); |
382 | cifs_reconnect(server); | 392 | cifs_reconnect(server); |
383 | wake_up(&server->response_q); | 393 | wake_up(&server->response_q); |
384 | return true; | 394 | return true; |
@@ -642,19 +652,11 @@ static void clean_demultiplex_info(struct TCP_Server_Info *server) | |||
642 | spin_unlock(&GlobalMid_Lock); | 652 | spin_unlock(&GlobalMid_Lock); |
643 | wake_up_all(&server->response_q); | 653 | wake_up_all(&server->response_q); |
644 | 654 | ||
645 | /* | 655 | /* check if we have blocked requests that need to free */ |
646 | * Check if we have blocked requests that need to free. Note that | 656 | spin_lock(&server->req_lock); |
647 | * cifs_max_pending is normally 50, but can be set at module install | 657 | if (server->credits <= 0) |
648 | * time to as little as two. | 658 | server->credits = 1; |
649 | */ | 659 | spin_unlock(&server->req_lock); |
650 | spin_lock(&GlobalMid_Lock); | ||
651 | if (atomic_read(&server->inFlight) >= cifs_max_pending) | ||
652 | atomic_set(&server->inFlight, cifs_max_pending - 1); | ||
653 | /* | ||
654 | * We do not want to set the max_pending too low or we could end up | ||
655 | * with the counter going negative. | ||
656 | */ | ||
657 | spin_unlock(&GlobalMid_Lock); | ||
658 | /* | 660 | /* |
659 | * Although there should not be any requests blocked on this queue it | 661 | * Although there should not be any requests blocked on this queue it |
660 | * can not hurt to be paranoid and try to wake up requests that may | 662 | * can not hurt to be paranoid and try to wake up requests that may |
@@ -1909,7 +1911,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1909 | tcp_ses->noblocksnd = volume_info->noblocksnd; | 1911 | tcp_ses->noblocksnd = volume_info->noblocksnd; |
1910 | tcp_ses->noautotune = volume_info->noautotune; | 1912 | tcp_ses->noautotune = volume_info->noautotune; |
1911 | tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; | 1913 | tcp_ses->tcp_nodelay = volume_info->sockopt_tcp_nodelay; |
1912 | atomic_set(&tcp_ses->inFlight, 0); | 1914 | tcp_ses->in_flight = 0; |
1915 | tcp_ses->credits = 1; | ||
1913 | init_waitqueue_head(&tcp_ses->response_q); | 1916 | init_waitqueue_head(&tcp_ses->response_q); |
1914 | init_waitqueue_head(&tcp_ses->request_q); | 1917 | init_waitqueue_head(&tcp_ses->request_q); |
1915 | INIT_LIST_HEAD(&tcp_ses->pending_mid_q); | 1918 | INIT_LIST_HEAD(&tcp_ses->pending_mid_q); |
@@ -3371,7 +3374,7 @@ cifs_ra_pages(struct cifs_sb_info *cifs_sb) | |||
3371 | int | 3374 | int |
3372 | cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) | 3375 | cifs_mount(struct cifs_sb_info *cifs_sb, struct smb_vol *volume_info) |
3373 | { | 3376 | { |
3374 | int rc = 0; | 3377 | int rc; |
3375 | int xid; | 3378 | int xid; |
3376 | struct cifs_ses *pSesInfo; | 3379 | struct cifs_ses *pSesInfo; |
3377 | struct cifs_tcon *tcon; | 3380 | struct cifs_tcon *tcon; |
@@ -3398,6 +3401,7 @@ try_mount_again: | |||
3398 | FreeXid(xid); | 3401 | FreeXid(xid); |
3399 | } | 3402 | } |
3400 | #endif | 3403 | #endif |
3404 | rc = 0; | ||
3401 | tcon = NULL; | 3405 | tcon = NULL; |
3402 | pSesInfo = NULL; | 3406 | pSesInfo = NULL; |
3403 | srvTcp = NULL; | 3407 | srvTcp = NULL; |
@@ -3759,9 +3763,11 @@ int cifs_negotiate_protocol(unsigned int xid, struct cifs_ses *ses) | |||
3759 | if (server->maxBuf != 0) | 3763 | if (server->maxBuf != 0) |
3760 | return 0; | 3764 | return 0; |
3761 | 3765 | ||
3766 | cifs_set_credits(server, 1); | ||
3762 | rc = CIFSSMBNegotiate(xid, ses); | 3767 | rc = CIFSSMBNegotiate(xid, ses); |
3763 | if (rc == -EAGAIN) { | 3768 | if (rc == -EAGAIN) { |
3764 | /* retry only once on 1st time connection */ | 3769 | /* retry only once on 1st time connection */ |
3770 | cifs_set_credits(server, 1); | ||
3765 | rc = CIFSSMBNegotiate(xid, ses); | 3771 | rc = CIFSSMBNegotiate(xid, ses); |
3766 | if (rc == -EAGAIN) | 3772 | if (rc == -EAGAIN) |
3767 | rc = -EHOSTDOWN; | 3773 | rc = -EHOSTDOWN; |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index bc7e24420ac0..d172c8ed9017 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -171,7 +171,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode, | |||
171 | } | 171 | } |
172 | tcon = tlink_tcon(tlink); | 172 | tcon = tlink_tcon(tlink); |
173 | 173 | ||
174 | if (enable_oplocks) | 174 | if (tcon->ses->server->oplocks) |
175 | oplock = REQ_OPLOCK; | 175 | oplock = REQ_OPLOCK; |
176 | 176 | ||
177 | if (nd) | 177 | if (nd) |
@@ -492,7 +492,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
492 | { | 492 | { |
493 | int xid; | 493 | int xid; |
494 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ | 494 | int rc = 0; /* to get around spurious gcc warning, set to zero here */ |
495 | __u32 oplock = enable_oplocks ? REQ_OPLOCK : 0; | 495 | __u32 oplock; |
496 | __u16 fileHandle = 0; | 496 | __u16 fileHandle = 0; |
497 | bool posix_open = false; | 497 | bool posix_open = false; |
498 | struct cifs_sb_info *cifs_sb; | 498 | struct cifs_sb_info *cifs_sb; |
@@ -518,6 +518,8 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
518 | } | 518 | } |
519 | pTcon = tlink_tcon(tlink); | 519 | pTcon = tlink_tcon(tlink); |
520 | 520 | ||
521 | oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0; | ||
522 | |||
521 | /* | 523 | /* |
522 | * Don't allow the separator character in a path component. | 524 | * Don't allow the separator character in a path component. |
523 | * The VFS will not allow "/", but "\" is allowed by posix. | 525 | * The VFS will not allow "/", but "\" is allowed by posix. |
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5e64748a2917..159fcc56dc2d 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -380,7 +380,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
380 | cFYI(1, "inode = 0x%p file flags are 0x%x for %s", | 380 | cFYI(1, "inode = 0x%p file flags are 0x%x for %s", |
381 | inode, file->f_flags, full_path); | 381 | inode, file->f_flags, full_path); |
382 | 382 | ||
383 | if (enable_oplocks) | 383 | if (tcon->ses->server->oplocks) |
384 | oplock = REQ_OPLOCK; | 384 | oplock = REQ_OPLOCK; |
385 | else | 385 | else |
386 | oplock = 0; | 386 | oplock = 0; |
@@ -505,7 +505,7 @@ static int cifs_reopen_file(struct cifsFileInfo *pCifsFile, bool can_flush) | |||
505 | cFYI(1, "inode = 0x%p file flags 0x%x for %s", | 505 | cFYI(1, "inode = 0x%p file flags 0x%x for %s", |
506 | inode, pCifsFile->f_flags, full_path); | 506 | inode, pCifsFile->f_flags, full_path); |
507 | 507 | ||
508 | if (enable_oplocks) | 508 | if (tcon->ses->server->oplocks) |
509 | oplock = REQ_OPLOCK; | 509 | oplock = REQ_OPLOCK; |
510 | else | 510 | else |
511 | oplock = 0; | 511 | oplock = 0; |
@@ -960,9 +960,9 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
960 | INIT_LIST_HEAD(&locks_to_send); | 960 | INIT_LIST_HEAD(&locks_to_send); |
961 | 961 | ||
962 | /* | 962 | /* |
963 | * Allocating count locks is enough because no locks can be added to | 963 | * Allocating count locks is enough because no FL_POSIX locks can be |
964 | * the list while we are holding cinode->lock_mutex that protects | 964 | * added to the list while we are holding cinode->lock_mutex that |
965 | * locking operations of this inode. | 965 | * protects locking operations of this inode. |
966 | */ | 966 | */ |
967 | for (; i < count; i++) { | 967 | for (; i < count; i++) { |
968 | lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); | 968 | lck = kmalloc(sizeof(struct lock_to_push), GFP_KERNEL); |
@@ -973,18 +973,20 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
973 | list_add_tail(&lck->llist, &locks_to_send); | 973 | list_add_tail(&lck->llist, &locks_to_send); |
974 | } | 974 | } |
975 | 975 | ||
976 | i = 0; | ||
977 | el = locks_to_send.next; | 976 | el = locks_to_send.next; |
978 | lock_flocks(); | 977 | lock_flocks(); |
979 | cifs_for_each_lock(cfile->dentry->d_inode, before) { | 978 | cifs_for_each_lock(cfile->dentry->d_inode, before) { |
979 | flock = *before; | ||
980 | if ((flock->fl_flags & FL_POSIX) == 0) | ||
981 | continue; | ||
980 | if (el == &locks_to_send) { | 982 | if (el == &locks_to_send) { |
981 | /* something is really wrong */ | 983 | /* |
984 | * The list ended. We don't have enough allocated | ||
985 | * structures - something is really wrong. | ||
986 | */ | ||
982 | cERROR(1, "Can't push all brlocks!"); | 987 | cERROR(1, "Can't push all brlocks!"); |
983 | break; | 988 | break; |
984 | } | 989 | } |
985 | flock = *before; | ||
986 | if ((flock->fl_flags & FL_POSIX) == 0) | ||
987 | continue; | ||
988 | length = 1 + flock->fl_end - flock->fl_start; | 990 | length = 1 + flock->fl_end - flock->fl_start; |
989 | if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK) | 991 | if (flock->fl_type == F_RDLCK || flock->fl_type == F_SHLCK) |
990 | type = CIFS_RDLCK; | 992 | type = CIFS_RDLCK; |
@@ -996,7 +998,6 @@ cifs_push_posix_locks(struct cifsFileInfo *cfile) | |||
996 | lck->length = length; | 998 | lck->length = length; |
997 | lck->type = type; | 999 | lck->type = type; |
998 | lck->offset = flock->fl_start; | 1000 | lck->offset = flock->fl_start; |
999 | i++; | ||
1000 | el = el->next; | 1001 | el = el->next; |
1001 | } | 1002 | } |
1002 | unlock_flocks(); | 1003 | unlock_flocks(); |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 703ef5c6fdb1..c273c12de98e 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -690,3 +690,22 @@ backup_cred(struct cifs_sb_info *cifs_sb) | |||
690 | 690 | ||
691 | return false; | 691 | return false; |
692 | } | 692 | } |
693 | |||
694 | void | ||
695 | cifs_add_credits(struct TCP_Server_Info *server, const unsigned int add) | ||
696 | { | ||
697 | spin_lock(&server->req_lock); | ||
698 | server->credits += add; | ||
699 | server->in_flight--; | ||
700 | spin_unlock(&server->req_lock); | ||
701 | wake_up(&server->request_q); | ||
702 | } | ||
703 | |||
704 | void | ||
705 | cifs_set_credits(struct TCP_Server_Info *server, const int val) | ||
706 | { | ||
707 | spin_lock(&server->req_lock); | ||
708 | server->credits = val; | ||
709 | server->oplocks = val > 1 ? enable_oplocks : false; | ||
710 | spin_unlock(&server->req_lock); | ||
711 | } | ||
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 0cc9584f5889..310918b6fcb4 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -254,44 +254,60 @@ smb_send(struct TCP_Server_Info *server, struct smb_hdr *smb_buffer, | |||
254 | return smb_sendv(server, &iov, 1); | 254 | return smb_sendv(server, &iov, 1); |
255 | } | 255 | } |
256 | 256 | ||
257 | static int wait_for_free_request(struct TCP_Server_Info *server, | 257 | static int |
258 | const int long_op) | 258 | wait_for_free_credits(struct TCP_Server_Info *server, const int optype, |
259 | int *credits) | ||
259 | { | 260 | { |
260 | if (long_op == CIFS_ASYNC_OP) { | 261 | int rc; |
262 | |||
263 | spin_lock(&server->req_lock); | ||
264 | if (optype == CIFS_ASYNC_OP) { | ||
261 | /* oplock breaks must not be held up */ | 265 | /* oplock breaks must not be held up */ |
262 | atomic_inc(&server->inFlight); | 266 | server->in_flight++; |
267 | *credits -= 1; | ||
268 | spin_unlock(&server->req_lock); | ||
263 | return 0; | 269 | return 0; |
264 | } | 270 | } |
265 | 271 | ||
266 | spin_lock(&GlobalMid_Lock); | ||
267 | while (1) { | 272 | while (1) { |
268 | if (atomic_read(&server->inFlight) >= cifs_max_pending) { | 273 | if (*credits <= 0) { |
269 | spin_unlock(&GlobalMid_Lock); | 274 | spin_unlock(&server->req_lock); |
270 | cifs_num_waiters_inc(server); | 275 | cifs_num_waiters_inc(server); |
271 | wait_event(server->request_q, | 276 | rc = wait_event_killable(server->request_q, |
272 | atomic_read(&server->inFlight) | 277 | has_credits(server, credits)); |
273 | < cifs_max_pending); | ||
274 | cifs_num_waiters_dec(server); | 278 | cifs_num_waiters_dec(server); |
275 | spin_lock(&GlobalMid_Lock); | 279 | if (rc) |
280 | return rc; | ||
281 | spin_lock(&server->req_lock); | ||
276 | } else { | 282 | } else { |
277 | if (server->tcpStatus == CifsExiting) { | 283 | if (server->tcpStatus == CifsExiting) { |
278 | spin_unlock(&GlobalMid_Lock); | 284 | spin_unlock(&server->req_lock); |
279 | return -ENOENT; | 285 | return -ENOENT; |
280 | } | 286 | } |
281 | 287 | ||
282 | /* can not count locking commands against total | 288 | /* |
283 | as they are allowed to block on server */ | 289 | * Can not count locking commands against total |
290 | * as they are allowed to block on server. | ||
291 | */ | ||
284 | 292 | ||
285 | /* update # of requests on the wire to server */ | 293 | /* update # of requests on the wire to server */ |
286 | if (long_op != CIFS_BLOCKING_OP) | 294 | if (optype != CIFS_BLOCKING_OP) { |
287 | atomic_inc(&server->inFlight); | 295 | *credits -= 1; |
288 | spin_unlock(&GlobalMid_Lock); | 296 | server->in_flight++; |
297 | } | ||
298 | spin_unlock(&server->req_lock); | ||
289 | break; | 299 | break; |
290 | } | 300 | } |
291 | } | 301 | } |
292 | return 0; | 302 | return 0; |
293 | } | 303 | } |
294 | 304 | ||
305 | static int | ||
306 | wait_for_free_request(struct TCP_Server_Info *server, const int optype) | ||
307 | { | ||
308 | return wait_for_free_credits(server, optype, get_credits_field(server)); | ||
309 | } | ||
310 | |||
295 | static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, | 311 | static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, |
296 | struct mid_q_entry **ppmidQ) | 312 | struct mid_q_entry **ppmidQ) |
297 | { | 313 | { |
@@ -359,7 +375,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, | |||
359 | mid = AllocMidQEntry(hdr, server); | 375 | mid = AllocMidQEntry(hdr, server); |
360 | if (mid == NULL) { | 376 | if (mid == NULL) { |
361 | mutex_unlock(&server->srv_mutex); | 377 | mutex_unlock(&server->srv_mutex); |
362 | atomic_dec(&server->inFlight); | 378 | cifs_add_credits(server, 1); |
363 | wake_up(&server->request_q); | 379 | wake_up(&server->request_q); |
364 | return -ENOMEM; | 380 | return -ENOMEM; |
365 | } | 381 | } |
@@ -392,7 +408,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct kvec *iov, | |||
392 | return rc; | 408 | return rc; |
393 | out_err: | 409 | out_err: |
394 | delete_mid(mid); | 410 | delete_mid(mid); |
395 | atomic_dec(&server->inFlight); | 411 | cifs_add_credits(server, 1); |
396 | wake_up(&server->request_q); | 412 | wake_up(&server->request_q); |
397 | return rc; | 413 | return rc; |
398 | } | 414 | } |
@@ -564,8 +580,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
564 | mutex_unlock(&ses->server->srv_mutex); | 580 | mutex_unlock(&ses->server->srv_mutex); |
565 | cifs_small_buf_release(in_buf); | 581 | cifs_small_buf_release(in_buf); |
566 | /* Update # of requests on wire to server */ | 582 | /* Update # of requests on wire to server */ |
567 | atomic_dec(&ses->server->inFlight); | 583 | cifs_add_credits(ses->server, 1); |
568 | wake_up(&ses->server->request_q); | ||
569 | return rc; | 584 | return rc; |
570 | } | 585 | } |
571 | rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); | 586 | rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); |
@@ -601,8 +616,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
601 | midQ->callback = DeleteMidQEntry; | 616 | midQ->callback = DeleteMidQEntry; |
602 | spin_unlock(&GlobalMid_Lock); | 617 | spin_unlock(&GlobalMid_Lock); |
603 | cifs_small_buf_release(in_buf); | 618 | cifs_small_buf_release(in_buf); |
604 | atomic_dec(&ses->server->inFlight); | 619 | cifs_add_credits(ses->server, 1); |
605 | wake_up(&ses->server->request_q); | ||
606 | return rc; | 620 | return rc; |
607 | } | 621 | } |
608 | spin_unlock(&GlobalMid_Lock); | 622 | spin_unlock(&GlobalMid_Lock); |
@@ -612,8 +626,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
612 | 626 | ||
613 | rc = cifs_sync_mid_result(midQ, ses->server); | 627 | rc = cifs_sync_mid_result(midQ, ses->server); |
614 | if (rc != 0) { | 628 | if (rc != 0) { |
615 | atomic_dec(&ses->server->inFlight); | 629 | cifs_add_credits(ses->server, 1); |
616 | wake_up(&ses->server->request_q); | ||
617 | return rc; | 630 | return rc; |
618 | } | 631 | } |
619 | 632 | ||
@@ -637,8 +650,7 @@ SendReceive2(const unsigned int xid, struct cifs_ses *ses, | |||
637 | midQ->resp_buf = NULL; | 650 | midQ->resp_buf = NULL; |
638 | out: | 651 | out: |
639 | delete_mid(midQ); | 652 | delete_mid(midQ); |
640 | atomic_dec(&ses->server->inFlight); | 653 | cifs_add_credits(ses->server, 1); |
641 | wake_up(&ses->server->request_q); | ||
642 | 654 | ||
643 | return rc; | 655 | return rc; |
644 | } | 656 | } |
@@ -688,8 +700,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
688 | if (rc) { | 700 | if (rc) { |
689 | mutex_unlock(&ses->server->srv_mutex); | 701 | mutex_unlock(&ses->server->srv_mutex); |
690 | /* Update # of requests on wire to server */ | 702 | /* Update # of requests on wire to server */ |
691 | atomic_dec(&ses->server->inFlight); | 703 | cifs_add_credits(ses->server, 1); |
692 | wake_up(&ses->server->request_q); | ||
693 | return rc; | 704 | return rc; |
694 | } | 705 | } |
695 | 706 | ||
@@ -721,8 +732,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
721 | /* no longer considered to be "in-flight" */ | 732 | /* no longer considered to be "in-flight" */ |
722 | midQ->callback = DeleteMidQEntry; | 733 | midQ->callback = DeleteMidQEntry; |
723 | spin_unlock(&GlobalMid_Lock); | 734 | spin_unlock(&GlobalMid_Lock); |
724 | atomic_dec(&ses->server->inFlight); | 735 | cifs_add_credits(ses->server, 1); |
725 | wake_up(&ses->server->request_q); | ||
726 | return rc; | 736 | return rc; |
727 | } | 737 | } |
728 | spin_unlock(&GlobalMid_Lock); | 738 | spin_unlock(&GlobalMid_Lock); |
@@ -730,8 +740,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
730 | 740 | ||
731 | rc = cifs_sync_mid_result(midQ, ses->server); | 741 | rc = cifs_sync_mid_result(midQ, ses->server); |
732 | if (rc != 0) { | 742 | if (rc != 0) { |
733 | atomic_dec(&ses->server->inFlight); | 743 | cifs_add_credits(ses->server, 1); |
734 | wake_up(&ses->server->request_q); | ||
735 | return rc; | 744 | return rc; |
736 | } | 745 | } |
737 | 746 | ||
@@ -747,8 +756,7 @@ SendReceive(const unsigned int xid, struct cifs_ses *ses, | |||
747 | rc = cifs_check_receive(midQ, ses->server, 0); | 756 | rc = cifs_check_receive(midQ, ses->server, 0); |
748 | out: | 757 | out: |
749 | delete_mid(midQ); | 758 | delete_mid(midQ); |
750 | atomic_dec(&ses->server->inFlight); | 759 | cifs_add_credits(ses->server, 1); |
751 | wake_up(&ses->server->request_q); | ||
752 | 760 | ||
753 | return rc; | 761 | return rc; |
754 | } | 762 | } |