diff options
author | Steve French <sfrench@us.ibm.com> | 2008-10-28 20:47:57 -0400 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2008-10-28 20:47:57 -0400 |
commit | edf1ae403896cb7750800508b14996ba6be39a53 (patch) | |
tree | ff792ea77e558d473a9f6515397728d31e73fd09 /fs/cifs/transport.c | |
parent | 49fdf6785fd660e18a1eb4588928f47e9fa29a9a (diff) |
[CIFS] Reduce number of socket retries in large write path
CIFS in some heavy stress conditions cifs could get EAGAIN
repeatedly in smb_send2 which led to repeated retries and eventually
failure of large writes which could lead to data corruption.
There are three changes that were suggested by various network
developers:
1) convert cifs from non-blocking to blocking tcp sendmsg
(we left in the retry on failure)
2) change cifs to not set sendbuf and rcvbuf size for the socket
(let tcp autotune the buffer sizes since that works much better
in the TCP stack now)
3) if we have a partial frame sent in smb_send2, mark the tcp
session as invalid (close the socket and reconnect) so we do
not corrupt the remaining part of the SMB with the beginning
of the next SMB.
This does not appear to hurt performance measurably and has
been run in various scenarios, but it definately removes
a corruption that we were seeing in some high stress
test cases.
Acked-by: Shirish Pargaonkar <shirishp@us.ibm.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/transport.c')
-rw-r--r-- | fs/cifs/transport.c | 41 |
1 files changed, 31 insertions, 10 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index bf0e6d8e382a..ba4d66644ebf 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c | |||
@@ -161,7 +161,7 @@ void DeleteTconOplockQEntries(struct cifsTconInfo *tcon) | |||
161 | 161 | ||
162 | int | 162 | int |
163 | smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | 163 | smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, |
164 | unsigned int smb_buf_length, struct sockaddr *sin) | 164 | unsigned int smb_buf_length, struct sockaddr *sin, bool noblocksnd) |
165 | { | 165 | { |
166 | int rc = 0; | 166 | int rc = 0; |
167 | int i = 0; | 167 | int i = 0; |
@@ -178,7 +178,10 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
178 | smb_msg.msg_namelen = sizeof(struct sockaddr); | 178 | smb_msg.msg_namelen = sizeof(struct sockaddr); |
179 | smb_msg.msg_control = NULL; | 179 | smb_msg.msg_control = NULL; |
180 | smb_msg.msg_controllen = 0; | 180 | smb_msg.msg_controllen = 0; |
181 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ | 181 | if (noblocksnd) |
182 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; | ||
183 | else | ||
184 | smb_msg.msg_flags = MSG_NOSIGNAL; | ||
182 | 185 | ||
183 | /* smb header is converted in header_assemble. bcc and rest of SMB word | 186 | /* smb header is converted in header_assemble. bcc and rest of SMB word |
184 | area, and byte area if necessary, is converted to littleendian in | 187 | area, and byte area if necessary, is converted to littleendian in |
@@ -229,8 +232,8 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, | |||
229 | } | 232 | } |
230 | 233 | ||
231 | static int | 234 | static int |
232 | smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | 235 | smb_send2(struct TCP_Server_Info *server, struct kvec *iov, int n_vec, |
233 | struct sockaddr *sin) | 236 | struct sockaddr *sin, bool noblocksnd) |
234 | { | 237 | { |
235 | int rc = 0; | 238 | int rc = 0; |
236 | int i = 0; | 239 | int i = 0; |
@@ -240,6 +243,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
240 | unsigned int total_len; | 243 | unsigned int total_len; |
241 | int first_vec = 0; | 244 | int first_vec = 0; |
242 | unsigned int smb_buf_length = smb_buffer->smb_buf_length; | 245 | unsigned int smb_buf_length = smb_buffer->smb_buf_length; |
246 | struct socket *ssocket = server->ssocket; | ||
243 | 247 | ||
244 | if (ssocket == NULL) | 248 | if (ssocket == NULL) |
245 | return -ENOTSOCK; /* BB eventually add reconnect code here */ | 249 | return -ENOTSOCK; /* BB eventually add reconnect code here */ |
@@ -248,7 +252,10 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
248 | smb_msg.msg_namelen = sizeof(struct sockaddr); | 252 | smb_msg.msg_namelen = sizeof(struct sockaddr); |
249 | smb_msg.msg_control = NULL; | 253 | smb_msg.msg_control = NULL; |
250 | smb_msg.msg_controllen = 0; | 254 | smb_msg.msg_controllen = 0; |
251 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ | 255 | if (noblocksnd) |
256 | smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; | ||
257 | else | ||
258 | smb_msg.msg_flags = MSG_NOSIGNAL; | ||
252 | 259 | ||
253 | /* smb header is converted in header_assemble. bcc and rest of SMB word | 260 | /* smb header is converted in header_assemble. bcc and rest of SMB word |
254 | area, and byte area if necessary, is converted to littleendian in | 261 | area, and byte area if necessary, is converted to littleendian in |
@@ -312,6 +319,16 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, | |||
312 | i = 0; /* in case we get ENOSPC on the next send */ | 319 | i = 0; /* in case we get ENOSPC on the next send */ |
313 | } | 320 | } |
314 | 321 | ||
322 | if ((total_len > 0) && (total_len != smb_buf_length + 4)) { | ||
323 | cFYI(1, ("partial send (%d remaining), terminating session", | ||
324 | total_len)); | ||
325 | /* If we have only sent part of an SMB then the next SMB | ||
326 | could be taken as the remainder of this one. We need | ||
327 | to kill the socket so the server throws away the partial | ||
328 | SMB */ | ||
329 | server->tcpStatus = CifsNeedReconnect; | ||
330 | } | ||
331 | |||
315 | if (rc < 0) { | 332 | if (rc < 0) { |
316 | cERROR(1, ("Error %d sending data on socket to server", rc)); | 333 | cERROR(1, ("Error %d sending data on socket to server", rc)); |
317 | } else | 334 | } else |
@@ -518,8 +535,9 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, | |||
518 | #ifdef CONFIG_CIFS_STATS2 | 535 | #ifdef CONFIG_CIFS_STATS2 |
519 | atomic_inc(&ses->server->inSend); | 536 | atomic_inc(&ses->server->inSend); |
520 | #endif | 537 | #endif |
521 | rc = smb_send2(ses->server->ssocket, iov, n_vec, | 538 | rc = smb_send2(ses->server, iov, n_vec, |
522 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 539 | (struct sockaddr *) &(ses->server->addr.sockAddr), |
540 | ses->server->noblocksnd); | ||
523 | #ifdef CONFIG_CIFS_STATS2 | 541 | #ifdef CONFIG_CIFS_STATS2 |
524 | atomic_dec(&ses->server->inSend); | 542 | atomic_dec(&ses->server->inSend); |
525 | midQ->when_sent = jiffies; | 543 | midQ->when_sent = jiffies; |
@@ -711,7 +729,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, | |||
711 | atomic_inc(&ses->server->inSend); | 729 | atomic_inc(&ses->server->inSend); |
712 | #endif | 730 | #endif |
713 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 731 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
714 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 732 | (struct sockaddr *) &(ses->server->addr.sockAddr), |
733 | ses->server->noblocksnd); | ||
715 | #ifdef CONFIG_CIFS_STATS2 | 734 | #ifdef CONFIG_CIFS_STATS2 |
716 | atomic_dec(&ses->server->inSend); | 735 | atomic_dec(&ses->server->inSend); |
717 | midQ->when_sent = jiffies; | 736 | midQ->when_sent = jiffies; |
@@ -851,7 +870,8 @@ send_nt_cancel(struct cifsTconInfo *tcon, struct smb_hdr *in_buf, | |||
851 | return rc; | 870 | return rc; |
852 | } | 871 | } |
853 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 872 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
854 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 873 | (struct sockaddr *) &(ses->server->addr.sockAddr), |
874 | ses->server->noblocksnd); | ||
855 | up(&ses->server->tcpSem); | 875 | up(&ses->server->tcpSem); |
856 | return rc; | 876 | return rc; |
857 | } | 877 | } |
@@ -941,7 +961,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, | |||
941 | atomic_inc(&ses->server->inSend); | 961 | atomic_inc(&ses->server->inSend); |
942 | #endif | 962 | #endif |
943 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, | 963 | rc = smb_send(ses->server->ssocket, in_buf, in_buf->smb_buf_length, |
944 | (struct sockaddr *) &(ses->server->addr.sockAddr)); | 964 | (struct sockaddr *) &(ses->server->addr.sockAddr), |
965 | ses->server->noblocksnd); | ||
945 | #ifdef CONFIG_CIFS_STATS2 | 966 | #ifdef CONFIG_CIFS_STATS2 |
946 | atomic_dec(&ses->server->inSend); | 967 | atomic_dec(&ses->server->inSend); |
947 | midQ->when_sent = jiffies; | 968 | midQ->when_sent = jiffies; |