From d58233a52f3d705b039d690c4cc0befd1ac54408 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Sat, 5 Jun 2004 19:57:58 +0000 Subject: [PATCH] timeout-logic-20040605 * The timeout logic in the AFS Client Service has been wrong for sometime. It is based on two different assumptions. First, the SMB client timeout is a fix value as was the case with OS/2 Lan Manager. This assumption is incorrect. The SMB timeout in Windows is a dynamic value computed based upon a fixed minimum timeout to which is added time based upon the size of the request and the performance characteristics of the connection. Second, it is the responsibility of the SMB Server to enforce the timeout requirements of the client. This is untrue. The SMB Server cannot be expected to know the requirements of the client. More importantly, if the SMB server uses the SMB client timeout as a value to restrict its behavior as an RX client, the performance characteristics of the local SMB session would be used to prematurely terminate WAN connections with significantly different performance characteristics. The timeout logic has therefore been modified in the following manner: . the Lan Manager Workstation (SMB) Session Timeout is used only as a basis for configuring the Connection Dead Timeout and Hard Dead Timeout values. The Connection Dead Timeout must be at least 15 seconds longer than the SMB Timeout and the Hard Dead Timeout must be at least double the Connection Dead Timeout. . New registry entries have been added to allow the Connection Dead Timeout and Hard Dead Timeout values independent of the Lan Manager Workstation Session Timeout . The test to enforce the SMB Client Timeout has been removed. One of the side-effects of removing the enforcement of the SMB Client Timeout is that regardless of whether or not the SMB client is available to receive the response (and how would the SMB server know) the RX protocol response can be used to update the AFS Client Service state for ready access by future SMB client requests. This should be the end of the "Server paused or restarting messages" --- src/WINNT/afsd/afsd_init.c | 10 ++++++++ src/WINNT/afsd/cm_conn.c | 48 +++++++++++++++++++------------------- src/WINNT/afsd/cm_conn.h | 5 +++- src/WINNT/afsd/cm_server.c | 2 +- 4 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/WINNT/afsd/afsd_init.c b/src/WINNT/afsd/afsd_init.c index 431f9bef7..c23efe60c 100644 --- a/src/WINNT/afsd/afsd_init.c +++ b/src/WINNT/afsd/afsd_init.c @@ -518,6 +518,16 @@ int afsd_InitCM(char **reasonP) if(rx_mtu != -1) afsi_log("RX maximum MTU is %d", rx_mtu); + dummyLen = sizeof(ConnDeadtimeout); + code = RegQueryValueEx(parmKey, "ConnDeadTimeout", NULL, NULL, + (BYTE *) &ConnDeadtimeout, &dummyLen); + afsi_log("ConnDeadTimeout is %d", ConnDeadtimeout); + + dummyLen = sizeof(HardDeadtimeout); + code = RegQueryValueEx(parmKey, "HardDeadTimeout", NULL, NULL, + (BYTE *) &HardDeadtimeout, &dummyLen); + afsi_log("HardDeadTimeout is %d", HardDeadtimeout); + RegCloseKey (parmKey); /* Call lanahelper to get Netbios name, lan adapter number and gateway flag */ diff --git a/src/WINNT/afsd/cm_conn.c b/src/WINNT/afsd/cm_conn.c index 29d23b6f8..b3e22c0e3 100644 --- a/src/WINNT/afsd/cm_conn.c +++ b/src/WINNT/afsd/cm_conn.c @@ -28,6 +28,8 @@ osi_rwlock_t cm_connLock; long RDRtimeout = CM_CONN_DEFAULTRDRTIMEOUT; +long ConnDeadtimeout = CM_CONN_CONNDEADTIME; +long HardDeadtimeout = CM_CONN_HARDDEADTIME; #define LANMAN_WKS_PARAM_KEY "SYSTEM\\CurrentControlSet\\Services\\lanmanworkstation\\parameters" #define LANMAN_WKS_SESSION_TIMEOUT "SessTimeout" @@ -52,8 +54,11 @@ void cm_InitConn(void) lock_InitializeRWLock(&cm_connLock, "connection global lock"); /* keisa - read timeout value for lanmanworkstation service. - * It is used as hardtimeout for connections. - * Default value is 45 + * jaltman - as per + * http://support.microsoft.com:80/support/kb/articles/Q102/0/67.asp&NoWebContent=1 + * the SessTimeout is a minimum timeout not a maximum timeout. Therefore, + * I believe that the default should not be short. Instead, we should wait until + * RX times out before reporting a timeout to the SMB client. */ code = RegOpenKeyEx(HKEY_LOCAL_MACHINE, LANMAN_WKS_PARAM_KEY, 0, KEY_QUERY_VALUE, &parmKey); @@ -66,13 +71,17 @@ void cm_InitConn(void) { afsi_log("lanmanworkstation : SessTimeout %d", sessTimeout); RDRtimeout = sessTimeout; - } - else - { - RDRtimeout = CM_CONN_DEFAULTRDRTIMEOUT; + if ( ConnDeadtimeout < RDRtimeout + 15 ) { + ConnDeadtimeout = RDRtimeout + 15; + afsi_log("ConnDeadTimeout increased to %d", ConnDeadtimeout); + } + if ( HardDeadtimeout < 2 * ConnDeadtimeout ) { + HardDeadtimeout = 2 * ConnDeadtimeout; + afsi_log("HardDeadTimeout increased to %d", HardDeadtimeout); + } } } - + osi_EndOnce(&once); } } @@ -335,13 +344,8 @@ long cm_ConnByMServers(cm_serverRef_t *serversp, cm_user_t *usersp, #endif /* leave 5 seconds margin of safety */ - timeLeft = RDRtimeout - timeUsed - 5; - hardTimeLeft = timeLeft; - - /* Time enough to do an RPC? */ - if (timeLeft < 1) { - return CM_ERROR_TIMEDOUT; - } + timeLeft = ConnDeadtimeout - timeUsed - 5; + hardTimeLeft = HardDeadtimeout - timeUsed - 5; lock_ObtainWrite(&cm_serverLock); @@ -360,11 +364,11 @@ long cm_ConnByMServers(cm_serverRef_t *serversp, cm_user_t *usersp, if (code == 0) { cm_PutServer(tsp); /* Set RPC timeout */ - if (timeLeft > CM_CONN_CONNDEADTIME) - timeLeft = CM_CONN_CONNDEADTIME; + if (timeLeft > ConnDeadtimeout) + timeLeft = ConnDeadtimeout; - if (hardTimeLeft > CM_CONN_HARDDEADTIME) - hardTimeLeft = CM_CONN_HARDDEADTIME; + if (hardTimeLeft > HardDeadtimeout) + hardTimeLeft = HardDeadtimeout; lock_ObtainMutex(&(*connpp)->mx); rx_SetConnDeadTime((*connpp)->callp, @@ -389,16 +393,12 @@ long cm_ConnByMServers(cm_serverRef_t *serversp, cm_user_t *usersp, firstError = CM_ERROR_ALLBUSY; else if (someOffline) firstError = CM_ERROR_ALLOFFLINE; -#ifndef COMMENT else if (!allDown && serversp) firstError = CM_ERROR_TIMEDOUT; /* Only return CM_ERROR_NOSUCHVOLUME if there are no servers for this volume */ else firstError = CM_ERROR_NOSUCHVOLUME; -#else - firstError = CM_ERROR_TIMEDOUT; -#endif /* COMMENT */ } osi_Log1(afsd_logp, "cm_ConnByMServers returning %x", firstError); return firstError; @@ -472,8 +472,8 @@ static void cm_NewRXConnection(cm_conn_t *tcp, cm_ucell_t *ucellp, serviceID, secObjp, secIndex); - rx_SetConnDeadTime(tcp->callp, CM_CONN_CONNDEADTIME); - rx_SetConnHardDeadTime(tcp->callp, CM_CONN_HARDDEADTIME); + rx_SetConnDeadTime(tcp->callp, ConnDeadtimeout); + rx_SetConnHardDeadTime(tcp->callp, HardDeadtimeout); tcp->ucgen = ucellp->gen; if (secObjp) rxs_Release(secObjp); /* Decrement the initial refCount */ diff --git a/src/WINNT/afsd/cm_conn.h b/src/WINNT/afsd/cm_conn.h index 7c22ec431..719d438d3 100644 --- a/src/WINNT/afsd/cm_conn.h +++ b/src/WINNT/afsd/cm_conn.h @@ -11,9 +11,12 @@ #define __CM_CONN_H_ENV__ 1 #define CM_CONN_DEFAULTRDRTIMEOUT 45 -#define CM_CONN_CONNDEADTIME 50 +#define CM_CONN_CONNDEADTIME 60 #define CM_CONN_HARDDEADTIME 120 +extern long ConnDeadtimeout; +extern long HardDeadtimeout; + typedef struct cm_conn { struct cm_conn *nextp; /* locked by cm_connLock */ struct cm_server *serverp; /* locked by cm_serverLock */ diff --git a/src/WINNT/afsd/cm_server.c b/src/WINNT/afsd/cm_server.c index d47139ff0..be349d495 100644 --- a/src/WINNT/afsd/cm_server.c +++ b/src/WINNT/afsd/cm_server.c @@ -98,7 +98,7 @@ void cm_CheckServers(long flags, cm_cell_t *cellp) code = RXAFS_GetTime(connp->callp, &secs, &usecs); } if (wasDown) - rx_SetConnDeadTime(connp->callp, CM_CONN_CONNDEADTIME); + rx_SetConnDeadTime(connp->callp, ConnDeadtimeout); cm_PutConn(connp); } /* got an unauthenticated connection to this server */ -- 2.39.5