finished applying @implemented and @unimplemented comments and remove the comments...
[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.32 2003/07/11 01:23:15 royce 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
37 #define NDEBUG
38 #include <internal/debug.h>
39
40 /* TYPES *********************************************************************/
41
42 typedef struct _PAGINGFILE
43 {
44 LIST_ENTRY PagingFileListEntry;
45 PFILE_OBJECT FileObject;
46 LARGE_INTEGER MaximumSize;
47 LARGE_INTEGER CurrentSize;
48 ULONG FreePages;
49 ULONG UsedPages;
50 PULONG AllocMap;
51 KSPIN_LOCK AllocMapLock;
52 ULONG AllocMapSize;
53 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
54 } PAGINGFILE, *PPAGINGFILE;
55
56 /* GLOBALS *******************************************************************/
57
58 #define MAX_PAGING_FILES (32)
59
60 /* List of paging files, both used and free */
61 static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
62
63 /* Lock for examining the list of paging files */
64 static KSPIN_LOCK PagingFileListLock;
65
66 /* Number of paging files */
67 static ULONG MiPagingFileCount;
68
69 /* Number of pages that are available for swapping */
70 static ULONG MiFreeSwapPages;
71
72 /* Number of pages that have been allocated for swapping */
73 static ULONG MiUsedSwapPages;
74
75 /*
76 * Number of pages that have been reserved for swapping but not yet allocated
77 */
78 static ULONG MiReservedSwapPages;
79
80 /*
81 * Ratio between reserved and available swap pages, e.g. setting this to five
82 * forces one swap page to be available for every five swap pages that are
83 * reserved. Setting this to zero turns off commit checking altogether.
84 */
85 #define MM_PAGEFILE_COMMIT_RATIO (1)
86
87 /*
88 * Number of pages that can be used for potentially swapable memory without
89 * pagefile space being reserved. The intention is that this allows smss
90 * to start up and create page files while ordinarily having a commit
91 * ratio of one.
92 */
93 #define MM_PAGEFILE_COMMIT_GRACE (256)
94
95 static PVOID MmCoreDumpPageFrame;
96 static PULONG MmCoreDumpBlockMap;
97 static ULONG MmCoreDumpSize;
98 static PULONG MmCoreDumpBlockMap = NULL;
99 static MM_DUMP_POINTERS MmCoreDumpDeviceFuncs;
100 ULONG MmCoreDumpType;
101
102 /*
103 * Translate between a swap entry and a file and offset pair.
104 */
105 #define FILE_FROM_ENTRY(i) ((i) >> 24)
106 #define OFFSET_FROM_ENTRY(i) (((i) & 0xffffff) - 1)
107 #define ENTRY_FROM_FILE_OFFSET(i, j) (((i) << 24) | ((j) + 1))
108
109 static BOOLEAN MmSwapSpaceMessage = FALSE;
110
111 /* FUNCTIONS *****************************************************************/
112
113 VOID
114 MmShowOutOfSpaceMessagePagingFile(VOID)
115 {
116 if (!MmSwapSpaceMessage)
117 {
118 DPRINT1("MM: Out of swap space.\n");
119 MmSwapSpaceMessage = TRUE;
120 }
121 }
122
123 NTSTATUS MmWriteToSwapPage(SWAPENTRY SwapEntry, PMDL Mdl)
124 {
125 ULONG i, offset, j;
126 LARGE_INTEGER file_offset;
127 IO_STATUS_BLOCK Iosb;
128 NTSTATUS Status;
129 KEVENT Event;
130 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
131
132 DPRINT("MmWriteToSwapPage\n");
133
134 if (SwapEntry == 0)
135 {
136 KeBugCheck(0);
137 return(STATUS_UNSUCCESSFUL);
138 }
139
140 i = FILE_FROM_ENTRY(SwapEntry);
141 offset = OFFSET_FROM_ENTRY(SwapEntry);
142
143 if (i >= MAX_PAGING_FILES)
144 {
145 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry);
146 KeBugCheck(0);
147 }
148 if (PagingFileList[i]->FileObject == NULL ||
149 PagingFileList[i]->FileObject->DeviceObject == NULL)
150 {
151 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
152 KeBugCheck(0);
153 }
154
155 file_offset.QuadPart = offset * PAGE_SIZE;
156 RetrievalPointers = PagingFileList[i]->RetrievalPointers;
157
158 for (j = 0; j < RetrievalPointers->NumberOfPairs; j++)
159 {
160 if ((ULONGLONG) file_offset.QuadPart < RetrievalPointers->Pair[j].Vcn)
161 {
162 if (j == 0)
163 {
164 file_offset.QuadPart += RetrievalPointers->Pair[0].Lcn - RetrievalPointers->StartVcn;
165 }
166 else
167 {
168 file_offset.QuadPart += RetrievalPointers->Pair[j].Lcn - RetrievalPointers->Pair[j-1].Vcn;
169 }
170 break;
171 }
172 }
173 if (j >= RetrievalPointers->NumberOfPairs)
174 {
175 CHECKPOINT1;
176 KeBugCheck(0);
177 }
178
179 KeInitializeEvent(&Event, NotificationEvent, FALSE);
180 Status = IoPageWrite(PagingFileList[i]->FileObject,
181 Mdl,
182 &file_offset,
183 &Event,
184 &Iosb);
185 if (Status == STATUS_PENDING)
186 {
187 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
188 return(Iosb.Status);
189 }
190 return(Status);
191 }
192
193 NTSTATUS MmReadFromSwapPage(SWAPENTRY SwapEntry, PMDL Mdl)
194 {
195 ULONG i, offset, j;
196 LARGE_INTEGER file_offset;
197 IO_STATUS_BLOCK Iosb;
198 NTSTATUS Status;
199 KEVENT Event;
200 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
201
202 DPRINT("MmReadFromSwapPage\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 RetrievalPointers = PagingFileList[i]->RetrievalPointers;
227
228 for (j = 0; j < RetrievalPointers->NumberOfPairs; j++)
229 {
230 if ((ULONGLONG) file_offset.QuadPart < RetrievalPointers->Pair[j].Vcn)
231 {
232 if (j == 0)
233 {
234 file_offset.QuadPart += RetrievalPointers->Pair[0].Lcn - RetrievalPointers->StartVcn;
235 }
236 else
237 {
238 file_offset.QuadPart += RetrievalPointers->Pair[j].Lcn - RetrievalPointers->Pair[j-1].Vcn;
239 }
240 break;
241 }
242 }
243 if (j >= RetrievalPointers->NumberOfPairs)
244 {
245 CHECKPOINT1;
246 KeBugCheck(0);
247 }
248 KeInitializeEvent(&Event, NotificationEvent, FALSE);
249 Status = IoPageRead(PagingFileList[i]->FileObject,
250 Mdl,
251 &file_offset,
252 &Event,
253 &Iosb);
254 if (Status == STATUS_PENDING)
255 {
256 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
257 return(Iosb.Status);
258 }
259 return(Status);
260 }
261
262 VOID
263 MmInitPagingFile(VOID)
264 {
265 ULONG i;
266
267 KeInitializeSpinLock(&PagingFileListLock);
268
269 MiFreeSwapPages = 0;
270 MiUsedSwapPages = 0;
271 MiReservedSwapPages = 0;
272
273 for (i = 0; i < MAX_PAGING_FILES; i++)
274 {
275 PagingFileList[i] = NULL;
276 }
277 MiPagingFileCount = 0;
278
279 /*
280 * Initialize the crash dump support.
281 */
282 MmCoreDumpPageFrame = MmAllocateSection(PAGE_SIZE);
283 if (MmCoreDumpType == MM_CORE_DUMP_TYPE_FULL)
284 {
285 MmCoreDumpSize = MmStats.NrTotalPages * 4096 + 1024 * 1024;
286 }
287 else
288 {
289 MmCoreDumpSize = 1024 * 1024;
290 }
291 }
292
293 BOOLEAN
294 MmReserveSwapPages(ULONG Nr)
295 {
296 KIRQL oldIrql;
297 ULONG MiAvailSwapPages;
298
299 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
300 MiAvailSwapPages =
301 (MiFreeSwapPages * MM_PAGEFILE_COMMIT_RATIO) + MM_PAGEFILE_COMMIT_GRACE;
302 MiReservedSwapPages = MiReservedSwapPages + Nr;
303 if (MM_PAGEFILE_COMMIT_RATIO != 0 && MiAvailSwapPages < MiReservedSwapPages)
304 {
305 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
306 return(FALSE);
307 }
308 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
309 return(TRUE);
310 }
311
312 VOID
313 MmDereserveSwapPages(ULONG Nr)
314 {
315 KIRQL oldIrql;
316
317 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
318 MiReservedSwapPages = MiReservedSwapPages - Nr;
319 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
320 }
321
322 static ULONG
323 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
324 {
325 KIRQL oldIrql;
326 ULONG i, j;
327
328 KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
329
330 for (i = 0; i < PagingFile->AllocMapSize; i++)
331 {
332 for (j = 0; j < 32; j++)
333 {
334 if (!(PagingFile->AllocMap[i] & (1 << j)))
335 {
336 break;
337 }
338 }
339 if (j == 32)
340 {
341 continue;
342 }
343 PagingFile->AllocMap[i] |= (1 << j);
344 PagingFile->UsedPages++;
345 PagingFile->FreePages--;
346 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
347 return((i * 32) + j);
348 }
349
350 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
351 return(0xFFFFFFFF);
352 }
353
354 VOID
355 MmFreeSwapPage(SWAPENTRY Entry)
356 {
357 ULONG i;
358 ULONG off;
359 KIRQL oldIrql;
360
361 i = FILE_FROM_ENTRY(Entry);
362 off = OFFSET_FROM_ENTRY(Entry);
363
364 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
365 if (PagingFileList[i] == NULL)
366 {
367 KeBugCheck(0);
368 }
369 KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock);
370
371 PagingFileList[i]->AllocMap[off / 32] &= (~(1 << (off % 32)));
372
373 PagingFileList[i]->FreePages++;
374 PagingFileList[i]->UsedPages--;
375
376 MiFreeSwapPages++;
377 MiUsedSwapPages--;
378
379 KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock);
380 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
381 }
382
383 BOOLEAN
384 MmIsAvailableSwapPage(VOID)
385 {
386 return(MiFreeSwapPages > 0);
387 }
388
389 SWAPENTRY
390 MmAllocSwapPage(VOID)
391 {
392 KIRQL oldIrql;
393 ULONG i;
394 ULONG off;
395 SWAPENTRY entry;
396
397 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
398
399 if (MiFreeSwapPages == 0)
400 {
401 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
402 return(0);
403 }
404
405 for (i = 0; i < MAX_PAGING_FILES; i++)
406 {
407 if (PagingFileList[i] != NULL &&
408 PagingFileList[i]->FreePages >= 1)
409 {
410 off = MiAllocPageFromPagingFile(PagingFileList[i]);
411 if (off == 0xFFFFFFFF)
412 {
413 KeBugCheck(0);
414 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
415 return(STATUS_UNSUCCESSFUL);
416 }
417 MiUsedSwapPages++;
418 MiFreeSwapPages--;
419 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
420
421 entry = ENTRY_FROM_FILE_OFFSET(i, off);
422 return(entry);
423 }
424 }
425
426 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
427 KeBugCheck(0);
428 return(0);
429 }
430
431 NTSTATUS STDCALL
432 MmDumpToPagingFile(ULONG BugCode,
433 ULONG BugCodeParameter1,
434 ULONG BugCodeParameter2,
435 ULONG BugCodeParameter3,
436 ULONG BugCodeParameter4,
437 PKTRAP_FRAME TrapFrame)
438 {
439 PMM_CORE_DUMP_HEADER Headers;
440 PVOID Context;
441 NTSTATUS Status;
442 UCHAR MdlBase[sizeof(MDL) + sizeof(PVOID)];
443 PMDL Mdl = (PMDL)MdlBase;
444 PETHREAD Thread = PsGetCurrentThread();
445 ULONG StackSize;
446 PULONG MdlMap;
447 ULONG NextOffset = 0;
448 ULONG i;
449
450 if (MmCoreDumpBlockMap == NULL)
451 {
452 return(STATUS_UNSUCCESSFUL);
453 }
454
455 DbgPrint("MM: Dumping core");
456
457 /* Prepare the dump headers. */
458 Headers = (PMM_CORE_DUMP_HEADER)MmCoreDumpPageFrame;
459 Headers->Magic = MM_CORE_DUMP_HEADER_MAGIC;
460 Headers->Version = MM_CORE_DUMP_HEADER_VERSION;
461 Headers->Type = MmCoreDumpType;
462 if (TrapFrame != NULL)
463 {
464 if (!(TrapFrame->Eflags & (1 << 17)))
465 {
466 memcpy(&Headers->TrapFrame, TrapFrame,
467 sizeof(KTRAP_FRAME) - (4 * sizeof(DWORD)));
468 }
469 else
470 {
471 memcpy(&Headers->TrapFrame, TrapFrame, sizeof(KTRAP_FRAME));
472 }
473 }
474 Headers->BugCheckCode = BugCode;
475 Headers->BugCheckParameters[0] = BugCodeParameter1;
476 Headers->BugCheckParameters[1] = BugCodeParameter2;
477 Headers->BugCheckParameters[2] = BugCodeParameter3;
478 Headers->BugCheckParameters[3] = BugCodeParameter4;
479 Headers->FaultingStackBase = (PVOID)Thread->Tcb.StackLimit;
480 Headers->FaultingStackSize = StackSize =
481 (ULONG)(Thread->Tcb.StackBase - Thread->Tcb.StackLimit);
482 Headers->PhysicalMemorySize = MmStats.NrTotalPages * PAGE_SIZE;
483
484 /* Initialize the dump device. */
485 Context = MmCoreDumpDeviceFuncs.Context;
486 Status = MmCoreDumpDeviceFuncs.DeviceInit(Context);
487 if (!NT_SUCCESS(Status))
488 {
489 DPRINT1("MM: Failed to initialize core dump device.\n");
490 return(Status);
491 }
492
493 /* Initialize the MDL. */
494 Mdl->Next = NULL;
495 Mdl->Size = sizeof(MDL) + sizeof(PVOID);
496 Mdl->MdlFlags = MDL_SOURCE_IS_NONPAGED_POOL;
497 Mdl->Process = NULL;
498 Mdl->MappedSystemVa = MmCoreDumpPageFrame;
499 Mdl->StartVa = NULL;
500 Mdl->ByteCount = PAGE_SIZE;
501 Mdl->ByteOffset = 0;
502 MdlMap = (PULONG)(Mdl + 1);
503
504 /* Dump the header. */
505 MdlMap[0] = MmGetPhysicalAddress(MmCoreDumpPageFrame).u.LowPart;
506 Status = MmCoreDumpDeviceFuncs.DeviceWrite(Context,
507 MmCoreDumpBlockMap[NextOffset],
508 Mdl);
509 if (!NT_SUCCESS(Status))
510 {
511 DPRINT1("MM: Failed to write core dump header\n.");
512 }
513 NextOffset++;
514 DbgPrint(".");
515
516 /* Write out the kernel mode stack of the faulting thread. */
517 for (i = 0; i < (StackSize / PAGE_SIZE); i++)
518 {
519 Mdl->MappedSystemVa = (PVOID)(Thread->Tcb.StackLimit + (i * PAGE_SIZE));
520 MdlMap[0] = MmGetPhysicalAddress(Mdl->MappedSystemVa).u.LowPart;
521 Status =
522 MmCoreDumpDeviceFuncs.DeviceWrite(Context,
523 MmCoreDumpBlockMap[NextOffset],
524 Mdl);
525 if (!NT_SUCCESS(Status))
526 {
527 DPRINT1("MM: Failed to write page to core dump.\n");
528 return(Status);
529 }
530 DbgPrint(".");
531 NextOffset++;
532 }
533
534 /* Write out the contents of physical memory. */
535 if (MmCoreDumpType == MM_CORE_DUMP_TYPE_FULL)
536 {
537 for (i = 0; i < MmStats.NrTotalPages; i++)
538 {
539 LARGE_INTEGER PhysicalAddress;
540 PhysicalAddress.QuadPart = i * PAGE_SIZE;
541 MdlMap[0] = i * PAGE_SIZE;
542 MmCreateVirtualMappingForKernel(MmCoreDumpPageFrame,
543 PAGE_READWRITE,
544 PhysicalAddress);
545 Status =
546 MmCoreDumpDeviceFuncs.DeviceWrite(Context,
547 MmCoreDumpBlockMap[NextOffset],
548 Mdl);
549 if (!NT_SUCCESS(Status))
550 {
551 DPRINT1("MM: Failed to write page to core dump.\n");
552 return(Status);
553 }
554 DbgPrint(".");
555 NextOffset++;
556 }
557 }
558
559 DbgPrint("\n");
560 return(STATUS_SUCCESS);
561 }
562
563 NTSTATUS STDCALL
564 NtCreatePagingFile(IN PUNICODE_STRING FileName,
565 IN PLARGE_INTEGER InitialSize,
566 IN PLARGE_INTEGER MaximumSize,
567 IN ULONG Reserved)
568 {
569 NTSTATUS Status;
570 OBJECT_ATTRIBUTES ObjectAttributes;
571 HANDLE FileHandle;
572 IO_STATUS_BLOCK IoStatus;
573 PFILE_OBJECT FileObject;
574 PPAGINGFILE PagingFile;
575 KIRQL oldIrql;
576 ULONG AllocMapSize;
577 ULONG Size;
578 FILE_FS_SIZE_INFORMATION FsSizeInformation;
579 PGET_RETRIEVAL_DESCRIPTOR RetrievalPointers;
580 ULONG i;
581 ULONG BytesPerAllocationUnit;
582 LARGE_INTEGER Vcn;
583 ULONG ExtentCount;
584
585 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
586 FileName, InitialSize->QuadPart);
587
588 if (MiPagingFileCount >= MAX_PAGING_FILES)
589 {
590 return(STATUS_TOO_MANY_PAGING_FILES);
591 }
592
593 InitializeObjectAttributes(&ObjectAttributes,
594 FileName,
595 0,
596 NULL,
597 NULL);
598
599 Status = IoCreateFile(&FileHandle,
600 FILE_ALL_ACCESS,
601 &ObjectAttributes,
602 &IoStatus,
603 NULL,
604 0,
605 0,
606 FILE_OPEN_IF,
607 FILE_SYNCHRONOUS_IO_NONALERT,
608 NULL,
609 0,
610 CreateFileTypeNone,
611 NULL,
612 SL_OPEN_PAGING_FILE);
613 if (!NT_SUCCESS(Status))
614 {
615 return(Status);
616 }
617
618 Status = NtQueryVolumeInformationFile(FileHandle,
619 &IoStatus,
620 &FsSizeInformation,
621 sizeof(FILE_FS_SIZE_INFORMATION),
622 FileFsSizeInformation);
623 if (!NT_SUCCESS(Status))
624 {
625 NtClose(FileHandle);
626 return Status;
627 }
628
629 BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit * FsSizeInformation.BytesPerSector;
630 if (BytesPerAllocationUnit < PAGE_SIZE)
631 {
632 NtClose(FileHandle);
633 return STATUS_UNSUCCESSFUL;
634 }
635
636 Status = NtSetInformationFile(FileHandle,
637 &IoStatus,
638 InitialSize,
639 sizeof(LARGE_INTEGER),
640 FileAllocationInformation);
641 if (!NT_SUCCESS(Status))
642 {
643 NtClose(FileHandle);
644 return(Status);
645 }
646
647 Status = ObReferenceObjectByHandle(FileHandle,
648 FILE_ALL_ACCESS,
649 IoFileObjectType,
650 UserMode,
651 (PVOID*)&FileObject,
652 NULL);
653 if (!NT_SUCCESS(Status))
654 {
655 NtClose(FileHandle);
656 return(Status);
657 }
658
659 RetrievalPointers = ExAllocatePool(NonPagedPool, sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR));
660
661 if (RetrievalPointers == NULL)
662 {
663 ObDereferenceObject(FileObject);
664 NtClose(FileHandle);
665 return(STATUS_NO_MEMORY);
666 }
667
668 Vcn.QuadPart = 0LL;
669 ExtentCount = 0;
670 while(1)
671 {
672 Status = NtFsControlFile(FileHandle,
673 0,
674 NULL,
675 NULL,
676 &IoStatus,
677 FSCTL_GET_RETRIEVAL_POINTERS,
678 &Vcn,
679 sizeof(LARGE_INTEGER),
680 RetrievalPointers,
681 sizeof(GET_RETRIEVAL_DESCRIPTOR) + sizeof(MAPPING_PAIR));
682 if (!NT_SUCCESS(Status))
683 {
684 ExFreePool(RetrievalPointers);
685 ObDereferenceObject(FileObject);
686 NtClose(FileHandle);
687 return(Status);
688 }
689 ExtentCount += RetrievalPointers->NumberOfPairs;
690 if (RetrievalPointers->Pair[0].Vcn < (ULONGLONG) InitialSize->QuadPart / BytesPerAllocationUnit)
691 {
692 Vcn.QuadPart = RetrievalPointers->Pair[0].Vcn;
693 }
694 else
695 {
696 break;
697 }
698 }
699 ExFreePool(RetrievalPointers);
700
701 PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
702 if (PagingFile == NULL)
703 {
704 ObDereferenceObject(FileObject);
705 NtClose(FileHandle);
706 return(STATUS_NO_MEMORY);
707 }
708
709 PagingFile->FileObject = FileObject;
710 PagingFile->MaximumSize.QuadPart = MaximumSize->QuadPart;
711 PagingFile->CurrentSize.QuadPart = InitialSize->QuadPart;
712 PagingFile->FreePages = InitialSize->QuadPart / PAGE_SIZE;
713 PagingFile->UsedPages = 0;
714 KeInitializeSpinLock(&PagingFile->AllocMapLock);
715
716 AllocMapSize = (PagingFile->FreePages / 32) + 1;
717 PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
718 AllocMapSize * sizeof(ULONG));
719 PagingFile->AllocMapSize = AllocMapSize;
720
721 if (PagingFile->AllocMap == NULL)
722 {
723 ExFreePool(PagingFile);
724 ObDereferenceObject(FileObject);
725 ZwClose(FileHandle);
726 return(STATUS_NO_MEMORY);
727 }
728
729 Size = sizeof(GET_RETRIEVAL_DESCRIPTOR) + ExtentCount * sizeof(MAPPING_PAIR);
730 PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size);
731 if (PagingFile->RetrievalPointers == NULL)
732 {
733 ExFreePool(PagingFile->AllocMap);
734 ExFreePool(PagingFile);
735 ObDereferenceObject(FileObject);
736 NtClose(FileHandle);
737 return(STATUS_NO_MEMORY);
738 }
739
740 Vcn.QuadPart = 0LL;
741 Status = NtFsControlFile(FileHandle,
742 0,
743 NULL,
744 NULL,
745 &IoStatus,
746 FSCTL_GET_RETRIEVAL_POINTERS,
747 &Vcn,
748 sizeof(LARGE_INTEGER),
749 PagingFile->RetrievalPointers,
750 Size);
751 if (!NT_SUCCESS(Status))
752 {
753 ExFreePool(PagingFile->RetrievalPointers);
754 ExFreePool(PagingFile->AllocMap);
755 ExFreePool(PagingFile);
756 ObDereferenceObject(FileObject);
757 NtClose(FileHandle);
758 return(STATUS_NO_MEMORY);
759 }
760
761 if (PagingFile->RetrievalPointers->NumberOfPairs != ExtentCount ||
762 PagingFile->RetrievalPointers->Pair[ExtentCount - 1].Vcn !=
763 (ULONGLONG) InitialSize->QuadPart / BytesPerAllocationUnit)
764 {
765 ExFreePool(PagingFile->RetrievalPointers);
766 ExFreePool(PagingFile->AllocMap);
767 ExFreePool(PagingFile);
768 ObDereferenceObject(FileObject);
769 NtClose(FileHandle);
770 return(STATUS_UNSUCCESSFUL);
771 }
772
773 /*
774 * Change the entries from lcn's to volume offset's.
775 */
776 PagingFile->RetrievalPointers->StartVcn *= BytesPerAllocationUnit;
777 for (i = 0; i < ExtentCount; i++)
778 {
779 PagingFile->RetrievalPointers->Pair[i].Lcn *= BytesPerAllocationUnit;
780 PagingFile->RetrievalPointers->Pair[i].Vcn *= BytesPerAllocationUnit;
781 }
782
783 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
784 for (i = 0; i < MAX_PAGING_FILES; i++)
785 {
786 if (PagingFileList[i] == NULL)
787 {
788 PagingFileList[i] = PagingFile;
789 break;
790 }
791 }
792 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
793 MiPagingFileCount++;
794 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
795
796 /* Check whether this pagefile can be a crash dump target. */
797 if (PagingFile->CurrentSize.QuadPart >= MmCoreDumpSize &&
798 MmCoreDumpBlockMap != NULL)
799 {
800 MmCoreDumpBlockMap =
801 ExAllocatePool(NonPagedPool,
802 (MmCoreDumpSize / PAGE_SIZE) * sizeof(ULONG));
803 if (MmCoreDumpBlockMap == NULL)
804 {
805 DPRINT1("Failed to allocate block map.\n");
806 NtClose(FileHandle);
807 return(STATUS_SUCCESS);
808 }
809 Status = ZwFsControlFile(FileHandle,
810 NULL,
811 NULL,
812 NULL,
813 &IoStatus,
814 FSCTL_GET_DUMP_BLOCK_MAP,
815 &MmCoreDumpSize,
816 sizeof(ULONG),
817 MmCoreDumpBlockMap,
818 (MmCoreDumpSize / PAGE_SIZE) * sizeof(ULONG));
819 if (!NT_SUCCESS(Status))
820 {
821 DPRINT1("Failed to get dump block map (Status %X)\n", Status);
822 NtClose(FileHandle);
823 ExFreePool(MmCoreDumpBlockMap);
824 MmCoreDumpBlockMap = NULL;
825 return(STATUS_SUCCESS);
826 }
827 Status = ZwDeviceIoControlFile(FileHandle,
828 NULL,
829 NULL,
830 NULL,
831 &IoStatus,
832 IOCTL_GET_DUMP_POINTERS,
833 NULL,
834 0,
835 &MmCoreDumpDeviceFuncs,
836 sizeof(MmCoreDumpDeviceFuncs));
837 if (!NT_SUCCESS(Status))
838 {
839 DPRINT1("Failed to get dump block map (Status %X)\n", Status);
840 NtClose(FileHandle);
841 ExFreePool(MmCoreDumpBlockMap);
842 MmCoreDumpBlockMap = NULL;
843 return(STATUS_SUCCESS);
844 }
845 }
846 NtClose(FileHandle);
847
848 MmSwapSpaceMessage = FALSE;
849
850 return(STATUS_SUCCESS);
851 }
852
853 /* EOF */