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