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