summary refs log tree commit diff
path: root/fs/cifs
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2006-07-16 04:32:51 +0000
committerSteve French <sfrench@us.ibm.com>2006-08-11 21:27:41 +0000
commit14a441a2b4ee1dfc00ec822d91d9fb20f401c62f (patch)
tree122a33e5e056bdd433e78b4f6a1c9f8e2d3385d2 /fs/cifs
parent3a5ff61c18659443f76bad6cf06f60103046de5d (diff)
downloadlinux-14a441a2b4ee1dfc00ec822d91d9fb20f401c62f.tar.gz
[CIFS] spinlock protect read of last srv response time in timeout path
Signed-off-by: Jeremy Allison <jra@samba.org>
Signed-off-by: Steve French <sfrench@us.ibm.com>
(cherry picked from b33a3f55e54fd210fc043eafcf83728b03bc9e02 commit)
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/transport.c99
1 files changed, 76 insertions, 23 deletions
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 95e23ca670a8..d16e6032d4cf 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -3,7 +3,8 @@
  *
  *   Copyright (C) International Business Machines  Corp., 2002,2005
  *   Author(s): Steve French (sfrench@us.ibm.com)
- *
+ *   Jeremy Allison (jra@samba.org) 2006.
+ *    
  *   This library is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU Lesser General Public License as published
  *   by the Free Software Foundation; either version 2.1 of the License, or
@@ -442,13 +443,46 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses,
 
 	/* No user interrupts in wait - wreaks havoc with performance */
 	if(timeout != MAX_SCHEDULE_TIMEOUT) {
-		timeout += jiffies;
-		wait_event(ses->server->response_q,
-			(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||
-			(time_after(jiffies, timeout) &&
-				time_after(jiffies, ses->server->lstrp + HZ)) ||
-			((ses->server->tcpStatus != CifsGood) &&
-			 (ses->server->tcpStatus != CifsNew)));
+		unsigned long curr_timeout;
+
+		for (;;) {
+			curr_timeout = timeout + jiffies;
+			wait_event(ses->server->response_q,
+				(!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
+				time_after(jiffies, curr_timeout) || 
+				((ses->server->tcpStatus != CifsGood) &&
+				 (ses->server->tcpStatus != CifsNew)));
+
+			if (time_after(jiffies, curr_timeout) &&
+				(midQ->midState & MID_REQUEST_SUBMITTED) &&
+				((ses->server->tcpStatus == CifsGood) ||
+				 (ses->server->tcpStatus == CifsNew))) {
+
+				unsigned long lrt;
+
+				/* We timed out. Is the server still
+				   sending replies ? */
+				spin_lock(&GlobalMid_Lock);
+				lrt = ses->server->lstrp;
+				spin_unlock(&GlobalMid_Lock);
+
+				/* Calculate 10 seconds past last receive time.
+				Although we prefer not to time out if the 
+				server is still responding - we will time
+				out if the server takes more than 15 (or 45 
+				or 180) seconds to respond to this request
+				and has not responded to any request from 
+				other threads on the client within 10 seconds */
+				lrt += (10 * HZ);
+				if (time_after(jiffies, lrt)) {
+					/* No replies for 10 seconds. */
+					cERROR(1,("server not responding"));
+					break;
+				}
+			} else {
+				break;
+			}
+		}
 	} else {
 		wait_event(ses->server->response_q,
 			(!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
@@ -710,21 +744,40 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses,
 
 	/* No user interrupts in wait - wreaks havoc with performance */
 	if(timeout != MAX_SCHEDULE_TIMEOUT) {
-		timeout += jiffies;
-		/* although we prefer not to time out if the server is still
-		responding - we will time out if the server takes
-		more than 15 (or 45 or 180) seconds to respond to this request
-		and has not responded to any request from other threads
-		on this client within a second (note that it is not worth
-		grabbing the GlobalMid_Lock and slowing things down in this
-		wait event to more accurately check the lstrsp field on some 
-		arch since we are already in an error path that will retry */
-		wait_event(ses->server->response_q,
-			(!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
-			(time_after(jiffies, timeout) &&
-				time_after(jiffies, ses->server->lstrp + HZ)) ||
-			((ses->server->tcpStatus != CifsGood) &&
-			 (ses->server->tcpStatus != CifsNew)));
+		unsigned long curr_timeout;
+
+		for (;;) {
+			curr_timeout = timeout + jiffies;
+			wait_event(ses->server->response_q,
+				(!(midQ->midState & MID_REQUEST_SUBMITTED)) || 
+				time_after(jiffies, curr_timeout) || 
+				((ses->server->tcpStatus != CifsGood) &&
+				 (ses->server->tcpStatus != CifsNew)));
+
+			if (time_after(jiffies, curr_timeout) &&
+				(midQ->midState & MID_REQUEST_SUBMITTED) &&
+				((ses->server->tcpStatus == CifsGood) ||
+				 (ses->server->tcpStatus == CifsNew))) {
+
+				unsigned long lrt;
+
+				/* We timed out. Is the server still
+				   sending replies ? */
+				spin_lock(&GlobalMid_Lock);
+				lrt = ses->server->lstrp;
+				spin_unlock(&GlobalMid_Lock);
+
+				/* Calculate 10 seconds past last receive time*/
+				lrt += (10 * HZ);
+				if (time_after(jiffies, lrt)) {
+					/* Server sent no reply in 10 seconds */
+					cERROR(1,("Server not responding"));
+					break;
+				}
+			} else {
+				break;
+			}
+		}
 	} else {
 		wait_event(ses->server->response_q,
 			(!(midQ->midState & MID_REQUEST_SUBMITTED)) ||