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