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 <jaltman@openafs.org>
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>
Reviewed-by: Asanka Herath <asanka@secure-endpoints.com>
Tested-by: Asanka Herath <asanka@secure-endpoints.com>
Reviewed-by: Derrick Brashear <shadow@dementia.org>
This commit is contained in:
Jeffrey Altman 2009-07-29 14:31:45 -04:00 committed by Jeffrey Altman
parent 7a333523ea
commit 2ade93993a
5 changed files with 237 additions and 11 deletions

View File

@ -30,6 +30,7 @@ unsigned short IdleDeadtimeout = CM_CONN_IDLEDEADTIME;
#define LANMAN_WKS_PARAM_KEY "SYSTEM\\CurrentControlSet\\Services\\lanmanworkstation\\parameters" #define LANMAN_WKS_PARAM_KEY "SYSTEM\\CurrentControlSet\\Services\\lanmanworkstation\\parameters"
#define LANMAN_WKS_SESSION_TIMEOUT "SessTimeout" #define LANMAN_WKS_SESSION_TIMEOUT "SessTimeout"
#define LANMAN_WKS_EXT_SESSION_TIMEOUT "ExtendedSessTimeout"
afs_uint32 cryptall = 0; afs_uint32 cryptall = 0;
afs_uint32 cm_anonvldb = 0; afs_uint32 cm_anonvldb = 0;
@ -63,11 +64,36 @@ void cm_InitConn(void)
0, KEY_QUERY_VALUE, &parmKey); 0, KEY_QUERY_VALUE, &parmKey);
if (code == ERROR_SUCCESS) if (code == ERROR_SUCCESS)
{ {
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); dummyLen = sizeof(DWORD);
code = RegQueryValueEx(parmKey, LANMAN_WKS_SESSION_TIMEOUT, NULL, NULL, code = RegQueryValueEx(parmKey,
LANMAN_WKS_EXT_SESSION_TIMEOUT,
NULL, NULL,
(BYTE *) &dwValue, &dummyLen); (BYTE *) &dwValue, &dummyLen);
if (code == ERROR_SUCCESS) if (code == ERROR_SUCCESS) {
RDRtimeout = dwValue; 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); RegCloseKey(parmKey);
} }
@ -98,17 +124,27 @@ void cm_InitConn(void)
RegCloseKey(parmKey); 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) { if (ConnDeadtimeout == 0) {
ConnDeadtimeout = (unsigned short) (RDRtimeout / 2); ConnDeadtimeout = (unsigned short) ((RDRtimeout / 2) < 50 ? (RDRtimeout / 2) : 50);
afsi_log("ConnDeadTimeout is %d", ConnDeadtimeout); afsi_log("ConnDeadTimeout is %d", ConnDeadtimeout);
} }
if (HardDeadtimeout == 0) { if (HardDeadtimeout == 0) {
HardDeadtimeout = (unsigned short) RDRtimeout; HardDeadtimeout = (unsigned short) (RDRtimeout > 125 ? 120 : (RDRtimeout - 5));
afsi_log("HardDeadTimeout is %d", HardDeadtimeout); afsi_log("HardDeadTimeout is %d", HardDeadtimeout);
} }
if (IdleDeadtimeout == 0) { if (IdleDeadtimeout == 0) {
IdleDeadtimeout = (unsigned short) RDRtimeout; IdleDeadtimeout = (unsigned short) ConnDeadtimeout;
afsi_log("IdleDeadTimeout is %d", IdleDeadtimeout); afsi_log("IdleDeadTimeout is %d", IdleDeadtimeout);
} }
osi_EndOnce(&once); osi_EndOnce(&once);

View File

@ -11,9 +11,15 @@
#define __CM_CONN_H_ENV__ 1 #define __CM_CONN_H_ENV__ 1
#define CM_CONN_DEFAULTRDRTIMEOUT 45 #define CM_CONN_DEFAULTRDRTIMEOUT 45
#ifndef CM_CONN_CONNDEADTIME
#define CM_CONN_CONNDEADTIME 0 #define CM_CONN_CONNDEADTIME 0
#endif
#ifndef CM_CONN_HARDDEADTIME
#define CM_CONN_HARDDEADTIME 0 #define CM_CONN_HARDDEADTIME 0
#endif
#ifndef CM_CONN_IDLEDEADTIME
#define CM_CONN_IDLEDEADTIME 0 #define CM_CONN_IDLEDEADTIME 0
#endif
extern unsigned short ConnDeadtimeout; extern unsigned short ConnDeadtimeout;
extern unsigned short HardDeadtimeout; extern unsigned short HardDeadtimeout;

View File

@ -786,3 +786,180 @@ cm_LoadAfsdHookLib(void)
return hLib; 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;
}

View File

@ -85,4 +85,8 @@ extern BOOL cm_TargetPerceivedAsDirectory(const fschar_t *target);
extern HANDLE cm_LoadAfsdHookLib(void); extern HANDLE cm_LoadAfsdHookLib(void);
extern BOOL cm_GetOSFileVersion(char *filename, LARGE_INTEGER *liVer);
extern BOOL msftSMBRedirectorSupportsExtendedTimeouts(void);
#endif /* __CM_UTILS_H_ENV__ */ #endif /* __CM_UTILS_H_ENV__ */

View File

@ -9692,7 +9692,7 @@ configureExtendedSMBSessionTimeouts(void)
{ {
dwType = REG_DWORD; dwType = REG_DWORD;
dwSize = sizeof(dwValue); dwSize = sizeof(dwValue);
dwValue = 600; /* 10 minutes */ dwValue = 300; /* 5 minutes */
RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize); RegSetValueEx( hkLanMan, "ExtendedSessTimeout", 0, dwType, (const BYTE *)&dwValue, dwSize);
} }
RegCloseKey(hkLanMan); RegCloseKey(hkLanMan);
@ -9997,7 +9997,10 @@ void smb_StartListeners(int locked)
configureBackConnectionHostNames(); configureBackConnectionHostNames();
/* Configure Extended SMB Session Timeouts */ /* Configure Extended SMB Session Timeouts */
if (msftSMBRedirectorSupportsExtendedTimeouts()) {
afsi_log("Microsoft SMB Redirector supports Extended Timeouts");
configureExtendedSMBSessionTimeouts(); configureExtendedSMBSessionTimeouts();
}
smb_ListenerState = SMB_LISTENER_STARTED; smb_ListenerState = SMB_LISTENER_STARTED;
cm_VolStatus_Network_Started(cm_NetbiosName cm_VolStatus_Network_Started(cm_NetbiosName