- use inlined probing macros for basic types
[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 = RTL_CONSTANT_STRING(L"DiskDump");
652 ANSI_STRING ProcName;
653 PIO_STACK_LOCATION StackPtr;
654 PLDR_DATA_TABLE_ENTRY 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 ModuleObject = LdrGetModuleObject(&DiskDumpName);
728 if (ModuleObject == NULL)
729 {
730 return(STATUS_OBJECT_NAME_NOT_FOUND);
731 }
732 RtlInitAnsiString(&ProcName, "DiskDumpFunctions");
733 Status = LdrGetProcedureAddress(ModuleObject->DllBase,
734 &ProcName,
735 0,
736 (PVOID*)&MmCoreDumpFunctions);
737 if (!NT_SUCCESS(Status))
738 {
739 ObDereferenceObject(PageFile);
740 return(Status);
741 }
742
743 /* Prepare for disk dumping. */
744 Status = MmCoreDumpFunctions->DumpPrepare(PageFileDevice,
745 &MmCoreDumpPointers);
746 if (!NT_SUCCESS(Status))
747 {
748 ObDereferenceObject(PageFile);
749 return(Status);
750 }
751
752 MmCoreDumpPageFile = PageFileNum;
753 ObDereferenceObject(PageFile);
754 return(STATUS_SUCCESS);
755 }
756
757 NTSTATUS STDCALL
758 NtCreatePagingFile(IN PUNICODE_STRING FileName,
759 IN PLARGE_INTEGER InitialSize,
760 IN PLARGE_INTEGER MaximumSize,
761 IN ULONG Reserved)
762 {
763 NTSTATUS Status;
764 OBJECT_ATTRIBUTES ObjectAttributes;
765 HANDLE FileHandle;
766 IO_STATUS_BLOCK IoStatus;
767 PFILE_OBJECT FileObject;
768 PPAGINGFILE PagingFile;
769 KIRQL oldIrql;
770 ULONG AllocMapSize;
771 FILE_FS_SIZE_INFORMATION FsSizeInformation;
772 PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
773 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList;
774 ULONG i;
775 ULONG BytesPerAllocationUnit;
776 LARGE_INTEGER Vcn;
777 ULONG ExtentCount;
778 LARGE_INTEGER MaxVcn;
779 ULONG Count;
780 ULONG Size;
781 KPROCESSOR_MODE PreviousMode;
782 UNICODE_STRING CapturedFileName;
783 LARGE_INTEGER SafeInitialSize, SafeMaximumSize;
784
785 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
786 FileName, InitialSize->QuadPart);
787
788 if (MiPagingFileCount >= MAX_PAGING_FILES)
789 {
790 return(STATUS_TOO_MANY_PAGING_FILES);
791 }
792
793 PreviousMode = ExGetPreviousMode();
794
795 Status = RtlCaptureUnicodeString(&CapturedFileName,
796 PreviousMode,
797 PagedPool,
798 FALSE,
799 FileName);
800 if (!NT_SUCCESS(Status))
801 {
802 return(Status);
803 }
804 if (PreviousMode != KernelMode)
805 {
806 _SEH_TRY
807 {
808 SafeInitialSize = ProbeForReadLargeInteger(InitialSize);
809 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
810 }
811 _SEH_HANDLE
812 {
813 Status = _SEH_GetExceptionCode();
814 }
815 _SEH_END;
816
817 if (!NT_SUCCESS(Status))
818 {
819 RtlReleaseCapturedUnicodeString(&CapturedFileName,
820 PreviousMode,
821 FALSE);
822 return Status;
823 }
824 }
825 else
826 {
827 SafeInitialSize = *InitialSize;
828 SafeMaximumSize = *MaximumSize;
829 }
830
831 InitializeObjectAttributes(&ObjectAttributes,
832 &CapturedFileName,
833 0,
834 NULL,
835 NULL);
836
837 Status = IoCreateFile(&FileHandle,
838 FILE_ALL_ACCESS,
839 &ObjectAttributes,
840 &IoStatus,
841 NULL,
842 0,
843 0,
844 FILE_OPEN_IF,
845 FILE_SYNCHRONOUS_IO_NONALERT,
846 NULL,
847 0,
848 CreateFileTypeNone,
849 NULL,
850 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
851
852 RtlReleaseCapturedUnicodeString(&CapturedFileName,
853 PreviousMode,
854 FALSE);
855 if (!NT_SUCCESS(Status))
856 {
857 return(Status);
858 }
859
860 Status = ZwQueryVolumeInformationFile(FileHandle,
861 &IoStatus,
862 &FsSizeInformation,
863 sizeof(FILE_FS_SIZE_INFORMATION),
864 FileFsSizeInformation);
865 if (!NT_SUCCESS(Status))
866 {
867 ZwClose(FileHandle);
868 return Status;
869 }
870
871 BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit * FsSizeInformation.BytesPerSector;
872 if (BytesPerAllocationUnit % PAGE_SIZE)
873 {
874 ZwClose(FileHandle);
875 return STATUS_UNSUCCESSFUL;
876 }
877
878 Status = ZwSetInformationFile(FileHandle,
879 &IoStatus,
880 &SafeInitialSize,
881 sizeof(LARGE_INTEGER),
882 FileAllocationInformation);
883 if (!NT_SUCCESS(Status))
884 {
885 ZwClose(FileHandle);
886 return(Status);
887 }
888
889 Status = ObReferenceObjectByHandle(FileHandle,
890 FILE_ALL_ACCESS,
891 IoFileObjectType,
892 PreviousMode,
893 (PVOID*)&FileObject,
894 NULL);
895 if (!NT_SUCCESS(Status))
896 {
897 ZwClose(FileHandle);
898 return(Status);
899 }
900
901 CurrentRetDescList = RetDescList = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
902
903 if (CurrentRetDescList == NULL)
904 {
905 ObDereferenceObject(FileObject);
906 ZwClose(FileHandle);
907 return(STATUS_NO_MEMORY);
908 }
909
910 #if defined(__GNUC__)
911 Vcn.QuadPart = 0LL;
912 #else
913
914 Vcn.QuadPart = 0;
915 #endif
916
917 ExtentCount = 0;
918 MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit;
919 while(1)
920 {
921 Status = ZwFsControlFile(FileHandle,
922 0,
923 NULL,
924 NULL,
925 &IoStatus,
926 FSCTL_GET_RETRIEVAL_POINTERS,
927 &Vcn,
928 sizeof(LARGE_INTEGER),
929 &CurrentRetDescList->RetrievalPointers,
930 sizeof(RETRIEVAL_POINTERS_BUFFER) + PAIRS_PER_RUN * 2 * sizeof(LARGE_INTEGER));
931 if (!NT_SUCCESS(Status))
932 {
933 while (RetDescList)
934 {
935 CurrentRetDescList = RetDescList;
936 RetDescList = RetDescList->Next;
937 ExFreePool(CurrentRetDescList);
938 }
939 ObDereferenceObject(FileObject);
940 ZwClose(FileHandle);
941 return(Status);
942 }
943 ExtentCount += CurrentRetDescList->RetrievalPointers.ExtentCount;
944 if (CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn.QuadPart < MaxVcn.QuadPart)
945 {
946 CurrentRetDescList->Next = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
947 if (CurrentRetDescList->Next == NULL)
948 {
949 while (RetDescList)
950 {
951 CurrentRetDescList = RetDescList;
952 RetDescList = RetDescList->Next;
953 ExFreePool(CurrentRetDescList);
954 }
955 ObDereferenceObject(FileObject);
956 ZwClose(FileHandle);
957 return(STATUS_NO_MEMORY);
958 }
959 Vcn = CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn;
960 CurrentRetDescList = CurrentRetDescList->Next;
961 }
962 else
963 {
964 break;
965 }
966 }
967
968 PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
969 if (PagingFile == NULL)
970 {
971 while (RetDescList)
972 {
973 CurrentRetDescList = RetDescList;
974 RetDescList = RetDescList->Next;
975 ExFreePool(CurrentRetDescList);
976 }
977 ObDereferenceObject(FileObject);
978 ZwClose(FileHandle);
979 return(STATUS_NO_MEMORY);
980 }
981
982 RtlZeroMemory(PagingFile, sizeof(*PagingFile));
983
984 PagingFile->FileObject = FileObject;
985 PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart;
986 PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart;
987 PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE);
988 PagingFile->UsedPages = 0;
989 KeInitializeSpinLock(&PagingFile->AllocMapLock);
990
991 AllocMapSize = (PagingFile->FreePages / 32) + 1;
992 PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
993 AllocMapSize * sizeof(ULONG));
994 PagingFile->AllocMapSize = AllocMapSize;
995
996 if (PagingFile->AllocMap == NULL)
997 {
998 while (RetDescList)
999 {
1000 CurrentRetDescList = RetDescList;
1001 RetDescList = RetDescList->Next;
1002 ExFreePool(CurrentRetDescList);
1003 }
1004 ExFreePool(PagingFile);
1005 ObDereferenceObject(FileObject);
1006 ZwClose(FileHandle);
1007 return(STATUS_NO_MEMORY);
1008 }
1009 DPRINT("ExtentCount: %d\n", ExtentCount);
1010 Size = sizeof(RETRIEVAL_POINTERS_BUFFER) + ExtentCount * 2 * sizeof(LARGE_INTEGER);
1011 PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size);
1012 if (PagingFile->RetrievalPointers == NULL)
1013 {
1014 while (RetDescList)
1015 {
1016 CurrentRetDescList = RetDescList;
1017 RetDescList = RetDescList->Next;
1018 ExFreePool(CurrentRetDescList);
1019 }
1020 ExFreePool(PagingFile->AllocMap);
1021 ExFreePool(PagingFile);
1022 ObDereferenceObject(FileObject);
1023 ZwClose(FileHandle);
1024 return(STATUS_NO_MEMORY);
1025 }
1026
1027 RtlZeroMemory(PagingFile->AllocMap, AllocMapSize * sizeof(ULONG));
1028 RtlZeroMemory(PagingFile->RetrievalPointers, Size);
1029
1030 Count = 0;
1031 PagingFile->RetrievalPointers->ExtentCount = ExtentCount;
1032 PagingFile->RetrievalPointers->StartingVcn = RetDescList->RetrievalPointers.StartingVcn;
1033 CurrentRetDescList = RetDescList;
1034 while (CurrentRetDescList)
1035 {
1036 memcpy(&PagingFile->RetrievalPointers->Extents[Count],
1037 CurrentRetDescList->RetrievalPointers.Extents,
1038 CurrentRetDescList->RetrievalPointers.ExtentCount * 2 * sizeof(LARGE_INTEGER));
1039 Count += CurrentRetDescList->RetrievalPointers.ExtentCount;
1040 RetDescList = CurrentRetDescList;
1041 CurrentRetDescList = CurrentRetDescList->Next;
1042 ExFreePool(RetDescList);
1043 }
1044
1045 if (PagingFile->RetrievalPointers->ExtentCount != ExtentCount ||
1046 PagingFile->RetrievalPointers->Extents[ExtentCount - 1].NextVcn.QuadPart != MaxVcn.QuadPart)
1047 {
1048 ExFreePool(PagingFile->RetrievalPointers);
1049 ExFreePool(PagingFile->AllocMap);
1050 ExFreePool(PagingFile);
1051 ObDereferenceObject(FileObject);
1052 ZwClose(FileHandle);
1053 return(STATUS_UNSUCCESSFUL);
1054 }
1055
1056 /*
1057 * Change the entries from lcn's to volume offset's.
1058 */
1059 PagingFile->RetrievalPointers->StartingVcn.QuadPart *= BytesPerAllocationUnit;
1060 for (i = 0; i < ExtentCount; i++)
1061 {
1062 PagingFile->RetrievalPointers->Extents[i].Lcn.QuadPart *= BytesPerAllocationUnit;
1063 PagingFile->RetrievalPointers->Extents[i].NextVcn.QuadPart *= BytesPerAllocationUnit;
1064 }
1065
1066 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
1067 for (i = 0; i < MAX_PAGING_FILES; i++)
1068 {
1069 if (PagingFileList[i] == NULL)
1070 {
1071 PagingFileList[i] = PagingFile;
1072 break;
1073 }
1074 }
1075 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
1076 MiPagingFileCount++;
1077 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
1078
1079 /* Check whether this pagefile can be a crash dump target. */
1080 if (MmCoreDumpType != MM_CORE_DUMP_TYPE_NONE &&
1081 PagingFile->CurrentSize.QuadPart >= MmCoreDumpSize &&
1082 MmCoreDumpPageFile == 0xFFFFFFFF)
1083 {
1084 MmInitializeCrashDump(FileHandle, i);
1085 }
1086 ZwClose(FileHandle);
1087
1088 MmSwapSpaceMessage = FALSE;
1089
1090 return(STATUS_SUCCESS);
1091 }
1092
1093 /* EOF */