Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1222 lines
37 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. virtmem.c
  5. Abstract:
  6. Routines to configure and set up virtual memory -- pagefiles, etc.
  7. Author:
  8. Ted Miller (tedm) 22-Apr-1995
  9. Revision History:
  10. --*/
  11. #include "setupp.h"
  12. #pragma hdrstop
  13. //
  14. // What's the ratio of 'beginning' pagefile size to 'max' pagefile size?
  15. //
  16. #define MAX_PAGEFILE_RATIO (2)
  17. #define MAX_PAGEFILE_SIZEMB ((2*1024) - 2)
  18. #define TINY_WINDIR_PAGEFILE_SIZE (2)
  19. #define MIN_PAGEFILE_STRING_LEN (5)
  20. //
  21. // Keys and values names
  22. //
  23. #define szMemoryManagementKeyPath L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management"
  24. #define szPageFileValueName L"PagingFiles"
  25. #define szSetupPageFileKeyPath L"SYSTEM\\Setup\\PageFile"
  26. #define szSetupKey L"SYSTEM\\Setup"
  27. #define szPageFileKeyName L"PageFile"
  28. WCHAR ExistingPagefileDrive = 0;
  29. BOOL LeaveExistingPagefile = FALSE;
  30. DWORD Zero = 0;
  31. DWORD One = 1;
  32. DWORD Two = 2;
  33. DWORD Three = 3;
  34. //
  35. // Keep AutoReboot as the last entry as we won't be updating that key on
  36. // upgrades. This is for Stress so we quit setting this key on each upgrade.
  37. //
  38. REGVALITEM CrashDumpValues[] = {{ L"LogEvent" ,&One,sizeof(DWORD),REG_DWORD },
  39. { L"SendAlert" ,&One,sizeof(DWORD),REG_DWORD },
  40. { L"CrashDumpEnabled",&One,sizeof(DWORD),REG_DWORD },
  41. { L"AutoReboot" ,&One,sizeof(DWORD),REG_DWORD }};
  42. VOID
  43. LOGITEM(
  44. IN PCWSTR p,
  45. ...
  46. )
  47. {
  48. WCHAR str[1024];
  49. va_list arglist;
  50. va_start(arglist,p);
  51. wvsprintf(str,p,arglist);
  52. va_end(arglist);
  53. //
  54. // Used to debug problem on MIPS that was the result of a chip
  55. // errata, when dividing 64 bit numbers with multiplies pending.
  56. //
  57. SetuplogError(
  58. LogSevInformation,str,0,NULL,NULL);
  59. }
  60. VOID
  61. RemoveSavedPagefileSetting(
  62. VOID
  63. )
  64. /*++
  65. Routine Description:
  66. Delete our record of what the user was previously using
  67. for a pagefile.
  68. --*/
  69. {
  70. HKEY Key;
  71. if ( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  72. szSetupKey,
  73. 0,
  74. MAXIMUM_ALLOWED,
  75. &Key ))
  76. {
  77. RegDeleteKey( Key, szPageFileKeyName );
  78. RegCloseKey( Key );
  79. }
  80. }
  81. BOOL
  82. MultiplePagefileSizes(
  83. IN PWCHAR pwzData,
  84. OUT PDWORD totalsize
  85. )
  86. /*++
  87. Routine Description:
  88. Calculate the sum off all pagefile sizes.
  89. Arguments:
  90. pwsData - multi_sz data read from the registry.
  91. totalsize - receives the sum of all pagefiles.
  92. Return Value:
  93. TRUE - if this was a multistring and formatted corretly, total size will then contain the sum.
  94. FALSE - badly formated or not multiple pagefiles.
  95. --*/
  96. {
  97. PWCHAR pstr = NULL;
  98. DWORD numPagefiles = 0;
  99. WCHAR PagefileDrive = 0;
  100. if( !pwzData || !pwzData[0] || !totalsize) {
  101. return FALSE;
  102. }
  103. *totalsize = 0;
  104. pstr = pwzData;
  105. while( pstr[0]) {
  106. if( wcsstr( pstr, TEXT(" ") ) ) {
  107. PagefileDrive = towupper( (WCHAR)pstr[0] );
  108. // Not valid drive letter!
  109. if( (PagefileDrive > 'Z') ||
  110. (PagefileDrive < 'A') ) {
  111. return FALSE;
  112. }
  113. *totalsize += (int)wcstoul(wcsstr( pstr, TEXT(" ") ),NULL,10);
  114. pstr += (wcslen(pstr) +1);
  115. numPagefiles++;
  116. }
  117. else {
  118. //Invalid format
  119. return FALSE;
  120. }
  121. }
  122. return (numPagefiles > 1);
  123. }
  124. BOOL
  125. RestoreOldPagefileSettings(
  126. VOID
  127. )
  128. /*++
  129. Routine Description:
  130. Copies, the pagefile saved during textmode setup to the correct loaction.
  131. So from HKLM\SYSTEM\Setup\PageFile
  132. to HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management.
  133. Arguments:
  134. Return Value:
  135. TRUE - Successfully restored the user's pagefile settings
  136. FALSE - Failed to restore settings.
  137. --*/
  138. {
  139. LONG Error;
  140. HKEY Key;
  141. DWORD cbData;
  142. PWCHAR Data=NULL;
  143. DWORD Type;
  144. //
  145. // Get the original page file info from
  146. //
  147. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  148. szSetupPageFileKeyPath,
  149. 0,
  150. KEY_READ,
  151. &Key );
  152. if( Error != ERROR_SUCCESS ) {
  153. goto c0;
  154. }
  155. // Find out the size of the data to be retrieved
  156. //
  157. cbData = 0;
  158. Error = RegQueryValueEx( Key,
  159. szPageFileValueName,
  160. 0,
  161. NULL,
  162. NULL,
  163. &cbData );
  164. if( Error != ERROR_SUCCESS || (cbData/sizeof(WCHAR)) < MIN_PAGEFILE_STRING_LEN ) {
  165. goto c2;
  166. }
  167. // Allocate a buffer for the data, and retrieve the data
  168. //
  169. Data = (PWCHAR)MyMalloc(cbData+2*sizeof(WCHAR));
  170. if( !Data ) {
  171. goto c2;
  172. }
  173. Error = RegQueryValueEx( Key,
  174. szPageFileValueName,
  175. 0,
  176. &Type,
  177. ( LPBYTE )Data,
  178. &cbData );
  179. if( (Error != ERROR_SUCCESS) ) {
  180. goto c2;
  181. }
  182. // Make sure it's doubly null terminated
  183. Data[cbData/2] = 0;
  184. Data[cbData/2+1] = 0;
  185. if( Data[cbData/2-1] != 0) {
  186. cbData += (2*sizeof(WCHAR));
  187. } else if( Data[cbData/2-2] != 0) {
  188. cbData += sizeof(WCHAR);
  189. }
  190. RegCloseKey( Key);
  191. // Now open key for write
  192. Error = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  193. szMemoryManagementKeyPath,
  194. 0,
  195. NULL,
  196. REG_OPTION_NON_VOLATILE,
  197. KEY_SET_VALUE,
  198. NULL,
  199. &Key,
  200. NULL );
  201. if( Error != ERROR_SUCCESS) {
  202. goto c1;
  203. }
  204. Error = RegSetValueEx( Key,
  205. szPageFileValueName,
  206. 0,
  207. REG_MULTI_SZ,
  208. (PVOID)Data,
  209. cbData);
  210. if( Error != ERROR_SUCCESS) {
  211. goto c2;
  212. }
  213. return TRUE;
  214. c2:
  215. RegCloseKey( Key);
  216. c1:
  217. if( Data) {
  218. MyFree( Data);
  219. }
  220. c0:
  221. return FALSE;
  222. }
  223. VOID
  224. CalculatePagefileSizes(
  225. OUT PDWORD PagefileMinMB,
  226. OUT PDWORD RecommendedPagefileMB,
  227. OUT PDWORD CrashDumpPagefileMinMB
  228. )
  229. /*++
  230. Routine Description:
  231. Calculate various key sizes relating to pagefile size.
  232. Arguments:
  233. PagefileMinMB - receives the minimum recommended size for a pagefile,
  234. in MB.
  235. RecommendedPagefileMB - receives the recommended size for a pagefile,
  236. in MB.
  237. CrashDumpPagefileMinMB - receives the size in MB for a pagefile to be
  238. used for crashdumps.
  239. Return Value:
  240. None.
  241. --*/
  242. {
  243. MEMORYSTATUSEX MemoryStatusEx;
  244. SYSTEM_INFO SystemInfo;
  245. DWORD AvailableMB;
  246. MemoryStatusEx.dwLength = sizeof(MEMORYSTATUSEX);
  247. GlobalMemoryStatusEx(&MemoryStatusEx);
  248. GetSystemInfo(&SystemInfo);
  249. //
  250. // Figure out how much memory we have available.
  251. //
  252. AvailableMB = (DWORD)(MemoryStatusEx.ullTotalPhys / (1024*1024));
  253. //
  254. // It's likely that our calculation is off because the BIOS may
  255. // be eat part of our first MB. Let's make sure we're mod-4.
  256. //
  257. AvailableMB = (AvailableMB + 3) & (0xFFFFFFF8);
  258. //
  259. // Set minimum acceptable size for the pagefile.
  260. //
  261. *PagefileMinMB = 48;
  262. //
  263. // Min size for crash dump pagefile is also physical memory+12mb.
  264. //
  265. *CrashDumpPagefileMinMB = AvailableMB + 12;
  266. //
  267. // Calculate the recommended size for the pagefile.
  268. // The recommended size is (memory size * 1.5)mb.
  269. //
  270. *RecommendedPagefileMB = AvailableMB + (AvailableMB >> 1);
  271. #if 1
  272. //
  273. // Set a Maximum of 2Gig.
  274. //
  275. if( *RecommendedPagefileMB > MAX_PAGEFILE_SIZEMB ) {
  276. *RecommendedPagefileMB = MAX_PAGEFILE_SIZEMB;
  277. }
  278. #endif
  279. //
  280. // If we're doing an upgrade, we're going to retrieve what
  281. // the user was using for a pagefile size. We'll take the
  282. // max of our RecommendedPagefileMB and what the user had.
  283. //
  284. if(Upgrade) {
  285. LONG Error;
  286. HKEY Key;
  287. DWORD cbData;
  288. PWCHAR Data;
  289. DWORD Type;
  290. //
  291. // Get the original page file info from
  292. // HKEY_LOCAL_MACHINE\SYSTEM\Setup\PageFile
  293. //
  294. Error = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  295. szSetupPageFileKeyPath,
  296. 0,
  297. KEY_READ,
  298. &Key );
  299. if( Error == ERROR_SUCCESS ) {
  300. //
  301. // Find out the size of the data to be retrieved
  302. //
  303. cbData = 0;
  304. Error = RegQueryValueEx( Key,
  305. szPageFileValueName,
  306. 0,
  307. NULL,
  308. NULL,
  309. &cbData );
  310. if( Error == ERROR_SUCCESS ) {
  311. //
  312. // Allocate a buffer for the data, and retrieve the data
  313. //
  314. Data = (PWCHAR)MyMalloc(cbData+(2*sizeof(WCHAR)));
  315. if( Data ) {
  316. Error = RegQueryValueEx( Key,
  317. szPageFileValueName,
  318. 0,
  319. &Type,
  320. ( LPBYTE )Data,
  321. &cbData );
  322. if( (Error == ERROR_SUCCESS) ) {
  323. //
  324. // We got the data. Take the bigger value.
  325. //
  326. //Make sure string is double null terminated.
  327. Data[cbData/2] = 0;
  328. Data[cbData/2+1] = 0;
  329. if( wcsstr( Data, TEXT(" ") ) ) {
  330. DWORD ExistingPageFileSize = 0;
  331. if( MultiplePagefileSizes( Data, &ExistingPageFileSize) && ExistingPageFileSize >= *RecommendedPagefileMB ) {
  332. LeaveExistingPagefile = TRUE;
  333. ExistingPagefileDrive = towupper( (WCHAR)Data[0] ); // points to first one in multstring
  334. } else {
  335. // We are here because user originally had one pagefile or the sum of all pagefiles was less the the recommended
  336. ExistingPageFileSize = (int)wcstoul(wcsstr( Data, TEXT(" ") ),NULL,10);
  337. if( ExistingPageFileSize >= *RecommendedPagefileMB ) {
  338. //
  339. // The user has a bigger pagefile than we think he needs.
  340. // Assume he knows better and take the bigger value.
  341. //
  342. *RecommendedPagefileMB = ExistingPageFileSize;
  343. //
  344. // Remember his drive letter too. This tells us that
  345. // the user may already have a decent pagefile and
  346. // we don't need to mess with it.
  347. //
  348. ExistingPagefileDrive = towupper( (WCHAR)Data[0] );
  349. //
  350. // If it's not valid, nuke the flag.
  351. //
  352. if( (ExistingPagefileDrive > 'Z') ||
  353. (ExistingPagefileDrive < 'A') ) {
  354. ExistingPagefileDrive = 0;
  355. }
  356. }
  357. }
  358. }
  359. }
  360. MyFree( Data );
  361. }
  362. }
  363. RegCloseKey( Key );
  364. }
  365. }
  366. }
  367. VOID
  368. BuildVolumeFreeSpaceList(
  369. OUT DWORD VolumeFreeSpaceMB[26]
  370. )
  371. /*++
  372. Routine Description:
  373. Build a list of free space available on each hard drive in the system.
  374. The space will include space taken up by a file called \pagefile.sys
  375. on each drive. Existing pagefiles are marked for deletion on the next boot.
  376. Arguments:
  377. VolumeFreeSpaceMB - receives free space for each of the 26 drives
  378. potentially describable in the drive letter namespace.
  379. Entries for drives that do not exist are left alone, so the caller
  380. should zero out the array before calling this routine.
  381. Return Value:
  382. None.
  383. --*/
  384. {
  385. DWORD SectorsPerCluster;
  386. DWORD BytesPerSector;
  387. DWORD FreeClusters;
  388. DWORD TotalClusters;
  389. DWORD d;
  390. PWCHAR p;
  391. ULONGLONG FreeSpace;
  392. INT DriveNo;
  393. WIN32_FIND_DATA FindData;
  394. WCHAR Filename[] = L"?:\\pagefile.sys";
  395. //
  396. // Space for logical drive strings. Each is x:\ + nul, and
  397. // there is an extra nul terminating the list.
  398. //
  399. WCHAR Buffer[(26*4)+1];
  400. //
  401. // Build up a list of free space on each available hard drive.
  402. //
  403. d = GetLogicalDriveStrings(sizeof(Buffer)/sizeof(Buffer[0]),Buffer);
  404. d = min( d, sizeof(Buffer)/sizeof(Buffer[0]));
  405. CharUpperBuff(Buffer,d);
  406. for(p=Buffer; *p; p+=lstrlen(p)+1) {
  407. DriveNo = (*p) - L'A';
  408. if((DriveNo >= 0) && (DriveNo < 26) && (p[1] == L':')
  409. && (MyGetDriveType(*p) == DRIVE_FIXED)
  410. && GetDiskFreeSpace(p,&SectorsPerCluster,&BytesPerSector,&FreeClusters,&TotalClusters)) {
  411. LOGITEM(
  412. L"BuildVolumeFreeSpaceList: %s, spc=%u, bps=%u, freeclus=%u, totalclus=%u\r\n",
  413. p,
  414. SectorsPerCluster,
  415. BytesPerSector,
  416. FreeClusters,
  417. TotalClusters
  418. );
  419. FreeSpace = UInt32x32To64(BytesPerSector * SectorsPerCluster, FreeClusters);
  420. LOGITEM(
  421. L"BuildVolumeFreeSpaceList: %s, FreeSpace = %u%u\r\n",
  422. p,
  423. (DWORD)(FreeSpace >> 32),
  424. (DWORD)FreeSpace
  425. );
  426. //
  427. // If there's already a page file here, include its size in the free space
  428. // for the drive. Delete the existing pagefile on the next reboot.
  429. //
  430. Filename[0] = *p;
  431. if(FileExists(Filename,&FindData)) {
  432. FreeSpace += FindData.nFileSizeLow;
  433. LOGITEM(
  434. L"BuildVolumeFreeSpaceList: %s had %u byte pagefile, new FreeSpace = %u%u\r\n",
  435. p,
  436. FindData.nFileSizeLow,
  437. (DWORD)(FreeSpace >> 32),
  438. (DWORD)FreeSpace
  439. );
  440. MoveFileEx(Filename,NULL,MOVEFILE_DELAY_UNTIL_REBOOT);
  441. }
  442. VolumeFreeSpaceMB[DriveNo] = (DWORD)(FreeSpace / (1024*1024));
  443. LOGITEM(L"BuildVolumeFreeSpaceList: Free space on %s is %u MB\r\n",p,VolumeFreeSpaceMB[DriveNo]);
  444. }
  445. }
  446. }
  447. BOOL
  448. SetUpVirtualMemory(
  449. VOID
  450. )
  451. /*++
  452. Routine Description:
  453. Configure a pagefile. If setting up a server, we attempt to set up a pagefile
  454. suitable for use with crashdump, meaning it has to be at least the size of
  455. system memory, and has to go on the nt drive. Otherwise we attempt to place
  456. a pagefile on the nt drive if there's enough space, and if that fails, we
  457. place it on any drive with any space.
  458. Arguments:
  459. None.
  460. Return Value:
  461. Boolean value indicating outcome.
  462. --*/
  463. {
  464. #define SYS_DRIVE_FREE_SPACE_BUFFER (100)
  465. #define ALT_DRIVE_FREE_SPACE_BUFFER (25)
  466. #define AnswerBufLen (4*MAX_PATH)
  467. #define RECORD_VM_SETTINGS( Drive, Size, Buffer ) { \
  468. PagefileDrive = Drive; \
  469. PagefileSizeMB = Size; \
  470. MaxPagefileSizeMB = __min( (VolumeFreeSpaceMB[PagefileDrive] - Buffer), \
  471. PagefileSizeMB * MAX_PAGEFILE_RATIO ); \
  472. \
  473. MaxPagefileSizeMB = __max( MaxPagefileSizeMB, PagefileSizeMB ); \
  474. \
  475. if( PagefileSizeMB >= CrashDumpPagefileMinMB ) { \
  476. EnableCrashDump = TRUE; \
  477. } \
  478. }
  479. DWORD VolumeFreeSpaceMB[26];
  480. DWORD PagefileMinMB;
  481. DWORD RecommendedPagefileMB;
  482. DWORD CrashDumpPagefileMinMB;
  483. WCHAR WindowsDirectory[MAX_PATH];
  484. UINT WindowsDriveNo,DriveNo;
  485. UINT PagefileDrive;
  486. BOOL EnableCrashDump;
  487. INT MaxSpaceDrive;
  488. DWORD PagefileSizeMB;
  489. DWORD MaxPagefileSizeMB;
  490. WCHAR PagefileTemplate[128];
  491. PWSTR PagefileSpec;
  492. DWORD d;
  493. BOOL b;
  494. BOOL UseExistingPageFile = FALSE;
  495. WCHAR AnswerFile[AnswerBufLen];
  496. WCHAR Answer[AnswerBufLen];
  497. WCHAR DriveName[] = L"?:\\";
  498. LOGITEM(L"SetUpVirtualMemory: ENTER\r\n");
  499. if( !GetWindowsDirectory(WindowsDirectory,MAX_PATH) ) {
  500. return FALSE;
  501. }
  502. WindowsDriveNo = (UINT)PtrToUlong(CharUpper((PWSTR)WindowsDirectory[0])) - (UINT)L'A';
  503. PagefileDrive = -1;
  504. EnableCrashDump = FALSE;
  505. //
  506. // Take care of some preliminaries.
  507. //
  508. CalculatePagefileSizes(
  509. &PagefileMinMB,
  510. &RecommendedPagefileMB,
  511. &CrashDumpPagefileMinMB
  512. );
  513. ZeroMemory(VolumeFreeSpaceMB,sizeof(VolumeFreeSpaceMB));
  514. BuildVolumeFreeSpaceList(VolumeFreeSpaceMB);
  515. //
  516. // Now figure out how large and where the pagefile will be.
  517. //
  518. //
  519. // ================================================================
  520. // 0. See if the user already has a reasonable pagefile.
  521. // ================================================================
  522. //
  523. if( (Upgrade) &&
  524. (ExistingPagefileDrive) ) {
  525. //
  526. // See if there was multiple pagefiles or if there's enough room on the existing drive
  527. // for the pagefile.
  528. //
  529. if( LeaveExistingPagefile ||
  530. VolumeFreeSpaceMB[(UINT)(ExistingPagefileDrive - L'A')] > (RecommendedPagefileMB + ALT_DRIVE_FREE_SPACE_BUFFER) ) {
  531. if( RestoreOldPagefileSettings()){
  532. LOGITEM(L"SetUpVirtualMemory: loc 0 - keep user's pagefile settings.\r\n");
  533. UseExistingPageFile = TRUE;
  534. PagefileDrive = (UINT)(ExistingPagefileDrive - L'A');
  535. } else {
  536. // Shouldn't happen unless their pagefile syntax was bad.
  537. // We will continue on to create one.
  538. LOGITEM(L"SetUpVirtualMemory: loc 0 - Could not restore user's pagefile settings.\r\n");
  539. }
  540. }
  541. }
  542. //
  543. // ================================================================
  544. // 1. See if the NT drive has enough space for the MAX pagefile
  545. // size.
  546. // ================================================================
  547. //
  548. if(PagefileDrive == -1) {
  549. if( VolumeFreeSpaceMB[WindowsDriveNo] > ((RecommendedPagefileMB * MAX_PAGEFILE_RATIO) + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
  550. LOGITEM(L"SetUpVirtualMemory: loc 1\r\n");
  551. //
  552. // Record our settings.
  553. //
  554. RECORD_VM_SETTINGS( WindowsDriveNo, RecommendedPagefileMB, SYS_DRIVE_FREE_SPACE_BUFFER );
  555. }
  556. }
  557. //
  558. // ================================================================
  559. // 2. See if any drive has enough space for the MAX pagefile
  560. // size.
  561. // ================================================================
  562. //
  563. if(PagefileDrive == -1) {
  564. for(DriveNo=0; DriveNo<26; DriveNo++) {
  565. if( (DriveNo != WindowsDriveNo) &&
  566. (VolumeFreeSpaceMB[DriveNo] > ((RecommendedPagefileMB * MAX_PAGEFILE_RATIO) + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
  567. //
  568. // He's got the space, but let's make sure he's not removable.
  569. //
  570. DriveName[0] = DriveNo + L'A';
  571. if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
  572. LOGITEM(L"SetUpVirtualMemory: loc 2 - found space on driveno %u\r\n",DriveNo);
  573. //
  574. // Record our settings.
  575. //
  576. RECORD_VM_SETTINGS( DriveNo, RecommendedPagefileMB, ALT_DRIVE_FREE_SPACE_BUFFER );
  577. break;
  578. }
  579. }
  580. }
  581. }
  582. //
  583. // ================================================================
  584. // 3. See if the NT drive has enough space for the recommended pagefile
  585. // size.
  586. // ================================================================
  587. //
  588. if(PagefileDrive == -1) {
  589. if( VolumeFreeSpaceMB[WindowsDriveNo] > (RecommendedPagefileMB + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
  590. LOGITEM(L"SetUpVirtualMemory: loc 3\r\n");
  591. //
  592. // Record our settings.
  593. //
  594. RECORD_VM_SETTINGS( WindowsDriveNo, RecommendedPagefileMB, SYS_DRIVE_FREE_SPACE_BUFFER );
  595. }
  596. }
  597. //
  598. // ================================================================
  599. // 4. See if any drive has enough space for the recommended pagefile
  600. // size.
  601. // ================================================================
  602. //
  603. if(PagefileDrive == -1) {
  604. for(DriveNo=0; DriveNo<26; DriveNo++) {
  605. if( (DriveNo != WindowsDriveNo) &&
  606. (VolumeFreeSpaceMB[DriveNo] > (RecommendedPagefileMB + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
  607. //
  608. // He's got the space, but let's make sure he's not removable.
  609. //
  610. DriveName[0] = DriveNo + L'A';
  611. if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
  612. LOGITEM(L"SetUpVirtualMemory: loc 4 - found space on driveno %u\r\n",DriveNo);
  613. //
  614. // Record our settings.
  615. //
  616. RECORD_VM_SETTINGS( DriveNo, RecommendedPagefileMB, ALT_DRIVE_FREE_SPACE_BUFFER );
  617. break;
  618. }
  619. }
  620. }
  621. }
  622. //
  623. // ================================================================
  624. // 5. See if the NT drive has enough space for the CrashDump pagefile
  625. // size.
  626. // ================================================================
  627. //
  628. if(PagefileDrive == -1) {
  629. if( VolumeFreeSpaceMB[WindowsDriveNo] > (CrashDumpPagefileMinMB + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
  630. LOGITEM(L"SetUpVirtualMemory: loc 5\r\n");
  631. //
  632. // Record our settings.
  633. //
  634. RECORD_VM_SETTINGS( WindowsDriveNo, CrashDumpPagefileMinMB, SYS_DRIVE_FREE_SPACE_BUFFER );
  635. }
  636. }
  637. //
  638. // ================================================================
  639. // 6. See if any drive has enough space for the CrashDump pagefile
  640. // size.
  641. // ================================================================
  642. //
  643. if(PagefileDrive == -1) {
  644. for(DriveNo=0; DriveNo<26; DriveNo++) {
  645. if( (DriveNo != WindowsDriveNo) &&
  646. (VolumeFreeSpaceMB[DriveNo] > (CrashDumpPagefileMinMB + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
  647. //
  648. // He's got the space, but let's make sure he's not removable.
  649. //
  650. DriveName[0] = DriveNo + L'A';
  651. if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
  652. LOGITEM(L"SetUpVirtualMemory: loc 6 - found space on driveno %u\r\n",DriveNo);
  653. //
  654. // Record our settings.
  655. //
  656. RECORD_VM_SETTINGS( DriveNo, CrashDumpPagefileMinMB, ALT_DRIVE_FREE_SPACE_BUFFER);
  657. break;
  658. }
  659. }
  660. }
  661. }
  662. //
  663. // ================================================================
  664. // 7. See if the NT drive has enough space for the minimum pagefile
  665. // size.
  666. // ================================================================
  667. //
  668. if(PagefileDrive == -1) {
  669. if( VolumeFreeSpaceMB[WindowsDriveNo] > (PagefileMinMB + SYS_DRIVE_FREE_SPACE_BUFFER) ) {
  670. LOGITEM(L"SetUpVirtualMemory: loc 7\r\n");
  671. //
  672. // Record our settings.
  673. //
  674. RECORD_VM_SETTINGS( WindowsDriveNo, PagefileMinMB, SYS_DRIVE_FREE_SPACE_BUFFER );
  675. }
  676. }
  677. //
  678. // ================================================================
  679. // 8. See if any drive has enough space for the minimum pagefile
  680. // size.
  681. // ================================================================
  682. //
  683. if(PagefileDrive == -1) {
  684. for(DriveNo=0; DriveNo<26; DriveNo++) {
  685. if( (DriveNo != WindowsDriveNo) &&
  686. (VolumeFreeSpaceMB[DriveNo] > (PagefileMinMB + ALT_DRIVE_FREE_SPACE_BUFFER)) ) {
  687. //
  688. // He's got the space, but let's make sure he's not removable.
  689. //
  690. DriveName[0] = DriveNo + L'A';
  691. if( GetDriveType(DriveName) != DRIVE_REMOVABLE ) {
  692. LOGITEM(L"SetUpVirtualMemory: loc 8 - found space on driveno %u\r\n",DriveNo);
  693. //
  694. // Record our settings.
  695. //
  696. RECORD_VM_SETTINGS( DriveNo, PagefileMinMB, ALT_DRIVE_FREE_SPACE_BUFFER );
  697. break;
  698. }
  699. }
  700. }
  701. }
  702. //
  703. // ================================================================
  704. // 9. Pick the drive with the most free space.
  705. // ================================================================
  706. //
  707. if(PagefileDrive == -1) {
  708. MaxSpaceDrive = 0;
  709. for(DriveNo=0; DriveNo<26; DriveNo++) {
  710. if(VolumeFreeSpaceMB[DriveNo] > VolumeFreeSpaceMB[MaxSpaceDrive]) {
  711. MaxSpaceDrive = DriveNo;
  712. }
  713. }
  714. if( VolumeFreeSpaceMB[MaxSpaceDrive] > ALT_DRIVE_FREE_SPACE_BUFFER ) {
  715. //
  716. // We're desperate here, so don't bother checking if he's
  717. // removable.
  718. //
  719. LOGITEM(L"SetUpVirtualMemory: loc 9 - MaxSpaceDrive is %u\r\n",MaxSpaceDrive);
  720. //
  721. // Record our settings.
  722. //
  723. RECORD_VM_SETTINGS( MaxSpaceDrive, VolumeFreeSpaceMB[MaxSpaceDrive] - ALT_DRIVE_FREE_SPACE_BUFFER, 0 );
  724. }
  725. }
  726. //
  727. // If we still don't have space for a pagefile, the user is out of luck.
  728. //
  729. if(PagefileDrive == -1) {
  730. LOGITEM(L"SetUpVirtualMemory: loc 10 -- out of luck\r\n");
  731. PagefileSpec = NULL;
  732. b = FALSE;
  733. SetuplogError(
  734. LogSevWarning,
  735. SETUPLOG_USE_MESSAGEID,
  736. MSG_LOG_PAGEFILE_FAIL,NULL,
  737. SETUPLOG_USE_MESSAGEID,
  738. MSG_LOG_NO_PAGING_DRIVES,
  739. NULL,NULL);
  740. } else {
  741. b = TRUE;
  742. PagefileSpec = PagefileTemplate;
  743. _snwprintf(
  744. PagefileTemplate,
  745. sizeof(PagefileTemplate)/sizeof(PagefileTemplate[0]),
  746. L"%c:\\pagefile.sys %u %u",
  747. PagefileDrive + L'A',
  748. PagefileSizeMB,
  749. MaxPagefileSizeMB
  750. );
  751. }
  752. if( b ) {
  753. //
  754. // Set pagefile in registry. I only want to do this in the
  755. // case of clean installs, and on upgrades if the existing
  756. // pagefile wasn't big enough. In the case of upgrades, if
  757. // the existing pagefile was big enough, then we will have
  758. // set UseExistingPageFile, which will tell us to leave the
  759. // registry settings as is.
  760. //
  761. if( !UseExistingPageFile ) {
  762. d = pSetupSetArrayToMultiSzValue(
  763. HKEY_LOCAL_MACHINE,
  764. szMemoryManagementKeyPath,
  765. szPageFileValueName,
  766. &PagefileSpec,
  767. PagefileSpec ? 1 : 0
  768. );
  769. if(d == NO_ERROR) {
  770. if(b) {
  771. SetuplogError(
  772. LogSevInformation,
  773. SETUPLOG_USE_MESSAGEID,
  774. MSG_LOG_CREATED_PAGEFILE,
  775. PagefileDrive+L'A',
  776. PagefileSizeMB,
  777. NULL,NULL);
  778. }
  779. } else {
  780. SetuplogError(
  781. LogSevWarning,
  782. SETUPLOG_USE_MESSAGEID,
  783. MSG_LOG_PAGEFILE_FAIL, NULL,
  784. SETUPLOG_USE_MESSAGEID,
  785. MSG_LOG_X_RETURNED_WINERR,
  786. szSetArrayToMultiSzValue,
  787. d,
  788. NULL,NULL);
  789. }
  790. //
  791. // Make sure there's at least a small pagefile
  792. // on the windows drive. Ignore errors here.
  793. //
  794. if( (PagefileDrive != WindowsDriveNo) &&
  795. (VolumeFreeSpaceMB[WindowsDriveNo] > TINY_WINDIR_PAGEFILE_SIZE) ) {
  796. //
  797. // There's not. Write a second string into our buffer just past
  798. // the first string (remember this will become a REG_MULTI_SZ
  799. //
  800. _snwprintf(
  801. PagefileTemplate,
  802. sizeof(PagefileTemplate)/sizeof(PagefileTemplate[0]),
  803. L"%c:\\pagefile.sys %u %u",
  804. WindowsDriveNo + L'A',
  805. TINY_WINDIR_PAGEFILE_SIZE,
  806. TINY_WINDIR_PAGEFILE_SIZE
  807. );
  808. pSetupAppendStringToMultiSz(
  809. HKEY_LOCAL_MACHINE,
  810. szMemoryManagementKeyPath,
  811. 0,
  812. szPageFileValueName,
  813. PagefileTemplate,
  814. TRUE
  815. );
  816. }
  817. b = b && (d == NO_ERROR);
  818. }
  819. }
  820. //
  821. // Now set the crashdump.
  822. //
  823. // The proper settings are as follows:
  824. //
  825. // Server Upgrades
  826. // ===============
  827. // existing setting new setting
  828. // 0 3
  829. // 1 1
  830. //
  831. // Workstation Upgrades
  832. // ====================
  833. // existing setting new setting
  834. // 0 3
  835. // 1 1
  836. //
  837. // Server Clean Install
  838. // ====================
  839. // new setting
  840. // 1 iff pagefile < MAX_PAGEFILE_SIZEMB else 2
  841. //
  842. // Workstation Clean Install
  843. // =========================
  844. // new setting
  845. // 3
  846. //
  847. //
  848. // Where:
  849. // 0 - no crash dump
  850. // 1 - dump all memory to crash file
  851. // 2 - dump kernel memory to crash file
  852. // 3 - dump a select set of memory (amounting to 64K) to crash file
  853. //
  854. //
  855. // See if the user has asked us to go a particular way
  856. // on the crashdump settings.
  857. //
  858. GetSystemDirectory(AnswerFile,MAX_PATH);
  859. pSetupConcatenatePaths(AnswerFile,WINNT_GUI_FILE,MAX_PATH,NULL);
  860. GetPrivateProfileString( TEXT("Unattended"),
  861. TEXT("CrashDumpSetting"),
  862. pwNull,
  863. Answer,
  864. AnswerBufLen,
  865. AnswerFile );
  866. if( lstrcmp( pwNull, Answer ) ) {
  867. d = wcstoul(Answer,NULL,10);
  868. if( d <= Three ) {
  869. CrashDumpValues[2].Data = &d;
  870. } else {
  871. CrashDumpValues[2].Data = &Three;
  872. }
  873. } else {
  874. //
  875. // No unattended values. Set it manually.
  876. //
  877. //
  878. // Take care of clean installs first.
  879. //
  880. if( !Upgrade ) {
  881. if( ProductType == PRODUCT_WORKSTATION ) {
  882. CrashDumpValues[2].Data = &Three;
  883. } else {
  884. if( PagefileSizeMB >= MAX_PAGEFILE_SIZEMB ) {
  885. CrashDumpValues[2].Data = &Two;
  886. } else {
  887. CrashDumpValues[2].Data = &One;
  888. }
  889. }
  890. } else {
  891. //
  892. // Upgrade.
  893. //
  894. // Here, we need to go retrieve the current value to
  895. // see what's there now. This will tell us how to migrate.
  896. //
  897. HKEY Key;
  898. DWORD cbData;
  899. DWORD ExistingCrashDumpSetting = 0;
  900. DWORD Type;
  901. d = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  902. L"System\\CurrentControlSet\\Control\\CrashControl",
  903. 0,
  904. KEY_READ,
  905. &Key );
  906. if( d == ERROR_SUCCESS ) {
  907. //
  908. // Find out the size of the data to be retrieved
  909. //
  910. cbData = sizeof(DWORD);
  911. d = RegQueryValueEx( Key,
  912. CrashDumpValues[2].Name,
  913. 0,
  914. &Type,
  915. ( LPBYTE )&ExistingCrashDumpSetting,
  916. &cbData );
  917. RegCloseKey( Key );
  918. }
  919. //
  920. // Make sure ExistingCrashDumpSetting is set.
  921. //
  922. if( d != ERROR_SUCCESS ) {
  923. ExistingCrashDumpSetting = (ProductType == PRODUCT_WORKSTATION) ? 0 : 1;
  924. }
  925. if( ProductType == PRODUCT_WORKSTATION ) {
  926. if( ExistingCrashDumpSetting == 0 ) {
  927. CrashDumpValues[2].Data = &Three;
  928. } else {
  929. CrashDumpValues[2].Data = &One;
  930. }
  931. } else {
  932. if( ExistingCrashDumpSetting == 0 ) {
  933. CrashDumpValues[2].Data = &Three;
  934. } else {
  935. CrashDumpValues[2].Data = &One;
  936. }
  937. }
  938. }
  939. }
  940. #ifdef PRERELEASE
  941. if( Upgrade ) {
  942. d = SetGroupOfValues(
  943. HKEY_LOCAL_MACHINE,
  944. L"System\\CurrentControlSet\\Control\\CrashControl",
  945. CrashDumpValues,
  946. sizeof(CrashDumpValues)/sizeof(CrashDumpValues[0]) - 1
  947. );
  948. } else {
  949. d = SetGroupOfValues(
  950. HKEY_LOCAL_MACHINE,
  951. L"System\\CurrentControlSet\\Control\\CrashControl",
  952. CrashDumpValues,
  953. sizeof(CrashDumpValues)/sizeof(CrashDumpValues[0])
  954. );
  955. }
  956. #else
  957. d = SetGroupOfValues(
  958. HKEY_LOCAL_MACHINE,
  959. L"System\\CurrentControlSet\\Control\\CrashControl",
  960. CrashDumpValues,
  961. sizeof(CrashDumpValues)/sizeof(CrashDumpValues[0])
  962. );
  963. #endif
  964. if(d == NO_ERROR) {
  965. SetuplogError(
  966. LogSevInformation,
  967. SETUPLOG_USE_MESSAGEID,
  968. MSG_LOG_CRASHDUMPOK,
  969. NULL,NULL);
  970. } else {
  971. SetuplogError(
  972. LogSevWarning,
  973. SETUPLOG_USE_MESSAGEID,
  974. MSG_LOG_CRASHDUMPFAIL, NULL,
  975. SETUPLOG_USE_MESSAGEID,
  976. MSG_LOG_X_RETURNED_STRING,
  977. szSetGroupOfValues,
  978. d,
  979. NULL,NULL);
  980. b = FALSE;
  981. }
  982. RemoveSavedPagefileSetting();
  983. LOGITEM(L"SetUpVirtualMemory: EXIT (%u)\r\n",b);
  984. return(b);
  985. }