Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenpagefile.c
Go to the documentation of this file.
00001 /* 00002 * ReactOS kernel 00003 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation; either version 2 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License along 00016 * with this program; if not, write to the Free Software Foundation, Inc., 00017 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00018 */ 00019 /* 00020 * PROJECT: ReactOS kernel 00021 * FILE: ntoskrnl/mm/pagefile.c 00022 * PURPOSE: Paging file functions 00023 * PROGRAMMER: David Welch (welch@mcmail.com) 00024 * UPDATE HISTORY: 00025 * Created 22/05/98 00026 */ 00027 00028 /* INCLUDES *****************************************************************/ 00029 00030 #include <ntoskrnl.h> 00031 #define NDEBUG 00032 #include <debug.h> 00033 00034 #if defined (ALLOC_PRAGMA) 00035 #pragma alloc_text(INIT, MmInitPagingFile) 00036 #endif 00037 00038 PVOID 00039 NTAPI 00040 MiFindExportedRoutineByName(IN PVOID DllBase, 00041 IN PANSI_STRING ExportName); 00042 00043 /* TYPES *********************************************************************/ 00044 00045 typedef struct _PAGINGFILE 00046 { 00047 LIST_ENTRY PagingFileListEntry; 00048 PFILE_OBJECT FileObject; 00049 LARGE_INTEGER MaximumSize; 00050 LARGE_INTEGER CurrentSize; 00051 ULONG FreePages; 00052 ULONG UsedPages; 00053 PULONG AllocMap; 00054 KSPIN_LOCK AllocMapLock; 00055 ULONG AllocMapSize; 00056 PRETRIEVAL_POINTERS_BUFFER RetrievalPointers; 00057 } 00058 PAGINGFILE, *PPAGINGFILE; 00059 00060 typedef struct _RETRIEVEL_DESCRIPTOR_LIST 00061 { 00062 struct _RETRIEVEL_DESCRIPTOR_LIST* Next; 00063 RETRIEVAL_POINTERS_BUFFER RetrievalPointers; 00064 } 00065 RETRIEVEL_DESCRIPTOR_LIST, *PRETRIEVEL_DESCRIPTOR_LIST; 00066 00067 /* GLOBALS *******************************************************************/ 00068 00069 #define PAIRS_PER_RUN (1024) 00070 00071 #define MAX_PAGING_FILES (32) 00072 00073 /* List of paging files, both used and free */ 00074 static PPAGINGFILE PagingFileList[MAX_PAGING_FILES]; 00075 00076 /* Lock for examining the list of paging files */ 00077 static KSPIN_LOCK PagingFileListLock; 00078 00079 /* Number of paging files */ 00080 static ULONG MiPagingFileCount; 00081 ULONG MmNumberOfPagingFiles; 00082 00083 /* Number of pages that are available for swapping */ 00084 PFN_COUNT MiFreeSwapPages; 00085 00086 /* Number of pages that have been allocated for swapping */ 00087 PFN_COUNT MiUsedSwapPages; 00088 00089 BOOLEAN MmZeroPageFile; 00090 00091 /* 00092 * Number of pages that have been reserved for swapping but not yet allocated 00093 */ 00094 static PFN_COUNT MiReservedSwapPages; 00095 00096 /* 00097 * Ratio between reserved and available swap pages, e.g. setting this to five 00098 * forces one swap page to be available for every five swap pages that are 00099 * reserved. Setting this to zero turns off commit checking altogether. 00100 */ 00101 #define MM_PAGEFILE_COMMIT_RATIO (1) 00102 00103 /* 00104 * Number of pages that can be used for potentially swapable memory without 00105 * pagefile space being reserved. The intention is that this allows smss 00106 * to start up and create page files while ordinarily having a commit 00107 * ratio of one. 00108 */ 00109 #define MM_PAGEFILE_COMMIT_GRACE (256) 00110 00111 /* 00112 * Translate between a swap entry and a file and offset pair. 00113 */ 00114 #define FILE_FROM_ENTRY(i) ((i) & 0x0f) 00115 #define OFFSET_FROM_ENTRY(i) ((i) >> 11) 00116 #define ENTRY_FROM_FILE_OFFSET(i, j) ((i) | ((j) << 11) | 0x400) 00117 00118 static BOOLEAN MmSwapSpaceMessage = FALSE; 00119 00120 /* FUNCTIONS *****************************************************************/ 00121 00122 VOID 00123 NTAPI 00124 MmBuildMdlFromPages(PMDL Mdl, PPFN_NUMBER Pages) 00125 { 00126 memcpy(Mdl + 1, Pages, sizeof(PFN_NUMBER) * (PAGE_ROUND_UP(Mdl->ByteOffset+Mdl->ByteCount)/PAGE_SIZE)); 00127 00128 /* FIXME: this flag should be set by the caller perhaps? */ 00129 Mdl->MdlFlags |= MDL_IO_PAGE_READ; 00130 } 00131 00132 00133 BOOLEAN 00134 NTAPI 00135 MmIsFileObjectAPagingFile(PFILE_OBJECT FileObject) 00136 { 00137 ULONG i; 00138 00139 /* Loop through all the paging files */ 00140 for (i = 0; i < MiPagingFileCount; i++) 00141 { 00142 /* Check if this is one of them */ 00143 if (PagingFileList[i]->FileObject == FileObject) return TRUE; 00144 } 00145 00146 /* Nothing found */ 00147 return FALSE; 00148 } 00149 00150 VOID 00151 NTAPI 00152 MmShowOutOfSpaceMessagePagingFile(VOID) 00153 { 00154 if (!MmSwapSpaceMessage) 00155 { 00156 DPRINT1("MM: Out of swap space.\n"); 00157 MmSwapSpaceMessage = TRUE; 00158 } 00159 } 00160 00161 static LARGE_INTEGER 00162 MmGetOffsetPageFile(PRETRIEVAL_POINTERS_BUFFER RetrievalPointers, LARGE_INTEGER Offset) 00163 { 00164 /* Simple binary search */ 00165 ULONG first, last, mid; 00166 first = 0; 00167 last = RetrievalPointers->ExtentCount - 1; 00168 while (first <= last) 00169 { 00170 mid = (last - first) / 2 + first; 00171 if (Offset.QuadPart < RetrievalPointers->Extents[mid].NextVcn.QuadPart) 00172 { 00173 if (mid == 0) 00174 { 00175 Offset.QuadPart += RetrievalPointers->Extents[0].Lcn.QuadPart - RetrievalPointers->StartingVcn.QuadPart; 00176 return Offset; 00177 } 00178 else 00179 { 00180 if (Offset.QuadPart >= RetrievalPointers->Extents[mid-1].NextVcn.QuadPart) 00181 { 00182 Offset.QuadPart += RetrievalPointers->Extents[mid].Lcn.QuadPart - RetrievalPointers->Extents[mid-1].NextVcn.QuadPart; 00183 return Offset; 00184 } 00185 last = mid - 1; 00186 } 00187 } 00188 else 00189 { 00190 if (mid == RetrievalPointers->ExtentCount - 1) 00191 { 00192 break; 00193 } 00194 if (Offset.QuadPart < RetrievalPointers->Extents[mid+1].NextVcn.QuadPart) 00195 { 00196 Offset.QuadPart += RetrievalPointers->Extents[mid+1].Lcn.QuadPart - RetrievalPointers->Extents[mid].NextVcn.QuadPart; 00197 return Offset; 00198 } 00199 first = mid + 1; 00200 } 00201 } 00202 KeBugCheck(MEMORY_MANAGEMENT); 00203 #if defined(__GNUC__) 00204 00205 return (LARGE_INTEGER)0LL; 00206 #else 00207 00208 { 00209 const LARGE_INTEGER dummy = 00210 { 00211 0 00212 }; 00213 return dummy; 00214 } 00215 #endif 00216 } 00217 00218 NTSTATUS 00219 NTAPI 00220 MmWriteToSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page) 00221 { 00222 ULONG i; 00223 ULONG_PTR offset; 00224 LARGE_INTEGER file_offset; 00225 IO_STATUS_BLOCK Iosb; 00226 NTSTATUS Status; 00227 KEVENT Event; 00228 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; 00229 PMDL Mdl = (PMDL)MdlBase; 00230 00231 DPRINT("MmWriteToSwapPage\n"); 00232 00233 if (SwapEntry == 0) 00234 { 00235 KeBugCheck(MEMORY_MANAGEMENT); 00236 return(STATUS_UNSUCCESSFUL); 00237 } 00238 00239 i = FILE_FROM_ENTRY(SwapEntry); 00240 offset = OFFSET_FROM_ENTRY(SwapEntry); 00241 00242 if (i >= MAX_PAGING_FILES) 00243 { 00244 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry); 00245 KeBugCheck(MEMORY_MANAGEMENT); 00246 } 00247 if (PagingFileList[i]->FileObject == NULL || 00248 PagingFileList[i]->FileObject->DeviceObject == NULL) 00249 { 00250 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry); 00251 KeBugCheck(MEMORY_MANAGEMENT); 00252 } 00253 00254 MmInitializeMdl(Mdl, NULL, PAGE_SIZE); 00255 MmBuildMdlFromPages(Mdl, &Page); 00256 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 00257 00258 file_offset.QuadPart = offset * PAGE_SIZE; 00259 file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset); 00260 00261 KeInitializeEvent(&Event, NotificationEvent, FALSE); 00262 Status = IoSynchronousPageWrite(PagingFileList[i]->FileObject, 00263 Mdl, 00264 &file_offset, 00265 &Event, 00266 &Iosb); 00267 if (Status == STATUS_PENDING) 00268 { 00269 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 00270 Status = Iosb.Status; 00271 } 00272 00273 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 00274 { 00275 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 00276 } 00277 return(Status); 00278 } 00279 00280 NTSTATUS 00281 NTAPI 00282 MmReadFromSwapPage(SWAPENTRY SwapEntry, PFN_NUMBER Page) 00283 { 00284 ULONG i; 00285 ULONG_PTR offset; 00286 LARGE_INTEGER file_offset; 00287 IO_STATUS_BLOCK Iosb; 00288 NTSTATUS Status; 00289 KEVENT Event; 00290 UCHAR MdlBase[sizeof(MDL) + sizeof(ULONG)]; 00291 PMDL Mdl = (PMDL)MdlBase; 00292 00293 DPRINT("MmReadFromSwapPage\n"); 00294 00295 if (SwapEntry == 0) 00296 { 00297 KeBugCheck(MEMORY_MANAGEMENT); 00298 return(STATUS_UNSUCCESSFUL); 00299 } 00300 00301 i = FILE_FROM_ENTRY(SwapEntry); 00302 offset = OFFSET_FROM_ENTRY(SwapEntry); 00303 00304 if (i >= MAX_PAGING_FILES) 00305 { 00306 DPRINT1("Bad swap entry 0x%.8X\n", SwapEntry); 00307 KeBugCheck(MEMORY_MANAGEMENT); 00308 } 00309 if (PagingFileList[i]->FileObject == NULL || 00310 PagingFileList[i]->FileObject->DeviceObject == NULL) 00311 { 00312 DPRINT1("Bad paging file 0x%.8X\n", SwapEntry); 00313 KeBugCheck(MEMORY_MANAGEMENT); 00314 } 00315 00316 MmInitializeMdl(Mdl, NULL, PAGE_SIZE); 00317 MmBuildMdlFromPages(Mdl, &Page); 00318 Mdl->MdlFlags |= MDL_PAGES_LOCKED; 00319 00320 file_offset.QuadPart = offset * PAGE_SIZE; 00321 file_offset = MmGetOffsetPageFile(PagingFileList[i]->RetrievalPointers, file_offset); 00322 00323 KeInitializeEvent(&Event, NotificationEvent, FALSE); 00324 Status = IoPageRead(PagingFileList[i]->FileObject, 00325 Mdl, 00326 &file_offset, 00327 &Event, 00328 &Iosb); 00329 if (Status == STATUS_PENDING) 00330 { 00331 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); 00332 Status = Iosb.Status; 00333 } 00334 if (Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA) 00335 { 00336 MmUnmapLockedPages (Mdl->MappedSystemVa, Mdl); 00337 } 00338 return(Status); 00339 } 00340 00341 VOID 00342 INIT_FUNCTION 00343 NTAPI 00344 MmInitPagingFile(VOID) 00345 { 00346 ULONG i; 00347 00348 KeInitializeSpinLock(&PagingFileListLock); 00349 00350 MiFreeSwapPages = 0; 00351 MiUsedSwapPages = 0; 00352 MiReservedSwapPages = 0; 00353 00354 for (i = 0; i < MAX_PAGING_FILES; i++) 00355 { 00356 PagingFileList[i] = NULL; 00357 } 00358 MiPagingFileCount = 0; 00359 } 00360 00361 BOOLEAN 00362 NTAPI 00363 MmReserveSwapPages(ULONG Nr) 00364 { 00365 KIRQL oldIrql; 00366 ULONG MiAvailSwapPages; 00367 00368 KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 00369 MiAvailSwapPages = 00370 (MiFreeSwapPages * MM_PAGEFILE_COMMIT_RATIO) + MM_PAGEFILE_COMMIT_GRACE; 00371 MiReservedSwapPages = MiReservedSwapPages + Nr; 00372 if ((MM_PAGEFILE_COMMIT_RATIO != 0) && (MiAvailSwapPages < MiReservedSwapPages)) 00373 { 00374 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 00375 return(FALSE); 00376 } 00377 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 00378 return(TRUE); 00379 } 00380 00381 VOID 00382 NTAPI 00383 MmDereserveSwapPages(ULONG Nr) 00384 { 00385 KIRQL oldIrql; 00386 00387 KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 00388 MiReservedSwapPages = MiReservedSwapPages - Nr; 00389 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 00390 } 00391 00392 static ULONG 00393 MiAllocPageFromPagingFile(PPAGINGFILE PagingFile) 00394 { 00395 KIRQL oldIrql; 00396 ULONG i, j; 00397 00398 KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql); 00399 00400 for (i = 0; i < PagingFile->AllocMapSize; i++) 00401 { 00402 for (j = 0; j < 32; j++) 00403 { 00404 if (!(PagingFile->AllocMap[i] & (1 << j))) 00405 { 00406 PagingFile->AllocMap[i] |= (1 << j); 00407 PagingFile->UsedPages++; 00408 PagingFile->FreePages--; 00409 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql); 00410 return((i * 32) + j); 00411 } 00412 } 00413 } 00414 00415 KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql); 00416 return(0xFFFFFFFF); 00417 } 00418 00419 VOID 00420 NTAPI 00421 MmFreeSwapPage(SWAPENTRY Entry) 00422 { 00423 ULONG i; 00424 ULONG_PTR off; 00425 KIRQL oldIrql; 00426 00427 i = FILE_FROM_ENTRY(Entry); 00428 off = OFFSET_FROM_ENTRY(Entry); 00429 00430 if (i >= MAX_PAGING_FILES) 00431 { 00432 DPRINT1("Bad swap entry 0x%.8X\n", Entry); 00433 KeBugCheck(MEMORY_MANAGEMENT); 00434 } 00435 00436 KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 00437 if (PagingFileList[i] == NULL) 00438 { 00439 KeBugCheck(MEMORY_MANAGEMENT); 00440 } 00441 KeAcquireSpinLockAtDpcLevel(&PagingFileList[i]->AllocMapLock); 00442 00443 PagingFileList[i]->AllocMap[off >> 5] &= (~(1 << (off % 32))); 00444 00445 PagingFileList[i]->FreePages++; 00446 PagingFileList[i]->UsedPages--; 00447 00448 MiFreeSwapPages++; 00449 MiUsedSwapPages--; 00450 00451 KeReleaseSpinLockFromDpcLevel(&PagingFileList[i]->AllocMapLock); 00452 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 00453 } 00454 00455 BOOLEAN 00456 NTAPI 00457 MmIsAvailableSwapPage(VOID) 00458 { 00459 return(MiFreeSwapPages > 0); 00460 } 00461 00462 SWAPENTRY 00463 NTAPI 00464 MmAllocSwapPage(VOID) 00465 { 00466 KIRQL oldIrql; 00467 ULONG i; 00468 ULONG off; 00469 SWAPENTRY entry; 00470 00471 KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 00472 00473 if (MiFreeSwapPages == 0) 00474 { 00475 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 00476 return(0); 00477 } 00478 00479 for (i = 0; i < MAX_PAGING_FILES; i++) 00480 { 00481 if (PagingFileList[i] != NULL && 00482 PagingFileList[i]->FreePages >= 1) 00483 { 00484 off = MiAllocPageFromPagingFile(PagingFileList[i]); 00485 if (off == 0xFFFFFFFF) 00486 { 00487 KeBugCheck(MEMORY_MANAGEMENT); 00488 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 00489 return(STATUS_UNSUCCESSFUL); 00490 } 00491 MiUsedSwapPages++; 00492 MiFreeSwapPages--; 00493 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 00494 00495 entry = ENTRY_FROM_FILE_OFFSET(i, off); 00496 return(entry); 00497 } 00498 } 00499 00500 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 00501 KeBugCheck(MEMORY_MANAGEMENT); 00502 return(0); 00503 } 00504 00505 static PRETRIEVEL_DESCRIPTOR_LIST FASTCALL 00506 MmAllocRetrievelDescriptorList(ULONG Pairs) 00507 { 00508 ULONG Size; 00509 PRETRIEVEL_DESCRIPTOR_LIST RetDescList; 00510 00511 Size = sizeof(RETRIEVEL_DESCRIPTOR_LIST) + Pairs * 2 * sizeof(LARGE_INTEGER); 00512 RetDescList = ExAllocatePool(NonPagedPool, Size); 00513 if (RetDescList) 00514 { 00515 RtlZeroMemory(RetDescList, Size); 00516 } 00517 00518 return RetDescList; 00519 } 00520 00521 NTSTATUS NTAPI 00522 NtCreatePagingFile(IN PUNICODE_STRING FileName, 00523 IN PLARGE_INTEGER InitialSize, 00524 IN PLARGE_INTEGER MaximumSize, 00525 IN ULONG Reserved) 00526 { 00527 NTSTATUS Status; 00528 OBJECT_ATTRIBUTES ObjectAttributes; 00529 HANDLE FileHandle; 00530 IO_STATUS_BLOCK IoStatus; 00531 PFILE_OBJECT FileObject; 00532 PPAGINGFILE PagingFile; 00533 KIRQL oldIrql; 00534 ULONG AllocMapSize; 00535 FILE_FS_SIZE_INFORMATION FsSizeInformation; 00536 PRETRIEVEL_DESCRIPTOR_LIST RetDescList; 00537 PRETRIEVEL_DESCRIPTOR_LIST CurrentRetDescList; 00538 ULONG i; 00539 ULONG BytesPerAllocationUnit; 00540 LARGE_INTEGER Vcn; 00541 ULONG ExtentCount; 00542 LARGE_INTEGER MaxVcn; 00543 ULONG Count; 00544 ULONG Size; 00545 KPROCESSOR_MODE PreviousMode; 00546 UNICODE_STRING CapturedFileName; 00547 LARGE_INTEGER SafeInitialSize, SafeMaximumSize; 00548 00549 DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n", 00550 FileName, InitialSize->QuadPart); 00551 00552 if (MiPagingFileCount >= MAX_PAGING_FILES) 00553 { 00554 return(STATUS_TOO_MANY_PAGING_FILES); 00555 } 00556 00557 PreviousMode = ExGetPreviousMode(); 00558 00559 if (PreviousMode != KernelMode) 00560 { 00561 _SEH2_TRY 00562 { 00563 SafeInitialSize = ProbeForReadLargeInteger(InitialSize); 00564 SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize); 00565 } 00566 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00567 { 00568 /* Return the exception code */ 00569 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00570 } 00571 _SEH2_END; 00572 } 00573 else 00574 { 00575 SafeInitialSize = *InitialSize; 00576 SafeMaximumSize = *MaximumSize; 00577 } 00578 00579 /* Pagefiles can't be larger than 4GB and ofcourse the minimum should be 00580 smaller than the maximum */ 00581 if (0 != SafeInitialSize.u.HighPart) 00582 { 00583 return STATUS_INVALID_PARAMETER_2; 00584 } 00585 if (0 != SafeMaximumSize.u.HighPart) 00586 { 00587 return STATUS_INVALID_PARAMETER_3; 00588 } 00589 if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart) 00590 { 00591 return STATUS_INVALID_PARAMETER_MIX; 00592 } 00593 00594 Status = ProbeAndCaptureUnicodeString(&CapturedFileName, 00595 PreviousMode, 00596 FileName); 00597 if (!NT_SUCCESS(Status)) 00598 { 00599 return(Status); 00600 } 00601 00602 InitializeObjectAttributes(&ObjectAttributes, 00603 &CapturedFileName, 00604 0, 00605 NULL, 00606 NULL); 00607 00608 Status = IoCreateFile(&FileHandle, 00609 FILE_ALL_ACCESS, 00610 &ObjectAttributes, 00611 &IoStatus, 00612 NULL, 00613 0, 00614 0, 00615 FILE_OPEN_IF, 00616 FILE_SYNCHRONOUS_IO_NONALERT, 00617 NULL, 00618 0, 00619 CreateFileTypeNone, 00620 NULL, 00621 SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING); 00622 00623 ReleaseCapturedUnicodeString(&CapturedFileName, 00624 PreviousMode); 00625 if (!NT_SUCCESS(Status)) 00626 { 00627 return(Status); 00628 } 00629 00630 Status = ZwQueryVolumeInformationFile(FileHandle, 00631 &IoStatus, 00632 &FsSizeInformation, 00633 sizeof(FILE_FS_SIZE_INFORMATION), 00634 FileFsSizeInformation); 00635 if (!NT_SUCCESS(Status)) 00636 { 00637 ZwClose(FileHandle); 00638 return Status; 00639 } 00640 00641 BytesPerAllocationUnit = FsSizeInformation.SectorsPerAllocationUnit * 00642 FsSizeInformation.BytesPerSector; 00643 /* FIXME: If we have 2048 BytesPerAllocationUnit (FAT16 < 128MB) there is 00644 * a problem if the paging file is fragmented. Suppose the first cluster 00645 * of the paging file is cluster 3042 but cluster 3043 is NOT part of the 00646 * paging file but of another file. We can't write a complete page (4096 00647 * bytes) to the physical location of cluster 3042 then. */ 00648 if (BytesPerAllocationUnit % PAGE_SIZE) 00649 { 00650 DPRINT1("BytesPerAllocationUnit %d is not a multiple of PAGE_SIZE %d\n", 00651 BytesPerAllocationUnit, PAGE_SIZE); 00652 ZwClose(FileHandle); 00653 return STATUS_UNSUCCESSFUL; 00654 } 00655 00656 Status = ZwSetInformationFile(FileHandle, 00657 &IoStatus, 00658 &SafeInitialSize, 00659 sizeof(LARGE_INTEGER), 00660 FileAllocationInformation); 00661 if (!NT_SUCCESS(Status)) 00662 { 00663 ZwClose(FileHandle); 00664 return(Status); 00665 } 00666 00667 Status = ObReferenceObjectByHandle(FileHandle, 00668 FILE_ALL_ACCESS, 00669 IoFileObjectType, 00670 PreviousMode, 00671 (PVOID*)&FileObject, 00672 NULL); 00673 if (!NT_SUCCESS(Status)) 00674 { 00675 ZwClose(FileHandle); 00676 return(Status); 00677 } 00678 00679 CurrentRetDescList = RetDescList = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN); 00680 00681 if (CurrentRetDescList == NULL) 00682 { 00683 ObDereferenceObject(FileObject); 00684 ZwClose(FileHandle); 00685 return(STATUS_NO_MEMORY); 00686 } 00687 00688 #if defined(__GNUC__) 00689 Vcn.QuadPart = 0LL; 00690 #else 00691 00692 Vcn.QuadPart = 0; 00693 #endif 00694 00695 ExtentCount = 0; 00696 MaxVcn.QuadPart = (SafeInitialSize.QuadPart + BytesPerAllocationUnit - 1) / BytesPerAllocationUnit; 00697 while(1) 00698 { 00699 Status = ZwFsControlFile(FileHandle, 00700 0, 00701 NULL, 00702 NULL, 00703 &IoStatus, 00704 FSCTL_GET_RETRIEVAL_POINTERS, 00705 &Vcn, 00706 sizeof(LARGE_INTEGER), 00707 &CurrentRetDescList->RetrievalPointers, 00708 sizeof(RETRIEVAL_POINTERS_BUFFER) + PAIRS_PER_RUN * 2 * sizeof(LARGE_INTEGER)); 00709 if (!NT_SUCCESS(Status)) 00710 { 00711 while (RetDescList) 00712 { 00713 CurrentRetDescList = RetDescList; 00714 RetDescList = RetDescList->Next; 00715 ExFreePool(CurrentRetDescList); 00716 } 00717 ObDereferenceObject(FileObject); 00718 ZwClose(FileHandle); 00719 return(Status); 00720 } 00721 ExtentCount += CurrentRetDescList->RetrievalPointers.ExtentCount; 00722 if (CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn.QuadPart < MaxVcn.QuadPart) 00723 { 00724 CurrentRetDescList->Next = MmAllocRetrievelDescriptorList(PAIRS_PER_RUN); 00725 if (CurrentRetDescList->Next == NULL) 00726 { 00727 while (RetDescList) 00728 { 00729 CurrentRetDescList = RetDescList; 00730 RetDescList = RetDescList->Next; 00731 ExFreePool(CurrentRetDescList); 00732 } 00733 ObDereferenceObject(FileObject); 00734 ZwClose(FileHandle); 00735 return(STATUS_NO_MEMORY); 00736 } 00737 Vcn = CurrentRetDescList->RetrievalPointers.Extents[CurrentRetDescList->RetrievalPointers.ExtentCount-1].NextVcn; 00738 CurrentRetDescList = CurrentRetDescList->Next; 00739 } 00740 else 00741 { 00742 break; 00743 } 00744 } 00745 00746 PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile)); 00747 if (PagingFile == NULL) 00748 { 00749 while (RetDescList) 00750 { 00751 CurrentRetDescList = RetDescList; 00752 RetDescList = RetDescList->Next; 00753 ExFreePool(CurrentRetDescList); 00754 } 00755 ObDereferenceObject(FileObject); 00756 ZwClose(FileHandle); 00757 return(STATUS_NO_MEMORY); 00758 } 00759 00760 RtlZeroMemory(PagingFile, sizeof(*PagingFile)); 00761 00762 PagingFile->FileObject = FileObject; 00763 PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart; 00764 PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart; 00765 PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE); 00766 PagingFile->UsedPages = 0; 00767 KeInitializeSpinLock(&PagingFile->AllocMapLock); 00768 00769 AllocMapSize = (PagingFile->FreePages / 32) + 1; 00770 PagingFile->AllocMap = ExAllocatePool(NonPagedPool, 00771 AllocMapSize * sizeof(ULONG)); 00772 PagingFile->AllocMapSize = AllocMapSize; 00773 00774 if (PagingFile->AllocMap == NULL) 00775 { 00776 while (RetDescList) 00777 { 00778 CurrentRetDescList = RetDescList; 00779 RetDescList = RetDescList->Next; 00780 ExFreePool(CurrentRetDescList); 00781 } 00782 ExFreePool(PagingFile); 00783 ObDereferenceObject(FileObject); 00784 ZwClose(FileHandle); 00785 return(STATUS_NO_MEMORY); 00786 } 00787 DPRINT("ExtentCount: %d\n", ExtentCount); 00788 Size = sizeof(RETRIEVAL_POINTERS_BUFFER) + ExtentCount * 2 * sizeof(LARGE_INTEGER); 00789 PagingFile->RetrievalPointers = ExAllocatePool(NonPagedPool, Size); 00790 if (PagingFile->RetrievalPointers == NULL) 00791 { 00792 while (RetDescList) 00793 { 00794 CurrentRetDescList = RetDescList; 00795 RetDescList = RetDescList->Next; 00796 ExFreePool(CurrentRetDescList); 00797 } 00798 ExFreePool(PagingFile->AllocMap); 00799 ExFreePool(PagingFile); 00800 ObDereferenceObject(FileObject); 00801 ZwClose(FileHandle); 00802 return(STATUS_NO_MEMORY); 00803 } 00804 00805 RtlZeroMemory(PagingFile->AllocMap, AllocMapSize * sizeof(ULONG)); 00806 RtlZeroMemory(PagingFile->RetrievalPointers, Size); 00807 00808 Count = 0; 00809 PagingFile->RetrievalPointers->ExtentCount = ExtentCount; 00810 PagingFile->RetrievalPointers->StartingVcn = RetDescList->RetrievalPointers.StartingVcn; 00811 CurrentRetDescList = RetDescList; 00812 while (CurrentRetDescList) 00813 { 00814 memcpy(&PagingFile->RetrievalPointers->Extents[Count], 00815 CurrentRetDescList->RetrievalPointers.Extents, 00816 CurrentRetDescList->RetrievalPointers.ExtentCount * 2 * sizeof(LARGE_INTEGER)); 00817 Count += CurrentRetDescList->RetrievalPointers.ExtentCount; 00818 RetDescList = CurrentRetDescList; 00819 CurrentRetDescList = CurrentRetDescList->Next; 00820 ExFreePool(RetDescList); 00821 } 00822 00823 if (PagingFile->RetrievalPointers->ExtentCount != ExtentCount || 00824 PagingFile->RetrievalPointers->Extents[ExtentCount - 1].NextVcn.QuadPart != MaxVcn.QuadPart) 00825 { 00826 ExFreePool(PagingFile->RetrievalPointers); 00827 ExFreePool(PagingFile->AllocMap); 00828 ExFreePool(PagingFile); 00829 ObDereferenceObject(FileObject); 00830 ZwClose(FileHandle); 00831 return(STATUS_UNSUCCESSFUL); 00832 } 00833 00834 /* 00835 * Change the entries from lcn's to volume offset's. 00836 */ 00837 PagingFile->RetrievalPointers->StartingVcn.QuadPart *= BytesPerAllocationUnit; 00838 for (i = 0; i < ExtentCount; i++) 00839 { 00840 PagingFile->RetrievalPointers->Extents[i].Lcn.QuadPart *= BytesPerAllocationUnit; 00841 PagingFile->RetrievalPointers->Extents[i].NextVcn.QuadPart *= BytesPerAllocationUnit; 00842 } 00843 00844 KeAcquireSpinLock(&PagingFileListLock, &oldIrql); 00845 for (i = 0; i < MAX_PAGING_FILES; i++) 00846 { 00847 if (PagingFileList[i] == NULL) 00848 { 00849 PagingFileList[i] = PagingFile; 00850 break; 00851 } 00852 } 00853 MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages; 00854 MiPagingFileCount++; 00855 KeReleaseSpinLock(&PagingFileListLock, oldIrql); 00856 00857 ZwClose(FileHandle); 00858 00859 MmSwapSpaceMessage = FALSE; 00860 00861 return(STATUS_SUCCESS); 00862 } 00863 00864 /* EOF */ Generated on Sun May 27 2012 04:18:53 for ReactOS by
1.7.6.1
|