PMMPAGING_FILE MmPagingFile[MAX_PAGING_FILES];
/* Lock for examining the list of paging files */
-static KSPIN_LOCK PagingFileListLock;
+KGUARDED_MUTEX MmPageFileCreationLock;
/* Number of paging files */
ULONG MmNumberOfPagingFiles;
{
ULONG i;
- KeInitializeSpinLock(&PagingFileListLock);
+ KeInitializeGuardedMutex(&MmPageFileCreationLock);
MiFreeSwapPages = 0;
MiUsedSwapPages = 0;
MmNumberOfPagingFiles = 0;
}
-static ULONG
-MiAllocPageFromPagingFile(PMMPAGING_FILE PagingFile)
-{
- KIRQL oldIrql;
- ULONG off;
-
- KeAcquireSpinLock(&PagingFile->AllocMapLock, &oldIrql);
- off = RtlFindClearBitsAndSet(PagingFile->AllocMap, 1, 0);
- KeReleaseSpinLock(&PagingFile->AllocMapLock, oldIrql);
-
- return off;
-}
-
VOID
NTAPI
MmFreeSwapPage(SWAPENTRY Entry)
{
ULONG i;
ULONG_PTR off;
- KIRQL oldIrql;
PMMPAGING_FILE PagingFile;
i = FILE_FROM_ENTRY(Entry);
off = OFFSET_FROM_ENTRY(Entry) - 1;
- KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
+ KeAcquireGuardedMutex(&MmPageFileCreationLock);
PagingFile = MmPagingFile[i];
if (PagingFile == NULL)
{
KeBugCheck(MEMORY_MANAGEMENT);
}
- KeAcquireSpinLockAtDpcLevel(&PagingFile->AllocMapLock);
- RtlClearBit(PagingFile->AllocMap, off >> 5);
+ RtlClearBit(PagingFile->Bitmap, off >> 5);
- PagingFile->FreePages++;
- PagingFile->UsedPages--;
+ PagingFile->FreeSpace++;
+ PagingFile->CurrentUsage--;
MiFreeSwapPages++;
MiUsedSwapPages--;
- KeReleaseSpinLockFromDpcLevel(&PagingFile->AllocMapLock);
- KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ KeReleaseGuardedMutex(&MmPageFileCreationLock);
}
SWAPENTRY
NTAPI
MmAllocSwapPage(VOID)
{
- KIRQL oldIrql;
ULONG i;
ULONG off;
SWAPENTRY entry;
- KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
+ KeAcquireGuardedMutex(&MmPageFileCreationLock);
if (MiFreeSwapPages == 0)
{
- KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ KeReleaseGuardedMutex(&MmPageFileCreationLock);
return(0);
}
for (i = 0; i < MAX_PAGING_FILES; i++)
{
if (MmPagingFile[i] != NULL &&
- MmPagingFile[i]->FreePages >= 1)
+ MmPagingFile[i]->FreeSpace >= 1)
{
- off = MiAllocPageFromPagingFile(MmPagingFile[i]);
+ off = RtlFindClearBitsAndSet(MmPagingFile[i]->Bitmap, 1, 0);
if (off == 0xFFFFFFFF)
{
KeBugCheck(MEMORY_MANAGEMENT);
- KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ KeReleaseGuardedMutex(&MmPageFileCreationLock);
return(STATUS_UNSUCCESSFUL);
}
MiUsedSwapPages++;
MiFreeSwapPages--;
- KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ KeReleaseGuardedMutex(&MmPageFileCreationLock);
entry = ENTRY_FROM_FILE_OFFSET(i, off + 1);
return(entry);
}
}
- KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ KeReleaseGuardedMutex(&MmPageFileCreationLock);
KeBugCheck(MEMORY_MANAGEMENT);
return(0);
}
NTSTATUS NTAPI
NtCreatePagingFile(IN PUNICODE_STRING FileName,
- IN PLARGE_INTEGER InitialSize,
+ IN PLARGE_INTEGER MinimumSize,
IN PLARGE_INTEGER MaximumSize,
IN ULONG Reserved)
{
IO_STATUS_BLOCK IoStatus;
PFILE_OBJECT FileObject;
PMMPAGING_FILE PagingFile;
- KIRQL oldIrql;
ULONG AllocMapSize;
ULONG Count;
KPROCESSOR_MODE PreviousMode;
- UNICODE_STRING CapturedFileName;
- LARGE_INTEGER SafeInitialSize, SafeMaximumSize, AllocationSize;
+ UNICODE_STRING PageFileName;
+ LARGE_INTEGER SafeMinimumSize, SafeMaximumSize, AllocationSize;
FILE_FS_DEVICE_INFORMATION FsDeviceInfo;
SECURITY_DESCRIPTOR SecurityDescriptor;
PACL Dacl;
+ PWSTR Buffer;
- DPRINT("NtCreatePagingFile(FileName %wZ, InitialSize %I64d)\n",
- FileName, InitialSize->QuadPart);
+ DPRINT("NtCreatePagingFile(FileName %wZ, MinimumSize %I64d)\n",
+ FileName, MinimumSize->QuadPart);
+
+ PAGED_CODE();
if (MmNumberOfPagingFiles >= MAX_PAGING_FILES)
{
_SEH2_TRY
{
- SafeInitialSize = ProbeForReadLargeInteger(InitialSize);
+ SafeMinimumSize = ProbeForReadLargeInteger(MinimumSize);
SafeMaximumSize = ProbeForReadLargeInteger(MaximumSize);
+
+ PageFileName.Length = FileName->Length;
+ PageFileName.MaximumLength = FileName->MaximumLength;
+ PageFileName.Buffer = FileName->Buffer;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
}
else
{
- SafeInitialSize = *InitialSize;
+ SafeMinimumSize = *MinimumSize;
SafeMaximumSize = *MaximumSize;
+
+ PageFileName.Length = FileName->Length;
+ PageFileName.MaximumLength = FileName->MaximumLength;
+ PageFileName.Buffer = FileName->Buffer;
}
/* Pagefiles can't be larger than 4GB and ofcourse the minimum should be
smaller than the maximum */
- if (0 != SafeInitialSize.u.HighPart)
+ if (0 != SafeMinimumSize.u.HighPart)
{
return STATUS_INVALID_PARAMETER_2;
}
{
return STATUS_INVALID_PARAMETER_3;
}
- if (SafeMaximumSize.u.LowPart < SafeInitialSize.u.LowPart)
+ if (SafeMaximumSize.u.LowPart < SafeMinimumSize.u.LowPart)
{
return STATUS_INVALID_PARAMETER_MIX;
}
- Status = ProbeAndCaptureUnicodeString(&CapturedFileName,
- PreviousMode,
- FileName);
- if (!NT_SUCCESS(Status))
+ /* Validate name length */
+ if (PageFileName.Length > 128 * sizeof(WCHAR))
{
- return(Status);
+ return STATUS_OBJECT_NAME_INVALID;
}
+ /* We won't care about any potential UNICODE_NULL */
+ PageFileName.MaximumLength = PageFileName.Length;
+ /* Allocate a buffer to keep name copy */
+ Buffer = ExAllocatePoolWithTag(PagedPool, PageFileName.Length, TAG_MM);
+ if (Buffer == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ /* Copy name */
+ if (PreviousMode != KernelMode)
+ {
+ _SEH2_TRY
+ {
+ if (PageFileName.Length != 0)
+ {
+ ProbeForRead(PageFileName.Buffer, PageFileName.Length, sizeof(WCHAR));
+ }
+
+ RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ ExFreePoolWithTag(Buffer, TAG_MM);
+
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ RtlCopyMemory(Buffer, PageFileName.Buffer, PageFileName.Length);
+ }
+
+ /* Erase caller's buffer with ours */
+ PageFileName.Buffer = Buffer;
+
/* Create the security descriptor for the page file */
Status = RtlCreateSecurityDescriptor(&SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
if (!NT_SUCCESS(Status))
{
- ReleaseCapturedUnicodeString(&CapturedFileName,
- PreviousMode);
+ ExFreePoolWithTag(Buffer, TAG_MM);
return Status;
}
Dacl = ExAllocatePoolWithTag(PagedPool, Count, 'lcaD');
if (Dacl == NULL)
{
- ReleaseCapturedUnicodeString(&CapturedFileName,
- PreviousMode);
+ ExFreePoolWithTag(Buffer, TAG_MM);
return STATUS_INSUFFICIENT_RESOURCES;
}
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(Dacl, 'lcaD');
- ReleaseCapturedUnicodeString(&CapturedFileName,
- PreviousMode);
+ ExFreePoolWithTag(Buffer, TAG_MM);
return Status;
}
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(Dacl, 'lcaD');
- ReleaseCapturedUnicodeString(&CapturedFileName,
- PreviousMode);
+ ExFreePoolWithTag(Buffer, TAG_MM);
return Status;
}
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(Dacl, 'lcaD');
- ReleaseCapturedUnicodeString(&CapturedFileName,
- PreviousMode);
+ ExFreePoolWithTag(Buffer, TAG_MM);
return Status;
}
if (!NT_SUCCESS(Status))
{
ExFreePoolWithTag(Dacl, 'lcaD');
- ReleaseCapturedUnicodeString(&CapturedFileName,
- PreviousMode);
+ ExFreePoolWithTag(Buffer, TAG_MM);
return Status;
}
InitializeObjectAttributes(&ObjectAttributes,
- &CapturedFileName,
+ &PageFileName,
OBJ_KERNEL_HANDLE,
NULL,
&SecurityDescriptor);
* of the paging file is cluster 3042 but cluster 3043 is NOT part of the
* paging file but of another file. We can't write a complete page (4096
* bytes) to the physical location of cluster 3042 then. */
- AllocationSize.QuadPart = SafeInitialSize.QuadPart + PAGE_SIZE;
+ AllocationSize.QuadPart = SafeMinimumSize.QuadPart + PAGE_SIZE;
/* First, attempt to replace the page file, if existing */
Status = IoCreateFile(&FileHandle,
/* If we failed, relax a bit constraints, someone may be already holding the
* the file, so share write, don't attempt to replace and don't delete on close
* (basically, don't do anything conflicting)
+ * This can happen if the caller attempts to extend a page file.
*/
if (!NT_SUCCESS(Status))
{
+ ULONG i;
+
Status = IoCreateFile(&FileHandle,
SYNCHRONIZE | FILE_WRITE_DATA,
&ObjectAttributes,
CreateFileTypeNone,
NULL,
SL_OPEN_PAGING_FILE | IO_NO_PARAMETER_CHECKING);
+ if (!NT_SUCCESS(Status))
+ {
+ ExFreePoolWithTag(Dacl, 'lcaD');
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return Status;
+ }
+
+ /* We opened it! Check we are that "someone" ;-)
+ * First, get the opened file object.
+ */
+ Status = ObReferenceObjectByHandle(FileHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ IoFileObjectType,
+ KernelMode,
+ (PVOID*)&FileObject,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ ZwClose(FileHandle);
+ ExFreePoolWithTag(Dacl, 'lcaD');
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return Status;
+ }
+
+ /* Find if it matches a previous page file */
+ PagingFile = NULL;
+
+ /* FIXME: should be calling unsafe instead,
+ * we should already be in a guarded region
+ */
+ KeAcquireGuardedMutex(&MmPageFileCreationLock);
+ if (MmNumberOfPagingFiles > 0)
+ {
+ i = 0;
+
+ while (MmPagingFile[i]->FileObject->SectionObjectPointer != FileObject->SectionObjectPointer)
+ {
+ ++i;
+ if (i >= MmNumberOfPagingFiles)
+ {
+ break;
+ }
+ }
+
+ /* This is the matching page file */
+ PagingFile = MmPagingFile[i];
+ }
+
+ /* If we didn't find the page file, fail */
+ if (PagingFile == NULL)
+ {
+ KeReleaseGuardedMutex(&MmPageFileCreationLock);
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ ExFreePoolWithTag(Dacl, 'lcaD');
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return STATUS_NOT_FOUND;
+ }
+
+ /* Don't allow page file shrinking */
+ if (PagingFile->MinimumSize > (SafeMinimumSize.QuadPart >> PAGE_SHIFT))
+ {
+ KeReleaseGuardedMutex(&MmPageFileCreationLock);
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ ExFreePoolWithTag(Dacl, 'lcaD');
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return STATUS_INVALID_PARAMETER_2;
+ }
+
+ if ((SafeMaximumSize.QuadPart >> PAGE_SHIFT) < PagingFile->MaximumSize)
+ {
+ KeReleaseGuardedMutex(&MmPageFileCreationLock);
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ ExFreePoolWithTag(Dacl, 'lcaD');
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return STATUS_INVALID_PARAMETER_3;
+ }
+
+ /* FIXME: implement parameters checking and page file extension */
+ UNIMPLEMENTED;
+
+ KeReleaseGuardedMutex(&MmPageFileCreationLock);
+ ObDereferenceObject(FileObject);
+ ZwClose(FileHandle);
+ ExFreePoolWithTag(Dacl, 'lcaD');
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return STATUS_NOT_IMPLEMENTED;
}
- ReleaseCapturedUnicodeString(&CapturedFileName,
- PreviousMode);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed creating page file: %lx\n", Status);
ExFreePoolWithTag(Dacl, 'lcaD');
- return(Status);
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return Status;
}
/* Set the security descriptor */
{
ExFreePoolWithTag(Dacl, 'lcaD');
ZwClose(FileHandle);
+ ExFreePoolWithTag(Buffer, TAG_MM);
return Status;
}
}
/* DACL is no longer needed, free it */
ExFreePoolWithTag(Dacl, 'lcaD');
- /* Set its end of file to initial size */
+ /* FIXME: To enable once page file managment is moved to ARM3 */
+#if 0
+ /* Check we won't overflow commit limit with the page file */
+ if (MmTotalCommitLimitMaximum + (SafeMaximumSize.QuadPart >> PAGE_SHIFT) <= MmTotalCommitLimitMaximum)
+ {
+ ZwClose(FileHandle);
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return STATUS_INVALID_PARAMETER_3;
+ }
+#endif
+
+ /* Set its end of file to minimal size */
Status = ZwSetInformationFile(FileHandle,
&IoStatus,
- &SafeInitialSize,
+ &SafeMinimumSize,
sizeof(LARGE_INTEGER),
FileEndOfFileInformation);
if (!NT_SUCCESS(Status) || !NT_SUCCESS(IoStatus.Status))
{
ZwClose(FileHandle);
- return(Status);
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return Status;
}
Status = ObReferenceObjectByHandle(FileHandle,
- FILE_ALL_ACCESS,
+ FILE_READ_DATA | FILE_WRITE_DATA,
IoFileObjectType,
KernelMode,
(PVOID*)&FileObject,
if (!NT_SUCCESS(Status))
{
ZwClose(FileHandle);
- return(Status);
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return Status;
}
/* Deny page file creation on a floppy disk */
{
ObDereferenceObject(FileObject);
ZwClose(FileHandle);
+ ExFreePoolWithTag(Buffer, TAG_MM);
return STATUS_FLOPPY_VOLUME;
}
- PagingFile = ExAllocatePool(NonPagedPool, sizeof(*PagingFile));
+ PagingFile = ExAllocatePoolWithTag(NonPagedPool, sizeof(*PagingFile), TAG_MM);
if (PagingFile == NULL)
{
ObDereferenceObject(FileObject);
ZwClose(FileHandle);
- return(STATUS_NO_MEMORY);
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(PagingFile, sizeof(*PagingFile));
PagingFile->FileHandle = FileHandle;
PagingFile->FileObject = FileObject;
- PagingFile->MaximumSize.QuadPart = SafeMaximumSize.QuadPart;
- PagingFile->CurrentSize.QuadPart = SafeInitialSize.QuadPart;
- PagingFile->FreePages = (ULONG)(SafeInitialSize.QuadPart / PAGE_SIZE);
- PagingFile->UsedPages = 0;
- KeInitializeSpinLock(&PagingFile->AllocMapLock);
-
- AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->FreePages + 31) / 32) * sizeof(ULONG));
- PagingFile->AllocMap = ExAllocatePoolWithTag(NonPagedPool,
- AllocMapSize,
- TAG_MM);
- if (PagingFile->AllocMap == NULL)
- {
- ExFreePool(PagingFile);
+ PagingFile->MaximumSize = (SafeMaximumSize.QuadPart >> PAGE_SHIFT);
+ PagingFile->Size = (SafeMinimumSize.QuadPart >> PAGE_SHIFT);
+ PagingFile->MinimumSize = (SafeMinimumSize.QuadPart >> PAGE_SHIFT);
+ /* First page is never used: it's the header
+ * TODO: write it
+ */
+ PagingFile->FreeSpace = (ULONG)(SafeMinimumSize.QuadPart / PAGE_SIZE) - 1;
+ PagingFile->CurrentUsage = 0;
+ PagingFile->PageFileName = PageFileName;
+ ASSERT(PagingFile->Size == PagingFile->FreeSpace + PagingFile->CurrentUsage + 1);
+
+ AllocMapSize = sizeof(RTL_BITMAP) + (((PagingFile->MaximumSize + 31) / 32) * sizeof(ULONG));
+ PagingFile->Bitmap = ExAllocatePoolWithTag(NonPagedPool,
+ AllocMapSize,
+ TAG_MM);
+ if (PagingFile->Bitmap == NULL)
+ {
+ ExFreePoolWithTag(PagingFile, TAG_MM);
ObDereferenceObject(FileObject);
ZwClose(FileHandle);
- return(STATUS_NO_MEMORY);
+ ExFreePoolWithTag(Buffer, TAG_MM);
+ return STATUS_INSUFFICIENT_RESOURCES;
}
- RtlInitializeBitMap(PagingFile->AllocMap,
- (PULONG)(PagingFile->AllocMap + 1),
- (ULONG)(PagingFile->FreePages));
- RtlClearAllBits(PagingFile->AllocMap);
+ RtlInitializeBitMap(PagingFile->Bitmap,
+ (PULONG)(PagingFile->Bitmap + 1),
+ (ULONG)(PagingFile->MaximumSize));
+ RtlClearAllBits(PagingFile->Bitmap);
- KeAcquireSpinLock(&PagingFileListLock, &oldIrql);
+ /* FIXME: should be calling unsafe instead,
+ * we should already be in a guarded region
+ */
+ KeAcquireGuardedMutex(&MmPageFileCreationLock);
ASSERT(MmPagingFile[MmNumberOfPagingFiles] == NULL);
MmPagingFile[MmNumberOfPagingFiles] = PagingFile;
MmNumberOfPagingFiles++;
- MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreePages;
- KeReleaseSpinLock(&PagingFileListLock, oldIrql);
+ MiFreeSwapPages = MiFreeSwapPages + PagingFile->FreeSpace;
+ KeReleaseGuardedMutex(&MmPageFileCreationLock);
MmSwapSpaceMessage = FALSE;
- return(STATUS_SUCCESS);
+ return STATUS_SUCCESS;
}
/* EOF */