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