diff options
author | Steve French <sfrench@us.ibm.com> | 2006-07-16 04:32:51 +0000 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2006-08-11 21:27:41 +0000 |
commit | 14a441a2b4ee1dfc00ec822d91d9fb20f401c62f (patch) | |
tree | 122a33e5e056bdd433e78b4f6a1c9f8e2d3385d2 /fs | |
parent | 3a5ff61c18659443f76bad6cf06f60103046de5d (diff) | |
download | lwn-14a441a2b4ee1dfc00ec822d91d9fb20f401c62f.tar.gz lwn-14a441a2b4ee1dfc00ec822d91d9fb20f401c62f.zip |
[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')
-rw-r--r-- | fs/cifs/transport.c | 99 |
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)) || |