ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

pagefile.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.