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