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