347ffec4a52acf306a72d9083df2e54e8b538493
[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 * Pierre Schweitzer
25 * UPDATE HISTORY:
26 * Created 22/05/98
27 */
28
29 /* INCLUDES *****************************************************************/
30
31 #include <ntoskrnl.h>
32 #define NDEBUG
33 #include <debug.h>
34
35 #if defined (ALLOC_PRAGMA)
36 #pragma alloc_text(INIT, MmInitPagingFile)
37 #endif
38
39
40 /* TYPES *********************************************************************/
41
42 typedef struct _MMPAGING_FILE
43 {
44 PFILE_OBJECT FileObject;
45 HANDLE FileHandle;
46 LARGE_INTEGER MaximumSize;
47 LARGE_INTEGER CurrentSize;
48 PFN_NUMBER FreePages;
49 PFN_NUMBER UsedPages;
50 PRTL_BITMAP AllocMap;
51 KSPIN_LOCK AllocMapLock;
52 }
53 MMPAGING_FILE, *PMMPAGING_FILE;
54
55 /* GLOBALS *******************************************************************/
56
57 #define PAIRS_PER_RUN (1024)
58
59 #define MAX_PAGING_FILES (16)
60
61 /* List of paging files, both used and free */
62 static PMMPAGING_FILE MmPagingFile[MAX_PAGING_FILES];
63
64 /* Lock for examining the list of paging files */
65 static KSPIN_LOCK PagingFileListLock;
66
67 /* Number of paging files */
68 ULONG MmNumberOfPagingFiles;
69
70 /* Number of pages that are available for swapping */
71 PFN_COUNT MiFreeSwapPages;
72
73 /* Number of pages that have been allocated for swapping */
74 PFN_COUNT MiUsedSwapPages;
75
76 BOOLEAN MmZeroPageFile;
77
78 /*
79 * Number of pages that have been reserved for swapping but not yet allocated
80 */
81 static PFN_COUNT MiReservedSwapPages;
82
83 /*
84 * Ratio between reserved and available swap pages, e.g. setting this to five
85 * forces one swap page to be available for every five swap pages that are
86 * reserved. Setting this to zero turns off commit checking altogether.
87 */
88 #define MM_PAGEFILE_COMMIT_RATIO (1)
89
90 /*
91 * Number of pages that can be used for potentially swapable memory without
92 * pagefile space being reserved. The intention is that this allows smss
93 * to start up and create page files while ordinarily having a commit
94 * ratio of one.
95 */
96 #define MM_PAGEFILE_COMMIT_GRACE (256)
97
98 /*
99 * Translate between a swap entry and a file and offset pair.
100 */
101 #define FILE_FROM_ENTRY(i) ((i) & 0x0f)
102 #define OFFSET_FROM_ENTRY(i) ((i) >> 11)
103 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400)
104
105 /* Make sure there can be only 16 paging files */
106 C_ASSERT(FILE_FROM_ENTRY(0xffffffff) < MAX_PAGING_FILES);
107
108 static BOOLEAN MmSwapSpaceMessage = FALSE;
109
110 /* FUNCTIONS *****************************************************************/
111
112 VOID
113 NTAPI
114 MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages)
115 {
116 memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE));
117
118 /* FIXME: this flag should be set by the caller perhaps? */
119 Mdl->MdlFlags |= MDL_IO_PAGE_READ;
120 }
121
122
123 BOOLEAN
124 NTAPI
125 MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject)
126 {
127 ULONG i;
128
129 /* Loop through all the paging files */
130 for (i = 0; i < MmNumberOfPagingFiles; i++)
131 {
132 /* Check if this is one of them */
133 if (MmPagingFile[i]->FileObject == FileObject) return TRUE;
134 }
135
136 /* Nothing found */
137 return FALSE;
138 }
139
140 VOID
141 NTAPI
142 MmShowOutOfSpaceMessagePagingFile(VOID)
143 {
144 if (!MmSwapSpaceMessage)
145 {
146 DPRINT1("MM: Out of swap space.\n");
147 MmSwapSpaceMessage = TRUE;
148 }
149 }
150
151 NTSTATUS
152 NTAPI
153 MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
154 {
155 ULONG i;
156 ULONG_PTR offset;
157 LARGE_INTEGER file_offset;
158 IO_STATUS_BLOCK Iosb;
159 NTSTATUS Status;
160 KEVENT Event;
161 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
162 PMDL Mdl = (PMDL)MdlBase;
163
164 DPRINT("MmWriteToSwapPage\n");
165
166 if (SwapEntry == 0)
167 {
168 KeBugCheck(MEMORY_MANAGEMENT);
169 return(STATUS_UNSUCCESSFUL);
170 }
171
172 i = FILE_FROM_ENTRY(SwapEntry);
173 offset = OFFSET_FROM_ENTRY(SwapEntry) - 1;
174
175 if (MmPagingFile[i]->FileObject == NULL ||
176 MmPagingFile[i]->FileObject->DeviceObject == NULL)
177 {
178 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry);
179 KeBugCheck(MEMORY_MANAGEMENT);
180 }
181
182 MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
183 MmBuildMdlFromPages(Mdl, &Page);
184 Mdl->MdlFlags |= MDL_PAGES_LOCKED;
185
186 file_offset.QuadPart = offset * PAGE_SIZE;
187
188 KeInitializeEvent(&Event, NotificationEvent, FALSE);
189 Status = IoSynchronousPageWrite(MmPagingFile[i]->FileObject,
190 Mdl,
191 &file_offset,
192 &Event,
193 &Iosb);
194 if (Status == STATUS_PENDING)
195 {
196 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
197 Status = Iosb.Status;
198 }
199
200 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
201 {
202 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
203 }
204 return(Status);
205 }
206
207
208 NTSTATUS
209 NTAPI
210 MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page)
211 {
212 return MiReadPageFile(Page, FILE_FROM_ENTRY(SwapEntry), OFFSET_FROM_ENTRY(SwapEntry) - 1);
213 }
214
215 NTSTATUS
216 NTAPI
217 MiReadPageFile(
218 _In_ PFN_NUMBER Page,
219 _In_ ULONG PageFileIndex,
220 _In_ ULONG_PTR PageFileOffset)
221 {
222 LARGE_INTEGER file_offset;
223 IO_STATUS_BLOCK Iosb;
224 NTSTATUS Status;
225 KEVENT Event;
226 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)];
227 PMDL Mdl = (PMDL)MdlBase;
228 PMMPAGING_FILE PagingFile;
229
230 DPRINT("MiReadSwapFile\n");
231
232 if (PageFileOffset == 0)
233 {
234 KeBugCheck(MEMORY_MANAGEMENT);
235 return(STATUS_UNSUCCESSFUL);
236 }
237
238 ASSERT(PageFileIndex < MAX_PAGING_FILES);
239
240 PagingFile = MmPagingFile[PageFileIndex];
241
242 if (PagingFile->FileObject == NULL || PagingFile->FileObject->DeviceObject == NULL)
243 {
244 DPRINT1("Bad paging file %u\n", PageFileIndex);
245 KeBugCheck(MEMORY_MANAGEMENT);
246 }
247
248 MmInitializeMdl(Mdl, NULL, PAGE_SIZE);
249 MmBuildMdlFromPages(Mdl, &Page);
250 Mdl->MdlFlags |= MDL_PAGES_LOCKED;
251
252 file_offset.QuadPart = PageFileOffset * PAGE_SIZE;
253
254 KeInitializeEvent(&Event, NotificationEvent, FALSE);
255 Status = IoPageRead(PagingFile->FileObject,
256 Mdl,
257 &file_offset,
258 &Event,
259 &Iosb);
260 if (Status == STATUS_PENDING)
261 {
262 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
263 Status = Iosb.Status;
264 }
265 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA)
266 {
267 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl);
268 }
269 return(Status);
270 }
271
272 VOID
273 INIT_FUNCTION
274 NTAPI
275 MmInitPagingFile(VOID)
276 {
277 ULONG i;
278
279 KeInitializeSpinLock(&PagingFileListLock);
280
281 MiFreeSwapPages = 0;
282 MiUsedSwapPages = 0;
283 MiReservedSwapPages = 0;
284
285 for (i = 0; i < MAX_PAGING_FILES; i++)
286 {
287 MmPagingFile[i] = NULL;
288 }
289 MmNumberOfPagingFiles = 0;
290 }
291
292 static ULONG
293 MiAllocPageFromPagingFile(PMMPAGING_FILE PagingFile)
294 {
295 KIRQL oldIrql;
296 ULONG off;
297
298 KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
299 off = RtlFindClearBitsAndSet(PagingFile->AllocMap, 1, 0);
300 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
301
302 return off;
303 }
304
305 VOID
306 NTAPI
307 MmFreeSwapPage(SWAPENTRY Entry)
308 {
309 ULONG i;
310 ULONG_PTR off;
311 KIRQL oldIrql;
312 PMMPAGING_FILE PagingFile;
313
314 i = FILE_FROM_ENTRY(Entry);
315 off = OFFSET_FROM_ENTRY(Entry) - 1;
316
317 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
318
319 PagingFile = MmPagingFile[i];
320 if (PagingFile == NULL)
321 {
322 KeBugCheck(MEMORY_MANAGEMENT);
323 }
324 KeAcquireSpinLockAtDpcLevel(&PagingFile->AllocMapLock);
325
326 RtlClearBit(PagingFile->AllocMap, off >> 5);
327
328 PagingFile->FreePages++;
329 PagingFile->UsedPages--;
330
331 MiFreeSwapPages++;
332 MiUsedSwapPages--;
333
334 KeReleaseSpinLockFromDpcLevel(&PagingFile->AllocMapLock);
335 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
336 }
337
338 SWAPENTRY
339 NTAPI
340 MmAllocSwapPage(VOID)
341 {
342 KIRQL oldIrql;
343 ULONG i;
344 ULONG off;
345 SWAPENTRY entry;
346
347 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
348
349 if (MiFreeSwapPages == 0)
350 {
351 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
352 return(0);
353 }
354
355 for (i = 0; i < MAX_PAGING_FILES; i++)
356 {
357 if (MmPagingFile[i] != NULL &&
358 MmPagingFile[i]->FreePages >= 1)
359 {
360 off = MiAllocPageFromPagingFile(MmPagingFile[i]);
361 if (off == 0xFFFFFFFF)
362 {
363 KeBugCheck(MEMORY_MANAGEMENT);
364 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
365 return(STATUS_UNSUCCESSFUL);
366 }
367 MiUsedSwapPages++;
368 MiFreeSwapPages--;
369 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
370
371 entry = ENTRY_FROM_FILE_OFFSET(i, off + 1);
372 return(entry);
373 }
374 }
375
376 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
377 KeBugCheck(MEMORY_MANAGEMENT);
378 return(0);
379 }
380
381 NTSTATUS NTAPI
382 NtCreatePagingFile(IN PUNICODE_STRING FileName,
383 IN PLARGE_INTEGER InitialSize,
384 IN PLARGE_INTEGER MaximumSize,
385 IN ULONG Reserved)
386 {
387 NTSTATUS Status;
388 OBJECT_ATTRIBUTES ObjectAttributes;
389 HANDLE FileHandle;
390 IO_STATUS_BLOCK IoStatus;
391 PFILE_OBJECT FileObject;
392 PMMPAGING_FILE PagingFile;
393 KIRQL oldIrql;
394 ULONG AllocMapSize;
395 ULONG Count;
396 KPROCESSOR_MODE PreviousMode;
397 UNICODE_STRING CapturedFileName;
398 LARGE_INTEGER SafeInitialSize, SafeMaximumSize, AllocationSize;
399 FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
400 SECURITY_DESCRIPTOR SecurityDescriptor;
401 PACL Dacl;
402
403 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
404 FileName, InitialSize->QuadPart);
405
406 if (MmNumberOfPagingFiles >= MAX_PAGING_FILES)
407 {
408 return STATUS_TOO_MANY_PAGING_FILES;
409 }
410
411 PreviousMode = ExGetPreviousMode();
412
413 if (PreviousMode != KernelMode)
414 {
415 if (SeSinglePrivilegeCheck(SeCreatePagefilePrivilege, PreviousMode) != TRUE)
416 {
417 return STATUS_PRIVILEGE_NOT_HELD;
418 }
419
420 _SEH2_TRY
421 {
422 SafeInitialSize = ProbeForReadLargeInteger(InitialSize);
423 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
424 }
425 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
426 {
427 /* Return the exception code */
428 _SEH2_YIELD(return _SEH2_GetExceptionCode());
429 }
430 _SEH2_END;
431 }
432 else
433 {
434 SafeInitialSize = *InitialSize;
435 SafeMaximumSize = *MaximumSize;
436 }
437
438 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
439 smaller than the maximum */
440 if (0 != SafeInitialSize.u.HighPart)
441 {
442 return STATUS_INVALID_PARAMETER_2;
443 }
444 if (0 != SafeMaximumSize.u.HighPart)
445 {
446 return STATUS_INVALID_PARAMETER_3;
447 }
448 if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart)
449 {
450 return STATUS_INVALID_PARAMETER_MIX;
451 }
452
453 Status = ProbeAndCaptureUnicodeString(&CapturedFileName,
454 PreviousMode,
455 FileName);
456 if (!NT_SUCCESS(Status))
457 {
458 return(Status);
459 }
460
461 /* Create the security descriptor for the page file */
462 Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
463 if (!NT_SUCCESS(Status))
464 {
465 ReleaseCapturedUnicodeString(&CapturedFileName,
466 PreviousMode);
467 return Status;
468 }
469
470 /* Create the DACL: we will only allow two SIDs */
471 Count = sizeof(ACL) + (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
472 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
473 Dacl = ExAllocatePoolWithTag(PagedPool, Count, 'lcaD');
474 if (Dacl == NULL)
475 {
476 ReleaseCapturedUnicodeString(&CapturedFileName,
477 PreviousMode);
478 return STATUS_INSUFFICIENT_RESOURCES;
479 }
480
481 /* Initialize the DACL */
482 Status = RtlCreateAcl(Dacl, Count, ACL_REVISION);
483 if (!NT_SUCCESS(Status))
484 {
485 ExFreePoolWithTag(Dacl, 'lcaD');
486 ReleaseCapturedUnicodeString(&CapturedFileName,
487 PreviousMode);
488 return Status;
489 }
490
491 /* Grant full access to admins */
492 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeAliasAdminsSid);
493 if (!NT_SUCCESS(Status))
494 {
495 ExFreePoolWithTag(Dacl, 'lcaD');
496 ReleaseCapturedUnicodeString(&CapturedFileName,
497 PreviousMode);
498 return Status;
499 }
500
501 /* Grant full access to SYSTEM */
502 Status = RtlAddAccessAllowedAce(Dacl, ACL_REVISION, FILE_ALL_ACCESS, SeLocalSystemSid);
503 if (!NT_SUCCESS(Status))
504 {
505 ExFreePoolWithTag(Dacl, 'lcaD');
506 ReleaseCapturedUnicodeString(&CapturedFileName,
507 PreviousMode);
508 return Status;
509 }
510
511 /* Attach the DACL to the security descriptor */
512 Status = RtlSetDaclSecurityDescriptor(&SecurityDescriptor, TRUE, Dacl, FALSE);
513 if (!NT_SUCCESS(Status))
514 {
515 ExFreePoolWithTag(Dacl, 'lcaD');
516 ReleaseCapturedUnicodeString(&CapturedFileName,
517 PreviousMode);
518 return Status;
519 }
520
521 InitializeObjectAttributes(&ObjectAttributes,
522 &CapturedFileName,
523 OBJ_KERNEL_HANDLE,
524 NULL,
525 &SecurityDescriptor);
526
527 /* Make sure we can at least store a complete page:
528 * If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is
529 * a problem if the paging file is fragmented. Suppose the first cluster
530 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the
531 * paging file but of another file. We can't write a complete page (4096
532 * bytes) to the physical location of cluster 3042 then. */
533 AllocationSize.QuadPart = SafeInitialSize.QuadPart + PAGE_SIZE;
534
535 /* First, attempt to replace the page file, if existing */
536 Status = IoCreateFile(&FileHandle,
537 SYNCHRONIZE | WRITE_DAC | FILE_READ_DATA | FILE_WRITE_DATA,
538 &ObjectAttributes,
539 &IoStatus,
540 &AllocationSize,
541 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
542 FILE_SHARE_WRITE,
543 FILE_SUPERSEDE,
544 FILE_DELETE_ON_CLOSE | FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
545 NULL,
546 0,
547 CreateFileTypeNone,
548 NULL,
549 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
550 /* If we failed, relax a bit constraints, someone may be already holding the
551 * the file, so share write, don't attempt to replace and don't delete on close
552 * (basically, don't do anything conflicting)
553 */
554 if (!NT_SUCCESS(Status))
555 {
556 Status = IoCreateFile(&FileHandle,
557 SYNCHRONIZE | FILE_WRITE_DATA,
558 &ObjectAttributes,
559 &IoStatus,
560 &AllocationSize,
561 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
562 FILE_SHARE_WRITE | FILE_SHARE_READ,
563 FILE_OPEN,
564 FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING,
565 NULL,
566 0,
567 CreateFileTypeNone,
568 NULL,
569 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
570 }
571
572 ReleaseCapturedUnicodeString(&CapturedFileName,
573 PreviousMode);
574 if (!NT_SUCCESS(Status))
575 {
576 DPRINT1("Failed creating page file: %lx\n", Status);
577 ExFreePoolWithTag(Dacl, 'lcaD');
578 return(Status);
579 }
580
581 /* Set the security descriptor */
582 if (NT_SUCCESS(IoStatus.Status))
583 {
584 Status = ZwSetSecurityObject(FileHandle, DACL_SECURITY_INFORMATION, &SecurityDescriptor);
585 if (!NT_SUCCESS(Status))
586 {
587 ExFreePoolWithTag(Dacl, 'lcaD');
588 ZwClose(FileHandle);
589 return Status;
590 }
591 }
592
593 /* DACL is no longer needed, free it */
594 ExFreePoolWithTag(Dacl, 'lcaD');
595
596 /* Set its end of file to initial size */
597 Status = ZwSetInformationFile(FileHandle,
598 &IoStatus,
599 &SafeInitialSize,
600 sizeof(LARGE_INTEGER),
601 FileEndOfFileInformation);
602 if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status))
603 {
604 ZwClose(FileHandle);
605 return(Status);
606 }
607
608 Status = ObReferenceObjectByHandle(FileHandle,
609 FILE_ALL_ACCESS,
610 IoFileObjectType,
611 KernelMode,
612 (PVOID*)&FileObject,
613 NULL);
614 if (!NT_SUCCESS(Status))
615 {
616 ZwClose(FileHandle);
617 return(Status);
618 }
619
620 /* Deny page file creation on a floppy disk */
621 FsDeviceInfo.Characteristics = 0;
622 IoQueryVolumeInformation(FileObject, FileFsDeviceInformation, sizeof(FsDeviceInfo), &FsDeviceInfo, &Count);
623 if (BooleanFlagOn(FsDeviceInfo.Characteristics, FILE_FLOPPY_DISKETTE))
624 {
625 ObDereferenceObject(FileObject);
626 ZwClose(FileHandle);
627 return STATUS_FLOPPY_VOLUME;
628 }
629
630 PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
631 if (PagingFile == NULL)
632 {
633 ObDereferenceObject(FileObject);
634 ZwClose(FileHandle);
635 return(STATUS_NO_MEMORY);
636 }
637
638 RtlZeroMemory(PagingFile, sizeof(*PagingFile));
639
640 PagingFile->FileHandle = FileHandle;
641 PagingFile->FileObject = FileObject;
642 PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart;
643 PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart;
644 PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE);
645 PagingFile->UsedPages = 0;
646 KeInitializeSpinLock(&PagingFile->AllocMapLock);
647
648 AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->FreePages + 31) / 32) * sizeof(ULONG));
649 PagingFile->AllocMap = ExAllocatePoolWithTag(NonPagedPool,
650 AllocMapSize,
651 TAG_MM);
652 if (PagingFile->AllocMap == NULL)
653 {
654 ExFreePool(PagingFile);
655 ObDereferenceObject(FileObject);
656 ZwClose(FileHandle);
657 return(STATUS_NO_MEMORY);
658 }
659
660 RtlInitializeBitMap(PagingFile->AllocMap,
661 (PULONG)(PagingFile->AllocMap + 1),
662 (ULONG)(PagingFile->FreePages));
663 RtlClearAllBits(PagingFile->AllocMap);
664
665 KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
666 ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL);
667 MmPagingFile[MmNumberOfPagingFiles] = PagingFile;
668 MmNumberOfPagingFiles++;
669 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
670 KeReleaseSpinLock(&PagingFileListLock, oldIrql);
671
672 MmSwapSpaceMessage = FALSE;
673
674 return(STATUS_SUCCESS);
675 }
676
677 /* EOF */