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