[NTOSKRNL]
[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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/mm/pagefile.c
22 * PURPOSE: Paging file functions
23 * PROGRAMMER: David Welch (welch@mcmail.com)
24 * UPDATE HISTORY:
25 * Created 22/05/98
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ntoskrnl.h>
31 #define NDEBUG
32 #include <debug.h>
33
34 #if defined (ALLOC_PRAGMA)
35 #pragma alloc_text(INIT, MmInitPagingFile)
36 #endif
37
38 PVOID
39 NTAPI
40 MiFindExportedRoutineByName(IN PVOID DllBase,
41 IN PANSI_STRING ExportName);
42
43 /* TYPES *********************************************************************/
44
45 typedef struct _PAGINGFILE
46 {
47 LIST_ENTRY PagingFileListEntry;
48 PFILE_OBJECT FileObject;
49 LARGE_INTEGER MaximumSize;
50 LARGE_INTEGER CurrentSize;
51 PFN_NUMBER FreePages;
52 PFN_NUMBER UsedPages;
53 PULONG AllocMap;
54 KSPIN_LOCK AllocMapLock;
55 ULONG AllocMapSize;
56 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers;
57 }
58 PAGINGFILE, *PPAGINGFILE;
59
60 typedef struct _RETRIEVEL_DESCRIPTOR_LIST
61 {
62 struct _RETRIEVEL_DESCRIPTOR_LIST* Next;
63 RETRIEVAL_POINTERS_BUFFER RetrievalPointers;
64 }
65 RETRIEVEL_DESCRIPTOR_LIST, *PRETRIEVEL_DESCRIPTOR_LIST;
66
67 /* GLOBALS *******************************************************************/
68
69 #define PAIRS_PER_RUN (1024)
70
71 #define MAX_PAGING_FILES (16)
72
73 /* List of paging files, both used and free */
74 static PPAGINGFILE PagingFileList[MAX_PAGING_FILES];
75
76 /* Lock for examining the list of paging files */
77 static KSPIN_LOCK PagingFileListLock;
78
79 /* Number of paging files */
80 ULONG MmNumberOfPagingFiles;
81
82 /* Number of pages that are available for swapping */
83 PFN_COUNT MiFreeSwapPages;
84
85 /* Number of pages that have been allocated for swapping */
86 PFN_COUNT MiUsedSwapPages;
87
88 BOOLEAN MmZeroPageFile;
89
90 /*
91 * Number of pages that have been reserved for swapping but not yet allocated
92 */
93 static PFN_COUNT MiReservedSwapPages;
94
95 /*
96 * Ratio between reserved and available swap pages, e.g. setting this to five
97 * forces one swap page to be available for every five swap pages that are
98 * reserved. Setting this to zero turns off commit checking altogether.
99 */
100 #define MM_PAGEFILE_COMMIT_RATIO (1)
101
102 /*
103 * Number of pages that can be used for potentially swapable memory without
104 * pagefile space being reserved. The intention is that this allows smss
105 * to start up and create page files while ordinarily having a commit
106 * ratio of one.
107 */
108 #define MM_PAGEFILE_COMMIT_GRACE (256)
109
110 /*
111 * Translate between a swap entry and a file and offset pair.
112 */
113 #define FILE_FROM_ENTRY(i) ((i) & 0x0f)
114 #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
115 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)
116
117 /* Make sure there can be only 16 paging files */
118 C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES);
119
120 static BOOLEAN MmSwapSpaceMessage = FALSE;
121
122 /* FUNCTIONS *****************************************************************/
123
124 VOID
125 NTAPI
126 MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages)
127 {
128 memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE));
129
130 /* FIXME: this flag should be set by the caller perhaps? */
131 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
132 }
133
134
135 BOOLEAN
136 NTAPI
137 MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject)
138 {
139 ULONG i;
140
141 /* Loop through all the paging files */
142 for (i = 0; i < MmNumberOfPagingFiles; i++)
143 {
144 /* Check if this is one of them */
145 if (PagingFileList[i]->FileObject == FileObject) return TRUE;
146 }
147
148 /* Nothing found */
149 return FALSE;
150 }
151
152 VOID
153 NTAPI
154 MmShowOutOfSpaceMessagePagingFile(VOID)
155 {
156 if (!MmSwapSpaceMessage)
157 {
158 DPRINT1("MM: Out of swap space.\n");
159 MmSwapSpaceMessage = TRUE;
160 }
161 }
162
163 static LARGE_INTEGER
164 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers, LARGE_INTEGER Offset)
165 {
166 /* Simple binary search */
167 ULONG first, last, mid;
168 first = 0;
169 last = RetrievalPointers->ExtentCount - 1;
170 while (first <= last)
171 {
172 mid = (last - first) / 2 + first;
173 if (Offset.QuadPart < RetrievalPointers->Extents[mid].NextVcn.QuadPart)
174 {
175 if (mid == 0)
176 {
177 Offset.QuadPart += RetrievalPointers->Extents[0].Lcn.QuadPart - RetrievalPointers->StartingVcn.QuadPart;
178 return Offset;
179 }
180 else
181 {
182 if (Offset.QuadPart >= RetrievalPointers->Extents[mid-1].NextVcn.QuadPart)
183 {
184 Offset.QuadPart += RetrievalPointers->Extents[mid].Lcn.QuadPart - RetrievalPointers->Extents[mid-1].NextVcn.QuadPart;
185 return Offset;
186 }
187 last = mid - 1;
188 }
189 }
190 else
191 {
192 if (mid == RetrievalPointers->ExtentCount - 1)
193 {
194 break;
195 }
196 if (Offset.QuadPart < RetrievalPointers->Extents[mid+1].NextVcn.QuadPart)
197 {
198 Offset.QuadPart += RetrievalPointers->Extents[mid+1].Lcn.QuadPart - RetrievalPointers->Extents[mid].NextVcn.QuadPart;
199 return Offset;
200 }
201 first = mid + 1;
202 }
203 }
204 KeBugCheck(MEMORY_MANAGEMENT);
205 #if defined(__GNUC__)
206
207 return (LARGE_INTEGER)0LL;
208 #else
209
210 {
211 const LARGE_INTEGER dummy =
212 {
213 0
214 };
215 return dummy;
216 }
217 #endif
218 }
219
220 NTSTATUS
221 NTAPI
222 MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
223 {
224 ULONG i;
225 ULONG_PTR offset;
226 LARGE_INTEGER file_offset;
227 IO_STATUS_BLOCK Iosb;
228 NTSTATUS Status;
229 KEVENT Event;
230 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
231 PMDL Mdl = (PMDL)MdlBase;
232
233 DPRINT("MmWriteToSwapPage\n");
234
235 if (SwapEntry == 0)
236 {
237 KeBugCheck(MEMORY_MANAGEMENT);
238 return(STATUS_UNSUCCESSFUL);
239 }
240
241 i = FILE_FROM_ENTRY(SwapEntry);
242 offset = OFFSET_FROM_ENTRY(SwapEntry);
243
244 if (PagingFileList[i]->FileObject == NULL ||
245 PagingFileList[i]->FileObject->DeviceObject == NULL)
246 {
247 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
248 KeBugCheck(MEMORY_MANAGEMENT);
249 }
250
251 MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
252 MmBuildMdlFromPages(Mdl, &Page);
253 Mdl->MdlFlags |= MDL_PAGES_LOCKED;
254
255 file_offset.QuadPart = offset * PAGE_SIZE;
256 file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset);
257
258 KeInitializeEvent(&Event, NotificationEvent, FALSE);
259 Status = IoSynchronousPageWrite(PagingFileList[i]->FileObject,
260 Mdl,
261 &file_offset,
262 &Event,
263 &Iosb);
264 if (Status == STATUS_PENDING)
265 {
266 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
267 Status = Iosb.Status;
268 }
269
270 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
271 {
272 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
273 }
274 return(Status);
275 }
276
277
278 NTSTATUS
279 NTAPI
280 MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
281 {
282 return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry));
283 }
284
285 NTSTATUS
286 NTAPI
287 MiReadPageFile(
288 _In_ PFN_NUMBER Page,
289 _In_ ULONG PageFileIndex,
290 _In_ ULONG_PTR PageFileOffset)
291 {
292 LARGE_INTEGER file_offset;
293 IO_STATUS_BLOCK Iosb;
294 NTSTATUS Status;
295 KEVENT Event;
296 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
297 PMDL Mdl = (PMDL)MdlBase;
298 PPAGINGFILE PagingFile;
299
300 DPRINT("MiReadSwapFile\n");
301
302 if (PageFileOffset == 0)
303 {
304 KeBugCheck(MEMORY_MANAGEMENT);
305 return(STATUS_UNSUCCESSFUL);
306 }
307
308 ASSERT(PageFileIndex < MAX_PAGING_FILES);
309
310 PagingFile = PagingFileList[PageFileIndex];
311
312 if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL)
313 {
314 DPRINT1("Bad paging file %u\n", PageFileIndex);
315 KeBugCheck(MEMORY_MANAGEMENT);
316 }
317
318 MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
319 MmBuildMdlFromPages(Mdl, &Page);
320 Mdl->MdlFlags |= MDL_PAGES_LOCKED;
321
322 file_offset.QuadPart = PageFileOffset * PAGE_SIZE;
323 file_offset = MmGetOffsetPageFile(PagingFile->RetrievalPointers, file_offset);
324
325 KeInitializeEvent(&Event, NotificationEvent, FALSE);
326 Status = IoPageRead(PagingFile->FileObject,
327 Mdl,
328 &file_offset,
329 &Event,
330 &Iosb);
331 if (Status == STATUS_PENDING)
332 {
333 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
334 Status = Iosb.Status;
335 }
336 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
337 {
338 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
339 }
340 return(Status);
341 }
342
343 VOID
344 INIT_FUNCTION
345 NTAPI
346 MmInitPagingFile(VOID)
347 {
348 ULONG i;
349
350 KeInitializeSpinLock(&PagingFileListLock);
351
352 MiFreeSwapPages = 0;
353 MiUsedSwapPages = 0;
354 MiReservedSwapPages = 0;
355
356 for (i = 0; i < MAX_PAGING_FILES; i++)
357 {
358 PagingFileList[i] = NULL;
359 }
360 MmNumberOfPagingFiles = 0;
361 }
362
363 static ULONG
364 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile)
365 {
366 KIRQL oldIrql;
367 ULONG i, j;
368
369 KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
370
371 for (i = 0; i < PagingFile->AllocMapSize; i++)
372 {
373 for (j = 0; j < 32; j++)
374 {
375 if (!(PagingFile->AllocMap[i] & (1 << j)))
376 {
377 PagingFile->AllocMap[i] |= (1 << j);
378 PagingFile->UsedPages++;
379 PagingFile->FreePages--;
380 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
381 return((i * 32) + j);
382 }
383 }
384 }
385
386 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
387 return(0xFFFFFFFF);
388 }
389
390 VOID
391 NTAPI
392 MmFreeSwapPage(SWAPENTRY Entry)
393 {
394 ULONG i;
395 ULONG_PTR off;
396 KIRQL oldIrql;
397
398 i = FILE_FROM_ENTRY(Entry);
399 off = OFFSET_FROM_ENTRY(Entry);
400
401 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
402 if (PagingFileList[i] == NULL)
403 {
404 KeBugCheck(MEMORY_MANAGEMENT);
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 SWAPENTRY
421 NTAPI
422 MmAllocSwapPage(VOID)
423 {
424 KIRQL oldIrql;
425 ULONG i;
426 ULONG off;
427 SWAPENTRY entry;
428
429 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
430
431 if (MiFreeSwapPages == 0)
432 {
433 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
434 return(0);
435 }
436
437 for (i = 0; i < MAX_PAGING_FILES; i++)
438 {
439 if (PagingFileList[i] != NULL &&
440 PagingFileList[i]->FreePages >= 1)
441 {
442 off = MiAllocPageFromPagingFile(PagingFileList[i]);
443 if (off == 0xFFFFFFFF)
444 {
445 KeBugCheck(MEMORY_MANAGEMENT);
446 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
447 return(STATUS_UNSUCCESSFUL);
448 }
449 MiUsedSwapPages++;
450 MiFreeSwapPages--;
451 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
452
453 entry = ENTRY_FROM_FILE_OFFSET(i, off);
454 return(entry);
455 }
456 }
457
458 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
459 KeBugCheck(MEMORY_MANAGEMENT);
460 return(0);
461 }
462
463 static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL
464 MmAllocRetrievelDescriptorList(ULONG Pairs)
465 {
466 ULONG Size;
467 PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
468
469 Size = sizeof(RETRIEVEL_DESCRIPTOR_LIST) + Pairs * 2 * sizeof(LARGE_INTEGER);
470 RetDescList = ExAllocatePool(NonPagedPool, Size);
471 if (RetDescList)
472 {
473 RtlZeroMemory(RetDescList, Size);
474 }
475
476 return RetDescList;
477 }
478
479 NTSTATUS NTAPI
480 NtCreatePagingFile(IN PUNICODE_STRING FileName,
481 IN PLARGE_INTEGER InitialSize,
482 IN PLARGE_INTEGER MaximumSize,
483 IN ULONG Reserved)
484 {
485 NTSTATUS Status;
486 OBJECT_ATTRIBUTES ObjectAttributes;
487 HANDLE FileHandle;
488 IO_STATUS_BLOCK IoStatus;
489 PFILE_OBJECT FileObject;
490 PPAGINGFILE PagingFile;
491 KIRQL oldIrql;
492 ULONG AllocMapSize;
493 FILE_FS_SIZE_INFORMATION FsSizeInformation;
494 PRETRIEVEL_DESCRIPTOR_LIST RetDescList;
495 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList;
496 ULONG i;
497 ULONG BytesPerAllocationUnit;
498 LARGE_INTEGER Vcn;
499 ULONG ExtentCount;
500 LARGE_INTEGER MaxVcn;
501 ULONG Count;
502 ULONG Size;
503 KPROCESSOR_MODE PreviousMode;
504 UNICODE_STRING CapturedFileName;
505 LARGE_INTEGER SafeInitialSize, SafeMaximumSize;
506
507 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
508 FileName, InitialSize->QuadPart);
509
510 if (MmNumberOfPagingFiles >= MAX_PAGING_FILES)
511 {
512 return(STATUS_TOO_MANY_PAGING_FILES);
513 }
514
515 PreviousMode = ExGetPreviousMode();
516
517 if (PreviousMode != KernelMode)
518 {
519 _SEH2_TRY
520 {
521 SafeInitialSize = ProbeForReadLargeInteger(InitialSize);
522 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
523 }
524 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
525 {
526 /* Return the exception code */
527 _SEH2_YIELD(return _SEH2_GetExceptionCode());
528 }
529 _SEH2_END;
530 }
531 else
532 {
533 SafeInitialSize = *InitialSize;
534 SafeMaximumSize = *MaximumSize;
535 }
536
537 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
538 smaller than the maximum */
539 if (0 != SafeInitialSize.u.HighPart)
540 {
541 return STATUS_INVALID_PARAMETER_2;
542 }
543 if (0 != SafeMaximumSize.u.HighPart)
544 {
545 return STATUS_INVALID_PARAMETER_3;
546 }
547 if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart)
548 {
549 return STATUS_INVALID_PARAMETER_MIX;
550 }
551
552 Status = ProbeAndCaptureUnicodeString(&CapturedFileName,
553 PreviousMode,
554 FileName);
555 if (!NT_SUCCESS(Status))
556 {
557 return(Status);
558 }
559
560 InitializeObjectAttributes(&ObjectAttributes,
561 &CapturedFileName,
562 0,
563 NULL,
564 NULL);
565
566 Status = IoCreateFile(&FileHandle,
567 FILE_ALL_ACCESS,
568 &ObjectAttributes,
569 &IoStatus,
570 NULL,
571 0,
572 0,
573 FILE_OPEN_IF,
574 FILE_SYNCHRONOUS_IO_NONALERT,
575 NULL,
576 0,
577 CreateFileTypeNone,
578 NULL,
579 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
580
581 ReleaseCapturedUnicodeString(&CapturedFileName,
582 PreviousMode);
583 if (!NT_SUCCESS(Status))
584 {
585 return(Status);
586 }
587
588 Status = ZwQueryVolumeInformationFile(FileHandle,
589 &IoStatus,
590 &FsSizeInformation,
591 sizeof(FILE_FS_SIZE_INFORMATION),
592 FileFsSizeInformation);
593 if (!NT_SUCCESS(Status))
594 {
595 ZwClose(FileHandle);
596 return Status;
597 }
598
599 BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit *
600 FsSizeInformation.BytesPerSector;
601 /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
602 * a problem if the paging file is fragmented. Suppose the first cluster
603 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
604 * paging file but of another file. We can't write a complete page (4096
605 * bytes) to the physical location of cluster 3042 then. */
606 if (BytesPerAllocationUnit % PAGE_SIZE)
607 {
608 DPRINT1("BytesPerAllocationUnit %lu is not a multiple of PAGE_SIZE %d\n",
609 BytesPerAllocationUnit, PAGE_SIZE);
610 ZwClose(FileHandle);
611 return STATUS_UNSUCCESSFUL;
612 }
613
614 Status = ZwSetInformationFile(FileHandle,
615 &IoStatus,
616 &SafeInitialSize,
617 sizeof(LARGE_INTEGER),
618 FileAllocationInformation);
619 if (!NT_SUCCESS(Status))
620 {
621 ZwClose(FileHandle);
622 return(Status);
623 }
624
625 Status = ObReferenceObjectByHandle(FileHandle,
626 FILE_ALL_ACCESS,
627 IoFileObjectType,
628 PreviousMode,
629 (PVOID*)&FileObject,
630 NULL);
631 if (!NT_SUCCESS(Status))
632 {
633 ZwClose(FileHandle);
634 return(Status);
635 }
636
637 CurrentRetDescList = RetDescList = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
638
639 if (CurrentRetDescList == NULL)
640 {
641 ObDereferenceObject(FileObject);
642 ZwClose(FileHandle);
643 return(STATUS_NO_MEMORY);
644 }
645
646 #if defined(__GNUC__)
647 Vcn.QuadPart = 0LL;
648 #else
649
650 Vcn.QuadPart = 0;
651 #endif
652
653 ExtentCount = 0;
654 MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit;
655 while(1)
656 {
657 Status = ZwFsControlFile(FileHandle,
658 0,
659 NULL,
660 NULL,
661 &IoStatus,
662 FSCTL_GET_RETRIEVAL_POINTERS,
663 &Vcn,
664 sizeof(LARGE_INTEGER),
665 &CurrentRetDescList->RetrievalPointers,
666 sizeof(RETRIEVAL_POINTERS_BUFFER) + PAIRS_PER_RUN * 2 * sizeof(LARGE_INTEGER));
667 if (!NT_SUCCESS(Status))
668 {
669 while (RetDescList)
670 {
671 CurrentRetDescList = RetDescList;
672 RetDescList = RetDescList->Next;
673 ExFreePool(CurrentRetDescList);
674 }
675 ObDereferenceObject(FileObject);
676 ZwClose(FileHandle);
677 return(Status);
678 }
679 ExtentCount += CurrentRetDescList->RetrievalPointers.ExtentCount;
680 if (CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn.QuadPart < MaxVcn.QuadPart)
681 {
682 CurrentRetDescList->Next = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN);
683 if (CurrentRetDescList->Next == NULL)
684 {
685 while (RetDescList)
686 {
687 CurrentRetDescList = RetDescList;
688 RetDescList = RetDescList->Next;
689 ExFreePool(CurrentRetDescList);
690 }
691 ObDereferenceObject(FileObject);
692 ZwClose(FileHandle);
693 return(STATUS_NO_MEMORY);
694 }
695 Vcn = CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn;
696 CurrentRetDescList = CurrentRetDescList->Next;
697 }
698 else
699 {
700 break;
701 }
702 }
703
704 PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
705 if (PagingFile == NULL)
706 {
707 while (RetDescList)
708 {
709 CurrentRetDescList = RetDescList;
710 RetDescList = RetDescList->Next;
711 ExFreePool(CurrentRetDescList);
712 }
713 ObDereferenceObject(FileObject);
714 ZwClose(FileHandle);
715 return(STATUS_NO_MEMORY);
716 }
717
718 RtlZeroMemory(PagingFile, sizeof(*PagingFile));
719
720 PagingFile->FileObject = FileObject;
721 PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart;
722 PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart;
723 PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE);
724 PagingFile->UsedPages = 0;
725 KeInitializeSpinLock(&PagingFile->AllocMapLock);
726
727 AllocMapSize = (PagingFile->FreePages / 32) + 1;
728 PagingFile->AllocMap = ExAllocatePool(NonPagedPool,
729 AllocMapSize * sizeof(ULONG));
730 PagingFile->AllocMapSize = AllocMapSize;
731
732 if (PagingFile->AllocMap == NULL)
733 {
734 while (RetDescList)
735 {
736 CurrentRetDescList = RetDescList;
737 RetDescList = RetDescList->Next;
738 ExFreePool(CurrentRetDescList);
739 }
740 ExFreePool(PagingFile);
741 ObDereferenceObject(FileObject);
742 ZwClose(FileHandle);
743 return(STATUS_NO_MEMORY);
744 }
745 DPRINT("ExtentCount: %lu\n", ExtentCount);
746 Size = sizeof(RETRIEVAL_POINTERS_BUFFER) + ExtentCount * 2 * sizeof(LARGE_INTEGER);
747 PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size);
748 if (PagingFile->RetrievalPointers == NULL)
749 {
750 while (RetDescList)
751 {
752 CurrentRetDescList = RetDescList;
753 RetDescList = RetDescList->Next;
754 ExFreePool(CurrentRetDescList);
755 }
756 ExFreePool(PagingFile->AllocMap);
757 ExFreePool(PagingFile);
758 ObDereferenceObject(FileObject);
759 ZwClose(FileHandle);
760 return(STATUS_NO_MEMORY);
761 }
762
763 RtlZeroMemory(PagingFile->AllocMap, AllocMapSize * sizeof(ULONG));
764 RtlZeroMemory(PagingFile->RetrievalPointers, Size);
765
766 Count = 0;
767 PagingFile->RetrievalPointers->ExtentCount = ExtentCount;
768 PagingFile->RetrievalPointers->StartingVcn = RetDescList->RetrievalPointers.StartingVcn;
769 CurrentRetDescList = RetDescList;
770 while (CurrentRetDescList)
771 {
772 memcpy(&PagingFile->RetrievalPointers->Extents[Count],
773 CurrentRetDescList->RetrievalPointers.Extents,
774 CurrentRetDescList->RetrievalPointers.ExtentCount * 2 * sizeof(LARGE_INTEGER));
775 Count += CurrentRetDescList->RetrievalPointers.ExtentCount;
776 RetDescList = CurrentRetDescList;
777 CurrentRetDescList = CurrentRetDescList->Next;
778 ExFreePool(RetDescList);
779 }
780
781 if (PagingFile->RetrievalPointers->ExtentCount != ExtentCount ||
782 PagingFile->RetrievalPointers->Extents[ExtentCount - 1].NextVcn.QuadPart != MaxVcn.QuadPart)
783 {
784 ExFreePool(PagingFile->RetrievalPointers);
785 ExFreePool(PagingFile->AllocMap);
786 ExFreePool(PagingFile);
787 ObDereferenceObject(FileObject);
788 ZwClose(FileHandle);
789 return(STATUS_UNSUCCESSFUL);
790 }
791
792 /*
793 * Change the entries from lcn's to volume offset's.
794 */
795 PagingFile->RetrievalPointers->StartingVcn.QuadPart *= BytesPerAllocationUnit;
796 for (i = 0; i < ExtentCount; i++)
797 {
798 PagingFile->RetrievalPointers->Extents[i].Lcn.QuadPart *= BytesPerAllocationUnit;
799 PagingFile->RetrievalPointers->Extents[i].NextVcn.QuadPart *= BytesPerAllocationUnit;
800 }
801
802 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
803 for (i = 0; i < MAX_PAGING_FILES; i++)
804 {
805 if (PagingFileList[i] == NULL)
806 {
807 PagingFileList[i] = PagingFile;
808 break;
809 }
810 }
811 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
812 MmNumberOfPagingFiles++;
813 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
814
815 ZwClose(FileHandle);
816
817 MmSwapSpaceMessage = FALSE;
818
819 return(STATUS_SUCCESS);
820 }
821
822 /* EOF */