From 14a441a2b4ee1dfc00ec822d91d9fb20f401c62f Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 16 Jul 2006 04:32:51 +0000 Subject: [CIFS] spinlock protect read of last srv response time in timeout path Signed-off-by: Jeremy Allison Signed-off-by: Steve French (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 @@ 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)) || -- cgit v0.10.2