[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)
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 95e23ca..d16e603 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 @@
/* 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 @@
/* 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)) ||