From 2ade93993a9a82a23f44355065e2b5573acca372 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Wed, 29 Jul 2009 14:31:45 -0400 Subject: [PATCH] Windows: test for and react to SMB Extended Session Timeout support SMB Extended Session Timeout Support is available only on Windows systems with specific versions of the mrxsmb.sys driver. Add a test for those driver versions. If a supporting version is present use the extended session timeout value instead of the standard timeout value for the redirector timeout. Adjust the rx hard, conn, and idle timeouts accordingly. The SMB module will define the ExtendedSessTimeout registry value if it does not exist. We rely on the fact that this is done after the rx timeout values are calculated. The mrxsmb driver only reads the value at boot. LICENSE MIT Reviewed-on: http://gerrit.openafs.org/248 Tested-by: Jeffrey Altman Reviewed-by: Jeffrey Altman Reviewed-by: Asanka Herath Tested-by: Asanka Herath Reviewed-by: Derrick Brashear --- src/WINNT/afsd/cm_conn.c | 54 ++++++++++-- src/WINNT/afsd/cm_conn.h | 6 ++ src/WINNT/afsd/cm_utils.c | 177 ++++++++++++++++++++++++++++++++++++++ src/WINNT/afsd/cm_utils.h | 4 + src/WINNT/afsd/smb.c | 7 +- 5 files changed, 237 insertions(+), 11 deletions(-) diff --git a/src/WINNT/afsd/cm_conn.c b/src/WINNT/afsd/cm_conn.c index 39b8a20297..c333dad87f 100644 --- a/src/WINNT/afsd/cm_conn.c +++ b/src/WINNT/afsd/cm_conn.c @@ -30,6 +30,7 @@ unsigned short IdleDeadtimeout = CM_CONN_IDLEDEADTIME; #define LANMAN_WKS_PARAM_KEY "SYSTEM\\CurrentControlSet\\Services\\lanmanworkstation\\parameters" #define LANMAN_WKS_SESSION_TIMEOUT "SessTimeout" +#define LANMAN_WKS_EXT_SESSION_TIMEOUT "ExtendedSessTimeout" afs_uint32 cryptall = 0; afs_uint32 cm_anonvldb = 0; @@ -63,11 +64,36 @@ void cm_InitConn(void) 0, KEY_QUERY_VALUE, &parmKey); if (code == ERROR_SUCCESS) { - dummyLen = sizeof(DWORD); - code = RegQueryValueEx(parmKey, LANMAN_WKS_SESSION_TIMEOUT, NULL, NULL, - (BYTE *) &dwValue, &dummyLen); - if (code == ERROR_SUCCESS) - RDRtimeout = dwValue; + BOOL extTimeouts = msftSMBRedirectorSupportsExtendedTimeouts(); + + if (extTimeouts) { + /* + * The default value is 1000 seconds. However, this default + * will not apply to "\\AFS" unless "AFS" is listed in + * ServersWithExtendedSessTimeout which we will add when we + * create the ExtendedSessTimeout value in smb_Init() + */ + dummyLen = sizeof(DWORD); + code = RegQueryValueEx(parmKey, + LANMAN_WKS_EXT_SESSION_TIMEOUT, + NULL, NULL, + (BYTE *) &dwValue, &dummyLen); + if (code == ERROR_SUCCESS) { + RDRtimeout = dwValue; + afsi_log("lanmanworkstation : ExtSessTimeout %u", RDRtimeout); + } + } + if (!extTimeouts || code != ERROR_SUCCESS) { + dummyLen = sizeof(DWORD); + code = RegQueryValueEx(parmKey, + LANMAN_WKS_SESSION_TIMEOUT, + NULL, NULL, + (BYTE *) &dwValue, &dummyLen); + if (code == ERROR_SUCCESS) { + RDRtimeout = dwValue; + afsi_log("lanmanworkstation : SessTimeout %u", RDRtimeout); + } + } RegCloseKey(parmKey); } @@ -98,17 +124,27 @@ void cm_InitConn(void) RegCloseKey(parmKey); } - afsi_log("lanmanworkstation : SessTimeout %u", RDRtimeout); + /* + * If these values were not set via cpp macro or obtained + * from the registry, we use a value that is derived from + * the smb redirector session timeout (RDRtimeout). + * + * The UNIX cache manager uses 120 seconds for the hard dead + * timeout and 50 seconds for the connection and idle timeouts. + * + * We base our values on those while making sure we leave + * enough time for overhead. + */ if (ConnDeadtimeout == 0) { - ConnDeadtimeout = (unsigned short) (RDRtimeout / 2); + ConnDeadtimeout = (unsigned short) ((RDRtimeout / 2) < 50 ? (RDRtimeout / 2) : 50); afsi_log("ConnDeadTimeout is %d", ConnDeadtimeout); } if (HardDeadtimeout == 0) { - HardDeadtimeout = (unsigned short) RDRtimeout; + HardDeadtimeout = (unsigned short) (RDRtimeout > 125 ? 120 : (RDRtimeout - 5)); afsi_log("HardDeadTimeout is %d", HardDeadtimeout); } if (IdleDeadtimeout == 0) { - IdleDeadtimeout = (unsigned short) RDRtimeout; + IdleDeadtimeout = (unsigned short) ConnDeadtimeout; afsi_log("IdleDeadTimeout is %d", IdleDeadtimeout); } osi_EndOnce(&once); diff --git a/src/WINNT/afsd/cm_conn.h b/src/WINNT/afsd/cm_conn.h index d5f41e2790..5e0b6732a2 100644 --- a/src/WINNT/afsd/cm_conn.h +++ b/src/WINNT/afsd/cm_conn.h @@ -11,9 +11,15 @@ #define __CM_CONN_H_ENV__ 1 #define CM_CONN_DEFAULTRDRTIMEOUT 45 +#ifndef CM_CONN_CONNDEADTIME #define CM_CONN_CONNDEADTIME 0 +#endif +#ifndef CM_CONN_HARDDEADTIME #define CM_CONN_HARDDEADTIME 0 +#endif +#ifndef CM_CONN_IDLEDEADTIME #define CM_CONN_IDLEDEADTIME 0 +#endif extern unsigned short ConnDeadtimeout; extern unsigned short HardDeadtimeout; diff --git a/src/WINNT/afsd/cm_utils.c b/src/WINNT/afsd/cm_utils.c index 90c12d3a94..30119678bf 100644 --- a/src/WINNT/afsd/cm_utils.c +++ b/src/WINNT/afsd/cm_utils.c @@ -786,3 +786,180 @@ cm_LoadAfsdHookLib(void) return hLib; } + +/* + * Obtain the file info structure for the specified file. + * If a full path is not specified, the search order is the + * same as that used by LoadLibrary(). + */ +BOOL +cm_GetOSFileVersion (char *filename, LARGE_INTEGER *liVer) +{ + DWORD dwHandle; + DWORD dwSize; + char* pInfo = NULL; + BOOL rc; + UINT uLen; + void *pbuf; + VS_FIXEDFILEINFO vsf; + + dwSize = GetFileVersionInfoSizeA(filename,&dwHandle); + if (dwSize == 0) { + rc = FALSE; + goto done; + } + pInfo = (char*)malloc(dwSize); + if (!pInfo) { + rc = FALSE; + goto done; + } + rc = GetFileVersionInfoA(filename, dwHandle, dwSize, pInfo); + if (!rc) + goto done; + rc = VerQueryValueA(pInfo,"\\",&pbuf, &uLen); + if (!rc) + goto done; + memcpy(&vsf, pbuf, sizeof(VS_FIXEDFILEINFO)); + + liVer->LowPart = vsf.dwFileVersionLS; + liVer->HighPart = vsf.dwFileVersionMS; + rc = TRUE; + + done: + if (pInfo) + free(pInfo); + return rc; +} + +typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL); +typedef BOOL (WINAPI *LPFN_DISABLEWOW64FSREDIRECTION) (PVOID *); +typedef BOOL (WINAPI *LPFN_REVERTWOW64FSREDIRECTION) (PVOID); + +BOOL msftSMBRedirectorSupportsExtendedTimeouts(void) +{ + static BOOL fChecked = FALSE; + static BOOL fSupportsExtendedTimeouts = FALSE; + + if (!fChecked) + { + BOOL isWow64 = FALSE; + OSVERSIONINFOEX Version; + HANDLE h1 = NULL; + LPFN_ISWOW64PROCESS fnIsWow64Process = NULL; + LPFN_DISABLEWOW64FSREDIRECTION fnDisableWow64FsRedirection = NULL; + LPFN_REVERTWOW64FSREDIRECTION fnRevertWow64FsRedirection = NULL; + PVOID Wow64RedirectionState; + LARGE_INTEGER fvFile, fvHotFixMin; + + h1 = GetModuleHandle("kernel32.dll"); /* no refcount increase */ + /* + * If we don't find the fnIsWow64Process function then we + * are not running in a Wow64 environment + */ + fnIsWow64Process = + (LPFN_ISWOW64PROCESS)GetProcAddress(h1, "IsWow64Process"); + + memset (&Version, 0x00, sizeof(Version)); + Version.dwOSVersionInfoSize = sizeof(Version); + GetVersionEx((OSVERSIONINFO *) &Version); + + /* + * Support is available as hot fixes / service packs on: + * XP SP2 + * XP SP3 + * 2003 and XP64 SP2 + * Vista and 2008 SP2 + * Win7 and 2008 R2 + */ + if (Version.dwPlatformId == VER_PLATFORM_WIN32_NT && + Version.dwMajorVersion >= 5) { + + /* 32-bit XP */ + if (Version.dwMajorVersion == 5 && + Version.dwMinorVersion == 1) { + + fvHotFixMin.HighPart = (5 << 16) | 1; + + switch (Version.wServicePackMajor) { + case 3: + fvHotFixMin.LowPart = (2600 << 16) | 5815; + break; + case 2: + fvHotFixMin.LowPart = (2600 << 16) | 3572; + break; + default: + fSupportsExtendedTimeouts = (Version.wServicePackMajor > 3); + goto checked; + } + } + + /* 64-bit XP and Server 2003 */ + else if (Version.dwMajorVersion == 5 && + Version.dwMinorVersion == 2) { + + fvHotFixMin.HighPart = (5 << 16) | 2; + + switch (Version.wServicePackMajor) { + case 2: + fvHotFixMin.LowPart = (3790 << 16) | 4479; + break; + case 1: + fvHotFixMin.LowPart = (3790 << 16) | 3310; + break; + default: + fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2); + goto checked; + } + } + + /* Vista and Server 2008 */ + else if (Version.dwMajorVersion == 6 && + Version.dwMinorVersion == 0) { + + fvHotFixMin.HighPart = (6 << 16) | 0; + + switch (Version.wServicePackMajor) { + case 2: + fvHotFixMin.LowPart = (6002 << 16) | 18005; + break; + default: + fSupportsExtendedTimeouts = (Version.wServicePackMajor > 2); + goto checked; + } + } + + /* Windows 7 and Server 2008 R2 and beyond */ + else if (Version.dwMajorVersion > 6 || + Version.dwMajorVersion == 6 && + Version.dwMinorVersion >= 1) { + fSupportsExtendedTimeouts = TRUE; + goto checked; + } + + /* If wow64, disable wow64 redirection and preserve the existing state */ + if (fnIsWow64Process && + fnIsWow64Process(GetCurrentProcess(), &isWow64) && + isWow64) { + fnDisableWow64FsRedirection = + (LPFN_DISABLEWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64DisableWow64FsRedirection"); + fnRevertWow64FsRedirection = + (LPFN_REVERTWOW64FSREDIRECTION)GetProcAddress(h1, "Wow64RevertWow64FsRedirection"); + fnDisableWow64FsRedirection(&Wow64RedirectionState); + } + + if (cm_GetOSFileVersion("drivers\\mrxsmb.sys", &fvFile) || + (fvFile.QuadPart >= fvHotFixMin.QuadPart)) + fSupportsExtendedTimeouts = TRUE; + + /* If wow64, restore the previous redirection state */ + if (fnIsWow64Process && isWow64) { + fnRevertWow64FsRedirection(Wow64RedirectionState); + } + } + checked: + fChecked = TRUE; + } + + return fSupportsExtendedTimeouts; +} + diff --git a/src/WINNT/afsd/cm_utils.h b/src/WINNT/afsd/cm_utils.h index f1708cc045..653ff96be0 100644 --- a/src/WINNT/afsd/cm_utils.h +++ b/src/WINNT/afsd/cm_utils.h @@ -85,4 +85,8 @@ extern BOOL cm_TargetPerceivedAsDirectory(const fschar_t *target); extern HANDLE cm_LoadAfsdHookLib(void); +extern BOOL cm_GetOSFileVersion(char *filename, LARGE_INTEGER *liVer); + +extern BOOL msftSMBRedirectorSupportsExtendedTimeouts(void); + #endif /* __CM_UTILS_H_ENV__ */ diff --git a/src/WINNT/afsd/smb.c b/src/WINNT/afsd/smb.c index 4cc33cb223..1611b2af5d 100644 --- a/src/WINNT/afsd/smb.c +++ b/src/WINNT/afsd/smb.c @@ -9692,7 +9692,7 @@ configureExtendedSMBSessionTimeouts(void) { dwType = REG_DWORD; dwSize = sizeof(dwValue); - dwValue = 600; /* 10 minutes */ + dwValue = 300; /* 5 minutes */ RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize); } RegCloseKey(hkLanMan); @@ -9997,7 +9997,10 @@ void smb_StartListeners(int locked) configureBackConnectionHostNames(); /* Configure Extended SMB Session Timeouts */ - configureExtendedSMBSessionTimeouts(); + if (msftSMBRedirectorSupportsExtendedTimeouts()) { + afsi_log("Microsoft SMB Redirector supports Extended Timeouts"); + configureExtendedSMBSessionTimeouts(); + } smb_ListenerState = SMB_LISTENER_STARTED; cm_VolStatus_Network_Started(cm_NetbiosName