util/osdiag: add query for Windows page file configuration and status

It's very common for OOM crashes on Windows to be caused by lack of page
file space (the NT kernel does not overcommit). Since Windows automatically
manages page file space by default, unless the machine is out of disk space,
this is typically caused by manual page file configurations that are too
small.

This patch obtains the current page file size, the amount of free page file
space, and also determines whether the page file is automatically or manually
managed.

Fixes #9090

Signed-off-by: Aaron Klotz <aaron@tailscale.com>
This commit is contained in:
Aaron Klotz
2023-08-24 12:15:20 -06:00
parent 535db01b3f
commit 6b6a8cf843
3 changed files with 92 additions and 4 deletions

View File

@@ -40,12 +40,14 @@ func errnoErr(e syscall.Errno) error {
var (
modadvapi32 = windows.NewLazySystemDLL("advapi32.dll")
modkernel32 = windows.NewLazySystemDLL("kernel32.dll")
modws2_32 = windows.NewLazySystemDLL("ws2_32.dll")
procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW")
procWSCEnumProtocols = modws2_32.NewProc("WSCEnumProtocols")
procWSCGetProviderInfo = modws2_32.NewProc("WSCGetProviderInfo")
procWSCGetProviderPath = modws2_32.NewProc("WSCGetProviderPath")
procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW")
procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx")
procWSCEnumProtocols = modws2_32.NewProc("WSCEnumProtocols")
procWSCGetProviderInfo = modws2_32.NewProc("WSCGetProviderInfo")
procWSCGetProviderPath = modws2_32.NewProc("WSCGetProviderPath")
)
func regEnumValue(key registry.Key, index uint32, valueName *uint16, valueNameLen *uint32, reserved *uint32, valueType *uint32, pData *byte, cbData *uint32) (ret error) {
@@ -56,6 +58,14 @@ func regEnumValue(key registry.Key, index uint32, valueName *uint16, valueNameLe
return
}
func globalMemoryStatusEx(memStatus *_MEMORYSTATUSEX) (err error) {
r1, _, e1 := syscall.Syscall(procGlobalMemoryStatusEx.Addr(), 1, uintptr(unsafe.Pointer(memStatus)), 0, 0)
if int32(r1) == 0 {
err = errnoErr(e1)
}
return
}
func wscEnumProtocols(iProtocols *int32, protocolBuffer *wsaProtocolInfo, bufLen *uint32, errno *int32) (ret int32) {
r0, _, _ := syscall.Syscall6(procWSCEnumProtocols.Addr(), 4, uintptr(unsafe.Pointer(iProtocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufLen)), uintptr(unsafe.Pointer(errno)), 0, 0)
ret = int32(r0)