- Fixed the freeing of memory from boot load drivers.
[reactos.git] / reactos / ntoskrnl / mm / pagefile.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: pagefile.c,v 1.37 2003/10/12 17:05:48 hbirr Exp $
20 *
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/mm/pagefile.c
23 * PURPOSE: Paging file functions
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * UPDATE HISTORY:
26 * Created 22/05/98
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include <ddk/ntddk.h>
32 #include <internal/io.h>
33 #include <internal/mm.h>
34 #include <napi/core.h>
35 #include <internal/ps.h>
36 #include <internal/ldr.h>
37
38 #define NDEBUG
39 #include <internal/debug.h>
40
41 /* TYPES *********************************************************************/
42
43 typedef struct _PAGINGFILE
44 {
45 LIST_ENTRY PagingFileListEntry;
46 PFILE_OBJECT FileObject;
47 LARGE_INTEGER MaximumSize;
48 LARGE_INTEGER CurrentSize;
49 ULONG FreePages;
50 ULONG UsedPages;
51 PULONG AllocMap;
52 KSPIN_LOCK AllocMapLock;
53 ULONG AllocMapSize;
54 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
55 } PAGINGFILE, *PPAGINGFILE;
56
57 /* GLOBALS *******************************************************************/
58
59 #define MAX_PAGING_FILES (32)
60
61 /* List of paging files, both used and free */
62 static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
63
64 /* Lock for examining the list of paging files */
65 static KSPIN_LOCK PagingFileListLock;
66
67 /* Number of paging files */
68 static ULONG MiPagingFileCount;
69
70 /* Number of pages that are available for swapping */
71 static ULONG MiFreeSwapPages;
72
73 /* Number of pages that have been allocated for swapping */
74 static ULONG MiUsedSwapPages;
75
76 /*
77 * Number of pages that have been reserved for swapping but not yet allocated
78 */
79 static ULONG MiReservedSwapPages;
80
81 /*
82 * Ratio between reserved and available swap pages, e.g. setting this to five
83 * forces one swap page to be available for every five swap pages that are
84 * reserved. Setting this to zero turns off commit checking altogether.
85 */
86 #define MM_PAGEFILE_COMMIT_RATIO (1)
87
88 /*
89 * Number of pages that can be used for potentially swapable memory without
90 * pagefile space being reserved. The intention is that this allows smss
91 * to start up and create page files while ordinarily having a commit
92 * ratio of one.
93 */
94 #define MM_PAGEFILE_COMMIT_GRACE (256)
95
96 static PVOID MmCoreDumpPageFrame = NULL;
97 static ULONG MmCoreDumpSize;
98 static DUMP_POINTERS MmCoreDumpPointers;
99 static PMM_CORE_DUMP_FUNCTIONS MmCoreDumpFunctions;
100 static ULONG MmCoreDumpPageFile = 0xFFFFFFFF;
101 static ROS_QUERY_LCN_MAPPING MmCoreDumpLcnMapping;
102
103 ULONG MmCoreDumpType = MM_CORE_DUMP_TYPE_NONE;
104
105 /*
106 * Translate between a swap entry and a file and offset pair.
107 */
108 #define FILE_FROM_ENTRY(i) ((i) >> 24)
109 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
110 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
111
112 static BOOLEAN MmSwapSpaceMessage = FALSE;
113
114 /* FUNCTIONS *****************************************************************/
115
116 VOID
117 MmShowOutOfSpaceMessagePagingFile(VOID)
118 {
119 if (!MmSwapSpaceMessage)
120 {
121 DPRINT1("MM: Out of swap space.\n");
122 MmSwapSpaceMessage = TRUE;
123 }
124 }
125
126 NTSTATUS MmWriteToSwapPage(SWAPENTRY SwapEntry, PMDL Mdl)
127 {
128 ULONG i, offset, j;
129 LARGE_INTEGER file_offset;
130 IO_STATUS_BLOCK Iosb;
131 NTSTATUS Status;
132 KEVENT Event;
133 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
134
135 DPRINT("MmWriteToSwapPage\n");
136
137 if (SwapEntry == 0)
138 {
139 KEBUGCHECK(0);
140 return(STATUS_UNSUCCESSFUL);
141 }
142
143 i = FILE_FROM_ENTRY(SwapEntry);
144 offset = OFFSET_FROM_ENTRY(SwapEntry);
145
146 if (i >= MAX_PAGING_FILES)
147 {
148 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
149 KEBUGCHECK(0);
150 }
151 if (PagingFileList[i]->FileObject == NULL ||
152 PagingFileList[i]->FileObject->DeviceObject == NULL)
153 {
154 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
155 KEBUGCHECK(0);
156 }
157
158 file_offset.QuadPart = offset * PAGE_SIZE;
159 RetrievalPointers = PagingFileList[i]->RetrievalPointers;
160
161 for (j = 0; j < RetrievalPointers->NumberOfPairs; j++)
162 {
163 if ((ULONGLONG) file_offset.QuadPart < RetrievalPointers->Pair[j].Vcn)
164 {
165 if (j == 0)
166 {
167 file_offset.QuadPart += RetrievalPointers->Pair[0].Lcn - RetrievalPointers->StartVcn;
168 }
169 else
170 {
171 file_offset.QuadPart += RetrievalPointers->Pair[j].Lcn - RetrievalPointers->Pair[j-1].Vcn;
172 }
173 break;
174 }
175 }
176 if (j >= RetrievalPointers->NumberOfPairs)
177 {
178 CHECKPOINT1;
179 KEBUGCHECK(0);
180 }
181
182 KeInitializeEvent(&Event, NotificationEvent, FALSE);
183 Status = IoPageWrite(PagingFileList[i]->FileObject,
184 Mdl,
185 &file_offset,
186 &Event,
187 &Iosb);
188 if (Status == STATUS_PENDING)
189 {
190 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
191 return(Iosb.Status);
192 }
193 return(Status);
194 }
195
196 NTSTATUS MmReadFromSwapPage(SWAPENTRY SwapEntry, PMDL Mdl)
197 {
198 ULONG i, offset, j;
199 LARGE_INTEGER file_offset;
200 IO_STATUS_BLOCK Iosb;
201 NTSTATUS Status;
202 KEVENT Event;
203 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
204
205 DPRINT("MmReadFromSwapPage\n");
206
207 if (SwapEntry == 0)
208 {
209 KEBUGCHECK(0);
210 return(STATUS_UNSUCCESSFUL);
211 }
212
213 i = FILE_FROM_ENTRY(SwapEntry);
214 offset = OFFSET_FROM_ENTRY(SwapEntry);
215
216 if (i >= MAX_PAGING_FILES)
217 {
218 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
219 KEBUGCHECK(0);
220 }
221 if (PagingFileList[i]->FileObject == NULL ||
222 PagingFileList[i]->FileObject->DeviceObject == NULL)
223 {
224 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
225 KEBUGCHECK(0);
226 }
227
228 file_offset.QuadPart = offset * PAGE_SIZE;
229 RetrievalPointers = PagingFileList[i]->RetrievalPointers;
230
231 for (j = 0; j < RetrievalPointers->NumberOfPairs; j++)
232 {
233 if ((ULONGLONG) file_offset.QuadPart < RetrievalPointers->Pair[j].Vcn)
234 {
235 if (j == 0)
236 {
237 file_offset.QuadPart += RetrievalPointers->Pair[0].Lcn - RetrievalPointers->StartVcn;
238 }
239 else
240 {
241 file_offset.QuadPart += RetrievalPointers->Pair[j].Lcn - RetrievalPointers->Pair[j-1].Vcn;
242 }
243 break;
244 }
245 }
246 if (j >= RetrievalPointers->NumberOfPairs)
247 {
248 CHECKPOINT1;
249 KEBUGCHECK(0);
250 }
251 KeInitializeEvent(&Event, NotificationEvent, FALSE);
252 Status = IoPageRead(PagingFileList[i]->FileObject,
253 Mdl,
254 &file_offset,
255 &Event,
256 &Iosb);
257 if (Status == STATUS_PENDING)
258 {
259 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
260 return(Iosb.Status);
261 }
262 return(Status);
263 }
264
265 VOID INIT_FUNCTION
266 MmInitPagingFile(VOID)
267 {
268 ULONG i;
269
270 KeInitializeSpinLock(&PagingFileListLock);
271
272 MiFreeSwapPages = 0;
273 MiUsedSwapPages = 0;
274 MiReservedSwapPages = 0;
275
276 for (i = 0; i < MAX_PAGING_FILES; i++)
277 {
278 PagingFileList[i] = NULL;
279 }
280 MiPagingFileCount = 0;
281
282 /*
283 * Initialize the crash dump support.
284 */
285 if (MmCoreDumpType != MM_CORE_DUMP_TYPE_NONE)
286 {
287 MmCoreDumpPageFrame = MmAllocateSection(PAGE_SIZE);
288 if (MmCoreDumpType == MM_CORE_DUMP_TYPE_FULL)
289 {
290 MmCoreDumpSize = MmStats.NrTotalPages * 4096 + 1024 * 1024;
291 }
292 else
293 {
294 MmCoreDumpSize = 1024 * 1024;
295 }
296 }
297 }
298
299 BOOLEAN
300 MmReserveSwapPages(ULONG Nr)
301 {
302 KIRQL oldIrql;
303 ULONG MiAvailSwapPages;
304
305 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
306 MiAvailSwapPages =
307 (MiFreeSwapPages * MM_PAGEFILE_COMMIT_RATIO) + MM_PAGEFILE_COMMIT_GRACE;
308 MiReservedSwapPages = MiReservedSwapPages + Nr;
309 if (MM_PAGEFILE_COMMIT_RATIO != 0 && MiAvailSwapPages < MiReservedSwapPages)
310 {
311 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
312 return(FALSE);
313 }
314 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
315 return(TRUE);
316 }
317
318 VOID
319 MmDereserveSwapPages(ULONG Nr)
320 {
321 KIRQL oldIrql;
322
323 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
324 MiReservedSwapPages = MiReservedSwapPages - Nr;
325 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
326 }
327
328 static ULONG
329 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
330 {
331 KIRQL oldIrql;
332 ULONG i, j;
333
334 KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
335
336 for (i = 0; i < PagingFile->AllocMapSize; i++)
337 {
338 for (j = 0; j < 32; j++)
339 {
340 if (!(PagingFile->AllocMap[i] & (1 << j)))
341 {
342 break;
343 }
344 }
345 if (j == 32)
346 {
347 continue;
348 }
349 PagingFile->AllocMap[i] |= (1 << j);
350 PagingFile->UsedPages++;
351 PagingFile->FreePages--;
352 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
353 return((i * 32) + j);
354 }
355
356 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
357 return(0xFFFFFFFF);
358 }
359
360 VOID
361 MmFreeSwapPage(SWAPENTRY Entry)
362 {
363 ULONG i;
364 ULONG off;
365 KIRQL oldIrql;
366
367 i = FILE_FROM_ENTRY(Entry);
368 off = OFFSET_FROM_ENTRY(Entry);
369
370 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
371 if (PagingFileList[i] == NULL)
372 {
373 KEBUGCHECK(0);
374 }
375 KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock);
376
377 PagingFileList[i]->AllocMap[off / 32] &= (~(1 << (off % 32)));
378
379 PagingFileList[i]->FreePages++;
380 PagingFileList[i]->UsedPages--;
381
382 MiFreeSwapPages++;
383 MiUsedSwapPages--;
384
385 KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock);
386 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
387 }
388
389 BOOLEAN
390 MmIsAvailableSwapPage(VOID)
391 {
392 return(MiFreeSwapPages > 0);
393 }
394
395 SWAPENTRY
396 MmAllocSwapPage(VOID)
397 {
398 KIRQL oldIrql;
399 ULONG i;
400 ULONG off;
401 SWAPENTRY entry;
402
403 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
404
405 if (MiFreeSwapPages == 0)
406 {
407 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
408 return(0);
409 }
410
411 for (i = 0; i < MAX_PAGING_FILES; i++)
412 {
413 if (PagingFileList[i] != NULL &&
414 PagingFileList[i]->FreePages >= 1)
415 {
416 off = MiAllocPageFromPagingFile(PagingFileList[i]);
417 if (off == 0xFFFFFFFF)
418 {
419 KEBUGCHECK(0);
420 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
421 return(STATUS_UNSUCCESSFUL);
422 }
423 MiUsedSwapPages++;
424 MiFreeSwapPages--;
425 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
426
427 entry = ENTRY_FROM_FILE_OFFSET(i, off);
428 return(entry);
429 }
430 }
431
432 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
433 KEBUGCHECK(0);
434 return(0);
435 }
436
437 LARGE_INTEGER STATIC
438 MmGetOffsetPageFile(PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers, LARGE_INTEGER Offset)
439 {
440 ULONG j;
441 for (j = 0; j < RetrievalPointers->NumberOfPairs; j++)
442 {
443 if (Offset.QuadPart < RetrievalPointers->Pair[j].Vcn)
444 {
445 if (j == 0)
446 {
447 Offset.QuadPart += RetrievalPointers->Pair[0].Lcn - RetrievalPointers->StartVcn;
448 }
449 else
450 {
451 Offset.QuadPart += RetrievalPointers->Pair[j].Lcn - RetrievalPointers->Pair[j-1].Vcn;
452 }
453 break;
454 }
455 }
456 if (j >= RetrievalPointers->NumberOfPairs)
457 {
458 CHECKPOINT1;
459 KEBUGCHECK(0);
460 }
461 return(Offset);
462 }
463
464 NTSTATUS STDCALL
465 MmDumpToPagingFile(ULONG BugCode,
466 ULONG BugCodeParameter1,
467 ULONG BugCodeParameter2,
468 ULONG BugCodeParameter3,
469 ULONG BugCodeParameter4,
470 PKTRAP_FRAME TrapFrame)
471 {
472 PMM_CORE_DUMP_HEADER Headers;
473 NTSTATUS Status;
474 UCHAR MdlBase[sizeof(MDL) + sizeof(PVOID)];
475 PMDL Mdl = (PMDL)MdlBase;
476 PETHREAD Thread = PsGetCurrentThread();
477 ULONG StackSize;
478 PULONG MdlMap;
479 LONGLONG NextOffset = 0;
480 ULONG i;
481 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
482 LARGE_INTEGER DiskOffset;
483
484 if (MmCoreDumpPageFile == 0xFFFFFFFF)
485 {
486 return(STATUS_UNSUCCESSFUL);
487 }
488
489 DbgPrint("\nMM: Dumping core: ");
490
491 /* Prepare the dump headers. */
492 Headers = (PMM_CORE_DUMP_HEADER)MmCoreDumpPageFrame;
493 Headers->Magic = MM_CORE_DUMP_HEADER_MAGIC;
494 Headers->Version = MM_CORE_DUMP_HEADER_VERSION;
495 Headers->Type = MmCoreDumpType;
496 if (TrapFrame != NULL)
497 {
498 if (!(TrapFrame->Eflags & (1 << 17)))
499 {
500 memcpy(&Headers->TrapFrame, TrapFrame,
501 sizeof(KTRAP_FRAME) - (4 * sizeof(DWORD)));
502 }
503 else
504 {
505 memcpy(&Headers->TrapFrame, TrapFrame, sizeof(KTRAP_FRAME));
506 }
507 }
508 Headers->BugCheckCode = BugCode;
509 Headers->BugCheckParameters[0] = BugCodeParameter1;
510 Headers->BugCheckParameters[1] = BugCodeParameter2;
511 Headers->BugCheckParameters[2] = BugCodeParameter3;
512 Headers->BugCheckParameters[3] = BugCodeParameter4;
513 Headers->FaultingStackBase = (PVOID)Thread->Tcb.StackLimit;
514 Headers->FaultingStackSize = StackSize =
515 (ULONG)(Thread->Tcb.StackBase - Thread->Tcb.StackLimit);
516 Headers->PhysicalMemorySize = MmStats.NrTotalPages * PAGE_SIZE;
517
518 /* Initialize the dump device. */
519 MmCoreDumpFunctions->DumpInit();
520 if (!NT_SUCCESS(Status))
521 {
522 DPRINT1("MM: Failed to initialize core dump device.\n");
523 return(Status);
524 }
525
526 /* Initialize the MDL. */
527 Mdl->Next = NULL;
528 Mdl->Size = sizeof(MDL) + sizeof(PVOID);
529 Mdl->MdlFlags = MDL_SOURCE_IS_NONPAGED_POOL;
530 Mdl->Process = NULL;
531 Mdl->MappedSystemVa = MmCoreDumpPageFrame;
532 Mdl->StartVa = NULL;
533 Mdl->ByteCount = PAGE_SIZE;
534 Mdl->ByteOffset = 0;
535 MdlMap = (PULONG)(Mdl + 1);
536
537
538 /* Initialize the retrieval offsets. */
539 RetrievalPointers = PagingFileList[MmCoreDumpPageFile]->RetrievalPointers;
540
541 /* Dump the header. */
542 MdlMap[0] = MmGetPhysicalAddress(MmCoreDumpPageFrame).u.LowPart;
543 DiskOffset = MmGetOffsetPageFile(RetrievalPointers, (LARGE_INTEGER)0LL);
544 DiskOffset.QuadPart += MmCoreDumpLcnMapping.LcnDiskOffset.QuadPart;
545 Status = MmCoreDumpFunctions->DumpWrite(DiskOffset, Mdl);
546 if (!NT_SUCCESS(Status))
547 {
548 DPRINT1("MM: Failed to write core dump header\n.");
549 return(Status);
550 }
551 NextOffset += PAGE_SIZE;;
552 DbgPrint("00");
553
554
555 /* Write out the contents of physical memory. */
556 if (MmCoreDumpType == MM_CORE_DUMP_TYPE_FULL)
557 {
558 for (i = 0; i < MmStats.NrTotalPages; i++)
559 {
560 LARGE_INTEGER PhysicalAddress;
561 PhysicalAddress.QuadPart = i * PAGE_SIZE;
562 MdlMap[0] = i * PAGE_SIZE;
563 MmCreateVirtualMappingDump(MmCoreDumpPageFrame,
564 PAGE_READWRITE,
565 PhysicalAddress);
566 DiskOffset = MmGetOffsetPageFile(RetrievalPointers,
567 (LARGE_INTEGER)NextOffset);
568 DiskOffset.QuadPart += MmCoreDumpLcnMapping.LcnDiskOffset.QuadPart;
569 Status = MmCoreDumpFunctions->DumpWrite(DiskOffset, Mdl);
570 if (!NT_SUCCESS(Status))
571 {
572 DPRINT1("MM: Failed to write page to core dump.\n");
573 return(Status);
574 }
575 if ((i % ((1024*1024) / PAGE_SIZE)) == 0)
576 {
577 DbgPrint("\b\b%.2d", i / ((1024*1024)/PAGE_SIZE));
578 }
579 NextOffset += PAGE_SIZE;
580 }
581 }
582
583 DbgPrint("\n");
584 MmCoreDumpFunctions->DumpFinish();
585 return(STATUS_SUCCESS);
586 }
587
588 NTSTATUS STDCALL
589 MmInitializeCrashDump(HANDLE PageFileHandle, ULONG PageFileNum)
590 {
591 PFILE_OBJECT PageFile;
592 PDEVICE_OBJECT PageFileDevice;
593 NTSTATUS Status;
594 PIRP Irp;
595 KEVENT Event;
596 IO_STATUS_BLOCK Iosb;
597 UNICODE_STRING DiskDumpName;
598 ANSI_STRING ProcName;
599 PIO_STACK_LOCATION StackPtr;
600 PMODULE_OBJECT ModuleObject;
601
602 Status = ZwFsControlFile(PageFileHandle,
603 0,
604 NULL,
605 NULL,
606 &Iosb,
607 FSCTL_ROS_QUERY_LCN_MAPPING,
608 NULL,
609 0,
610 &MmCoreDumpLcnMapping,
611 sizeof(ROS_QUERY_LCN_MAPPING));
612 if (!NT_SUCCESS(Status) ||
613 Iosb.Information != sizeof(ROS_QUERY_LCN_MAPPING))
614 {
615 return(Status);
616 }
617
618 /* Get the underlying storage device. */
619 Status =
620 ObReferenceObjectByHandle(PageFileHandle,
621 FILE_ALL_ACCESS,
622 NULL,
623 KernelMode,
624 (PVOID*)&PageFile,
625 NULL);
626 if (!NT_SUCCESS(Status))
627 {
628 return(Status);
629 }
630
631 PageFileDevice = PageFile->Vpb->RealDevice;
632
633 /* Get the dump pointers. */
634 KeInitializeEvent(&Event, NotificationEvent, FALSE);
635 Irp = IoBuildDeviceIoControlRequest(IOCTL_SCSI_GET_DUMP_POINTERS,
636 PageFileDevice,
637 NULL,
638 0,
639 &MmCoreDumpPointers,
640 sizeof(MmCoreDumpPointers),
641 FALSE,
642 &Event,
643 &Iosb);
644 StackPtr = IoGetNextIrpStackLocation(Irp);
645 StackPtr->FileObject = PageFile;
646 StackPtr->DeviceObject = PageFileDevice;
647 StackPtr->Parameters.DeviceIoControl.InputBufferLength = 0;
648 StackPtr->Parameters.DeviceIoControl.OutputBufferLength = sizeof(MmCoreDumpPointers);
649
650 Status = IoCallDriver(PageFileDevice,Irp);
651 if (Status == STATUS_PENDING)
652 {
653 Status = KeWaitForSingleObject(&Event,
654 Executive,
655 KernelMode,
656 FALSE,
657 NULL);
658 }
659 if (Status != STATUS_SUCCESS ||
660 Iosb.Information != sizeof(MmCoreDumpPointers))
661 {
662 ObDereferenceObject(PageFile);
663 return(Status);
664 }
665
666 /* Load the diskdump driver. */
667 RtlInitUnicodeStringFromLiteral(&DiskDumpName, L"DiskDump");
668 ModuleObject = LdrGetModuleObject(&DiskDumpName);
669 if (ModuleObject == NULL)
670 {
671 return(STATUS_OBJECT_NAME_NOT_FOUND);
672 }
673 RtlInitAnsiString(&ProcName, "DiskDumpFunctions");
674 Status = LdrGetProcedureAddress(ModuleObject->Base,
675 &ProcName,
676 0,
677 (PVOID*)&MmCoreDumpFunctions);
678 if (!NT_SUCCESS(Status))
679 {
680 ObDereferenceObject(PageFile);
681 return(Status);
682 }
683
684 /* Prepare for disk dumping. */
685 Status = MmCoreDumpFunctions->DumpPrepare(PageFileDevice,
686 &MmCoreDumpPointers);
687 if (!NT_SUCCESS(Status))
688 {
689 ObDereferenceObject(PageFile);
690 return(Status);
691 }
692
693 MmCoreDumpPageFile = PageFileNum;
694 ObDereferenceObject(PageFile);
695 return(STATUS_SUCCESS);
696 }
697
698 NTSTATUS STDCALL
699 NtCreatePagingFile(IN PUNICODE_STRING FileName,
700 IN PLARGE_INTEGER InitialSize,
701 IN PLARGE_INTEGER MaximumSize,
702 IN ULONG Reserved)
703 {
704 NTSTATUS Status;
705 OBJECT_ATTRIBUTES ObjectAttributes;
706 HANDLE FileHandle;
707 IO_STATUS_BLOCK IoStatus;
708 PFILE_OBJECT FileObject;
709 PPAGINGFILE PagingFile;
710 KIRQL oldIrql;
711 ULONG AllocMapSize;
712 ULONG Size;
713 FILE_FS_SIZE_INFORMATION FsSizeInformation;
714 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
715 ULONG i;
716 ULONG BytesPerAllocationUnit;
717 LARGE_INTEGER Vcn;
718 ULONG ExtentCount;
719 ULONG MaxVcn;
720
721 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
722 FileName, InitialSize->QuadPart);
723
724 if (MiPagingFileCount >= MAX_PAGING_FILES)
725 {
726 return(STATUS_TOO_MANY_PAGING_FILES);
727 }
728
729 InitializeObjectAttributes(&ObjectAttributes,
730 FileName,
731 0,
732 NULL,
733 NULL);
734
735 Status = IoCreateFile(&FileHandle,
736 FILE_ALL_ACCESS,
737 &ObjectAttributes,
738 &IoStatus,
739 NULL,
740 0,
741 0,
742 FILE_OPEN_IF,
743 FILE_SYNCHRONOUS_IO_NONALERT,
744 NULL,
745 0,
746 CreateFileTypeNone,
747 NULL,
748 SL_OPEN_PAGING_FILE);
749 if (!NT_SUCCESS(Status))
750 {
751 return(Status);
752 }
753
754 Status = NtQueryVolumeInformationFile(FileHandle,
755 &IoStatus,
756 &FsSizeInformation,
757 sizeof(FILE_FS_SIZE_INFORMATION),
758 FileFsSizeInformation);
759 if (!NT_SUCCESS(Status))
760 {
761 NtClose(FileHandle);
762 return Status;
763 }
764
765 BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit * FsSizeInformation.BytesPerSector;
766 if (BytesPerAllocationUnit % PAGE_SIZE)
767 {
768 NtClose(FileHandle);
769 return STATUS_UNSUCCESSFUL;
770 }
771
772 Status = NtSetInformationFile(FileHandle,
773 &IoStatus,
774 InitialSize,
775 sizeof(LARGE_INTEGER),
776 FileAllocationInformation);
777 if (!NT_SUCCESS(Status))
778 {
779 NtClose(FileHandle);
780 return(Status);
781 }
782
783 Status = ObReferenceObjectByHandle(FileHandle,
784 FILE_ALL_ACCESS,
785 IoFileObjectType,
786 UserMode,
787 (PVOID*)&FileObject,
788 NULL);
789 if (!NT_SUCCESS(Status))
790 {
791 NtClose(FileHandle);
792 return(Status);
793 }
794
795 RetrievalPointers = ExAllocatePool(NonPagedPool, sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR));
796
797 if (RetrievalPointers == NULL)
798 {
799 ObDereferenceObject(FileObject);
800 NtClose(FileHandle);
801 return(STATUS_NO_MEMORY);
802 }
803
804 Vcn.QuadPart = 0LL;
805 ExtentCount = 0;
806 MaxVcn = (InitialSize->QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit;
807 while(1)
808 {
809 Status = NtFsControlFile(FileHandle,
810 0,
811 NULL,
812 NULL,
813 &IoStatus,
814 FSCTL_GET_RETRIEVAL_POINTERS,
815 &Vcn,
816 sizeof(LARGE_INTEGER),
817 RetrievalPointers,
818 sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR));
819 if (!NT_SUCCESS(Status))
820 {
821 ExFreePool(RetrievalPointers);
822 ObDereferenceObject(FileObject);
823 NtClose(FileHandle);
824 return(Status);
825 }
826 ExtentCount += RetrievalPointers->NumberOfPairs;
827 if ((ULONG)RetrievalPointers->Pair[0].Vcn < MaxVcn)
828 {
829 Vcn.QuadPart = RetrievalPointers->Pair[0].Vcn;
830 }
831 else
832 {
833 break;
834 }
835 }
836 ExFreePool(RetrievalPointers);
837
838 PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
839 if (PagingFile == NULL)
840 {
841 ObDereferenceObject(FileObject);
842 NtClose(FileHandle);
843 return(STATUS_NO_MEMORY);
844 }
845
846 PagingFile->FileObject = FileObject;
847 PagingFile->MaximumSize.QuadPart = MaximumSize->QuadPart;
848 PagingFile->CurrentSize.QuadPart = InitialSize->QuadPart;
849 PagingFile->FreePages = InitialSize->QuadPart / PAGE_SIZE;
850 PagingFile->UsedPages = 0;
851 KeInitializeSpinLock(&PagingFile->AllocMapLock);
852
853 AllocMapSize = (PagingFile->FreePages / 32) + 1;
854 PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
855 AllocMapSize * sizeof(ULONG));
856 PagingFile->AllocMapSize = AllocMapSize;
857
858 if (PagingFile->AllocMap == NULL)
859 {
860 ExFreePool(PagingFile);
861 ObDereferenceObject(FileObject);
862 ZwClose(FileHandle);
863 return(STATUS_NO_MEMORY);
864 }
865
866 Size = sizeof(GET_RETRIEVAL_DESCRIPTOR) + ExtentCount * sizeof(MAPPING_PAIR);
867 PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size);
868 if (PagingFile->RetrievalPointers == NULL)
869 {
870 ExFreePool(PagingFile->AllocMap);
871 ExFreePool(PagingFile);
872 ObDereferenceObject(FileObject);
873 NtClose(FileHandle);
874 return(STATUS_NO_MEMORY);
875 }
876
877 Vcn.QuadPart = 0LL;
878 Status = NtFsControlFile(FileHandle,
879 0,
880 NULL,
881 NULL,
882 &IoStatus,
883 FSCTL_GET_RETRIEVAL_POINTERS,
884 &Vcn,
885 sizeof(LARGE_INTEGER),
886 PagingFile->RetrievalPointers,
887 Size);
888 if (!NT_SUCCESS(Status))
889 {
890 ExFreePool(PagingFile->RetrievalPointers);
891 ExFreePool(PagingFile->AllocMap);
892 ExFreePool(PagingFile);
893 ObDereferenceObject(FileObject);
894 NtClose(FileHandle);
895 return(STATUS_NO_MEMORY);
896 }
897
898 if (PagingFile->RetrievalPointers->NumberOfPairs != ExtentCount ||
899 (ULONG)PagingFile->RetrievalPointers->Pair[ExtentCount - 1].Vcn != MaxVcn)
900 {
901 ExFreePool(PagingFile->RetrievalPointers);
902 ExFreePool(PagingFile->AllocMap);
903 ExFreePool(PagingFile);
904 ObDereferenceObject(FileObject);
905 NtClose(FileHandle);
906 return(STATUS_UNSUCCESSFUL);
907 }
908
909 /*
910 * Change the entries from lcn's to volume offset's.
911 */
912 PagingFile->RetrievalPointers->StartVcn *= BytesPerAllocationUnit;
913 for (i = 0; i < ExtentCount; i++)
914 {
915 PagingFile->RetrievalPointers->Pair[i].Lcn *= BytesPerAllocationUnit;
916 PagingFile->RetrievalPointers->Pair[i].Vcn *= BytesPerAllocationUnit;
917 }
918
919 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
920 for (i = 0; i < MAX_PAGING_FILES; i++)
921 {
922 if (PagingFileList[i] == NULL)
923 {
924 PagingFileList[i] = PagingFile;
925 break;
926 }
927 }
928 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
929 MiPagingFileCount++;
930 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
931
932 /* Check whether this pagefile can be a crash dump target. */
933 if (MmCoreDumpType != MM_CORE_DUMP_TYPE_NONE &&
934 PagingFile->CurrentSize.QuadPart >= MmCoreDumpSize &&
935 MmCoreDumpPageFile == 0xFFFFFFFF)
936 {
937 MmInitializeCrashDump(FileHandle, i);
938 }
939 NtClose(FileHandle);
940
941 MmSwapSpaceMessage = FALSE;
942
943 return(STATUS_SUCCESS);
944 }
945
946 /* EOF */