aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/transport.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-10-28 20:47:57 -0400
committerSteve French <sfrench@us.ibm.com>2008-10-28 20:47:57 -0400
commitedf1ae403896cb7750800508b14996ba6be39a53 (patch)
treeff792ea77e558d473a9f6515397728d31e73fd09 /fs/cifs/transport.c
parent49fdf6785fd660e18a1eb4588928f47e9fa29a9a (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.c41
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
162int 162int
163smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, 163smb_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
231static int 234static int
232smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, 235smb_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;