mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 02:25:17 +00:00
[CACHE]
The cache manager rewrite I started years ago has finally appeared in ReactOS' trunk and although at this point it's not quite perfectly integrated, it's enough to boot up the bootcd or livecd. To check out the more mature original, check out arty-newcc-reactos, branch arty-newcc on bitbucket.org . Amine Khaldi encouraged me quite a bit to not give up on it, and was able to reach out and be an advocate when i really wasn't able to. Others agree that the time has come to begin removing the old cache manager. I expect the remaining problems in the version going to trunk will be taken care of relatively quickly. The motivation for this effort lies in the particularly hairy relationship between ReactOS' cache manager and data sections. This code completely removes page sharing between cache manager and section and reimagines cache manager as being a facility layered on the memory manager, not really caring about individual pages, but simply managing data section objects where caching might occur. It took me about 2 years to do the first pass of this rewrite and most of this year to fix some lingering issues, properly implement demand paging in ReactOS (code which didn't come with this patch in a recognizable form), and finish getting the PrivateCacheMap and SharedCacheMap relationship correct. Currently, the new ntoskrnl/cache directory contains an own implementation of data file sections. After things have settled down, we can begin to deprecate and remove the parts of ReactOS' section implementation that depend on a close relationship with cache manager. Eventually, I think that the extra code added to ntoskrnl/cache/section will be removed and ReactOS' own sections will replace the use of the special MM_CACHE_SECTION_SEGMENT in the cache path. Note also, that this makes all cache manager (and new section parts) use wide file offsets. If my section code were to take over other parts of the ReactOS memory manager, they would also benefit from these improvements. I invite anyone who wants to to peek at this code and fix whatever bugs can be found. svn path=/trunk/; revision=49423
This commit is contained in:
parent
7697abf4a2
commit
f2e646d5b4
30 changed files with 5908 additions and 125 deletions
|
@ -99,4 +99,9 @@
|
|||
-->
|
||||
<property name="BUILD_MP" value="1" />
|
||||
|
||||
<!--
|
||||
Whether to compile the new cache manager
|
||||
-->
|
||||
<property name="NEWCC" value="0" />
|
||||
|
||||
</group>
|
||||
|
|
86
reactos/include/ndk/inline_ntcurrentteb.h
Normal file
86
reactos/include/ndk/inline_ntcurrentteb.h
Normal file
|
@ -0,0 +1,86 @@
|
|||
#ifndef _INLINE_NT_CURRENTTEB_H_
|
||||
#define _INLINE_NT_CURRENTTEB_H_
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#if defined(_M_IX86)
|
||||
FORCEINLINE struct _TEB * NtCurrentTeb(void)
|
||||
{
|
||||
struct _TEB *ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"movl %%fs:0x18, %0\n"
|
||||
: "=r" (ret)
|
||||
: /* no inputs */
|
||||
);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#elif defined(_M_ARM)
|
||||
|
||||
//
|
||||
// NT-ARM is not documented
|
||||
//
|
||||
#include <armddk.h>
|
||||
|
||||
#elif defined(_M_AMD64)
|
||||
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
|
||||
{
|
||||
return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB, Self));
|
||||
}
|
||||
#elif defined(_M_PPC)
|
||||
extern __inline__ struct _TEB * NtCurrentTeb(void)
|
||||
{
|
||||
return __readfsdword_winnt(0x18);
|
||||
}
|
||||
#else
|
||||
extern __inline__ struct _TEB * NtCurrentTeb(void)
|
||||
{
|
||||
return __readfsdword_winnt(0x18);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__WATCOMC__)
|
||||
|
||||
extern PVOID GetCurrentFiber(void);
|
||||
#pragma aux GetCurrentFiber = \
|
||||
"mov eax, dword ptr fs:0x10" \
|
||||
value [eax] \
|
||||
modify [eax];
|
||||
|
||||
extern struct _TEB * NtCurrentTeb(void);
|
||||
#pragma aux NtCurrentTeb = \
|
||||
"mov eax, dword ptr fs:0x18" \
|
||||
value [eax] \
|
||||
modify [eax];
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#if (_MSC_FULL_VER >= 13012035)
|
||||
|
||||
__inline PVOID GetCurrentFiber(void) { return (PVOID)(ULONG_PTR)__readfsdword(0x10); }
|
||||
__inline struct _TEB * NtCurrentTeb(void) { return (struct _TEB *)(ULONG_PTR)__readfsdword(0x18); }
|
||||
|
||||
#else
|
||||
|
||||
static __inline PVOID GetCurrentFiber(void)
|
||||
{
|
||||
PVOID p;
|
||||
__asm mov eax, fs:[10h]
|
||||
__asm mov [p], eax
|
||||
return p;
|
||||
}
|
||||
|
||||
static __inline struct _TEB * NtCurrentTeb(void)
|
||||
{
|
||||
struct _TEB *p;
|
||||
__asm mov eax, fs:[18h]
|
||||
__asm mov [p], eax
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif /* _MSC_FULL_VER */
|
||||
|
||||
#endif /* __GNUC__/__WATCOMC__/_MSC_VER */
|
||||
|
||||
#endif//_INLINE_NT_CURRENTTEB_H_
|
|
@ -329,35 +329,7 @@ NtCreateThread(
|
|||
IN BOOLEAN CreateSuspended
|
||||
);
|
||||
|
||||
#ifndef NTOS_MODE_USER
|
||||
#if defined(_M_IX86)
|
||||
FORCEINLINE
|
||||
PTEB
|
||||
NtCurrentTeb(VOID)
|
||||
{
|
||||
#ifndef __GNUC__
|
||||
return (PTEB)(ULONG_PTR)__readfsdword(0x18);
|
||||
#else
|
||||
struct _TEB *ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"movl %%fs:0x18, %0\n"
|
||||
: "=r" (ret)
|
||||
: /* no inputs */
|
||||
);
|
||||
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
#elif defined (_M_AMD64)
|
||||
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
|
||||
{
|
||||
return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB, Self));
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
struct _TEB * NtCurrentTeb(void);
|
||||
#endif
|
||||
#include "inline_ntcurrentteb.h"
|
||||
|
||||
NTSYSCALLAPI
|
||||
NTSTATUS
|
||||
|
|
|
@ -5086,43 +5086,6 @@ static __inline__ PVOID GetCurrentFiber(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(_M_IX86)
|
||||
extern __inline__ struct _TEB * NtCurrentTeb(void)
|
||||
{
|
||||
struct _TEB *ret;
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"movl %%fs:0x18, %0\n"
|
||||
: "=r" (ret)
|
||||
: /* no inputs */
|
||||
);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#elif defined(_M_ARM)
|
||||
|
||||
//
|
||||
// NT-ARM is not documented
|
||||
//
|
||||
#include <armddk.h>
|
||||
|
||||
#elif defined(_M_AMD64)
|
||||
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
|
||||
{
|
||||
return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB, Self));
|
||||
}
|
||||
#elif defined(_M_PPC)
|
||||
extern __inline__ struct _TEB * NtCurrentTeb(void)
|
||||
{
|
||||
return __readfsdword_winnt(0x18);
|
||||
}
|
||||
#else
|
||||
extern __inline__ struct _TEB * NtCurrentTeb(void)
|
||||
{
|
||||
return __readfsdword_winnt(0x18);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__WATCOMC__)
|
||||
|
||||
extern PVOID GetCurrentFiber(void);
|
||||
|
@ -5131,18 +5094,11 @@ extern PVOID GetCurrentFiber(void);
|
|||
value [eax] \
|
||||
modify [eax];
|
||||
|
||||
extern struct _TEB * NtCurrentTeb(void);
|
||||
#pragma aux NtCurrentTeb = \
|
||||
"mov eax, dword ptr fs:0x18" \
|
||||
value [eax] \
|
||||
modify [eax];
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#if (_MSC_FULL_VER >= 13012035)
|
||||
|
||||
__inline PVOID GetCurrentFiber(void) { return (PVOID)(ULONG_PTR)__readfsdword(0x10); }
|
||||
__inline struct _TEB * NtCurrentTeb(void) { return (struct _TEB *)(ULONG_PTR)__readfsdword(0x18); }
|
||||
|
||||
#else
|
||||
|
||||
|
@ -5154,18 +5110,12 @@ static __inline PVOID GetCurrentFiber(void)
|
|||
return p;
|
||||
}
|
||||
|
||||
static __inline struct _TEB * NtCurrentTeb(void)
|
||||
{
|
||||
struct _TEB *p;
|
||||
__asm mov eax, fs:[18h]
|
||||
__asm mov [p], eax
|
||||
return p;
|
||||
}
|
||||
|
||||
#endif /* _MSC_FULL_VER */
|
||||
|
||||
#endif /* __GNUC__/__WATCOMC__/_MSC_VER */
|
||||
|
||||
#include "inline_ntcurrentteb.h"
|
||||
|
||||
static __inline PVOID GetFiberData(void)
|
||||
{
|
||||
return *((PVOID *)GetCurrentFiber());
|
||||
|
|
347
reactos/ntoskrnl/cache/cachesub.c
vendored
Normal file
347
reactos/ntoskrnl/cache/cachesub.c
vendored
Normal file
|
@ -0,0 +1,347 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel
|
||||
* FILE: ntoskrnl/cache/cachesup.c
|
||||
* PURPOSE: Logging and configuration routines
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
* Art Yerkes
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newcc.h"
|
||||
#include "section/newmm.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* STRUCTURES *****************************************************************/
|
||||
|
||||
typedef struct _WORK_QUEUE_WITH_READ_AHEAD
|
||||
{
|
||||
WORK_QUEUE_ITEM WorkItem;
|
||||
PFILE_OBJECT FileObject;
|
||||
LARGE_INTEGER FileOffset;
|
||||
ULONG Length;
|
||||
} WORK_QUEUE_WITH_READ_AHEAD, *PWORK_QUEUE_WITH_READ_AHEAD;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
PDEVICE_OBJECT
|
||||
NTAPI
|
||||
MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcSetReadAheadGranularity(IN PFILE_OBJECT FileObject,
|
||||
IN ULONG Granularity)
|
||||
{
|
||||
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
if (Map)
|
||||
{
|
||||
Map->ReadAheadGranularity = Granularity;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcpReadAhead(PVOID Context)
|
||||
{
|
||||
LARGE_INTEGER Offset;
|
||||
PWORK_QUEUE_WITH_READ_AHEAD WorkItem = (PWORK_QUEUE_WITH_READ_AHEAD)Context;
|
||||
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)WorkItem->FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
DPRINT("Reading ahead %08x%08x:%x %wZ\n",
|
||||
WorkItem->FileOffset.HighPart,
|
||||
WorkItem->FileOffset.LowPart,
|
||||
WorkItem->Length,
|
||||
&WorkItem->FileObject->FileName);
|
||||
Offset.HighPart = WorkItem->FileOffset.HighPart;
|
||||
Offset.LowPart = PAGE_ROUND_DOWN(WorkItem->FileOffset.LowPart);
|
||||
if (Map)
|
||||
{
|
||||
PLIST_ENTRY ListEntry;
|
||||
volatile char *chptr;
|
||||
PNOCC_BCB Bcb;
|
||||
for (ListEntry = Map->AssociatedBcb.Flink;
|
||||
ListEntry != &Map->AssociatedBcb;
|
||||
ListEntry = ListEntry->Flink)
|
||||
{
|
||||
Bcb = CONTAINING_RECORD(ListEntry, NOCC_BCB, ThisFileList);
|
||||
if ((Offset.QuadPart + WorkItem->Length < Bcb->FileOffset.QuadPart) ||
|
||||
(Bcb->FileOffset.QuadPart + Bcb->Length < Offset.QuadPart))
|
||||
continue;
|
||||
for (chptr = Bcb->BaseAddress, Offset = Bcb->FileOffset;
|
||||
chptr < ((PCHAR)Bcb->BaseAddress) + Bcb->Length &&
|
||||
Offset.QuadPart <
|
||||
WorkItem->FileOffset.QuadPart + WorkItem->Length;
|
||||
chptr += PAGE_SIZE, Offset.QuadPart += PAGE_SIZE)
|
||||
{
|
||||
*chptr ^= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
ObDereferenceObject(WorkItem->FileObject);
|
||||
ExFreePool(WorkItem);
|
||||
DPRINT("Done\n");
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcScheduleReadAhead(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length)
|
||||
{
|
||||
PWORK_QUEUE_WITH_READ_AHEAD WorkItem;
|
||||
DPRINT("Schedule read ahead %08x%08x:%x %wZ\n",
|
||||
FileOffset->HighPart,
|
||||
FileOffset->LowPart,
|
||||
Length,
|
||||
&FileObject->FileName);
|
||||
WorkItem = ExAllocatePool(NonPagedPool, sizeof(*WorkItem));
|
||||
if (!WorkItem) KeBugCheck(0);
|
||||
ObReferenceObject(FileObject);
|
||||
WorkItem->FileObject = FileObject;
|
||||
WorkItem->FileOffset = *FileOffset;
|
||||
WorkItem->Length = Length;
|
||||
ExInitializeWorkItem(((PWORK_QUEUE_ITEM)WorkItem), (PWORKER_THREAD_ROUTINE)CcpReadAhead, WorkItem);
|
||||
ExQueueWorkItem((PWORK_QUEUE_ITEM)WorkItem, DelayedWorkQueue);
|
||||
DPRINT("Done\n");
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcSetDirtyPinnedData(IN PVOID BcbVoid,
|
||||
IN OPTIONAL PLARGE_INTEGER Lsn)
|
||||
{
|
||||
PNOCC_BCB Bcb = (PNOCC_BCB)BcbVoid;
|
||||
Bcb->Dirty = TRUE;
|
||||
}
|
||||
|
||||
LARGE_INTEGER
|
||||
NTAPI
|
||||
CcGetFlushedValidData(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
||||
IN BOOLEAN CcInternalCaller)
|
||||
{
|
||||
LARGE_INTEGER Result = {{0}};
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
_CcpFlushCache(IN PNOCC_CACHE_MAP Map,
|
||||
IN OPTIONAL PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
OUT OPTIONAL PIO_STATUS_BLOCK IoStatus,
|
||||
BOOLEAN Delete,
|
||||
const char *File,
|
||||
int Line)
|
||||
{
|
||||
PNOCC_BCB Bcb = NULL;
|
||||
LARGE_INTEGER LowerBound, UpperBound;
|
||||
PLIST_ENTRY ListEntry;
|
||||
IO_STATUS_BLOCK IOSB = { };
|
||||
|
||||
DPRINT1("CcFlushCache (while file) (%s:%d)\n", File, Line);
|
||||
|
||||
if (FileOffset && Length)
|
||||
{
|
||||
LowerBound.QuadPart = FileOffset->QuadPart;
|
||||
UpperBound.QuadPart = LowerBound.QuadPart + Length;
|
||||
}
|
||||
else
|
||||
{
|
||||
LowerBound.QuadPart = 0;
|
||||
UpperBound.QuadPart = 0x7fffffffffffffffull;
|
||||
}
|
||||
|
||||
CcpLock();
|
||||
ListEntry = Map->AssociatedBcb.Flink;
|
||||
|
||||
while (ListEntry != &Map->AssociatedBcb)
|
||||
{
|
||||
Bcb = CONTAINING_RECORD(ListEntry, NOCC_BCB, ThisFileList);
|
||||
CcpReferenceCache(Bcb - CcCacheSections);
|
||||
|
||||
if (Bcb->FileOffset.QuadPart + Bcb->Length >= LowerBound.QuadPart &&
|
||||
Bcb->FileOffset.QuadPart < UpperBound.QuadPart)
|
||||
{
|
||||
DPRINT
|
||||
("Bcb #%x (@%08x%08x)\n",
|
||||
Bcb - CcCacheSections,
|
||||
Bcb->FileOffset.u.HighPart, Bcb->FileOffset.u.LowPart);
|
||||
|
||||
Bcb->RefCount++;
|
||||
CcpUnlock();
|
||||
MiFlushMappedSection(Bcb->BaseAddress, &Bcb->FileOffset, &Map->FileSizes.FileSize, Bcb->Dirty);
|
||||
CcpLock();
|
||||
Bcb->RefCount--;
|
||||
|
||||
Bcb->Dirty = FALSE;
|
||||
|
||||
ListEntry = ListEntry->Flink;
|
||||
if (Delete && Bcb->RefCount < 2)
|
||||
{
|
||||
Bcb->RefCount = 1;
|
||||
CcpDereferenceCache(Bcb - CcCacheSections, FALSE);
|
||||
}
|
||||
else
|
||||
CcpUnpinData(Bcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
ListEntry = ListEntry->Flink;
|
||||
CcpUnpinData(Bcb);
|
||||
}
|
||||
|
||||
DPRINT("End loop\n");
|
||||
}
|
||||
CcpUnlock();
|
||||
|
||||
if (IoStatus) *IoStatus = IOSB;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcFlushCache(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
||||
IN OPTIONAL PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
OUT OPTIONAL PIO_STATUS_BLOCK IoStatus)
|
||||
{
|
||||
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap;
|
||||
|
||||
// Not cached
|
||||
if (!Map)
|
||||
{
|
||||
if (IoStatus)
|
||||
{
|
||||
IoStatus->Status = STATUS_SUCCESS;
|
||||
IoStatus->Information = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
CcpFlushCache(Map, FileOffset, Length, IoStatus, TRUE);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcFlushImageSection
|
||||
(PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
||||
MMFLUSH_TYPE FlushType)
|
||||
{
|
||||
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap;
|
||||
PNOCC_BCB Bcb;
|
||||
PLIST_ENTRY Entry;
|
||||
IO_STATUS_BLOCK IOSB;
|
||||
BOOLEAN Result = TRUE;
|
||||
|
||||
if (!Map) return TRUE;
|
||||
|
||||
for (Entry = Map->AssociatedBcb.Flink;
|
||||
Entry != &Map->AssociatedBcb;
|
||||
Entry = Entry->Flink)
|
||||
{
|
||||
Bcb = CONTAINING_RECORD(Entry, NOCC_BCB, ThisFileList);
|
||||
|
||||
if (!Bcb->Dirty) continue;
|
||||
|
||||
switch (FlushType)
|
||||
{
|
||||
case MmFlushForDelete:
|
||||
CcPurgeCacheSection
|
||||
(SectionObjectPointer,
|
||||
&Bcb->FileOffset,
|
||||
Bcb->Length,
|
||||
FALSE);
|
||||
break;
|
||||
case MmFlushForWrite:
|
||||
CcFlushCache
|
||||
(SectionObjectPointer,
|
||||
&Bcb->FileOffset,
|
||||
Bcb->Length,
|
||||
&IOSB);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Always succeeds for us
|
||||
PVOID
|
||||
NTAPI
|
||||
CcRemapBcb(IN PVOID Bcb)
|
||||
{
|
||||
CcpLock();
|
||||
ASSERT(RtlTestBit(CcCacheBitmap, ((PNOCC_BCB)Bcb) - CcCacheSections));
|
||||
CcpReferenceCache(((PNOCC_BCB)Bcb) - CcCacheSections);
|
||||
CcpUnlock();
|
||||
return Bcb;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcShutdownSystem()
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
DPRINT1("CC: Shutdown\n");
|
||||
|
||||
for (i = 0; i < CACHE_NUM_SECTIONS; i++)
|
||||
{
|
||||
PNOCC_BCB Bcb = &CcCacheSections[i];
|
||||
if (Bcb->SectionObject)
|
||||
{
|
||||
DPRINT1
|
||||
("Evicting #%02x %08x%08x %wZ\n",
|
||||
i,
|
||||
Bcb->FileOffset.u.HighPart, Bcb->FileOffset.u.LowPart,
|
||||
&MmGetFileObjectForSection
|
||||
((PROS_SECTION_OBJECT)Bcb->SectionObject)->FileName);
|
||||
CcpFlushCache(Bcb->Map, NULL, 0, NULL, TRUE);
|
||||
Bcb->Dirty = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINT1("Done\n");
|
||||
}
|
||||
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcRepinBcb(IN PVOID Bcb)
|
||||
{
|
||||
CcpLock();
|
||||
ASSERT(RtlTestBit(CcCacheBitmap, ((PNOCC_BCB)Bcb) - CcCacheSections));
|
||||
DPRINT("CcRepinBcb(#%x)\n", ((PNOCC_BCB)Bcb) - CcCacheSections);
|
||||
CcpReferenceCache(((PNOCC_BCB)Bcb) - CcCacheSections);
|
||||
CcpUnlock();
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcUnpinRepinnedBcb(IN PVOID Bcb,
|
||||
IN BOOLEAN WriteThrough,
|
||||
OUT PIO_STATUS_BLOCK IoStatus)
|
||||
{
|
||||
PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
|
||||
|
||||
if (WriteThrough)
|
||||
{
|
||||
DPRINT("BCB #%x\n", RealBcb - CcCacheSections);
|
||||
|
||||
CcpFlushCache
|
||||
(RealBcb->Map,
|
||||
&RealBcb->FileOffset,
|
||||
RealBcb->Length,
|
||||
IoStatus, RealBcb->Dirty);
|
||||
}
|
||||
|
||||
CcUnpinData(Bcb);
|
||||
}
|
||||
|
||||
/* EOF */
|
214
reactos/ntoskrnl/cache/copysup.c
vendored
Normal file
214
reactos/ntoskrnl/cache/copysup.c
vendored
Normal file
|
@ -0,0 +1,214 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel
|
||||
* FILE: ntoskrnl/cache/copysup.c
|
||||
* PURPOSE: Logging and configuration routines
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newcc.h"
|
||||
#include "section/newmm.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
ULONG CcFastMdlReadWait;
|
||||
ULONG CcFastMdlReadNotPossible;
|
||||
ULONG CcFastReadNotPossible;
|
||||
ULONG CcFastReadWait;
|
||||
ULONG CcFastReadNoWait;
|
||||
ULONG CcFastReadResourceMiss;
|
||||
|
||||
#define TAG_COPY_READ TAG('C', 'o', 'p', 'y')
|
||||
#define TAG_COPY_WRITE TAG('R', 'i', 't', 'e')
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcCopyRead(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN Wait,
|
||||
OUT PVOID Buffer,
|
||||
OUT PIO_STATUS_BLOCK IoStatus)
|
||||
{
|
||||
PCHAR ReadBuffer;
|
||||
ULONG ReadLen;
|
||||
PVOID Bcb;
|
||||
PCHAR BufferTarget = (PCHAR)Buffer;
|
||||
LARGE_INTEGER CacheOffset, EndOfExtent, NextOffset;
|
||||
|
||||
DPRINT
|
||||
("CcCopyRead(%x,%x,%d,%d,%x)\n",
|
||||
FileObject,
|
||||
FileOffset->LowPart,
|
||||
Length,
|
||||
Wait,
|
||||
Buffer);
|
||||
|
||||
CacheOffset.QuadPart = FileOffset->QuadPart;
|
||||
EndOfExtent.QuadPart = FileOffset->QuadPart + Length;
|
||||
|
||||
while (CacheOffset.QuadPart < EndOfExtent.QuadPart)
|
||||
{
|
||||
NextOffset.QuadPart = CacheOffset.QuadPart;
|
||||
NextOffset.LowPart = (NextOffset.LowPart + CACHE_STRIPE) & ~(CACHE_STRIPE-1);
|
||||
ReadLen = EndOfExtent.QuadPart - CacheOffset.QuadPart;
|
||||
if (CacheOffset.QuadPart + ReadLen > NextOffset.QuadPart)
|
||||
{
|
||||
ReadLen = NextOffset.QuadPart - CacheOffset.QuadPart;
|
||||
}
|
||||
|
||||
DPRINT("Reading %d bytes in this go (at %08x%08x)\n", ReadLen, CacheOffset.HighPart, CacheOffset.LowPart);
|
||||
|
||||
if (!CcPinRead
|
||||
(FileObject,
|
||||
&CacheOffset,
|
||||
ReadLen,
|
||||
Wait ? PIN_WAIT : PIN_IF_BCB,
|
||||
&Bcb,
|
||||
(PVOID*)&ReadBuffer))
|
||||
{
|
||||
IoStatus->Status = STATUS_UNSUCCESSFUL;
|
||||
IoStatus->Information = 0;
|
||||
DPRINT("Failed CcCopyRead\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DPRINT1("Copying %d bytes at %08x%08x\n", ReadLen, CacheOffset.HighPart, CacheOffset.LowPart);
|
||||
RtlCopyMemory
|
||||
(BufferTarget,
|
||||
ReadBuffer,
|
||||
ReadLen);
|
||||
|
||||
BufferTarget += ReadLen;
|
||||
|
||||
CacheOffset = NextOffset;
|
||||
CcUnpinData(Bcb);
|
||||
}
|
||||
|
||||
IoStatus->Status = STATUS_SUCCESS;
|
||||
IoStatus->Information = Length;
|
||||
|
||||
DPRINT("Done with CcCopyRead\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcFastCopyRead(IN PFILE_OBJECT FileObject,
|
||||
IN ULONG FileOffset,
|
||||
IN ULONG Length,
|
||||
IN ULONG PageCount,
|
||||
OUT PVOID Buffer,
|
||||
OUT PIO_STATUS_BLOCK IoStatus)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcCopyWrite(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN Wait,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
INT Count = 0;
|
||||
BOOLEAN Result;
|
||||
PNOCC_BCB Bcb;
|
||||
PVOID WriteBuf;
|
||||
ULONG WriteLen;
|
||||
LARGE_INTEGER CurrentOffset = *FileOffset;
|
||||
LARGE_INTEGER EndOffset;
|
||||
LARGE_INTEGER NextOffset;
|
||||
|
||||
EndOffset.QuadPart = CurrentOffset.QuadPart + Length;
|
||||
|
||||
DPRINT
|
||||
("CcCopyWrite(%x,%x,%d,%d,%x)\n",
|
||||
FileObject,
|
||||
FileOffset->LowPart,
|
||||
Length,
|
||||
Wait,
|
||||
Buffer);
|
||||
|
||||
while (CurrentOffset.QuadPart < EndOffset.QuadPart)
|
||||
{
|
||||
NextOffset.HighPart = CurrentOffset.HighPart;
|
||||
NextOffset.LowPart = (CurrentOffset.LowPart + CACHE_STRIPE) & ~(CACHE_STRIPE - 1);
|
||||
DPRINT("NextOffset %08x%08x\n", NextOffset.u.HighPart, NextOffset.u.LowPart);
|
||||
WriteLen = MIN(NextOffset.QuadPart - CurrentOffset.QuadPart, Length);
|
||||
DPRINT("Copying %x bytes from %08x%08x\n",
|
||||
WriteLen,
|
||||
CurrentOffset.u.HighPart, CurrentOffset.u.LowPart);
|
||||
DPRINT("CcPreparePinWrite\n");
|
||||
Result = CcPreparePinWrite
|
||||
(FileObject, &CurrentOffset, WriteLen, FALSE, Wait ? PIN_WAIT : PIN_IF_BCB,
|
||||
(PVOID *)&Bcb, &WriteBuf);
|
||||
DPRINT("Result %s %x %x\n", Result ? "TRUE" : "FALSE", Bcb, WriteBuf);
|
||||
if (!Result)
|
||||
{
|
||||
DPRINT1("CcPreparePinWrite Failed?\n");
|
||||
if (Wait) RtlRaiseStatus(STATUS_NOT_MAPPED_DATA); else return FALSE;
|
||||
}
|
||||
DPRINT1("Copying actual memory to BCB#%x (@%x) (from buffer at %x)\n", Bcb - CcCacheSections, WriteBuf, Bcb->BaseAddress);
|
||||
|
||||
//MiZeroFillSection(WriteBuf, &CurrentOffset, WriteLen);
|
||||
RtlCopyMemory(WriteBuf, ((PCHAR)Buffer) + Count, WriteLen);
|
||||
Count += WriteLen;
|
||||
Length -= WriteLen;
|
||||
CurrentOffset = NextOffset;
|
||||
Bcb->Dirty = TRUE;
|
||||
CcUnpinData(Bcb);
|
||||
}
|
||||
|
||||
DPRINT("Done with CcCopyWrite\n");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcFastCopyWrite(IN PFILE_OBJECT FileObject,
|
||||
IN ULONG FileOffset,
|
||||
IN ULONG Length,
|
||||
IN PVOID Buffer)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcCanIWrite(IN PFILE_OBJECT FileObject,
|
||||
IN ULONG BytesToWrite,
|
||||
IN BOOLEAN Wait,
|
||||
IN UCHAR Retrying)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcDeferWrite(IN PFILE_OBJECT FileObject,
|
||||
IN PCC_POST_DEFERRED_WRITE PostRoutine,
|
||||
IN PVOID Context1,
|
||||
IN PVOID Context2,
|
||||
IN ULONG BytesToWrite,
|
||||
IN BOOLEAN Retrying)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
}
|
||||
|
||||
/* EOF */
|
513
reactos/ntoskrnl/cache/fssup.c
vendored
Normal file
513
reactos/ntoskrnl/cache/fssup.c
vendored
Normal file
|
@ -0,0 +1,513 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel
|
||||
* FILE: ntoskrnl/cache/fssup.c
|
||||
* PURPOSE: Logging and configuration routines
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
* Art Yerkes
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newcc.h"
|
||||
#include "section/newmm.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
PFSN_PREFETCHER_GLOBALS CcPfGlobals;
|
||||
extern LONG CcOutstandingDeletes;
|
||||
extern KEVENT CcpLazyWriteEvent;
|
||||
extern KEVENT CcFinalizeEvent;
|
||||
extern VOID NTAPI CcpUnmapThread(PVOID Unused);
|
||||
extern VOID NTAPI CcpLazyWriteThread(PVOID Unused);
|
||||
HANDLE CcUnmapThreadHandle, CcLazyWriteThreadHandle;
|
||||
CLIENT_ID CcUnmapThreadId, CcLazyWriteThreadId;
|
||||
|
||||
typedef struct _NOCC_PRIVATE_CACHE_MAP
|
||||
{
|
||||
LIST_ENTRY ListEntry;
|
||||
PFILE_OBJECT FileObject;
|
||||
PNOCC_CACHE_MAP Map;
|
||||
} NOCC_PRIVATE_CACHE_MAP, *PNOCC_PRIVATE_CACHE_MAP;
|
||||
|
||||
LIST_ENTRY CcpAllSharedCacheMaps;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
// Interact with legacy balance manager for now
|
||||
// This can fall away when our section implementation supports
|
||||
// demand paging properly
|
||||
NTSTATUS
|
||||
CcRosTrimCache(ULONG Target, ULONG Priority, PULONG NrFreed)
|
||||
{
|
||||
ULONG i, Freed, BcbHead;
|
||||
|
||||
*NrFreed = 0;
|
||||
|
||||
for (i = 0; i < CACHE_NUM_SECTIONS; i++) {
|
||||
BcbHead = (i+CcCacheClockHand) % CACHE_NUM_SECTIONS;
|
||||
|
||||
// Reference a cache stripe so it won't go away
|
||||
CcpLock();
|
||||
if (CcCacheSections[BcbHead].BaseAddress) {
|
||||
CcpReferenceCache(i);
|
||||
CcpUnlock();
|
||||
} else {
|
||||
CcpUnlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
// Defer to MM to try recovering pages from it
|
||||
Freed = MiCacheEvictPages
|
||||
(CcCacheSections[BcbHead].BaseAddress, Target);
|
||||
|
||||
Target -= Freed;
|
||||
*NrFreed += Freed;
|
||||
|
||||
CcpLock();
|
||||
CcpDereferenceCache(BcbHead, FALSE);
|
||||
CcpUnlock();
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcInitializeCacheManager(VOID)
|
||||
{
|
||||
int i;
|
||||
|
||||
DPRINT("Initialize\n");
|
||||
for (i = 0; i < CACHE_NUM_SECTIONS; i++)
|
||||
{
|
||||
KeInitializeEvent(&CcCacheSections[i].ExclusiveWait, SynchronizationEvent, FALSE);
|
||||
InitializeListHead(&CcCacheSections[i].ThisFileList);
|
||||
}
|
||||
|
||||
InitializeListHead(&CcpAllSharedCacheMaps);
|
||||
|
||||
KeInitializeEvent(&CcDeleteEvent, SynchronizationEvent, FALSE);
|
||||
KeInitializeEvent(&CcFinalizeEvent, SynchronizationEvent, FALSE);
|
||||
KeInitializeEvent(&CcpLazyWriteEvent, SynchronizationEvent, FALSE);
|
||||
|
||||
CcCacheBitmap->Buffer = ((PULONG)&CcCacheBitmap[1]);
|
||||
CcCacheBitmap->SizeOfBitMap = ROUND_UP(CACHE_NUM_SECTIONS, 32);
|
||||
DPRINT("Cache has %d entries\n", CcCacheBitmap->SizeOfBitMap);
|
||||
ExInitializeFastMutex(&CcMutex);
|
||||
|
||||
// MM stub
|
||||
KeInitializeEvent(&MmWaitPageEvent, SynchronizationEvent, FALSE);
|
||||
|
||||
// Until we're fully demand paged, we can do things the old way through
|
||||
// the balance manager
|
||||
MmInitializeMemoryConsumer(MC_CACHE, CcRosTrimCache);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcPfInitializePrefetcher(VOID)
|
||||
{
|
||||
/* Notify debugger */
|
||||
DbgPrintEx(DPFLTR_PREFETCHER_ID,
|
||||
DPFLTR_TRACE_LEVEL,
|
||||
"CCPF: InitializePrefetecher()\n");
|
||||
|
||||
/* Setup the Prefetcher Data */
|
||||
InitializeListHead(&CcPfGlobals.ActiveTraces);
|
||||
InitializeListHead(&CcPfGlobals.CompletedTraces);
|
||||
ExInitializeFastMutex(&CcPfGlobals.CompletedTracesLock);
|
||||
|
||||
/* FIXME: Setup the rest of the prefetecher */
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcpAcquireFileLock(PNOCC_CACHE_MAP Map)
|
||||
{
|
||||
DPRINT("Calling AcquireForLazyWrite: %x\n", Map->LazyContext);
|
||||
return Map->Callbacks.AcquireForLazyWrite(Map->LazyContext, TRUE);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcpReleaseFileLock(PNOCC_CACHE_MAP Map)
|
||||
{
|
||||
DPRINT("Releasing Lazy Write %x\n", Map->LazyContext);
|
||||
Map->Callbacks.ReleaseFromLazyWrite(Map->LazyContext);
|
||||
}
|
||||
|
||||
// Must have CcpLock()
|
||||
PFILE_OBJECT CcpFindOtherStreamFileObject(PFILE_OBJECT FileObject)
|
||||
{
|
||||
PLIST_ENTRY Entry, Private;
|
||||
for (Entry = CcpAllSharedCacheMaps.Flink;
|
||||
Entry != &CcpAllSharedCacheMaps;
|
||||
Entry = Entry->Flink)
|
||||
{
|
||||
// 'Identical' test for other stream file object
|
||||
PNOCC_CACHE_MAP Map = CONTAINING_RECORD(Entry, NOCC_CACHE_MAP, Entry);
|
||||
for (Private = Map->PrivateCacheMaps.Flink;
|
||||
Private != &Map->PrivateCacheMaps;
|
||||
Private = Private->Flink)
|
||||
{
|
||||
PNOCC_PRIVATE_CACHE_MAP PrivateMap = CONTAINING_RECORD(Private, NOCC_PRIVATE_CACHE_MAP, ListEntry);
|
||||
if (PrivateMap->FileObject->Flags & FO_STREAM_FILE &&
|
||||
PrivateMap->FileObject->DeviceObject == FileObject->DeviceObject &&
|
||||
PrivateMap->FileObject->Vpb == FileObject->Vpb &&
|
||||
PrivateMap->FileObject->FsContext == FileObject->FsContext &&
|
||||
PrivateMap->FileObject->FsContext2 == FileObject->FsContext2 &&
|
||||
1)
|
||||
{
|
||||
return PrivateMap->FileObject;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Thanks: http://windowsitpro.com/Windows/Articles/ArticleID/3864/pg/2/2.html
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcInitializeCacheMap(IN PFILE_OBJECT FileObject,
|
||||
IN PCC_FILE_SIZES FileSizes,
|
||||
IN BOOLEAN PinAccess,
|
||||
IN PCACHE_MANAGER_CALLBACKS Callbacks,
|
||||
IN PVOID LazyWriteContext)
|
||||
{
|
||||
PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap;
|
||||
|
||||
CcpLock();
|
||||
if (!Map && FileObject->Flags & FO_STREAM_FILE)
|
||||
{
|
||||
PFILE_OBJECT IdenticalStreamFileObject =
|
||||
CcpFindOtherStreamFileObject(FileObject);
|
||||
if (IdenticalStreamFileObject)
|
||||
Map = IdenticalStreamFileObject->SectionObjectPointer->SharedCacheMap;
|
||||
if (Map)
|
||||
{
|
||||
DPRINT1
|
||||
("Linking SFO %x to previous SFO %x through cache map %x #\n",
|
||||
FileObject, IdenticalStreamFileObject, Map);
|
||||
}
|
||||
}
|
||||
if (!Map)
|
||||
{
|
||||
DPRINT("Initializing file object for (%p) %wZ\n", FileObject, &FileObject->FileName);
|
||||
Map = ExAllocatePool(NonPagedPool, sizeof(NOCC_CACHE_MAP));
|
||||
FileObject->SectionObjectPointer->SharedCacheMap = Map;
|
||||
Map->FileSizes = *FileSizes;
|
||||
Map->LazyContext = LazyWriteContext;
|
||||
Map->ReadAheadGranularity = PAGE_SIZE;
|
||||
RtlCopyMemory(&Map->Callbacks, Callbacks, sizeof(*Callbacks));
|
||||
// For now ...
|
||||
DPRINT("FileSizes->ValidDataLength %08x%08x\n", FileSizes->ValidDataLength.HighPart, FileSizes->ValidDataLength.LowPart);
|
||||
InitializeListHead(&Map->AssociatedBcb);
|
||||
InitializeListHead(&Map->PrivateCacheMaps);
|
||||
InsertTailList(&CcpAllSharedCacheMaps, &Map->Entry);
|
||||
DPRINT("New Map %x\n", Map);
|
||||
}
|
||||
if (!PrivateCacheMap)
|
||||
{
|
||||
PrivateCacheMap = ExAllocatePool(NonPagedPool, sizeof(*PrivateCacheMap));
|
||||
FileObject->PrivateCacheMap = PrivateCacheMap;
|
||||
PrivateCacheMap->FileObject = FileObject;
|
||||
ObReferenceObject(PrivateCacheMap->FileObject);
|
||||
}
|
||||
|
||||
PrivateCacheMap->Map = Map;
|
||||
InsertTailList(&Map->PrivateCacheMaps, &PrivateCacheMap->ListEntry);
|
||||
|
||||
CcpUnlock();
|
||||
}
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
CcpCountCacheSections(IN PNOCC_CACHE_MAP Map)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
ULONG Count;
|
||||
|
||||
for (Count = 0, Entry = Map->AssociatedBcb.Flink; Entry != &Map->AssociatedBcb; Entry = Entry->Flink, Count++);
|
||||
|
||||
return Count;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcUninitializeCacheMap(IN PFILE_OBJECT FileObject,
|
||||
IN OPTIONAL PLARGE_INTEGER TruncateSize,
|
||||
IN OPTIONAL PCACHE_UNINITIALIZE_EVENT UninitializeEvent)
|
||||
{
|
||||
BOOLEAN LastMap = FALSE;
|
||||
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
PNOCC_PRIVATE_CACHE_MAP PrivateCacheMap = FileObject->PrivateCacheMap;
|
||||
|
||||
DPRINT("Uninitializing file object for %wZ SectionObjectPointer %x\n", &FileObject->FileName, FileObject->SectionObjectPointer);
|
||||
|
||||
ASSERT(UninitializeEvent == NULL);
|
||||
|
||||
if (Map)
|
||||
CcpFlushCache(Map, NULL, 0, NULL, FALSE);
|
||||
|
||||
CcpLock();
|
||||
if (PrivateCacheMap)
|
||||
{
|
||||
ASSERT(!Map || Map == PrivateCacheMap->Map);
|
||||
ASSERT(PrivateCacheMap->FileObject == FileObject);
|
||||
|
||||
RemoveEntryList(&PrivateCacheMap->ListEntry);
|
||||
if (IsListEmpty(&PrivateCacheMap->Map->PrivateCacheMaps))
|
||||
{
|
||||
while (!IsListEmpty(&Map->AssociatedBcb))
|
||||
{
|
||||
PNOCC_BCB Bcb = CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
|
||||
DPRINT("Evicting cache stripe #%x\n", Bcb - CcCacheSections);
|
||||
Bcb->RefCount = 1;
|
||||
CcpDereferenceCache(Bcb - CcCacheSections, TRUE);
|
||||
}
|
||||
RemoveEntryList(&PrivateCacheMap->Map->Entry);
|
||||
ExFreePool(PrivateCacheMap->Map);
|
||||
FileObject->SectionObjectPointer->SharedCacheMap = NULL;
|
||||
LastMap = TRUE;
|
||||
}
|
||||
ObDereferenceObject(PrivateCacheMap->FileObject);
|
||||
FileObject->PrivateCacheMap = NULL;
|
||||
ExFreePool(PrivateCacheMap);
|
||||
}
|
||||
CcpUnlock();
|
||||
|
||||
DPRINT("Uninit complete\n");
|
||||
|
||||
return LastMap;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcSetFileSizes(IN PFILE_OBJECT FileObject,
|
||||
IN PCC_FILE_SIZES FileSizes)
|
||||
{
|
||||
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
if (!Map) return;
|
||||
Map->FileSizes = *FileSizes;
|
||||
PNOCC_BCB Bcb = Map->AssociatedBcb.Flink == &Map->AssociatedBcb ?
|
||||
NULL : CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
|
||||
if (!Bcb) return;
|
||||
MmExtendCacheSection(Bcb->SectionObject, &FileSizes->FileSize, FALSE);
|
||||
DPRINT("FileSizes->FileSize %x\n", FileSizes->FileSize.LowPart);
|
||||
DPRINT("FileSizes->AllocationSize %x\n", FileSizes->AllocationSize.LowPart);
|
||||
DPRINT("FileSizes->ValidDataLength %x\n", FileSizes->ValidDataLength.LowPart);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcGetFileSizes
|
||||
(IN PFILE_OBJECT FileObject,
|
||||
IN PCC_FILE_SIZES FileSizes)
|
||||
{
|
||||
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
if (!Map) return FALSE;
|
||||
*FileSizes = Map->FileSizes;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcPurgeCacheSection(IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
||||
IN OPTIONAL PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN UninitializeCacheMaps)
|
||||
{
|
||||
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)SectionObjectPointer->SharedCacheMap;
|
||||
if (!Map) return TRUE;
|
||||
CcpFlushCache(Map, NULL, 0, NULL, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcSetDirtyPageThreshold(IN PFILE_OBJECT FileObject,
|
||||
IN ULONG DirtyPageThreshold)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcZeroData(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER StartOffset,
|
||||
IN PLARGE_INTEGER EndOffset,
|
||||
IN BOOLEAN Wait)
|
||||
{
|
||||
PNOCC_BCB Bcb = NULL;
|
||||
PLIST_ENTRY ListEntry = NULL;
|
||||
LARGE_INTEGER LowerBound = *StartOffset;
|
||||
LARGE_INTEGER UpperBound = *EndOffset;
|
||||
LARGE_INTEGER Target, End;
|
||||
PVOID PinnedBcb, PinnedBuffer;
|
||||
PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
|
||||
DPRINT
|
||||
("S %08x%08x E %08x%08x\n",
|
||||
StartOffset->u.HighPart, StartOffset->u.LowPart,
|
||||
EndOffset->u.HighPart, EndOffset->u.LowPart);
|
||||
|
||||
if (!Map)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
IO_STATUS_BLOCK IOSB;
|
||||
PCHAR ZeroBuf = ExAllocatePool(PagedPool, PAGE_SIZE);
|
||||
ULONG ToWrite;
|
||||
|
||||
if (!ZeroBuf) RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
|
||||
DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE);
|
||||
RtlZeroMemory(ZeroBuf, PAGE_SIZE);
|
||||
|
||||
Target.QuadPart = PAGE_ROUND_DOWN(LowerBound.QuadPart);
|
||||
End.QuadPart = PAGE_ROUND_UP(UpperBound.QuadPart);
|
||||
|
||||
// Handle leading page
|
||||
if (LowerBound.QuadPart != Target.QuadPart)
|
||||
{
|
||||
ToWrite = MIN(UpperBound.QuadPart - LowerBound.QuadPart, (PAGE_SIZE - LowerBound.QuadPart) & (PAGE_SIZE - 1));
|
||||
DPRINT("Zero last half %08x%08x %x\n", Target.u.HighPart, Target.u.LowPart, ToWrite);
|
||||
Status = MiSimpleRead(FileObject, &Target, ZeroBuf, PAGE_SIZE, &IOSB);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ExFreePool(ZeroBuf);
|
||||
RtlRaiseStatus(Status);
|
||||
}
|
||||
DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf + LowerBound.QuadPart - Target.QuadPart, ToWrite);
|
||||
RtlZeroMemory(ZeroBuf + LowerBound.QuadPart - Target.QuadPart, ToWrite);
|
||||
Status = MiSimpleWrite(FileObject, &Target, ZeroBuf, MIN(PAGE_SIZE,UpperBound.QuadPart-Target.QuadPart), &IOSB);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ExFreePool(ZeroBuf);
|
||||
RtlRaiseStatus(Status);
|
||||
}
|
||||
Target.QuadPart += PAGE_SIZE;
|
||||
}
|
||||
|
||||
DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, PAGE_SIZE);
|
||||
RtlZeroMemory(ZeroBuf, PAGE_SIZE);
|
||||
|
||||
while (UpperBound.QuadPart - Target.QuadPart > PAGE_SIZE)
|
||||
{
|
||||
DPRINT("Zero full page %08x%08x\n", Target.u.HighPart, Target.u.LowPart);
|
||||
Status = MiSimpleWrite(FileObject, &Target, ZeroBuf, PAGE_SIZE, &IOSB);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ExFreePool(ZeroBuf);
|
||||
RtlRaiseStatus(Status);
|
||||
}
|
||||
Target.QuadPart += PAGE_SIZE;
|
||||
}
|
||||
|
||||
if (UpperBound.QuadPart > Target.QuadPart)
|
||||
{
|
||||
ToWrite = UpperBound.QuadPart - Target.QuadPart;
|
||||
DPRINT("Zero first half %08x%08x %x\n", Target.u.HighPart, Target.u.LowPart, ToWrite);
|
||||
Status = MiSimpleRead(FileObject, &Target, ZeroBuf, PAGE_SIZE, &IOSB);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ExFreePool(ZeroBuf);
|
||||
RtlRaiseStatus(Status);
|
||||
}
|
||||
DPRINT1("RtlZeroMemory(%x,%x)\n", ZeroBuf, ToWrite);
|
||||
RtlZeroMemory(ZeroBuf, ToWrite);
|
||||
Status = MiSimpleWrite(FileObject, &Target, ZeroBuf, MIN(PAGE_SIZE, UpperBound.QuadPart-Target.QuadPart), &IOSB);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ExFreePool(ZeroBuf);
|
||||
RtlRaiseStatus(Status);
|
||||
}
|
||||
Target.QuadPart += PAGE_SIZE;
|
||||
}
|
||||
|
||||
ExFreePool(ZeroBuf);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
CcpLock();
|
||||
ListEntry = Map->AssociatedBcb.Flink;
|
||||
|
||||
while (ListEntry != &Map->AssociatedBcb)
|
||||
{
|
||||
Bcb = CONTAINING_RECORD(ListEntry, NOCC_BCB, ThisFileList);
|
||||
CcpReferenceCache(Bcb - CcCacheSections);
|
||||
|
||||
if (Bcb->FileOffset.QuadPart + Bcb->Length >= LowerBound.QuadPart &&
|
||||
Bcb->FileOffset.QuadPart < UpperBound.QuadPart)
|
||||
{
|
||||
DPRINT
|
||||
("Bcb #%x (@%08x%08x)\n",
|
||||
Bcb - CcCacheSections,
|
||||
Bcb->FileOffset.u.HighPart, Bcb->FileOffset.u.LowPart);
|
||||
|
||||
Target.QuadPart = MAX(Bcb->FileOffset.QuadPart, LowerBound.QuadPart);
|
||||
End.QuadPart = MIN(Map->FileSizes.ValidDataLength.QuadPart, UpperBound.QuadPart);
|
||||
End.QuadPart = MIN(End.QuadPart, Bcb->FileOffset.QuadPart + Bcb->Length);
|
||||
CcpUnlock();
|
||||
|
||||
if (!CcPreparePinWrite
|
||||
(FileObject,
|
||||
&Target,
|
||||
End.QuadPart - Target.QuadPart,
|
||||
TRUE,
|
||||
Wait,
|
||||
&PinnedBcb,
|
||||
&PinnedBuffer))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
ASSERT(PinnedBcb == Bcb);
|
||||
|
||||
CcpLock();
|
||||
ListEntry = ListEntry->Flink;
|
||||
// Return from pin state
|
||||
CcpUnpinData(PinnedBcb);
|
||||
}
|
||||
|
||||
CcpUnpinData(Bcb);
|
||||
}
|
||||
|
||||
CcpUnlock();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
PFILE_OBJECT
|
||||
NTAPI
|
||||
CcGetFileObjectFromSectionPtrs(IN PSECTION_OBJECT_POINTERS SectionObjectPointer)
|
||||
{
|
||||
PFILE_OBJECT Result = NULL;
|
||||
PNOCC_CACHE_MAP Map = SectionObjectPointer->SharedCacheMap;
|
||||
CcpLock();
|
||||
if (!IsListEmpty(&Map->AssociatedBcb))
|
||||
{
|
||||
PNOCC_BCB Bcb = CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList);
|
||||
Result = MmGetFileObjectForSection((PROS_SECTION_OBJECT)Bcb->SectionObject);
|
||||
}
|
||||
CcpUnlock();
|
||||
return Result;
|
||||
}
|
||||
|
||||
PFILE_OBJECT
|
||||
NTAPI
|
||||
CcGetFileObjectFromBcb(PVOID Bcb)
|
||||
{
|
||||
PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
|
||||
DPRINT("BCB #%x\n", RealBcb - CcCacheSections);
|
||||
return MmGetFileObjectForSection((PROS_SECTION_OBJECT)RealBcb->SectionObject);
|
||||
}
|
||||
|
||||
/* EOF */
|
36
reactos/ntoskrnl/cache/lazyrite.c
vendored
Normal file
36
reactos/ntoskrnl/cache/lazyrite.c
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel
|
||||
* FILE: ntoskrnl/cache/lazyrite.c
|
||||
* PURPOSE: Logging and configuration routines
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newcc.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
KEVENT CcpLazyWriteEvent;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID NTAPI
|
||||
CcpLazyWriteThread(PVOID Unused)
|
||||
{
|
||||
/* Not implemented */
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
CcWaitForCurrentLazyWriterActivity(VOID)
|
||||
{
|
||||
//KeWaitForSingleObject(&CcpLazyWriteEvent, Executive, KernelMode, FALSE, NULL);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* EOF */
|
75
reactos/ntoskrnl/cache/logsup.c
vendored
Normal file
75
reactos/ntoskrnl/cache/logsup.c
vendored
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel
|
||||
* FILE: ntoskrnl/cache/logsup.c
|
||||
* PURPOSE: Logging and configuration routines
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newcc.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcSetAdditionalCacheAttributes(IN PFILE_OBJECT FileObject,
|
||||
IN BOOLEAN DisableReadAhead,
|
||||
IN BOOLEAN DisableWriteBehind)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcSetLogHandleForFile(IN PFILE_OBJECT FileObject,
|
||||
IN PVOID LogHandle,
|
||||
IN PFLUSH_TO_LSN FlushToLsnRoutine)
|
||||
{
|
||||
PNOCC_CACHE_MAP Map = FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
if (!Map) return;
|
||||
Map->LogHandle = LogHandle;
|
||||
Map->FlushToLsn = FlushToLsnRoutine;
|
||||
}
|
||||
|
||||
LARGE_INTEGER
|
||||
NTAPI
|
||||
CcGetDirtyPages(IN PVOID LogHandle,
|
||||
IN PDIRTY_PAGE_ROUTINE DirtyPageRoutine,
|
||||
IN PVOID Context1,
|
||||
IN PVOID Context2)
|
||||
{
|
||||
LARGE_INTEGER Result = {{0}};
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
return Result;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcIsThereDirtyData(IN PVPB Vpb)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LARGE_INTEGER
|
||||
NTAPI
|
||||
CcGetLsnForFileObject(IN PFILE_OBJECT FileObject,
|
||||
OUT OPTIONAL PLARGE_INTEGER OldestLsn)
|
||||
{
|
||||
LARGE_INTEGER Result = {{0}};
|
||||
UNIMPLEMENTED;
|
||||
while (TRUE);
|
||||
return Result;
|
||||
}
|
||||
|
||||
/* EOF */
|
143
reactos/ntoskrnl/cache/mdlsup.c
vendored
Normal file
143
reactos/ntoskrnl/cache/mdlsup.c
vendored
Normal file
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel
|
||||
* FILE: ntoskrnl/cache/logsup.c
|
||||
* PURPOSE: Logging and configuration routines
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newcc.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
|
||||
PMDL
|
||||
NTAPI
|
||||
CcpBuildCacheMdl
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER FileOffset,
|
||||
ULONG Length,
|
||||
PIO_STATUS_BLOCK IOSB)
|
||||
{
|
||||
PMDL Mdl;
|
||||
PVOID Bcb, Buffer;
|
||||
|
||||
BOOLEAN Result = CcMapData
|
||||
(FileObject,
|
||||
FileOffset,
|
||||
Length,
|
||||
PIN_WAIT,
|
||||
&Bcb,
|
||||
&Buffer);
|
||||
|
||||
if (!Result)
|
||||
{
|
||||
IOSB->Information = 0;
|
||||
IOSB->Status = STATUS_UNSUCCESSFUL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IOSB->Information = Length;
|
||||
IOSB->Status = STATUS_SUCCESS;
|
||||
|
||||
Mdl = IoAllocateMdl
|
||||
(Buffer,
|
||||
Length,
|
||||
FALSE,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
if (!Mdl)
|
||||
{
|
||||
IOSB->Information = 0;
|
||||
IOSB->Status = STATUS_NO_MEMORY;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IOSB->Information = Length;
|
||||
IOSB->Status = STATUS_SUCCESS;
|
||||
|
||||
return Mdl;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcMdlRead(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
OUT PMDL *MdlChain,
|
||||
OUT PIO_STATUS_BLOCK IoStatus)
|
||||
{
|
||||
*MdlChain = CcpBuildCacheMdl
|
||||
(FileObject,
|
||||
FileOffset,
|
||||
Length,
|
||||
IoStatus);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcMdlReadComplete(IN PFILE_OBJECT FileObject,
|
||||
IN PMDL MdlChain)
|
||||
{
|
||||
IoFreeMdl(MdlChain);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcMdlReadComplete2(IN PMDL MdlChain,
|
||||
IN PFILE_OBJECT FileObject)
|
||||
{
|
||||
DPRINT("Not sure\n");
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcPrepareMdlWrite(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
OUT PMDL *MdlChain,
|
||||
OUT PIO_STATUS_BLOCK IoStatus)
|
||||
{
|
||||
*MdlChain = CcpBuildCacheMdl
|
||||
(FileObject,
|
||||
FileOffset,
|
||||
Length,
|
||||
IoStatus);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcMdlWriteComplete(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN PMDL MdlChain)
|
||||
{
|
||||
IoFreeMdl(MdlChain);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcMdlWriteComplete2(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN PMDL MdlChain)
|
||||
{
|
||||
DPRINT("Not sure\n");
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcMdlWriteAbort(IN PFILE_OBJECT FileObject,
|
||||
IN PMDL MdlChain)
|
||||
{
|
||||
ASSERT(FALSE);
|
||||
IoFreeMdl(MdlChain);
|
||||
}
|
||||
|
||||
/* EOF */
|
170
reactos/ntoskrnl/cache/newcc.h
vendored
Normal file
170
reactos/ntoskrnl/cache/newcc.h
vendored
Normal file
|
@ -0,0 +1,170 @@
|
|||
#pragma once
|
||||
|
||||
struct _MM_CACHE_SECTION_SEGMENT;
|
||||
|
||||
typedef struct _NOCC_BCB
|
||||
{
|
||||
/* Public part */
|
||||
PUBLIC_BCB Bcb;
|
||||
|
||||
struct _NOCC_CACHE_MAP *Map;
|
||||
struct _MM_CACHE_SECTION_SEGMENT *SectionObject;
|
||||
LARGE_INTEGER FileOffset;
|
||||
ULONG Length;
|
||||
PVOID BaseAddress;
|
||||
BOOLEAN Dirty;
|
||||
PVOID OwnerPointer;
|
||||
|
||||
/* Reference counts */
|
||||
ULONG RefCount;
|
||||
|
||||
LIST_ENTRY ThisFileList;
|
||||
|
||||
KEVENT ExclusiveWait;
|
||||
ULONG ExclusiveWaiter;
|
||||
BOOLEAN Exclusive;
|
||||
} NOCC_BCB, *PNOCC_BCB;
|
||||
|
||||
typedef struct _NOCC_CACHE_MAP
|
||||
{
|
||||
LIST_ENTRY Entry;
|
||||
LIST_ENTRY AssociatedBcb;
|
||||
LIST_ENTRY PrivateCacheMaps;
|
||||
ULONG NumberOfMaps;
|
||||
ULONG RefCount;
|
||||
CC_FILE_SIZES FileSizes;
|
||||
CACHE_MANAGER_CALLBACKS Callbacks;
|
||||
PVOID LazyContext;
|
||||
PVOID LogHandle;
|
||||
PFLUSH_TO_LSN FlushToLsn;
|
||||
ULONG ReadAheadGranularity;
|
||||
} NOCC_CACHE_MAP, *PNOCC_CACHE_MAP;
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcPfInitializePrefetcher(
|
||||
VOID
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcMdlReadComplete2(
|
||||
IN PMDL MemoryDescriptorList,
|
||||
IN PFILE_OBJECT FileObject
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcMdlWriteComplete2(
|
||||
IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN PMDL MdlChain
|
||||
);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcInitView(VOID);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcpUnpinData(PNOCC_BCB Bcb);
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcInitializeCacheManager(VOID);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcShutdownSystem();
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcInitCacheZeroPage(VOID);
|
||||
|
||||
/* Called by section.c */
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcFlushImageSection(PSECTION_OBJECT_POINTERS SectionObjectPointer, MMFLUSH_TYPE FlushType);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
_CcpFlushCache
|
||||
(IN PNOCC_CACHE_MAP Map,
|
||||
IN OPTIONAL PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
OUT OPTIONAL PIO_STATUS_BLOCK IoStatus,
|
||||
BOOLEAN Delete,
|
||||
const char *File,
|
||||
int Line);
|
||||
|
||||
#define CcpFlushCache(M,F,L,I,D) _CcpFlushCache(M,F,L,I,D,__FILE__,__LINE__)
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcGetFileSizes(PFILE_OBJECT FileObject, PCC_FILE_SIZES FileSizes);
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
CcpCountCacheSections(PNOCC_CACHE_MAP Map);
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcpAcquireFileLock(PNOCC_CACHE_MAP Map);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcpReleaseFileLock(PNOCC_CACHE_MAP Map);
|
||||
|
||||
/*
|
||||
* Macro for generic cache manage bugchecking. Note that this macro assumes
|
||||
* that the file name including extension is always longer than 4 characters.
|
||||
*/
|
||||
#define KEBUGCHECKCC \
|
||||
KEBUGCHECKEX(CACHE_MANAGER, \
|
||||
(*(ULONG*)(__FILE__ + sizeof(__FILE__) - 4) << 16) | \
|
||||
(__LINE__ & 0xFFFF), 0, 0, 0)
|
||||
|
||||
/* Private data */
|
||||
|
||||
#define CACHE_SINGLE_FILE_MAX (16)
|
||||
#define CACHE_OVERALL_SIZE (32 * 1024 * 1024)
|
||||
#define CACHE_STRIPE VACB_MAPPING_GRANULARITY
|
||||
#define CACHE_SHIFT 18
|
||||
#define CACHE_NUM_SECTIONS (CACHE_OVERALL_SIZE / CACHE_STRIPE)
|
||||
#define CACHE_ROUND_UP(x) (((x) + (CACHE_STRIPE-1)) & ~(CACHE_STRIPE-1))
|
||||
#define CACHE_ROUND_DOWN(x) ((x) & ~(CACHE_STRIPE-1))
|
||||
#define INVALID_CACHE ((ULONG)~0)
|
||||
|
||||
extern NOCC_BCB CcCacheSections[CACHE_NUM_SECTIONS];
|
||||
extern PRTL_BITMAP CcCacheBitmap;
|
||||
extern FAST_MUTEX CcMutex;
|
||||
extern KEVENT CcDeleteEvent;
|
||||
extern ULONG CcCacheClockHand;
|
||||
extern LIST_ENTRY CcPendingUnmap;
|
||||
extern KEVENT CcpLazyWriteEvent;
|
||||
|
||||
#define CcpLock() _CcpLock(__FILE__,__LINE__)
|
||||
#define CcpUnlock() _CcpUnlock(__FILE__,__LINE__)
|
||||
|
||||
extern VOID _CcpLock(const char *file, int line);
|
||||
extern VOID _CcpUnlock(const char *file, int line);
|
||||
|
||||
extern VOID CcpReferenceCache(ULONG Sector);
|
||||
extern VOID CcpDereferenceCache(ULONG Sector, BOOLEAN Immediate);
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcpMapData
|
||||
(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN ULONG Flags,
|
||||
OUT PVOID *BcbResult,
|
||||
OUT PVOID *Buffer);
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcpPinMappedData(IN PNOCC_CACHE_MAP Map,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN ULONG Flags,
|
||||
IN OUT PVOID *Bcb);
|
785
reactos/ntoskrnl/cache/pinsup.c
vendored
Normal file
785
reactos/ntoskrnl/cache/pinsup.c
vendored
Normal file
|
@ -0,0 +1,785 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS Kernel
|
||||
* FILE: ntoskrnl/cache/pinsup.c
|
||||
* PURPOSE: Logging and configuration routines
|
||||
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
* Art Yerkes
|
||||
*/
|
||||
|
||||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newcc.h"
|
||||
#include "section/newmm.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
/* The following is a test mode that only works with modified filesystems.
|
||||
* it maps the cache sections read only until they're pinned writable, and then
|
||||
* turns them readonly again when they're unpinned.
|
||||
* This helped me determine that a certain bug was not a memory overwrite. */
|
||||
//#define PIN_WRITE_ONLY
|
||||
|
||||
/* GLOBALS ********************************************************************/
|
||||
|
||||
#define TAG_MAP_SEC TAG('C', 'c', 'S', 'x')
|
||||
#define TAG_MAP_READ TAG('M', 'c', 'p', 'y')
|
||||
#define TAG_MAP_BCB TAG('B', 'c', 'b', ' ')
|
||||
|
||||
NOCC_BCB CcCacheSections[CACHE_NUM_SECTIONS];
|
||||
CHAR CcpBitmapBuffer[sizeof(RTL_BITMAP) + ROUND_UP((CACHE_NUM_SECTIONS), 32) / 8];
|
||||
PRTL_BITMAP CcCacheBitmap = (PRTL_BITMAP)&CcpBitmapBuffer;
|
||||
FAST_MUTEX CcMutex;
|
||||
KEVENT CcDeleteEvent;
|
||||
KEVENT CcFinalizeEvent;
|
||||
ULONG CcCacheClockHand;
|
||||
LONG CcOutstandingDeletes;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
PETHREAD LastThread;
|
||||
VOID _CcpLock(const char *file, int line)
|
||||
{
|
||||
//DPRINT("<<<---<<< CC In Mutex(%s:%d %x)!\n", file, line, PsGetCurrentThread());
|
||||
ExAcquireFastMutex(&CcMutex);
|
||||
}
|
||||
|
||||
VOID _CcpUnlock(const char *file, int line)
|
||||
{
|
||||
ExReleaseFastMutex(&CcMutex);
|
||||
//DPRINT(">>>--->>> CC Exit Mutex!\n", file, line);
|
||||
}
|
||||
|
||||
PDEVICE_OBJECT
|
||||
NTAPI
|
||||
MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject);
|
||||
|
||||
NTSTATUS CcpAllocateSection
|
||||
(PFILE_OBJECT FileObject,
|
||||
ULONG Length,
|
||||
ULONG Protect,
|
||||
PMM_CACHE_SECTION_SEGMENT *Result)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
LARGE_INTEGER MaxSize;
|
||||
|
||||
MaxSize.QuadPart = Length;
|
||||
|
||||
DPRINT("Making Section for File %x\n", FileObject);
|
||||
DPRINT("File name %wZ\n", &FileObject->FileName);
|
||||
Status = MmCreateCacheSection
|
||||
(Result,
|
||||
STANDARD_RIGHTS_REQUIRED,
|
||||
NULL,
|
||||
&MaxSize,
|
||||
Protect,
|
||||
SEC_RESERVE | SEC_CACHE,
|
||||
FileObject);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
typedef struct _WORK_QUEUE_WITH_CONTEXT
|
||||
{
|
||||
WORK_QUEUE_ITEM WorkItem;
|
||||
PVOID ToUnmap;
|
||||
LARGE_INTEGER FileOffset;
|
||||
LARGE_INTEGER MapSize;
|
||||
PMM_CACHE_SECTION_SEGMENT ToDeref;
|
||||
PACQUIRE_FOR_LAZY_WRITE AcquireForLazyWrite;
|
||||
PRELEASE_FROM_LAZY_WRITE ReleaseFromLazyWrite;
|
||||
PVOID LazyContext;
|
||||
BOOLEAN Dirty;
|
||||
} WORK_QUEUE_WITH_CONTEXT, *PWORK_QUEUE_WITH_CONTEXT;
|
||||
|
||||
VOID
|
||||
CcpUnmapCache(PVOID Context)
|
||||
{
|
||||
PWORK_QUEUE_WITH_CONTEXT WorkItem = (PWORK_QUEUE_WITH_CONTEXT)Context;
|
||||
DPRINT("Unmapping (finally) %x\n", WorkItem->ToUnmap);
|
||||
WorkItem->AcquireForLazyWrite(WorkItem->LazyContext, TRUE);
|
||||
MiFlushMappedSection(WorkItem->ToUnmap, &WorkItem->FileOffset, &WorkItem->MapSize, WorkItem->Dirty);
|
||||
WorkItem->ReleaseFromLazyWrite(WorkItem->LazyContext);
|
||||
MmUnmapCacheViewInSystemSpace(WorkItem->ToUnmap);
|
||||
MmFinalizeSegment(WorkItem->ToDeref);
|
||||
ExFreePool(WorkItem);
|
||||
DPRINT("Done\n");
|
||||
}
|
||||
|
||||
/* Must have acquired the mutex */
|
||||
VOID CcpDereferenceCache(ULONG Start, BOOLEAN Immediate)
|
||||
{
|
||||
PVOID ToUnmap;
|
||||
PNOCC_BCB Bcb;
|
||||
BOOLEAN Dirty;
|
||||
LARGE_INTEGER MappedSize;
|
||||
LARGE_INTEGER BaseOffset;
|
||||
PWORK_QUEUE_WITH_CONTEXT WorkItem;
|
||||
|
||||
DPRINT("CcpDereferenceCache(#%x)\n", Start);
|
||||
|
||||
Bcb = &CcCacheSections[Start];
|
||||
|
||||
Dirty = Bcb->Dirty;
|
||||
ToUnmap = Bcb->BaseAddress;
|
||||
BaseOffset = Bcb->FileOffset;
|
||||
MappedSize = Bcb->Map->FileSizes.ValidDataLength;
|
||||
|
||||
DPRINT("Dereference #%x (count %d)\n", Start, Bcb->RefCount);
|
||||
ASSERT(Bcb->SectionObject);
|
||||
ASSERT(Bcb->RefCount == 1);
|
||||
|
||||
DPRINT("Firing work item for %x\n", Bcb->BaseAddress);
|
||||
|
||||
if (Immediate)
|
||||
{
|
||||
PMM_CACHE_SECTION_SEGMENT ToDeref = Bcb->SectionObject;
|
||||
BOOLEAN Dirty = Bcb->Dirty;
|
||||
|
||||
Bcb->Map = NULL;
|
||||
Bcb->SectionObject = NULL;
|
||||
Bcb->BaseAddress = NULL;
|
||||
Bcb->FileOffset.QuadPart = 0;
|
||||
Bcb->Length = 0;
|
||||
Bcb->RefCount = 0;
|
||||
Bcb->Dirty = FALSE;
|
||||
RemoveEntryList(&Bcb->ThisFileList);
|
||||
|
||||
CcpUnlock();
|
||||
MiFlushMappedSection(ToUnmap, &BaseOffset, &MappedSize, Dirty);
|
||||
MmUnmapCacheViewInSystemSpace(ToUnmap);
|
||||
MmFinalizeSegment(ToDeref);
|
||||
CcpLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
WorkItem = ExAllocatePool(NonPagedPool, sizeof(*WorkItem));
|
||||
if (!WorkItem) KeBugCheck(0);
|
||||
WorkItem->ToUnmap = Bcb->BaseAddress;
|
||||
WorkItem->FileOffset = Bcb->FileOffset;
|
||||
WorkItem->Dirty = Bcb->Dirty;
|
||||
WorkItem->MapSize = MappedSize;
|
||||
WorkItem->ToDeref = Bcb->SectionObject;
|
||||
WorkItem->AcquireForLazyWrite = Bcb->Map->Callbacks.AcquireForLazyWrite;
|
||||
WorkItem->ReleaseFromLazyWrite = Bcb->Map->Callbacks.ReleaseFromLazyWrite;
|
||||
WorkItem->LazyContext = Bcb->Map->LazyContext;
|
||||
|
||||
ExInitializeWorkItem(((PWORK_QUEUE_ITEM)WorkItem), (PWORKER_THREAD_ROUTINE)CcpUnmapCache, WorkItem);
|
||||
|
||||
Bcb->Map = NULL;
|
||||
Bcb->SectionObject = NULL;
|
||||
Bcb->BaseAddress = NULL;
|
||||
Bcb->FileOffset.QuadPart = 0;
|
||||
Bcb->Length = 0;
|
||||
Bcb->RefCount = 0;
|
||||
Bcb->Dirty = FALSE;
|
||||
RemoveEntryList(&Bcb->ThisFileList);
|
||||
|
||||
CcpUnlock();
|
||||
ExQueueWorkItem((PWORK_QUEUE_ITEM)WorkItem, DelayedWorkQueue);
|
||||
CcpLock();
|
||||
}
|
||||
DPRINT("Done\n");
|
||||
}
|
||||
|
||||
/* Needs mutex */
|
||||
ULONG CcpAllocateCacheSections
|
||||
(PFILE_OBJECT FileObject,
|
||||
PMM_CACHE_SECTION_SEGMENT SectionObject)
|
||||
{
|
||||
ULONG i = INVALID_CACHE;
|
||||
PNOCC_CACHE_MAP Map;
|
||||
PNOCC_BCB Bcb;
|
||||
|
||||
DPRINT("AllocateCacheSections: FileObject %x\n", FileObject);
|
||||
|
||||
if (!FileObject->SectionObjectPointer)
|
||||
return INVALID_CACHE;
|
||||
|
||||
Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
|
||||
if (!Map)
|
||||
return INVALID_CACHE;
|
||||
|
||||
DPRINT("Allocating Cache Section\n");
|
||||
|
||||
i = RtlFindClearBitsAndSet(CcCacheBitmap, 1, CcCacheClockHand);
|
||||
CcCacheClockHand = (i + 1) % CACHE_NUM_SECTIONS;
|
||||
|
||||
if (i != INVALID_CACHE)
|
||||
{
|
||||
DPRINT("Setting up Bcb #%x\n", i);
|
||||
|
||||
Bcb = &CcCacheSections[i];
|
||||
|
||||
ASSERT(Bcb->RefCount < 2);
|
||||
|
||||
if (Bcb->RefCount > 0)
|
||||
{
|
||||
CcpDereferenceCache(i, FALSE);
|
||||
}
|
||||
|
||||
ASSERT(!Bcb->RefCount);
|
||||
Bcb->RefCount = 1;
|
||||
|
||||
DPRINT("Bcb #%x RefCount %d\n", Bcb - CcCacheSections, Bcb->RefCount);
|
||||
|
||||
if (!RtlTestBit(CcCacheBitmap, i))
|
||||
{
|
||||
DPRINT("Somebody stoeled BCB #%x\n", i);
|
||||
}
|
||||
ASSERT(RtlTestBit(CcCacheBitmap, i));
|
||||
|
||||
DPRINT("Allocated #%x\n", i);
|
||||
ASSERT(CcCacheSections[i].RefCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Failed to allocate cache segment\n");
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Must have acquired the mutex */
|
||||
VOID CcpReferenceCache(ULONG Start)
|
||||
{
|
||||
PNOCC_BCB Bcb;
|
||||
Bcb = &CcCacheSections[Start];
|
||||
ASSERT(Bcb->SectionObject);
|
||||
Bcb->RefCount++;
|
||||
RtlSetBit(CcCacheBitmap, Start);
|
||||
|
||||
}
|
||||
|
||||
VOID CcpMarkForExclusive(ULONG Start)
|
||||
{
|
||||
PNOCC_BCB Bcb;
|
||||
Bcb = &CcCacheSections[Start];
|
||||
Bcb->ExclusiveWaiter++;
|
||||
}
|
||||
|
||||
/* Must not have the mutex */
|
||||
VOID CcpReferenceCacheExclusive(ULONG Start)
|
||||
{
|
||||
PNOCC_BCB Bcb = &CcCacheSections[Start];
|
||||
|
||||
KeWaitForSingleObject(&Bcb->ExclusiveWait, Executive, KernelMode, FALSE, NULL);
|
||||
CcpLock();
|
||||
ASSERT(Bcb->ExclusiveWaiter);
|
||||
ASSERT(Bcb->SectionObject);
|
||||
Bcb->Exclusive = TRUE;
|
||||
Bcb->ExclusiveWaiter--;
|
||||
RtlSetBit(CcCacheBitmap, Start);
|
||||
CcpUnlock();
|
||||
}
|
||||
|
||||
/* Find a map that encompasses the target range */
|
||||
/* Must have the mutex */
|
||||
ULONG CcpFindMatchingMap(PLIST_ENTRY Head, PLARGE_INTEGER FileOffset, ULONG Length)
|
||||
{
|
||||
PLIST_ENTRY Entry;
|
||||
//DPRINT("Find Matching Map: (%x) %x:%x\n", FileOffset->LowPart, Length);
|
||||
for (Entry = Head->Flink; Entry != Head; Entry = Entry->Flink)
|
||||
{
|
||||
//DPRINT("Link @%x\n", Entry);
|
||||
PNOCC_BCB Bcb = CONTAINING_RECORD(Entry, NOCC_BCB, ThisFileList);
|
||||
//DPRINT("Selected BCB %x #%x\n", Bcb, Bcb - CcCacheSections);
|
||||
//DPRINT("This File: %x:%x\n", Bcb->FileOffset.LowPart, Bcb->Length);
|
||||
if (FileOffset->QuadPart >= Bcb->FileOffset.QuadPart &&
|
||||
FileOffset->QuadPart < Bcb->FileOffset.QuadPart + CACHE_STRIPE)
|
||||
{
|
||||
//DPRINT("Found match at #%x\n", Bcb - CcCacheSections);
|
||||
return Bcb - CcCacheSections;
|
||||
}
|
||||
}
|
||||
|
||||
//DPRINT("This region isn't mapped\n");
|
||||
|
||||
return INVALID_CACHE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcpMapData
|
||||
(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN ULONG Flags,
|
||||
OUT PVOID *BcbResult,
|
||||
OUT PVOID *Buffer)
|
||||
{
|
||||
BOOLEAN Success = FALSE, FaultIn = FALSE;
|
||||
/* Note: windows 2000 drivers treat this as a bool */
|
||||
//BOOLEAN Wait = (Flags & MAP_WAIT) || (Flags == TRUE);
|
||||
LARGE_INTEGER Target, EndInterval;
|
||||
ULONG BcbHead;
|
||||
PNOCC_BCB Bcb = NULL;
|
||||
PMM_CACHE_SECTION_SEGMENT SectionObject = NULL;
|
||||
NTSTATUS Status;
|
||||
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
|
||||
if (!Map)
|
||||
{
|
||||
DPRINT1("File object was not mapped\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DPRINT("CcMapData(F->%x,%08x%08x:%d)\n", FileObject, FileOffset->HighPart, FileOffset->LowPart, Length);
|
||||
|
||||
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
||||
|
||||
Target.HighPart = FileOffset->HighPart;
|
||||
Target.LowPart = CACHE_ROUND_DOWN(FileOffset->LowPart);
|
||||
|
||||
CcpLock();
|
||||
|
||||
/* Find out if any range is a superset of what we want */
|
||||
/* Find an accomodating section */
|
||||
BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
|
||||
|
||||
if (BcbHead != INVALID_CACHE)
|
||||
{
|
||||
Bcb = &CcCacheSections[BcbHead];
|
||||
Success = TRUE;
|
||||
*BcbResult = Bcb;
|
||||
*Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
|
||||
DPRINT
|
||||
("Bcb #%x Buffer maps (%08x%08x) At %x Length %x (Getting %x:%x) %wZ\n",
|
||||
Bcb - CcCacheSections,
|
||||
Bcb->FileOffset.HighPart,
|
||||
Bcb->FileOffset.LowPart,
|
||||
Bcb->BaseAddress,
|
||||
Bcb->Length,
|
||||
*Buffer,
|
||||
Length,
|
||||
&FileObject->FileName);
|
||||
DPRINT("w1n\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ULONG SectionSize;
|
||||
|
||||
DPRINT("File size %08x%08x\n", Map->FileSizes.ValidDataLength.HighPart, Map->FileSizes.ValidDataLength.LowPart);
|
||||
|
||||
if (Map->FileSizes.ValidDataLength.QuadPart)
|
||||
{
|
||||
SectionSize = min(CACHE_STRIPE, Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart);
|
||||
}
|
||||
else
|
||||
{
|
||||
SectionSize = CACHE_STRIPE;
|
||||
}
|
||||
|
||||
DPRINT("Allocating a cache stripe at %x:%d\n",
|
||||
Target.LowPart, SectionSize);
|
||||
//ASSERT(SectionSize <= CACHE_STRIPE);
|
||||
|
||||
CcpUnlock();
|
||||
Status = CcpAllocateSection
|
||||
(FileObject,
|
||||
SectionSize,
|
||||
#ifdef PIN_WRITE_ONLY
|
||||
PAGE_READONLY,
|
||||
#else
|
||||
PAGE_READWRITE,
|
||||
#endif
|
||||
&SectionObject);
|
||||
CcpLock();
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
*BcbResult = NULL;
|
||||
*Buffer = NULL;
|
||||
DPRINT1("End %08x\n", Status);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
retry:
|
||||
/* Returns a reference */
|
||||
DPRINT("Allocating cache sections: %wZ\n", &FileObject->FileName);
|
||||
BcbHead = CcpAllocateCacheSections(FileObject, SectionObject);
|
||||
if (BcbHead == INVALID_CACHE)
|
||||
{
|
||||
ULONG i;
|
||||
DbgPrint("Cache Map:");
|
||||
for (i = 0; i < CACHE_NUM_SECTIONS; i++)
|
||||
{
|
||||
if (!(i % 64)) DbgPrint("\n");
|
||||
DbgPrint("%c", CcCacheSections[i].RefCount + (RtlTestBit(CcCacheBitmap, i) ? '@' : '`'));
|
||||
}
|
||||
DbgPrint("\n");
|
||||
KeWaitForSingleObject(&CcDeleteEvent, Executive, KernelMode, FALSE, NULL);
|
||||
goto retry;
|
||||
}
|
||||
|
||||
DPRINT("BcbHead #%x (final)\n", BcbHead);
|
||||
|
||||
if (BcbHead == INVALID_CACHE)
|
||||
{
|
||||
*BcbResult = NULL;
|
||||
*Buffer = NULL;
|
||||
DPRINT1("End\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
DPRINT("Selected BCB #%x\n", BcbHead);
|
||||
ULONG ViewSize = CACHE_STRIPE;
|
||||
|
||||
Bcb = &CcCacheSections[BcbHead];
|
||||
Status = MmMapCacheViewInSystemSpaceAtOffset
|
||||
(SectionObject,
|
||||
&Bcb->BaseAddress,
|
||||
&Target,
|
||||
&ViewSize);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
*BcbResult = NULL;
|
||||
*Buffer = NULL;
|
||||
MmFinalizeSegment(SectionObject);
|
||||
RemoveEntryList(&Bcb->ThisFileList);
|
||||
RtlZeroMemory(Bcb, sizeof(*Bcb));
|
||||
RtlClearBit(CcCacheBitmap, BcbHead);
|
||||
DPRINT1("Failed to map\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
Success = TRUE;
|
||||
//DPRINT("w1n\n");
|
||||
|
||||
Bcb->Length = MIN(Map->FileSizes.ValidDataLength.QuadPart - Target.QuadPart, CACHE_STRIPE);
|
||||
Bcb->SectionObject = SectionObject;
|
||||
Bcb->Map = Map;
|
||||
Bcb->FileOffset = Target;
|
||||
InsertTailList(&Map->AssociatedBcb, &Bcb->ThisFileList);
|
||||
|
||||
*BcbResult = &CcCacheSections[BcbHead];
|
||||
*Buffer = ((PCHAR)Bcb->BaseAddress) + (int)(FileOffset->QuadPart - Bcb->FileOffset.QuadPart);
|
||||
FaultIn = TRUE;
|
||||
|
||||
DPRINT
|
||||
("Bcb #%x Buffer maps (%08x%08x) At %x Length %x (Getting %x:%x) %wZ\n",
|
||||
Bcb - CcCacheSections,
|
||||
Bcb->FileOffset.HighPart,
|
||||
Bcb->FileOffset.LowPart,
|
||||
Bcb->BaseAddress,
|
||||
Bcb->Length,
|
||||
*Buffer,
|
||||
Length,
|
||||
&FileObject->FileName);
|
||||
|
||||
EndInterval.QuadPart = Bcb->FileOffset.QuadPart + Bcb->Length - 1;
|
||||
ASSERT((EndInterval.QuadPart & ~(CACHE_STRIPE - 1)) == (Bcb->FileOffset.QuadPart & ~(CACHE_STRIPE - 1)));
|
||||
|
||||
//DPRINT("TERM!\n");
|
||||
|
||||
cleanup:
|
||||
CcpUnlock();
|
||||
if (Success)
|
||||
{
|
||||
if (FaultIn)
|
||||
{
|
||||
// Fault in the pages. This forces reads to happen now.
|
||||
ULONG i;
|
||||
CHAR Dummy;
|
||||
PCHAR FaultIn = Bcb->BaseAddress;
|
||||
DPRINT1
|
||||
("Faulting in pages at this point: file %wZ %08x%08x:%x\n",
|
||||
&FileObject->FileName,
|
||||
Bcb->FileOffset.HighPart,
|
||||
Bcb->FileOffset.LowPart,
|
||||
Bcb->Length);
|
||||
for (i = 0; i < Bcb->Length; i++)
|
||||
{
|
||||
Dummy = FaultIn[i];
|
||||
}
|
||||
}
|
||||
ASSERT(Bcb >= CcCacheSections && Bcb < (CcCacheSections + CACHE_NUM_SECTIONS));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcMapData
|
||||
(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN ULONG Flags,
|
||||
OUT PVOID *BcbResult,
|
||||
OUT PVOID *Buffer)
|
||||
{
|
||||
BOOLEAN Result;
|
||||
|
||||
Result = CcpMapData
|
||||
(FileObject,
|
||||
FileOffset,
|
||||
Length,
|
||||
Flags,
|
||||
BcbResult,
|
||||
Buffer);
|
||||
|
||||
if (Result)
|
||||
{
|
||||
PNOCC_BCB Bcb = (PNOCC_BCB)*BcbResult;
|
||||
ASSERT(Bcb >= CcCacheSections && Bcb < CcCacheSections + CACHE_NUM_SECTIONS);
|
||||
ASSERT(Bcb->BaseAddress);
|
||||
CcpLock();
|
||||
CcpReferenceCache(Bcb - CcCacheSections);
|
||||
CcpUnlock();
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcpPinMappedData(IN PNOCC_CACHE_MAP Map,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN ULONG Flags,
|
||||
IN OUT PVOID *Bcb)
|
||||
{
|
||||
BOOLEAN Exclusive = Flags & PIN_EXCLUSIVE;
|
||||
ULONG BcbHead;
|
||||
PNOCC_BCB TheBcb;
|
||||
|
||||
CcpLock();
|
||||
|
||||
ASSERT(Map->AssociatedBcb.Flink == &Map->AssociatedBcb || (CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList) >= CcCacheSections && CONTAINING_RECORD(Map->AssociatedBcb.Flink, NOCC_BCB, ThisFileList) < CcCacheSections + CACHE_NUM_SECTIONS));
|
||||
BcbHead = CcpFindMatchingMap(&Map->AssociatedBcb, FileOffset, Length);
|
||||
if (BcbHead == INVALID_CACHE)
|
||||
{
|
||||
CcpUnlock();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TheBcb = &CcCacheSections[BcbHead];
|
||||
|
||||
if (Exclusive)
|
||||
{
|
||||
DPRINT("Requesting #%x Exclusive\n", BcbHead);
|
||||
CcpMarkForExclusive(BcbHead);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Reference #%x\n", BcbHead);
|
||||
CcpReferenceCache(BcbHead);
|
||||
}
|
||||
|
||||
if (Exclusive)
|
||||
CcpReferenceCacheExclusive(BcbHead);
|
||||
|
||||
CcpUnlock();
|
||||
|
||||
*Bcb = TheBcb;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcPinMappedData(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN ULONG Flags,
|
||||
IN OUT PVOID *Bcb)
|
||||
{
|
||||
PVOID Buffer;
|
||||
PNOCC_CACHE_MAP Map = (PNOCC_CACHE_MAP)FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
|
||||
if (!Map)
|
||||
{
|
||||
DPRINT1("Not cached\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (CcpMapData(FileObject, FileOffset, Length, Flags, Bcb, &Buffer))
|
||||
{
|
||||
return CcpPinMappedData(Map, FileOffset, Length, Flags, Bcb);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("could not map\n");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcPinRead(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN ULONG Flags,
|
||||
OUT PVOID *Bcb,
|
||||
OUT PVOID *Buffer)
|
||||
{
|
||||
PNOCC_BCB RealBcb;
|
||||
BOOLEAN Result;
|
||||
|
||||
Result = CcPinMappedData
|
||||
(FileObject,
|
||||
FileOffset,
|
||||
Length,
|
||||
Flags,
|
||||
Bcb);
|
||||
|
||||
if (Result)
|
||||
{
|
||||
CcpLock();
|
||||
RealBcb = *Bcb;
|
||||
*Buffer = ((PCHAR)RealBcb->BaseAddress) + (int)(FileOffset->QuadPart - RealBcb->FileOffset.QuadPart);
|
||||
CcpUnlock();
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
CcPreparePinWrite(IN PFILE_OBJECT FileObject,
|
||||
IN PLARGE_INTEGER FileOffset,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN Zero,
|
||||
IN ULONG Flags,
|
||||
OUT PVOID *Bcb,
|
||||
OUT PVOID *Buffer)
|
||||
{
|
||||
BOOLEAN Result;
|
||||
PNOCC_BCB RealBcb;
|
||||
#ifdef PIN_WRITE_ONLY
|
||||
PVOID BaseAddress;
|
||||
SIZE_T NumberOfBytes;
|
||||
ULONG OldProtect;
|
||||
#endif
|
||||
|
||||
DPRINT1("CcPreparePinWrite(%x:%x)\n", Buffer, Length);
|
||||
|
||||
Result = CcPinRead
|
||||
(FileObject,
|
||||
FileOffset,
|
||||
Length,
|
||||
Flags,
|
||||
Bcb,
|
||||
Buffer);
|
||||
|
||||
if (Result)
|
||||
{
|
||||
CcpLock();
|
||||
RealBcb = *Bcb;
|
||||
|
||||
#ifdef PIN_WRITE_ONLY
|
||||
BaseAddress = RealBcb->BaseAddress;
|
||||
NumberOfBytes = RealBcb->Length;
|
||||
|
||||
MiProtectVirtualMemory
|
||||
(NULL,
|
||||
&BaseAddress,
|
||||
&NumberOfBytes,
|
||||
PAGE_READWRITE,
|
||||
&OldProtect);
|
||||
#endif
|
||||
|
||||
CcpUnlock();
|
||||
RealBcb->Dirty = TRUE;
|
||||
|
||||
if (Zero)
|
||||
{
|
||||
DPRINT
|
||||
("Zero fill #%x %08x%08x:%x Buffer %x %wZ\n",
|
||||
RealBcb - CcCacheSections,
|
||||
FileOffset->u.HighPart,
|
||||
FileOffset->u.LowPart,
|
||||
Length,
|
||||
*Buffer,
|
||||
&FileObject->FileName);
|
||||
|
||||
DPRINT1("RtlZeroMemory(%x,%x)\n", *Buffer, Length);
|
||||
RtlZeroMemory(*Buffer, Length);
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcpUnpinData(IN PNOCC_BCB RealBcb)
|
||||
{
|
||||
if (RealBcb->RefCount <= 2)
|
||||
{
|
||||
RealBcb->Exclusive = FALSE;
|
||||
if (RealBcb->ExclusiveWaiter)
|
||||
{
|
||||
DPRINT("Triggering exclusive waiter\n");
|
||||
KeSetEvent(&RealBcb->ExclusiveWait, IO_NO_INCREMENT, FALSE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (RealBcb->RefCount > 1)
|
||||
{
|
||||
DPRINT("Removing one reference #%x\n", RealBcb - CcCacheSections);
|
||||
RealBcb->RefCount--;
|
||||
KeSetEvent(&CcDeleteEvent, IO_DISK_INCREMENT, FALSE);
|
||||
}
|
||||
if (RealBcb->RefCount == 1)
|
||||
{
|
||||
DPRINT("Clearing allocation bit #%x\n", RealBcb - CcCacheSections);
|
||||
RtlClearBit(CcCacheBitmap, RealBcb - CcCacheSections);
|
||||
|
||||
#ifdef PIN_WRITE_ONLY
|
||||
PVOID BaseAddress = RealBcb->BaseAddress;
|
||||
SIZE_T NumberOfBytes = RealBcb->Length;
|
||||
ULONG OldProtect;
|
||||
|
||||
MiProtectVirtualMemory
|
||||
(NULL,
|
||||
&BaseAddress,
|
||||
&NumberOfBytes,
|
||||
PAGE_READONLY,
|
||||
&OldProtect);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcUnpinData(IN PVOID Bcb)
|
||||
{
|
||||
PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
|
||||
ULONG Selected = RealBcb - CcCacheSections;
|
||||
|
||||
ASSERT(RealBcb >= CcCacheSections && RealBcb - CcCacheSections < CACHE_NUM_SECTIONS);
|
||||
DPRINT("CcUnpinData Bcb #%x (RefCount %d)\n", Selected, RealBcb->RefCount);
|
||||
|
||||
CcpLock();
|
||||
CcpUnpinData(RealBcb);
|
||||
CcpUnlock();
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcSetBcbOwnerPointer(IN PVOID Bcb,
|
||||
IN PVOID OwnerPointer)
|
||||
{
|
||||
PNOCC_BCB RealBcb = (PNOCC_BCB)Bcb;
|
||||
CcpLock();
|
||||
CcpReferenceCache(RealBcb - CcCacheSections);
|
||||
RealBcb->OwnerPointer = OwnerPointer;
|
||||
CcpUnlock();
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CcUnpinDataForThread(IN PVOID Bcb,
|
||||
IN ERESOURCE_THREAD ResourceThreadId)
|
||||
{
|
||||
CcUnpinData(Bcb);
|
||||
}
|
||||
|
||||
/* EOF */
|
710
reactos/ntoskrnl/cache/section/data.c
vendored
Normal file
710
reactos/ntoskrnl/cache/section/data.c
vendored
Normal file
|
@ -0,0 +1,710 @@
|
|||
/*
|
||||
* Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/mm/section.c
|
||||
* PURPOSE: Implements section objects
|
||||
*
|
||||
* PROGRAMMERS: Rex Jolliff
|
||||
* David Welch
|
||||
* Eric Kohl
|
||||
* Emanuele Aliberti
|
||||
* Eugene Ingerman
|
||||
* Casper Hornstrup
|
||||
* KJK::Hyperion
|
||||
* Guido de Jong
|
||||
* Ge van Geldorp
|
||||
* Royce Mitchell III
|
||||
* Filip Navara
|
||||
* Aleksey Bragin
|
||||
* Jason Filby
|
||||
* Thomas Weidenmueller
|
||||
* Gunnar Andre' Dalsnes
|
||||
* Mike Nordell
|
||||
* Alex Ionescu
|
||||
* Gregor Anich
|
||||
* Steven Edwards
|
||||
* Herve Poussineau
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newmm.h"
|
||||
#include "../newcc.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#define DPRINTC DPRINT
|
||||
|
||||
extern KEVENT MpwThreadEvent;
|
||||
extern KSPIN_LOCK MiSectionPageTableLock;
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
ULONG_PTR MmSubsectionBase;
|
||||
BOOLEAN MmAllocationFragment;
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiSimpleRead
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER FileOffset,
|
||||
PVOID Buffer,
|
||||
ULONG Length,
|
||||
PIO_STATUS_BLOCK ReadStatus);
|
||||
|
||||
static const INFORMATION_CLASS_INFO ExSectionInfoClass[] =
|
||||
{
|
||||
ICI_SQ_SAME( sizeof(SECTION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionBasicInformation */
|
||||
ICI_SQ_SAME( sizeof(SECTION_IMAGE_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* SectionImageInformation */
|
||||
};
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
/* Note: Mmsp prefix denotes "Memory Manager Section Private". */
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
_MmLockCacheSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, const char *file, int line)
|
||||
{
|
||||
DPRINT("MmLockSectionSegment(%p,%s:%d)\n", Segment, file, line);
|
||||
ExAcquireFastMutex(&Segment->Lock);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
_MmUnlockCacheSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, const char *file, int line)
|
||||
{
|
||||
ExReleaseFastMutex(&Segment->Lock);
|
||||
DPRINT("MmUnlockSectionSegment(%p,%s:%d)\n", Segment, file, line);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiZeroFillSection
|
||||
(PVOID Address,
|
||||
PLARGE_INTEGER FileOffsetPtr,
|
||||
ULONG Length)
|
||||
{
|
||||
PFN_NUMBER Page;
|
||||
PMMSUPPORT AddressSpace;
|
||||
PMEMORY_AREA MemoryArea;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment;
|
||||
LARGE_INTEGER FileOffset = *FileOffsetPtr, End, FirstMapped;
|
||||
DPRINT1("MiZeroFillSection(Address %x,Offset %x,Length %x)\n", Address, FileOffset.LowPart, Length);
|
||||
AddressSpace = MmGetKernelAddressSpace();
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
|
||||
{
|
||||
return STATUS_NOT_MAPPED_DATA;
|
||||
}
|
||||
|
||||
Segment = MemoryArea->Data.CacheData.Segment;
|
||||
End.QuadPart = FileOffset.QuadPart + Length;
|
||||
End.LowPart = PAGE_ROUND_DOWN(End.LowPart);
|
||||
FileOffset.LowPart = PAGE_ROUND_UP(FileOffset.LowPart);
|
||||
FirstMapped.QuadPart = MemoryArea->Data.CacheData.ViewOffset.QuadPart;
|
||||
DPRINT
|
||||
("Pulling zero pages for %08x%08x-%08x%08x\n",
|
||||
FileOffset.u.HighPart, FileOffset.u.LowPart,
|
||||
End.u.HighPart, End.u.LowPart);
|
||||
while (FileOffset.QuadPart < End.QuadPart)
|
||||
{
|
||||
PVOID Address;
|
||||
ULONG Entry;
|
||||
|
||||
if (!NT_SUCCESS(MmRequestPageMemoryConsumer(MC_CACHE, TRUE, &Page)))
|
||||
break;
|
||||
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
|
||||
Entry = MiGetPageEntryCacheSectionSegment(Segment, &FileOffset);
|
||||
if (Entry == 0)
|
||||
{
|
||||
MiSetPageEntryCacheSectionSegment(Segment, &FileOffset, MAKE_PFN_SSE(Page));
|
||||
Address = ((PCHAR)MemoryArea->StartingAddress) + FileOffset.QuadPart - FirstMapped.QuadPart;
|
||||
MmReferencePage(Page);
|
||||
MmCreateVirtualMapping(NULL, Address, PAGE_READWRITE, &Page, 1);
|
||||
MmInsertRmap(Page, NULL, Address);
|
||||
}
|
||||
else
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, Page);
|
||||
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
|
||||
FileOffset.QuadPart += PAGE_SIZE;
|
||||
}
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiFlushMappedSection
|
||||
(PVOID BaseAddress,
|
||||
PLARGE_INTEGER BaseOffset,
|
||||
PLARGE_INTEGER FileSize,
|
||||
BOOLEAN WriteData,
|
||||
const char *File,
|
||||
int Line)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
ULONG_PTR PageAddress;
|
||||
PMMSUPPORT AddressSpace = MmGetKernelAddressSpace();
|
||||
PMEMORY_AREA MemoryArea;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment;
|
||||
ULONG_PTR BeginningAddress, EndingAddress;
|
||||
LARGE_INTEGER ViewOffset;
|
||||
LARGE_INTEGER FileOffset;
|
||||
PFN_NUMBER Page;
|
||||
PPFN_NUMBER Pages;
|
||||
|
||||
DPRINT1("MiFlushMappedSection(%x,%08x,%x,%d,%s:%d)\n", BaseAddress, BaseOffset->LowPart, FileSize, WriteData, File, Line);
|
||||
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
|
||||
if (!MemoryArea || MemoryArea->Type != MEMORY_AREA_SECTION_VIEW)
|
||||
{
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
return STATUS_NOT_MAPPED_DATA;
|
||||
}
|
||||
BeginningAddress = PAGE_ROUND_DOWN((ULONG_PTR)MemoryArea->StartingAddress);
|
||||
EndingAddress = PAGE_ROUND_UP((ULONG_PTR)MemoryArea->EndingAddress);
|
||||
Segment = MemoryArea->Data.CacheData.Segment;
|
||||
ViewOffset.QuadPart = MemoryArea->Data.CacheData.ViewOffset.QuadPart;
|
||||
|
||||
ASSERT(ViewOffset.QuadPart == BaseOffset->QuadPart);
|
||||
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
|
||||
Pages = ExAllocatePool
|
||||
(NonPagedPool,
|
||||
sizeof(PFN_NUMBER) *
|
||||
((EndingAddress - BeginningAddress) >> PAGE_SHIFT));
|
||||
|
||||
if (!Pages)
|
||||
{
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
for (PageAddress = BeginningAddress;
|
||||
PageAddress < EndingAddress;
|
||||
PageAddress += PAGE_SIZE)
|
||||
{
|
||||
ULONG Entry;
|
||||
FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
|
||||
Entry =
|
||||
MiGetPageEntryCacheSectionSegment
|
||||
(MemoryArea->Data.CacheData.Segment,
|
||||
&FileOffset);
|
||||
Page = PFN_FROM_SSE(Entry);
|
||||
if (Entry != 0 && !IS_SWAP_FROM_SSE(Entry) &&
|
||||
(MmIsDirtyPageRmap(Page) || IS_DIRTY_SSE(Entry)) &&
|
||||
FileOffset.QuadPart < FileSize->QuadPart)
|
||||
{
|
||||
Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = Page;
|
||||
}
|
||||
else
|
||||
Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT] = 0;
|
||||
}
|
||||
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
|
||||
for (PageAddress = BeginningAddress;
|
||||
PageAddress < EndingAddress;
|
||||
PageAddress += PAGE_SIZE)
|
||||
{
|
||||
FileOffset.QuadPart = ViewOffset.QuadPart + PageAddress - BeginningAddress;
|
||||
Page = Pages[(PageAddress - BeginningAddress) >> PAGE_SHIFT];
|
||||
if (Page)
|
||||
{
|
||||
ULONG Entry;
|
||||
if (WriteData) {
|
||||
DPRINT("MiWriteBackPage(%wZ,addr %x,%08x%08x)\n", &Segment->FileObject->FileName, PageAddress, FileOffset.u.HighPart, FileOffset.u.LowPart);
|
||||
Status = MiWriteBackPage(Segment->FileObject, &FileOffset, PAGE_SIZE, Page);
|
||||
} else
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
if (NT_SUCCESS(Status)) {
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
MmSetCleanAllRmaps(Page);
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
Entry = MiGetPageEntryCacheSectionSegment(Segment, &FileOffset);
|
||||
if (Entry && !IS_SWAP_FROM_SSE(Entry) && PFN_FROM_SSE(Entry) == Page)
|
||||
MiSetPageEntryCacheSectionSegment(Segment, &FileOffset, CLEAN_SSE(Entry));
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
} else {
|
||||
DPRINT
|
||||
("Writeback from section flush %08x%08x (%x) %x@%x (%08x%08x:%wZ) failed %x\n",
|
||||
FileOffset.u.HighPart, FileOffset.u.LowPart,
|
||||
(ULONG)(FileSize->QuadPart - FileOffset.QuadPart),
|
||||
PageAddress,
|
||||
Page,
|
||||
FileSize->u.HighPart,
|
||||
FileSize->u.LowPart,
|
||||
&Segment->FileObject->FileName,
|
||||
Status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePool(Pages);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmFinalizeSegment(PMM_CACHE_SECTION_SEGMENT Segment)
|
||||
{
|
||||
KIRQL OldIrql = 0;
|
||||
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
if (Segment->Flags & MM_DATAFILE_SEGMENT) {
|
||||
KeAcquireSpinLock(&Segment->FileObject->IrpListLock, &OldIrql);
|
||||
if (Segment->Flags & MM_SEGMENT_FINALIZE) {
|
||||
KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
return;
|
||||
} else {
|
||||
Segment->Flags |= MM_SEGMENT_FINALIZE;
|
||||
}
|
||||
}
|
||||
DPRINTC("Finalizing segment %x\n", Segment);
|
||||
if (Segment->Flags & MM_DATAFILE_SEGMENT)
|
||||
{
|
||||
//Segment->FileObject->SectionObjectPointer->DataSectionObject = NULL;
|
||||
KeReleaseSpinLock(&Segment->FileObject->IrpListLock, OldIrql);
|
||||
MiFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
ObDereferenceObject(Segment->FileObject);
|
||||
} else {
|
||||
MiFreePageTablesSectionSegment(Segment, MiFreeSegmentPage);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
}
|
||||
DPRINTC("Segment %x destroy\n", Segment);
|
||||
ExFreePool(Segment);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmCreateCacheSection
|
||||
(PMM_CACHE_SECTION_SEGMENT *SegmentObject,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
PLARGE_INTEGER UMaximumSize,
|
||||
ULONG SectionPageProtection,
|
||||
ULONG AllocationAttributes,
|
||||
PFILE_OBJECT FileObject)
|
||||
/*
|
||||
* Create a section backed by a data file
|
||||
*/
|
||||
{
|
||||
NTSTATUS Status;
|
||||
ULARGE_INTEGER MaximumSize;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment;
|
||||
ULONG FileAccess;
|
||||
IO_STATUS_BLOCK Iosb;
|
||||
CC_FILE_SIZES FileSizes;
|
||||
FILE_STANDARD_INFORMATION FileInfo;
|
||||
|
||||
/*
|
||||
* Check file access required
|
||||
*/
|
||||
if (SectionPageProtection & PAGE_READWRITE ||
|
||||
SectionPageProtection & PAGE_EXECUTE_READWRITE)
|
||||
{
|
||||
FileAccess = FILE_READ_DATA | FILE_WRITE_DATA;
|
||||
}
|
||||
else
|
||||
{
|
||||
FileAccess = FILE_READ_DATA;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reference the file handle
|
||||
*/
|
||||
ObReferenceObject(FileObject);
|
||||
|
||||
DPRINT("Getting original file size\n");
|
||||
/* A hack: If we're cached, we can overcome deadlocking with the upper
|
||||
* layer filesystem call by retriving the object sizes from the cache
|
||||
* which is made to keep track. If I had to guess, they were figuring
|
||||
* out a similar problem.
|
||||
*/
|
||||
if (!CcGetFileSizes(FileObject, &FileSizes))
|
||||
{
|
||||
/*
|
||||
* FIXME: This is propably not entirely correct. We can't look into
|
||||
* the standard FCB header because it might not be initialized yet
|
||||
* (as in case of the EXT2FS driver by Manoj Paul Joseph where the
|
||||
* standard file information is filled on first request).
|
||||
*/
|
||||
Status = IoQueryFileInformation
|
||||
(FileObject,
|
||||
FileStandardInformation,
|
||||
sizeof(FILE_STANDARD_INFORMATION),
|
||||
&FileInfo,
|
||||
&Iosb.Information);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
|
||||
ASSERT(Status != STATUS_PENDING);
|
||||
|
||||
FileSizes.ValidDataLength = FileInfo.EndOfFile;
|
||||
FileSizes.FileSize = FileInfo.EndOfFile;
|
||||
}
|
||||
DPRINT("Got %08x\n", FileSizes.ValidDataLength.u.LowPart);
|
||||
|
||||
/*
|
||||
* FIXME: Revise this once a locking order for file size changes is
|
||||
* decided
|
||||
*/
|
||||
if (UMaximumSize != NULL)
|
||||
{
|
||||
MaximumSize.QuadPart = UMaximumSize->QuadPart;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Got file size %08x%08x\n", FileSizes.FileSize.u.HighPart, FileSizes.FileSize.u.LowPart);
|
||||
MaximumSize.QuadPart = FileSizes.FileSize.QuadPart;
|
||||
}
|
||||
|
||||
Segment = ExAllocatePoolWithTag(NonPagedPool, sizeof(MM_CACHE_SECTION_SEGMENT),
|
||||
TAG_MM_SECTION_SEGMENT);
|
||||
if (Segment == NULL)
|
||||
{
|
||||
return(STATUS_NO_MEMORY);
|
||||
}
|
||||
|
||||
ExInitializeFastMutex(&Segment->Lock);
|
||||
|
||||
Segment->ReferenceCount = 1;
|
||||
|
||||
/*
|
||||
* Set the lock before assigning the segment to the file object
|
||||
*/
|
||||
ExAcquireFastMutex(&Segment->Lock);
|
||||
|
||||
DPRINT("Filling out Segment info (No previous data section)\n");
|
||||
ObReferenceObject(FileObject);
|
||||
Segment->FileObject = FileObject;
|
||||
Segment->Protection = SectionPageProtection;
|
||||
Segment->Flags = MM_DATAFILE_SEGMENT;
|
||||
memset(&Segment->Image, 0, sizeof(Segment->Image));
|
||||
Segment->WriteCopy = FALSE;
|
||||
if (AllocationAttributes & SEC_RESERVE)
|
||||
{
|
||||
Segment->Length.QuadPart = Segment->RawLength.QuadPart = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Segment->RawLength = MaximumSize;
|
||||
Segment->Length.QuadPart = PAGE_ROUND_UP(Segment->RawLength.QuadPart);
|
||||
}
|
||||
|
||||
MiInitializeSectionPageTable(Segment);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
|
||||
/* Extend file if section is longer */
|
||||
DPRINT("MaximumSize %08x%08x ValidDataLength %08x%08x\n",
|
||||
MaximumSize.u.HighPart, MaximumSize.u.LowPart,
|
||||
FileSizes.ValidDataLength.u.HighPart, FileSizes.ValidDataLength.u.LowPart);
|
||||
if (MaximumSize.QuadPart > FileSizes.ValidDataLength.QuadPart)
|
||||
{
|
||||
DPRINT("Changing file size to %08x%08x, segment %x\n", MaximumSize.u.HighPart, MaximumSize.u.LowPart, Segment);
|
||||
Status = IoSetInformation(FileObject, FileEndOfFileInformation, sizeof(LARGE_INTEGER), &MaximumSize);
|
||||
DPRINT("Change: Status %x\n", Status);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Could not expand section\n");
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINTC("Segment %x created (%x)\n", Segment, Segment->Flags);
|
||||
|
||||
*SegmentObject = Segment;
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiMapViewOfSegment
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
PVOID* BaseAddress,
|
||||
SIZE_T ViewSize,
|
||||
ULONG Protect,
|
||||
PLARGE_INTEGER ViewOffset,
|
||||
ULONG AllocationType,
|
||||
const char *file,
|
||||
int line)
|
||||
{
|
||||
PMEMORY_AREA MArea;
|
||||
NTSTATUS Status;
|
||||
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
||||
|
||||
BoundaryAddressMultiple.QuadPart = 0;
|
||||
|
||||
Status = MmCreateMemoryArea
|
||||
(AddressSpace,
|
||||
MEMORY_AREA_CACHE,
|
||||
BaseAddress,
|
||||
ViewSize,
|
||||
Protect,
|
||||
&MArea,
|
||||
FALSE,
|
||||
AllocationType,
|
||||
BoundaryAddressMultiple);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Mapping between 0x%.8X and 0x%.8X failed (%X).\n",
|
||||
(*BaseAddress), (char*)(*BaseAddress) + ViewSize, Status);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
DPRINTC("MiMapViewOfSegment %x %x %x %x %x %wZ %s:%d\n", MmGetAddressSpaceOwner(AddressSpace), *BaseAddress, Segment, ViewOffset ? ViewOffset->LowPart : 0, ViewSize, Segment->FileObject ? &Segment->FileObject->FileName : NULL, file, line);
|
||||
|
||||
MArea->Data.CacheData.Segment = Segment;
|
||||
if (ViewOffset)
|
||||
MArea->Data.CacheData.ViewOffset = *ViewOffset;
|
||||
else
|
||||
MArea->Data.CacheData.ViewOffset.QuadPart = 0;
|
||||
|
||||
#if 0
|
||||
MArea->NotPresent = MmNotPresentFaultPageFile;
|
||||
MArea->AccessFault = MiCowSectionPage;
|
||||
MArea->PageOut = MmPageOutPageFileView;
|
||||
#endif
|
||||
|
||||
DPRINTC
|
||||
("MiMapViewOfSegment(P %x, A %x, T %x)\n",
|
||||
MmGetAddressSpaceOwner(AddressSpace), *BaseAddress, MArea->Type);
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiFreeSegmentPage
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
PLARGE_INTEGER FileOffset)
|
||||
{
|
||||
ULONG Entry;
|
||||
PFILE_OBJECT FileObject = Segment->FileObject;
|
||||
|
||||
Entry = MiGetPageEntryCacheSectionSegment(Segment, FileOffset);
|
||||
DPRINTC("MiFreeSegmentPage(%x:%08x%08x -> Entry %x\n",
|
||||
Segment, FileOffset->HighPart, FileOffset->LowPart, Entry);
|
||||
|
||||
if (Entry && !IS_SWAP_FROM_SSE(Entry))
|
||||
{
|
||||
// The segment is carrying a dirty page.
|
||||
PFN_NUMBER OldPage = PFN_FROM_SSE(Entry);
|
||||
if (IS_DIRTY_SSE(Entry) && FileObject)
|
||||
{
|
||||
DPRINT("MiWriteBackPage(%x,%wZ,%08x%08x)\n", Segment, &FileObject->FileName, FileOffset->u.HighPart, FileOffset->u.LowPart);
|
||||
MiWriteBackPage(FileObject, FileOffset, PAGE_SIZE, OldPage);
|
||||
}
|
||||
DPRINTC("Free page %x (off %x from %x) (ref ct %d, ent %x, dirty? %s)\n", OldPage, FileOffset->LowPart, Segment, MmGetReferenceCountPage(OldPage), Entry, IS_DIRTY_SSE(Entry) ? "true" : "false");
|
||||
|
||||
MiSetPageEntryCacheSectionSegment(Segment, FileOffset, 0);
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, OldPage);
|
||||
}
|
||||
else if (IS_SWAP_FROM_SSE(Entry))
|
||||
{
|
||||
DPRINT("Free swap\n");
|
||||
MmFreeSwapPage(SWAPENTRY_FROM_SSE(Entry));
|
||||
}
|
||||
|
||||
DPRINT("Done\n");
|
||||
}
|
||||
|
||||
VOID
|
||||
MmFreeCacheSectionPage
|
||||
(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
|
||||
PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty)
|
||||
{
|
||||
ULONG Entry;
|
||||
PVOID *ContextData = Context;
|
||||
PMMSUPPORT AddressSpace;
|
||||
PEPROCESS Process;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment;
|
||||
LARGE_INTEGER Offset;
|
||||
|
||||
DPRINT("MmFreeSectionPage(%x,%x,%x,%x,%d)\n", MmGetAddressSpaceOwner(ContextData[0]), Address, Page, SwapEntry, Dirty);
|
||||
|
||||
AddressSpace = ContextData[0];
|
||||
Process = MmGetAddressSpaceOwner(AddressSpace);
|
||||
Address = (PVOID)PAGE_ROUND_DOWN(Address);
|
||||
Segment = ContextData[1];
|
||||
Offset.QuadPart = (ULONG_PTR)Address - (ULONG_PTR)MemoryArea->StartingAddress +
|
||||
MemoryArea->Data.CacheData.ViewOffset.QuadPart;
|
||||
|
||||
Entry = MiGetPageEntryCacheSectionSegment(Segment, &Offset);
|
||||
|
||||
if (Page)
|
||||
{
|
||||
DPRINT("Removing page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
|
||||
MmSetSavedSwapEntryPage(Page, 0);
|
||||
MmDeleteRmap(Page, Process, Address);
|
||||
MmDeleteVirtualMapping(Process, Address, FALSE, NULL, NULL);
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, Page);
|
||||
}
|
||||
if (Page != 0 && PFN_FROM_SSE(Entry) == Page && Dirty)
|
||||
{
|
||||
DPRINT("Freeing section page %x:%x -> %x\n", Segment, Offset.LowPart, Entry);
|
||||
MiSetPageEntryCacheSectionSegment(Segment, &Offset, DIRTY_SSE(Entry));
|
||||
}
|
||||
else if (SwapEntry != 0)
|
||||
{
|
||||
MmFreeSwapPage(SwapEntry);
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmUnmapViewOfCacheSegment
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PVOID BaseAddress)
|
||||
{
|
||||
PVOID Context[2];
|
||||
PMEMORY_AREA MemoryArea;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment;
|
||||
|
||||
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, BaseAddress);
|
||||
if (MemoryArea == NULL)
|
||||
{
|
||||
ASSERT(MemoryArea);
|
||||
return(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
MemoryArea->DeleteInProgress = TRUE;
|
||||
Segment = MemoryArea->Data.CacheData.Segment;
|
||||
MemoryArea->Data.CacheData.Segment = NULL;
|
||||
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
|
||||
Context[0] = AddressSpace;
|
||||
Context[1] = Segment;
|
||||
DPRINT("MmFreeMemoryArea(%x,%x)\n", MmGetAddressSpaceOwner(AddressSpace), MemoryArea->StartingAddress);
|
||||
MmFreeMemoryArea(AddressSpace, MemoryArea, MmFreeCacheSectionPage, Context);
|
||||
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
|
||||
DPRINTC("MiUnmapViewOfSegment %x %x %x\n", MmGetAddressSpaceOwner(AddressSpace), BaseAddress, Segment);
|
||||
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmExtendCacheSection
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
PLARGE_INTEGER NewSize,
|
||||
BOOLEAN ExtendFile)
|
||||
{
|
||||
LARGE_INTEGER OldSize;
|
||||
DPRINT("Extend Segment %x\n", Segment);
|
||||
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
OldSize.QuadPart = Segment->RawLength.QuadPart;
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
|
||||
DPRINT("OldSize %08x%08x NewSize %08x%08x\n",
|
||||
OldSize.u.HighPart, OldSize.u.LowPart,
|
||||
NewSize->u.HighPart, NewSize->u.LowPart);
|
||||
|
||||
if (ExtendFile && OldSize.QuadPart < NewSize->QuadPart)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
Status = IoSetInformation(Segment->FileObject, FileEndOfFileInformation, sizeof(LARGE_INTEGER), NewSize);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
Segment->RawLength.QuadPart = NewSize->QuadPart;
|
||||
Segment->Length.QuadPart = MAX(Segment->Length.QuadPart, PAGE_ROUND_UP(Segment->RawLength.LowPart));
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmMapCacheViewInSystemSpaceAtOffset
|
||||
(IN PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
OUT PVOID *MappedBase,
|
||||
PLARGE_INTEGER FileOffset,
|
||||
IN OUT PULONG ViewSize)
|
||||
{
|
||||
PMMSUPPORT AddressSpace;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT("MmMapViewInSystemSpaceAtOffset() called offset %08x%08x\n", FileOffset->HighPart, FileOffset->LowPart);
|
||||
|
||||
AddressSpace = MmGetKernelAddressSpace();
|
||||
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
|
||||
Status = MiMapViewOfSegment
|
||||
(AddressSpace,
|
||||
Segment,
|
||||
MappedBase,
|
||||
*ViewSize,
|
||||
PAGE_READWRITE,
|
||||
FileOffset,
|
||||
0);
|
||||
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS NTAPI
|
||||
MmUnmapCacheViewInSystemSpace (IN PVOID MappedBase)
|
||||
{
|
||||
PMMSUPPORT AddressSpace;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT("MmUnmapViewInSystemSpace() called\n");
|
||||
|
||||
AddressSpace = MmGetKernelAddressSpace();
|
||||
|
||||
Status = MmUnmapViewOfCacheSegment(AddressSpace, MappedBase);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* EOF */
|
728
reactos/ntoskrnl/cache/section/fault.c
vendored
Normal file
728
reactos/ntoskrnl/cache/section/fault.c
vendored
Normal file
|
@ -0,0 +1,728 @@
|
|||
/*
|
||||
* Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/mm/section/fault.c
|
||||
* PURPOSE: Consolidate fault handlers for sections
|
||||
*
|
||||
* PROGRAMMERS: Arty
|
||||
* Rex Jolliff
|
||||
* David Welch
|
||||
* Eric Kohl
|
||||
* Emanuele Aliberti
|
||||
* Eugene Ingerman
|
||||
* Casper Hornstrup
|
||||
* KJK::Hyperion
|
||||
* Guido de Jong
|
||||
* Ge van Geldorp
|
||||
* Royce Mitchell III
|
||||
* Filip Navara
|
||||
* Aleksey Bragin
|
||||
* Jason Filby
|
||||
* Thomas Weidenmueller
|
||||
* Gunnar Andre' Dalsnes
|
||||
* Mike Nordell
|
||||
* Alex Ionescu
|
||||
* Gregor Anich
|
||||
* Steven Edwards
|
||||
* Herve Poussineau
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newmm.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#define DPRINTC DPRINT
|
||||
|
||||
extern KEVENT MmWaitPageEvent;
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmNotPresentFaultCachePage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
MEMORY_AREA* MemoryArea,
|
||||
PVOID Address,
|
||||
BOOLEAN Locked,
|
||||
PMM_REQUIRED_RESOURCES Required)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PVOID PAddress;
|
||||
ULONG Consumer;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment;
|
||||
LARGE_INTEGER FileOffset, TotalOffset;
|
||||
ULONG Entry;
|
||||
ULONG Attributes;
|
||||
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
||||
|
||||
DPRINT("Not Present: %p %p (%p-%p)\n", AddressSpace, Address, MemoryArea->StartingAddress, MemoryArea->EndingAddress);
|
||||
|
||||
/*
|
||||
* There is a window between taking the page fault and locking the
|
||||
* address space when another thread could load the page so we check
|
||||
* that.
|
||||
*/
|
||||
if (MmIsPagePresent(Process, Address))
|
||||
{
|
||||
DPRINT("Done\n");
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
|
||||
TotalOffset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress;
|
||||
|
||||
Segment = MemoryArea->Data.CacheData.Segment;
|
||||
|
||||
TotalOffset.QuadPart += MemoryArea->Data.CacheData.ViewOffset.QuadPart;
|
||||
FileOffset = TotalOffset;
|
||||
|
||||
//Consumer = (Segment->Flags & MM_DATAFILE_SEGMENT) ? MC_CACHE : MC_USER;
|
||||
Consumer = MC_CACHE;
|
||||
|
||||
if (Segment->FileObject)
|
||||
{
|
||||
DPRINT("FileName %wZ\n", &Segment->FileObject->FileName);
|
||||
}
|
||||
|
||||
DPRINT("Total Offset %08x%08x\n", TotalOffset.HighPart, TotalOffset.LowPart);
|
||||
|
||||
/*
|
||||
* Lock the segment
|
||||
*/
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
|
||||
/*
|
||||
* Get the entry corresponding to the offset within the section
|
||||
*/
|
||||
Entry = MiGetPageEntryCacheSectionSegment(Segment, &TotalOffset);
|
||||
|
||||
Attributes = PAGE_READONLY;
|
||||
|
||||
if (Required->State && Required->Page[0])
|
||||
{
|
||||
DPRINT("Have file and page, set page %x in section @ %x #\n", Required->Page[0], TotalOffset.LowPart);
|
||||
|
||||
if (Required->SwapEntry)
|
||||
MmSetSavedSwapEntryPage(Required->Page[0], Required->SwapEntry);
|
||||
|
||||
if (Required->State & 2)
|
||||
{
|
||||
DPRINT("Set in section @ %x\n", TotalOffset.LowPart);
|
||||
Status = MiSetPageEntryCacheSectionSegment
|
||||
(Segment, &TotalOffset, Entry = MAKE_PFN_SSE(Required->Page[0]));
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, Required->Page[0]);
|
||||
}
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
MiSetPageEvent(Process, Address);
|
||||
DPRINT("Status %x\n", Status);
|
||||
return STATUS_MM_RESTART_OPERATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Set %x in address space @ %x\n", Required->Page[0], Address);
|
||||
Status = MmCreateVirtualMapping(Process, Address, Attributes, Required->Page, 1);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
MmInsertRmap(Required->Page[0], Process, Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Drop the reference for our address space ...
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, Required->Page[0]);
|
||||
}
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
DPRINTC("XXX Set Event %x\n", Status);
|
||||
MiSetPageEvent(Process, Address);
|
||||
DPRINT("Status %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
else if (Entry)
|
||||
{
|
||||
PFN_NUMBER Page = PFN_FROM_SSE(Entry);
|
||||
DPRINT("Take reference to page %x #\n", Page);
|
||||
|
||||
MmReferencePage(Page);
|
||||
|
||||
Status = MmCreateVirtualMapping(Process, Address, Attributes, &Page, 1);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
MmInsertRmap(Page, Process, Address);
|
||||
}
|
||||
DPRINT("XXX Set Event %x\n", Status);
|
||||
MiSetPageEvent(Process, Address);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
DPRINT("Status %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Get page into section\n");
|
||||
/*
|
||||
* If the entry is zero (and it can't change because we have
|
||||
* locked the segment) then we need to load the page.
|
||||
*/
|
||||
//DPRINT1("Read from file %08x %wZ\n", FileOffset.LowPart, &Section->FileObject->FileName);
|
||||
Required->State = 2;
|
||||
Required->Context = Segment->FileObject;
|
||||
Required->Consumer = Consumer;
|
||||
Required->FileOffset = FileOffset;
|
||||
Required->Amount = PAGE_SIZE;
|
||||
Required->DoAcquisition = MiReadFilePage;
|
||||
MiSetPageEntryCacheSectionSegment(Segment, &TotalOffset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
ASSERT(FALSE);
|
||||
return STATUS_ACCESS_VIOLATION;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiCopyPageToPage(PFN_NUMBER DestPage, PFN_NUMBER SrcPage)
|
||||
{
|
||||
PEPROCESS Process;
|
||||
KIRQL Irql, Irql2;
|
||||
PVOID TempAddress, TempSource;
|
||||
|
||||
Process = PsGetCurrentProcess();
|
||||
TempAddress = MiMapPageInHyperSpace(Process, DestPage, &Irql);
|
||||
if (TempAddress == NULL)
|
||||
{
|
||||
return(STATUS_NO_MEMORY);
|
||||
}
|
||||
TempSource = MiMapPageInHyperSpace(Process, SrcPage, &Irql2);
|
||||
if (!TempSource) {
|
||||
MiUnmapPageInHyperSpace(Process, TempAddress, Irql);
|
||||
return(STATUS_NO_MEMORY);
|
||||
}
|
||||
|
||||
memcpy(TempAddress, TempSource, PAGE_SIZE);
|
||||
|
||||
MiUnmapPageInHyperSpace(Process, TempSource, Irql2);
|
||||
MiUnmapPageInHyperSpace(Process, TempAddress, Irql);
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiCowCacheSectionPage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PVOID Address,
|
||||
BOOLEAN Locked,
|
||||
PMM_REQUIRED_RESOURCES Required)
|
||||
{
|
||||
PMM_CACHE_SECTION_SEGMENT Segment;
|
||||
PFN_NUMBER NewPage, OldPage;
|
||||
NTSTATUS Status;
|
||||
PVOID PAddress;
|
||||
LARGE_INTEGER Offset;
|
||||
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
||||
|
||||
DPRINT("MmAccessFaultSectionView(%x, %x, %x, %x)\n", AddressSpace, MemoryArea, Address, Locked);
|
||||
|
||||
Segment = MemoryArea->Data.CacheData.Segment;
|
||||
|
||||
/*
|
||||
* Lock the segment
|
||||
*/
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
|
||||
/*
|
||||
* Find the offset of the page
|
||||
*/
|
||||
PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
|
||||
Offset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress +
|
||||
MemoryArea->Data.CacheData.ViewOffset.QuadPart;
|
||||
|
||||
if (!Required->Page[0])
|
||||
{
|
||||
SWAPENTRY SwapEntry;
|
||||
if (MmIsPageSwapEntry(Process, Address))
|
||||
{
|
||||
MmGetPageFileMapping(Process, Address, &SwapEntry);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
if (SwapEntry == MM_WAIT_ENTRY)
|
||||
return STATUS_SUCCESS + 1; // Wait ... somebody else is getting it right now
|
||||
else
|
||||
return STATUS_SUCCESS; // Nonwait swap entry ... handle elsewhere
|
||||
}
|
||||
Required->Page[1] = MmGetPfnForProcess(Process, Address);
|
||||
Required->Consumer = MC_CACHE;
|
||||
Required->Amount = 1;
|
||||
Required->File = __FILE__;
|
||||
Required->Line = __LINE__;
|
||||
Required->DoAcquisition = MiGetOnePage;
|
||||
MmCreatePageFileMapping(Process, Address, MM_WAIT_ENTRY);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||||
}
|
||||
|
||||
NewPage = Required->Page[0];
|
||||
OldPage = Required->Page[1];
|
||||
|
||||
DPRINT("Allocated page %x\n", NewPage);
|
||||
|
||||
/*
|
||||
* Unshare the old page.
|
||||
*/
|
||||
MmDeleteRmap(OldPage, Process, PAddress);
|
||||
|
||||
/*
|
||||
* Copy the old page
|
||||
*/
|
||||
DPRINT("Copying\n");
|
||||
MiCopyPageToPage(NewPage, OldPage);
|
||||
|
||||
/*
|
||||
* Set the PTE to point to the new page
|
||||
*/
|
||||
Status = MmCreateVirtualMapping
|
||||
(Process, Address, PAGE_READWRITE, &NewPage, 1);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("MmCreateVirtualMapping failed, not out of memory\n");
|
||||
ASSERT(FALSE);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
MmInsertRmap(NewPage, Process, PAddress);
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, OldPage);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
|
||||
DPRINT("Address 0x%.8X\n", Address);
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
KEVENT MmWaitPageEvent;
|
||||
|
||||
typedef struct _WORK_QUEUE_WITH_CONTEXT
|
||||
{
|
||||
WORK_QUEUE_ITEM WorkItem;
|
||||
PMMSUPPORT AddressSpace;
|
||||
PMEMORY_AREA MemoryArea;
|
||||
PMM_REQUIRED_RESOURCES Required;
|
||||
NTSTATUS Status;
|
||||
KEVENT Wait;
|
||||
AcquireResource DoAcquisition;
|
||||
} WORK_QUEUE_WITH_CONTEXT, *PWORK_QUEUE_WITH_CONTEXT;
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmpFaultWorker
|
||||
(PWORK_QUEUE_WITH_CONTEXT WorkItem)
|
||||
{
|
||||
DPRINT("Calling work\n");
|
||||
WorkItem->Status =
|
||||
WorkItem->Required->DoAcquisition
|
||||
(WorkItem->AddressSpace,
|
||||
WorkItem->MemoryArea,
|
||||
WorkItem->Required);
|
||||
DPRINT("Status %x\n", WorkItem->Status);
|
||||
KeSetEvent(&WorkItem->Wait, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmpSectionAccessFaultInner
|
||||
(KPROCESSOR_MODE Mode,
|
||||
PMMSUPPORT AddressSpace,
|
||||
ULONG_PTR Address,
|
||||
BOOLEAN FromMdl,
|
||||
PETHREAD Thread)
|
||||
{
|
||||
MEMORY_AREA* MemoryArea;
|
||||
NTSTATUS Status;
|
||||
BOOLEAN Locked = FromMdl;
|
||||
MM_REQUIRED_RESOURCES Resources = { 0 };
|
||||
|
||||
DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
|
||||
|
||||
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
|
||||
{
|
||||
DPRINT1("Page fault at high IRQL was %d\n", KeGetCurrentIrql());
|
||||
return(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the memory area for the faulting address
|
||||
*/
|
||||
if (Address >= (ULONG_PTR)MmSystemRangeStart)
|
||||
{
|
||||
/*
|
||||
* Check permissions
|
||||
*/
|
||||
if (Mode != KernelMode)
|
||||
{
|
||||
DPRINT("MmAccessFault(Mode %d, Address %x)\n", Mode, Address);
|
||||
return(STATUS_ACCESS_VIOLATION);
|
||||
}
|
||||
AddressSpace = MmGetKernelAddressSpace();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddressSpace = &PsGetCurrentProcess()->Vm;
|
||||
}
|
||||
|
||||
if (!FromMdl)
|
||||
{
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
|
||||
if (MemoryArea == NULL ||
|
||||
MemoryArea->DeleteInProgress)
|
||||
{
|
||||
if (!FromMdl)
|
||||
{
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
}
|
||||
DPRINT("Address: %x\n", Address);
|
||||
return (STATUS_ACCESS_VIOLATION);
|
||||
}
|
||||
|
||||
DPRINT
|
||||
("Type %x (%x -> %x)\n",
|
||||
MemoryArea->Type,
|
||||
MemoryArea->StartingAddress,
|
||||
MemoryArea->EndingAddress);
|
||||
|
||||
Resources.DoAcquisition = NULL;
|
||||
|
||||
// Note: fault handlers are called with address space locked
|
||||
// We return STATUS_MORE_PROCESSING_REQUIRED if anything is needed
|
||||
Status = MiCowCacheSectionPage
|
||||
(AddressSpace, MemoryArea, (PVOID)Address, Locked, &Resources);
|
||||
|
||||
if (!FromMdl)
|
||||
{
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
}
|
||||
|
||||
if (Status == STATUS_SUCCESS + 1)
|
||||
{
|
||||
// Wait page ...
|
||||
DPRINT("Waiting for %x\n", Address);
|
||||
MiWaitForPageEvent(MmGetAddressSpaceOwner(AddressSpace), Address);
|
||||
DPRINT("Restarting fault %x\n", Address);
|
||||
Status = STATUS_MM_RESTART_OPERATION;
|
||||
}
|
||||
else if (Status == STATUS_MM_RESTART_OPERATION)
|
||||
{
|
||||
// Clean slate
|
||||
RtlZeroMemory(&Resources, sizeof(Resources));
|
||||
}
|
||||
else if (Status == STATUS_MORE_PROCESSING_REQUIRED)
|
||||
{
|
||||
if (Thread->ActiveFaultCount > 0)
|
||||
{
|
||||
WORK_QUEUE_WITH_CONTEXT Context = { };
|
||||
DPRINT("Already fault handling ... going to work item (%x)\n", Address);
|
||||
Context.AddressSpace = AddressSpace;
|
||||
Context.MemoryArea = MemoryArea;
|
||||
Context.Required = &Resources;
|
||||
KeInitializeEvent(&Context.Wait, NotificationEvent, FALSE);
|
||||
ExInitializeWorkItem(&Context.WorkItem, (PWORKER_THREAD_ROUTINE)MmpFaultWorker, &Context);
|
||||
DPRINT("Queue work item\n");
|
||||
ExQueueWorkItem(&Context.WorkItem, DelayedWorkQueue);
|
||||
DPRINT("Wait\n");
|
||||
KeWaitForSingleObject(&Context.Wait, 0, KernelMode, FALSE, NULL);
|
||||
Status = Context.Status;
|
||||
DPRINT("Status %x\n", Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
Status = Resources.DoAcquisition(AddressSpace, MemoryArea, &Resources);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
Status = STATUS_MM_RESTART_OPERATION;
|
||||
}
|
||||
}
|
||||
|
||||
if (!FromMdl)
|
||||
{
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
}
|
||||
}
|
||||
while (Status == STATUS_MM_RESTART_OPERATION);
|
||||
|
||||
if (!NT_SUCCESS(Status) && MemoryArea->Type == 1)
|
||||
{
|
||||
DPRINT1("Completed page fault handling %x %x\n", Address, Status);
|
||||
DPRINT1
|
||||
("Type %x (%x -> %x)\n",
|
||||
MemoryArea->Type,
|
||||
MemoryArea->StartingAddress,
|
||||
MemoryArea->EndingAddress);
|
||||
}
|
||||
|
||||
if (!FromMdl)
|
||||
{
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
}
|
||||
|
||||
return(Status);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmAccessFaultCacheSection
|
||||
(KPROCESSOR_MODE Mode,
|
||||
ULONG_PTR Address,
|
||||
BOOLEAN FromMdl)
|
||||
{
|
||||
PETHREAD Thread;
|
||||
PMMSUPPORT AddressSpace;
|
||||
NTSTATUS Status;
|
||||
|
||||
DPRINT("MmpAccessFault(Mode %d, Address %x)\n", Mode, Address);
|
||||
|
||||
Thread = PsGetCurrentThread();
|
||||
|
||||
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
|
||||
{
|
||||
DPRINT1("Page fault at high IRQL %d, address %x\n", KeGetCurrentIrql(), Address);
|
||||
return(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the memory area for the faulting address
|
||||
*/
|
||||
if (Address >= (ULONG_PTR)MmSystemRangeStart)
|
||||
{
|
||||
/*
|
||||
* Check permissions
|
||||
*/
|
||||
if (Mode != KernelMode)
|
||||
{
|
||||
DPRINT1("Address: %x:%x\n", PsGetCurrentProcess(), Address);
|
||||
return(STATUS_ACCESS_VIOLATION);
|
||||
}
|
||||
AddressSpace = MmGetKernelAddressSpace();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddressSpace = &PsGetCurrentProcess()->Vm;
|
||||
}
|
||||
|
||||
Thread->ActiveFaultCount++;
|
||||
Status = MmpSectionAccessFaultInner(Mode, AddressSpace, Address, FromMdl, Thread);
|
||||
Thread->ActiveFaultCount--;
|
||||
|
||||
return(Status);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmNotPresentFaultCacheSectionInner
|
||||
(KPROCESSOR_MODE Mode,
|
||||
PMMSUPPORT AddressSpace,
|
||||
ULONG_PTR Address,
|
||||
BOOLEAN FromMdl,
|
||||
PETHREAD Thread)
|
||||
{
|
||||
BOOLEAN Locked = FromMdl;
|
||||
PMEMORY_AREA MemoryArea;
|
||||
MM_REQUIRED_RESOURCES Resources = { 0 };
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
if (!FromMdl)
|
||||
{
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the memory area specific fault handler
|
||||
*/
|
||||
do
|
||||
{
|
||||
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, (PVOID)Address);
|
||||
if (MemoryArea == NULL || MemoryArea->DeleteInProgress)
|
||||
{
|
||||
Status = STATUS_ACCESS_VIOLATION;
|
||||
if (MemoryArea)
|
||||
{
|
||||
DPRINT1("Type %x DIP %x\n", MemoryArea->Type, MemoryArea->DeleteInProgress);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("No memory area\n");
|
||||
}
|
||||
DPRINT1("Process %x, Address %x\n", MmGetAddressSpaceOwner(AddressSpace), Address);
|
||||
break;
|
||||
}
|
||||
|
||||
DPRINTC
|
||||
("Type %x (%x -> %x -> %x) in %x\n",
|
||||
MemoryArea->Type,
|
||||
MemoryArea->StartingAddress,
|
||||
Address,
|
||||
MemoryArea->EndingAddress,
|
||||
PsGetCurrentThread());
|
||||
|
||||
Resources.DoAcquisition = NULL;
|
||||
|
||||
// Note: fault handlers are called with address space locked
|
||||
// We return STATUS_MORE_PROCESSING_REQUIRED if anything is needed
|
||||
|
||||
Status = MmNotPresentFaultCachePage
|
||||
(AddressSpace, MemoryArea, (PVOID)Address, Locked, &Resources);
|
||||
|
||||
if (!FromMdl)
|
||||
{
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
}
|
||||
|
||||
if (Status == STATUS_SUCCESS)
|
||||
{
|
||||
; // Nothing
|
||||
}
|
||||
else if (Status == STATUS_SUCCESS + 1)
|
||||
{
|
||||
// Wait page ...
|
||||
DPRINT("Waiting for %x\n", Address);
|
||||
MiWaitForPageEvent(MmGetAddressSpaceOwner(AddressSpace), Address);
|
||||
DPRINT("Done waiting for %x\n", Address);
|
||||
Status = STATUS_MM_RESTART_OPERATION;
|
||||
}
|
||||
else if (Status == STATUS_MM_RESTART_OPERATION)
|
||||
{
|
||||
// Clean slate
|
||||
DPRINT("Clear resource\n");
|
||||
RtlZeroMemory(&Resources, sizeof(Resources));
|
||||
}
|
||||
else if (Status == STATUS_MORE_PROCESSING_REQUIRED)
|
||||
{
|
||||
if (Thread->ActiveFaultCount > 1)
|
||||
{
|
||||
WORK_QUEUE_WITH_CONTEXT Context = { };
|
||||
DPRINTC("Already fault handling ... going to work item (%x)\n", Address);
|
||||
Context.AddressSpace = AddressSpace;
|
||||
Context.MemoryArea = MemoryArea;
|
||||
Context.Required = &Resources;
|
||||
KeInitializeEvent(&Context.Wait, NotificationEvent, FALSE);
|
||||
ExInitializeWorkItem(&Context.WorkItem, (PWORKER_THREAD_ROUTINE)MmpFaultWorker, &Context);
|
||||
DPRINT("Queue work item\n");
|
||||
ExQueueWorkItem(&Context.WorkItem, DelayedWorkQueue);
|
||||
DPRINT("Wait\n");
|
||||
KeWaitForSingleObject(&Context.Wait, 0, KernelMode, FALSE, NULL);
|
||||
Status = Context.Status;
|
||||
DPRINTC("Status %x\n", Status);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("DoAcquisition %x\n", Resources.DoAcquisition);
|
||||
Status = Resources.DoAcquisition
|
||||
(AddressSpace, MemoryArea, &Resources);
|
||||
DPRINT("DoAcquisition %x -> %x\n", Resources.DoAcquisition, Status);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
Status = STATUS_MM_RESTART_OPERATION;
|
||||
}
|
||||
}
|
||||
else if (NT_SUCCESS(Status))
|
||||
{
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
if (!FromMdl)
|
||||
{
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
}
|
||||
}
|
||||
while (Status == STATUS_MM_RESTART_OPERATION);
|
||||
|
||||
DPRINTC("Completed page fault handling: %x:%x %x\n", MmGetAddressSpaceOwner(AddressSpace), Address, Status);
|
||||
if (!FromMdl)
|
||||
{
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
}
|
||||
|
||||
MiSetPageEvent(MmGetAddressSpaceOwner(AddressSpace), Address);
|
||||
DPRINT("Done %x\n", Status);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmNotPresentFaultCacheSection
|
||||
(KPROCESSOR_MODE Mode,
|
||||
ULONG_PTR Address,
|
||||
BOOLEAN FromMdl)
|
||||
{
|
||||
PETHREAD Thread;
|
||||
PMMSUPPORT AddressSpace;
|
||||
NTSTATUS Status;
|
||||
|
||||
Address &= ~(PAGE_SIZE - 1);
|
||||
DPRINT("MmNotPresentFault(Mode %d, Address %x)\n", Mode, Address);
|
||||
|
||||
Thread = PsGetCurrentThread();
|
||||
|
||||
if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
|
||||
{
|
||||
DPRINT1("Page fault at high IRQL %d, address %x\n", KeGetCurrentIrql(), Address);
|
||||
ASSERT(FALSE);
|
||||
return(STATUS_UNSUCCESSFUL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the memory area for the faulting address
|
||||
*/
|
||||
if (Address >= (ULONG_PTR)MmSystemRangeStart)
|
||||
{
|
||||
/*
|
||||
* Check permissions
|
||||
*/
|
||||
if (Mode != KernelMode)
|
||||
{
|
||||
DPRINTC("Address: %x\n", Address);
|
||||
return(STATUS_ACCESS_VIOLATION);
|
||||
}
|
||||
AddressSpace = MmGetKernelAddressSpace();
|
||||
}
|
||||
else
|
||||
{
|
||||
AddressSpace = &PsGetCurrentProcess()->Vm;
|
||||
}
|
||||
|
||||
Thread->ActiveFaultCount++;
|
||||
Status = MmNotPresentFaultCacheSectionInner
|
||||
(Mode, AddressSpace, Address, FromMdl, Thread);
|
||||
Thread->ActiveFaultCount--;
|
||||
|
||||
ASSERT(Status != STATUS_UNSUCCESSFUL);
|
||||
ASSERT(Status != STATUS_INVALID_PARAMETER);
|
||||
DPRINT("MmAccessFault %x:%x -> %x\n", MmGetAddressSpaceOwner(AddressSpace), Address, Status);
|
||||
|
||||
return(Status);
|
||||
}
|
309
reactos/ntoskrnl/cache/section/io.c
vendored
Normal file
309
reactos/ntoskrnl/cache/section/io.c
vendored
Normal file
|
@ -0,0 +1,309 @@
|
|||
/*
|
||||
* Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/mm/section.c
|
||||
* PURPOSE: Implements section objects
|
||||
*
|
||||
* PROGRAMMERS: Rex Jolliff
|
||||
* David Welch
|
||||
* Eric Kohl
|
||||
* Emanuele Aliberti
|
||||
* Eugene Ingerman
|
||||
* Casper Hornstrup
|
||||
* KJK::Hyperion
|
||||
* Guido de Jong
|
||||
* Ge van Geldorp
|
||||
* Royce Mitchell III
|
||||
* Filip Navara
|
||||
* Aleksey Bragin
|
||||
* Jason Filby
|
||||
* Thomas Weidenmueller
|
||||
* Gunnar Andre' Dalsnes
|
||||
* Mike Nordell
|
||||
* Alex Ionescu
|
||||
* Gregor Anich
|
||||
* Steven Edwards
|
||||
* Herve Poussineau
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newmm.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
#include <reactos/exeformat.h>
|
||||
|
||||
#if defined (ALLOC_PRAGMA)
|
||||
#pragma alloc_text(INIT, MmCreatePhysicalMemorySection)
|
||||
#pragma alloc_text(INIT, MmInitSectionImplementation)
|
||||
#endif
|
||||
|
||||
KEVENT CcpLazyWriteEvent;
|
||||
|
||||
PDEVICE_OBJECT
|
||||
NTAPI
|
||||
MmGetDeviceObjectForFile(IN PFILE_OBJECT FileObject)
|
||||
{
|
||||
return IoGetRelatedDeviceObject(FileObject);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiSimpleReadComplete
|
||||
(PDEVICE_OBJECT DeviceObject,
|
||||
PIRP Irp,
|
||||
PVOID Context)
|
||||
{
|
||||
/* Unlock MDL Pages, page 167. */
|
||||
DPRINT("MiSimpleReadComplete %x\n", Irp);
|
||||
PMDL Mdl = Irp->MdlAddress;
|
||||
while (Mdl)
|
||||
{
|
||||
DPRINT("MDL Unlock %x\n", Mdl);
|
||||
MmUnlockPages(Mdl);
|
||||
Mdl = Mdl->Next;
|
||||
}
|
||||
|
||||
/* Check if there's an MDL */
|
||||
while ((Mdl = Irp->MdlAddress))
|
||||
{
|
||||
/* Clear all of them */
|
||||
Irp->MdlAddress = Mdl->Next;
|
||||
IoFreeMdl(Mdl);
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiSimpleRead
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER FileOffset,
|
||||
PVOID Buffer,
|
||||
ULONG Length,
|
||||
PIO_STATUS_BLOCK ReadStatus)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PIRP Irp = NULL;
|
||||
KEVENT ReadWait;
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
ASSERT(FileObject);
|
||||
ASSERT(FileOffset);
|
||||
ASSERT(Buffer);
|
||||
ASSERT(ReadStatus);
|
||||
|
||||
DeviceObject = MmGetDeviceObjectForFile(FileObject);
|
||||
ReadStatus->Status = STATUS_INTERNAL_ERROR;
|
||||
ReadStatus->Information = 0;
|
||||
|
||||
ASSERT(DeviceObject);
|
||||
|
||||
DPRINT
|
||||
("PAGING READ: FileObject %x <%wZ> Offset %08x%08x Length %d\n",
|
||||
&FileObject,
|
||||
&FileObject->FileName,
|
||||
FileOffset->HighPart,
|
||||
FileOffset->LowPart,
|
||||
Length);
|
||||
|
||||
KeInitializeEvent(&ReadWait, NotificationEvent, FALSE);
|
||||
|
||||
Irp = IoBuildAsynchronousFsdRequest
|
||||
(IRP_MJ_READ,
|
||||
DeviceObject,
|
||||
Buffer,
|
||||
Length,
|
||||
FileOffset,
|
||||
ReadStatus);
|
||||
|
||||
if (!Irp)
|
||||
{
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
Irp->Flags |= IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_API;
|
||||
|
||||
Irp->UserEvent = &ReadWait;
|
||||
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
||||
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
||||
IrpSp = IoGetNextIrpStackLocation(Irp);
|
||||
IrpSp->Control |= SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
|
||||
IrpSp->FileObject = FileObject;
|
||||
IrpSp->CompletionRoutine = MiSimpleReadComplete;
|
||||
|
||||
Status = IoCallDriver(DeviceObject, Irp);
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
DPRINT1("KeWaitForSingleObject(&ReadWait)\n");
|
||||
if (!NT_SUCCESS
|
||||
(KeWaitForSingleObject
|
||||
(&ReadWait,
|
||||
Suspended,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL)))
|
||||
{
|
||||
DPRINT1("Warning: Failed to wait for synchronous IRP\n");
|
||||
ASSERT(FALSE);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINT("Paging IO Done: %08x\n", ReadStatus->Status);
|
||||
Status =
|
||||
ReadStatus->Status == STATUS_END_OF_FILE ?
|
||||
STATUS_SUCCESS : ReadStatus->Status;
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiSimpleWrite
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER FileOffset,
|
||||
PVOID Buffer,
|
||||
ULONG Length,
|
||||
PIO_STATUS_BLOCK ReadStatus,
|
||||
const char *File,
|
||||
int Line)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PIRP Irp = NULL;
|
||||
KEVENT ReadWait;
|
||||
PDEVICE_OBJECT DeviceObject;
|
||||
PIO_STACK_LOCATION IrpSp;
|
||||
|
||||
ASSERT(FileObject);
|
||||
ASSERT(FileOffset);
|
||||
ASSERT(Buffer);
|
||||
ASSERT(ReadStatus);
|
||||
|
||||
ObReferenceObject(FileObject);
|
||||
DeviceObject = MmGetDeviceObjectForFile(FileObject);
|
||||
ASSERT(DeviceObject);
|
||||
|
||||
DPRINT
|
||||
("PAGING WRITE: FileObject %x Offset %x Length %d (%s:%d)\n",
|
||||
&FileObject,
|
||||
FileOffset->LowPart,
|
||||
Length,
|
||||
File,
|
||||
Line);
|
||||
|
||||
KeInitializeEvent(&ReadWait, NotificationEvent, FALSE);
|
||||
|
||||
Irp = IoBuildAsynchronousFsdRequest
|
||||
(IRP_MJ_WRITE,
|
||||
DeviceObject,
|
||||
Buffer,
|
||||
Length,
|
||||
FileOffset,
|
||||
ReadStatus);
|
||||
|
||||
if (!Irp)
|
||||
{
|
||||
ObDereferenceObject(FileObject);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
Irp->Flags = IRP_PAGING_IO | IRP_SYNCHRONOUS_PAGING_IO | IRP_NOCACHE | IRP_SYNCHRONOUS_API;
|
||||
|
||||
Irp->UserEvent = &ReadWait;
|
||||
Irp->Tail.Overlay.OriginalFileObject = FileObject;
|
||||
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
||||
IrpSp = IoGetNextIrpStackLocation(Irp);
|
||||
IrpSp->Control |= SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR;
|
||||
IrpSp->FileObject = FileObject;
|
||||
IrpSp->CompletionRoutine = MiSimpleReadComplete;
|
||||
|
||||
DPRINT("Call Driver\n");
|
||||
Status = IoCallDriver(DeviceObject, Irp);
|
||||
DPRINT("Status %x\n", Status);
|
||||
|
||||
ObDereferenceObject(FileObject);
|
||||
|
||||
if (Status == STATUS_PENDING)
|
||||
{
|
||||
DPRINT1("KeWaitForSingleObject(&ReadWait)\n");
|
||||
if (!NT_SUCCESS
|
||||
(KeWaitForSingleObject
|
||||
(&ReadWait,
|
||||
Suspended,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL)))
|
||||
{
|
||||
DPRINT1("Warning: Failed to wait for synchronous IRP\n");
|
||||
ASSERT(FALSE);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
DPRINT("Paging IO Done: %08x\n", ReadStatus->Status);
|
||||
return ReadStatus->Status;
|
||||
}
|
||||
|
||||
extern KEVENT MpwThreadEvent;
|
||||
FAST_MUTEX MiWriteMutex;
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiWriteBackPage
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER FileOffset,
|
||||
ULONG Length,
|
||||
PFN_NUMBER Page,
|
||||
const char *File,
|
||||
int Line)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PVOID Hyperspace;
|
||||
IO_STATUS_BLOCK Iosb;
|
||||
KIRQL OldIrql;
|
||||
PVOID PageBuffer = ExAllocatePool(NonPagedPool, PAGE_SIZE);
|
||||
|
||||
if (!PageBuffer) return STATUS_NO_MEMORY;
|
||||
|
||||
OldIrql = KfRaiseIrql(DISPATCH_LEVEL);
|
||||
Hyperspace = MmCreateHyperspaceMapping(Page);
|
||||
RtlCopyMemory(PageBuffer, Hyperspace, PAGE_SIZE);
|
||||
MmDeleteHyperspaceMapping(Hyperspace);
|
||||
KfLowerIrql(OldIrql);
|
||||
|
||||
DPRINT1("MiWriteBackPage(%wZ,%08x%08x,%s:%d)\n", &FileObject->FileName, FileOffset->u.HighPart, FileOffset->u.LowPart, File, Line);
|
||||
Status = MiSimpleWrite
|
||||
(FileObject,
|
||||
FileOffset,
|
||||
PageBuffer,
|
||||
Length,
|
||||
&Iosb);
|
||||
|
||||
ExFreePool(PageBuffer);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("MiSimpleWrite failed (%x)\n", Status);
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
454
reactos/ntoskrnl/cache/section/newmm.h
vendored
Normal file
454
reactos/ntoskrnl/cache/section/newmm.h
vendored
Normal file
|
@ -0,0 +1,454 @@
|
|||
#pragma once
|
||||
|
||||
#include <internal/arch/mm.h>
|
||||
|
||||
/* TYPES *********************************************************************/
|
||||
|
||||
#define MM_WAIT_ENTRY 0x7ffff800
|
||||
#define PFN_FROM_SSE(E) ((E) >> PAGE_SHIFT)
|
||||
#define IS_SWAP_FROM_SSE(E) ((E) & 0x00000001)
|
||||
#define MM_IS_WAIT_PTE(E) \
|
||||
(IS_SWAP_FROM_SSE(E) && SWAPENTRY_FROM_SSE(E) == MM_WAIT_ENTRY)
|
||||
#define MAKE_PFN_SSE(P) ((P) << PAGE_SHIFT)
|
||||
#define SWAPENTRY_FROM_SSE(E) ((E) >> 1)
|
||||
#define MAKE_SWAP_SSE(S) (((S) << 1) | 0x1)
|
||||
#define DIRTY_SSE(E) ((E) | 2)
|
||||
#define CLEAN_SSE(E) ((E) & ~2)
|
||||
#define IS_DIRTY_SSE(E) ((E) & 2)
|
||||
|
||||
#define MEMORY_AREA_CACHE (2)
|
||||
#define MM_SEGMENT_FINALIZE (0x40000000)
|
||||
|
||||
#define RMAP_SEGMENT_MASK ~0xff
|
||||
#define RMAP_IS_SEGMENT(x) (((ULONG_PTR)(x) & RMAP_SEGMENT_MASK) == RMAP_SEGMENT_MASK)
|
||||
|
||||
#define MIN(x,y) (((x)<(y))?(x):(y))
|
||||
#define MAX(x,y) (((x)>(y))?(x):(y))
|
||||
|
||||
/* Determine what's needed to make paged pool fit in this category.
|
||||
* it seems that something more is required to satisfy arm3. */
|
||||
#define BALANCER_CAN_EVICT(Consumer) \
|
||||
(((Consumer) == MC_USER) || \
|
||||
((Consumer) == MC_CACHE))
|
||||
|
||||
#define SEC_CACHE (0x40000000)
|
||||
|
||||
#define MiWaitForPageEvent(Process,Address) do { \
|
||||
DPRINT("MiWaitForPageEvent %x:%x #\n", Process, Address); \
|
||||
KeWaitForSingleObject(&MmWaitPageEvent, 0, KernelMode, FALSE, NULL); \
|
||||
} while(0)
|
||||
|
||||
#define MiSetPageEvent(Process,Address) do { \
|
||||
DPRINT("MiSetPageEvent %x:%x #\n",Process, Address); \
|
||||
KeSetEvent(&MmWaitPageEvent, IO_NO_INCREMENT, FALSE); \
|
||||
} while(0)
|
||||
|
||||
/* We store 8 bits of location with a page association */
|
||||
#define ENTRIES_PER_ELEMENT 256
|
||||
|
||||
extern KEVENT MmWaitPageEvent;
|
||||
|
||||
typedef struct _MM_CACHE_SECTION_SEGMENT
|
||||
{
|
||||
FAST_MUTEX Lock; /* lock which protects the page directory */
|
||||
PFILE_OBJECT FileObject;
|
||||
ULARGE_INTEGER RawLength; /* length of the segment which is part of the mapped file */
|
||||
ULARGE_INTEGER Length; /* absolute length of the segment */
|
||||
ULONG ReferenceCount;
|
||||
ULONG Protection;
|
||||
ULONG Flags;
|
||||
BOOLEAN WriteCopy;
|
||||
|
||||
struct
|
||||
{
|
||||
LONG FileOffset; /* start offset into the file for image sections */
|
||||
ULONG_PTR VirtualAddress; /* dtart offset into the address range for image sections */
|
||||
ULONG Characteristics;
|
||||
} Image;
|
||||
|
||||
RTL_GENERIC_TABLE PageTable;
|
||||
} MM_CACHE_SECTION_SEGMENT, *PMM_CACHE_SECTION_SEGMENT;
|
||||
|
||||
typedef struct _CACHE_SECTION_PAGE_TABLE
|
||||
{
|
||||
LARGE_INTEGER FileOffset;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment;
|
||||
ULONG Refcount;
|
||||
ULONG PageEntries[ENTRIES_PER_ELEMENT];
|
||||
} CACHE_SECTION_PAGE_TABLE, *PCACHE_SECTION_PAGE_TABLE;
|
||||
|
||||
struct _MM_REQUIRED_RESOURCES;
|
||||
|
||||
typedef NTSTATUS (NTAPI * AcquireResource)
|
||||
(PMMSUPPORT AddressSpace,
|
||||
struct _MEMORY_AREA *MemoryArea,
|
||||
struct _MM_REQUIRED_RESOURCES *Required);
|
||||
typedef NTSTATUS (NTAPI * NotPresentFaultHandler)
|
||||
(PMMSUPPORT AddressSpace,
|
||||
struct _MEMORY_AREA *MemoryArea,
|
||||
PVOID Address,
|
||||
BOOLEAN Locked,
|
||||
struct _MM_REQUIRED_RESOURCES *Required);
|
||||
typedef NTSTATUS (NTAPI * FaultHandler)
|
||||
(PMMSUPPORT AddressSpace,
|
||||
struct _MEMORY_AREA *MemoryArea,
|
||||
PVOID Address,
|
||||
struct _MM_REQUIRED_RESOURCES *Required);
|
||||
|
||||
typedef struct _MM_REQUIRED_RESOURCES
|
||||
{
|
||||
ULONG Consumer;
|
||||
ULONG Amount;
|
||||
ULONG Offset;
|
||||
ULONG State;
|
||||
PVOID Context;
|
||||
LARGE_INTEGER FileOffset;
|
||||
AcquireResource DoAcquisition;
|
||||
PFN_NUMBER Page[2];
|
||||
PVOID Buffer[2];
|
||||
SWAPENTRY SwapEntry;
|
||||
const char *File;
|
||||
int Line;
|
||||
} MM_REQUIRED_RESOURCES, *PMM_REQUIRED_RESOURCES;
|
||||
|
||||
PFN_NUMBER
|
||||
NTAPI
|
||||
MmWithdrawSectionPage
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER FileOffset, BOOLEAN *Dirty);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmFinalizeSectionPageOut
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER FileOffset, PFN_NUMBER Page,
|
||||
BOOLEAN Dirty);
|
||||
|
||||
/* sptab.c *******************************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiInitializeSectionPageTable(PMM_CACHE_SECTION_SEGMENT Segment);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiSetPageEntryCacheSectionSegment
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
PLARGE_INTEGER Offset,
|
||||
ULONG Entry, const char *file, int line);
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
_MiGetPageEntryCacheSectionSegment
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
PLARGE_INTEGER Offset, const char *file, int line);
|
||||
|
||||
#define MiSetPageEntryCacheSectionSegment(S,O,E) _MiSetPageEntryCacheSectionSegment(S,O,E,__FILE__,__LINE__)
|
||||
#define MiGetPageEntryCacheSectionSegment(S,O) _MiGetPageEntryCacheSectionSegment(S,O,__FILE__,__LINE__)
|
||||
|
||||
typedef VOID (NTAPI *FREE_SECTION_PAGE_FUN)
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
PLARGE_INTEGER Offset);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiFreePageTablesSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, FREE_SECTION_PAGE_FUN FreePage);
|
||||
|
||||
/* Yields a lock */
|
||||
PMM_CACHE_SECTION_SEGMENT
|
||||
NTAPI
|
||||
MmGetSectionAssociation(PFN_NUMBER Page, PLARGE_INTEGER Offset);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmSetSectionAssociation(PFN_NUMBER Page, PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmDeleteSectionAssociation(PFN_NUMBER Page);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmpPageOutPhysicalAddress(PFN_NUMBER Page);
|
||||
|
||||
/* io.c **********************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
MmspWaitForFileLock(PFILE_OBJECT File);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiSimpleRead
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER FileOffset,
|
||||
PVOID Buffer,
|
||||
ULONG Length,
|
||||
PIO_STATUS_BLOCK ReadStatus);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiSimpleWrite
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER FileOffset,
|
||||
PVOID Buffer,
|
||||
ULONG Length,
|
||||
PIO_STATUS_BLOCK ReadStatus,
|
||||
const char *file,
|
||||
int line);
|
||||
|
||||
#define MiSimpleWrite(F,O,B,L,R) _MiSimpleWrite(F,O,B,L,R,__FILE__,__LINE__)
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiWriteBackPage
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER Offset,
|
||||
ULONG Length,
|
||||
PFN_NUMBER Page,
|
||||
const char *File,
|
||||
int Line);
|
||||
|
||||
#define MiWriteBackPage(F,O,L,P) _MiWriteBackPage(F,O,L,P,__FILE__,__LINE__)
|
||||
|
||||
/* section.c *****************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmAccessFaultCacheSection
|
||||
(KPROCESSOR_MODE Mode,
|
||||
ULONG_PTR Address,
|
||||
BOOLEAN FromMdl);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiReadFilePage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES RequiredResources);
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
MiChecksumPage(PFN_NUMBER Page, BOOLEAN Lock);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiGetOnePage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES RequiredResources);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiSwapInPage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES RequiredResources);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiWriteSwapPage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES Resources);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiWriteFilePage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES Resources);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiFreeSegmentPage
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
PLARGE_INTEGER FileOffset);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiCowCacheSectionPage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PVOID Address,
|
||||
BOOLEAN Locked,
|
||||
PMM_REQUIRED_RESOURCES Required);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiZeroFillSection(PVOID Address, PLARGE_INTEGER FileOffsetPtr, ULONG Length);
|
||||
|
||||
VOID
|
||||
MmPageOutDeleteMapping(PVOID Context, PEPROCESS Process, PVOID Address);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
_MmLockCacheSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, const char *file, int line);
|
||||
|
||||
#define MmLockCacheSectionSegment(x) _MmLockCacheSectionSegment(x,__FILE__,__LINE__)
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
_MmUnlockCacheSectionSegment(PMM_CACHE_SECTION_SEGMENT Segment, const char *file, int line);
|
||||
|
||||
#define MmUnlockCacheSectionSegment(x) _MmUnlockCacheSectionSegment(x,__FILE__,__LINE__)
|
||||
|
||||
VOID
|
||||
MmFreeCacheSectionPage
|
||||
(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
|
||||
PFN_NUMBER Page, SWAPENTRY SwapEntry, BOOLEAN Dirty);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiFlushMappedSection(PVOID BaseAddress, PLARGE_INTEGER BaseOffset, PLARGE_INTEGER FileSize, BOOLEAN Dirty, const char *File, int Line);
|
||||
|
||||
#define MiFlushMappedSection(A,O,S,D) _MiFlushMappedSection(A,O,S,D,__FILE__,__LINE__)
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmFinalizeSegment(PMM_CACHE_SECTION_SEGMENT Segment);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmFreeSectionSegments(PFILE_OBJECT FileObject);
|
||||
|
||||
NTSTATUS NTAPI
|
||||
MmMapCacheViewInSystemSpaceAtOffset
|
||||
(IN PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
OUT PVOID * MappedBase,
|
||||
IN PLARGE_INTEGER ViewOffset,
|
||||
IN OUT PULONG ViewSize);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiMapViewOfSegment
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
PVOID* BaseAddress,
|
||||
SIZE_T ViewSize,
|
||||
ULONG Protect,
|
||||
PLARGE_INTEGER ViewOffset,
|
||||
ULONG AllocationType,
|
||||
const char *file,
|
||||
int line);
|
||||
|
||||
#define MiMapViewOfSegment(AddressSpace,Segment,BaseAddress,ViewSize,Protect,ViewOffset,AllocationType) _MiMapViewOfSegment(AddressSpace,Segment,BaseAddress,ViewSize,Protect,ViewOffset,AllocationType,__FILE__,__LINE__)
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmUnmapViewOfCacheSegment
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PVOID BaseAddress);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmUnmapCacheViewInSystemSpace(PVOID Address);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmNotPresentFaultCachePage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PVOID Address,
|
||||
BOOLEAN Locked,
|
||||
PMM_REQUIRED_RESOURCES Required);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmPageOutPageFileView
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PVOID Address,
|
||||
PMM_REQUIRED_RESOURCES Required);
|
||||
|
||||
FORCEINLINE
|
||||
BOOLEAN
|
||||
_MmTryToLockAddressSpace(IN PMMSUPPORT AddressSpace, const char *file, int line)
|
||||
{
|
||||
BOOLEAN Result = KeTryToAcquireGuardedMutex(&CONTAINING_RECORD(AddressSpace, EPROCESS, Vm)->AddressCreationLock);
|
||||
//DbgPrint("(%s:%d) Try Lock Address Space %x -> %s\n", file, line, AddressSpace, Result ? "true" : "false");
|
||||
return Result;
|
||||
}
|
||||
|
||||
#define MmTryToLockAddressSpace(x) _MmTryToLockAddressSpace(x,__FILE__,__LINE__)
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiWidenSegment
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES RequiredResources);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiSwapInSectionPage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES RequiredResources);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmExtendCacheSection(PMM_CACHE_SECTION_SEGMENT Section, PLARGE_INTEGER NewSize, BOOLEAN ExtendFile);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiFlushMappedSection(PVOID BaseAddress, PLARGE_INTEGER BaseOffset, PLARGE_INTEGER FileSize, BOOLEAN Dirty, const char *File, int Line);
|
||||
|
||||
#define MiFlushMappedSection(A,O,S,D) _MiFlushMappedSection(A,O,S,D,__FILE__,__LINE__)
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmCreateCacheSection
|
||||
(PMM_CACHE_SECTION_SEGMENT *SegmentObject,
|
||||
ACCESS_MASK DesiredAccess,
|
||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
PLARGE_INTEGER UMaximumSize,
|
||||
ULONG SectionPageProtection,
|
||||
ULONG AllocationAttributes,
|
||||
PFILE_OBJECT FileObject);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiSimpleRead
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER FileOffset,
|
||||
PVOID Buffer,
|
||||
ULONG Length,
|
||||
PIO_STATUS_BLOCK ReadStatus);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiSimpleWrite
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER FileOffset,
|
||||
PVOID Buffer,
|
||||
ULONG Length,
|
||||
PIO_STATUS_BLOCK ReadStatus,
|
||||
const char *file,
|
||||
int line);
|
||||
|
||||
#define MiSimpleWrite(F,O,B,L,R) _MiSimpleWrite(F,O,B,L,R,__FILE__,__LINE__)
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiWriteBackPage
|
||||
(PFILE_OBJECT FileObject,
|
||||
PLARGE_INTEGER Offset,
|
||||
ULONG Length,
|
||||
PFN_NUMBER Page,
|
||||
const char *File,
|
||||
int Line);
|
||||
|
||||
#define MiWriteBackPage(F,O,L,P) _MiWriteBackPage(F,O,L,P,__FILE__,__LINE__)
|
||||
|
||||
PVOID
|
||||
NTAPI
|
||||
MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset);
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmNotPresentFaultCacheSection
|
||||
(KPROCESSOR_MODE Mode,
|
||||
ULONG_PTR Address,
|
||||
BOOLEAN FromMdl);
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
MiCacheEvictPages(PVOID BaseAddress, ULONG Target);
|
269
reactos/ntoskrnl/cache/section/reqtools.c
vendored
Normal file
269
reactos/ntoskrnl/cache/section/reqtools.c
vendored
Normal file
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/mm/section.c
|
||||
* PURPOSE: Implements section objects
|
||||
*
|
||||
* PROGRAMMERS: Rex Jolliff
|
||||
* David Welch
|
||||
* Eric Kohl
|
||||
* Emanuele Aliberti
|
||||
* Eugene Ingerman
|
||||
* Casper Hornstrup
|
||||
* KJK::Hyperion
|
||||
* Guido de Jong
|
||||
* Ge van Geldorp
|
||||
* Royce Mitchell III
|
||||
* Filip Navara
|
||||
* Aleksey Bragin
|
||||
* Jason Filby
|
||||
* Thomas Weidenmueller
|
||||
* Gunnar Andre' Dalsnes
|
||||
* Mike Nordell
|
||||
* Alex Ionescu
|
||||
* Gregor Anich
|
||||
* Steven Edwards
|
||||
* Herve Poussineau
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newmm.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#define DPRINTC DPRINT
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiGetOnePage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES Required)
|
||||
{
|
||||
int i;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
for (i = 0; i < Required->Amount; i++)
|
||||
{
|
||||
DPRINTC("MiGetOnePage(%s:%d)\n", Required->File, Required->Line);
|
||||
Status = MmRequestPageMemoryConsumer(Required->Consumer, TRUE, &Required->Page[i]);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
while (i > 0)
|
||||
{
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, Required->Page[i-1]);
|
||||
i--;
|
||||
}
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiReadFilePage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES RequiredResources)
|
||||
{
|
||||
PFILE_OBJECT FileObject = RequiredResources->Context;
|
||||
PPFN_NUMBER Page = &RequiredResources->Page[RequiredResources->Offset];
|
||||
PLARGE_INTEGER FileOffset = &RequiredResources->FileOffset;
|
||||
NTSTATUS Status;
|
||||
PVOID PageBuf = NULL;
|
||||
PMEMORY_AREA TmpArea;
|
||||
IO_STATUS_BLOCK IOSB;
|
||||
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
||||
|
||||
BoundaryAddressMultiple.QuadPart = 0;
|
||||
|
||||
DPRINTC
|
||||
("Pulling page %08x%08x from %wZ to %x\n",
|
||||
FileOffset->u.HighPart, FileOffset->u.LowPart,
|
||||
&FileObject->FileName,
|
||||
Page);
|
||||
|
||||
Status = MmRequestPageMemoryConsumer(RequiredResources->Consumer, TRUE, Page);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Status: %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
MmLockAddressSpace(MmGetKernelAddressSpace());
|
||||
Status = MmCreateMemoryArea
|
||||
(MmGetKernelAddressSpace(),
|
||||
MEMORY_AREA_VIRTUAL_MEMORY,
|
||||
&PageBuf,
|
||||
PAGE_SIZE,
|
||||
PAGE_READWRITE,
|
||||
&TmpArea,
|
||||
FALSE,
|
||||
MEM_TOP_DOWN,
|
||||
BoundaryAddressMultiple);
|
||||
|
||||
DPRINT("Status %x, PageBuf %x\n", Status, PageBuf);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("STATUS_NO_MEMORY: %x\n", Status);
|
||||
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, *Page);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
Status = MmCreateVirtualMapping(NULL, PageBuf, PAGE_READWRITE, Page, 1);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
MmFreeMemoryArea(MmGetKernelAddressSpace(), TmpArea, NULL, NULL);
|
||||
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, *Page);
|
||||
DPRINT1("Status: %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
|
||||
Status = MiSimpleRead
|
||||
(FileObject,
|
||||
FileOffset,
|
||||
PageBuf,
|
||||
RequiredResources->Amount,
|
||||
&IOSB);
|
||||
RtlZeroMemory
|
||||
((PCHAR)PageBuf+RequiredResources->Amount,
|
||||
PAGE_SIZE-RequiredResources->Amount);
|
||||
|
||||
DPRINT("Read Status %x (Page %x)\n", Status, *Page);
|
||||
|
||||
MmLockAddressSpace(MmGetKernelAddressSpace());
|
||||
MmFreeMemoryArea(MmGetKernelAddressSpace(), TmpArea, NULL, NULL);
|
||||
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, *Page);
|
||||
DPRINT("Status: %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
MiChecksumPage(PFN_NUMBER Page, BOOLEAN Lock)
|
||||
{
|
||||
int i;
|
||||
NTSTATUS Status;
|
||||
ULONG Total = 0;
|
||||
PULONG PageBuf = NULL;
|
||||
PMEMORY_AREA TmpArea;
|
||||
PHYSICAL_ADDRESS BoundaryAddressMultiple;
|
||||
|
||||
BoundaryAddressMultiple.QuadPart = 0;
|
||||
|
||||
if (Lock) MmLockAddressSpace(MmGetKernelAddressSpace());
|
||||
|
||||
Status = MmCreateMemoryArea
|
||||
(MmGetKernelAddressSpace(),
|
||||
MEMORY_AREA_VIRTUAL_MEMORY,
|
||||
(PVOID*)&PageBuf,
|
||||
PAGE_SIZE,
|
||||
PAGE_READWRITE,
|
||||
&TmpArea,
|
||||
FALSE,
|
||||
MEM_TOP_DOWN,
|
||||
BoundaryAddressMultiple);
|
||||
|
||||
DPRINT("Status %x, PageBuf %x\n", Status, PageBuf);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("STATUS_NO_MEMORY: %x\n", Status);
|
||||
if (Lock) MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
return 0;
|
||||
}
|
||||
|
||||
Status = MmCreateVirtualMapping(NULL, PageBuf, PAGE_READWRITE, &Page, 1);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
MmFreeMemoryArea(MmGetKernelAddressSpace(), TmpArea, NULL, NULL);
|
||||
if (Lock) MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
DPRINT1("Status: %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
for (i = 0; i < 1024; i++) {
|
||||
Total += PageBuf[i];
|
||||
}
|
||||
|
||||
MmFreeMemoryArea(MmGetKernelAddressSpace(), TmpArea, NULL, NULL);
|
||||
if (Lock) MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
|
||||
return Total;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiSwapInPage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES Resources)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
|
||||
Status = MmRequestPageMemoryConsumer(Resources->Consumer, TRUE, &Resources->Page[Resources->Offset]);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("MmRequestPageMemoryConsumer failed, status = %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = MmReadFromSwapPage(Resources->SwapEntry, Resources->Page[Resources->Offset]);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("MmReadFromSwapPage failed, status = %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
MmSetSavedSwapEntryPage(Resources->Page[Resources->Offset], Resources->SwapEntry);
|
||||
|
||||
DPRINT1("MiSwapInPage(%x,%x)\n", Resources->Page[Resources->Offset], Resources->SwapEntry);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiWriteFilePage
|
||||
(PMMSUPPORT AddressSpace,
|
||||
PMEMORY_AREA MemoryArea,
|
||||
PMM_REQUIRED_RESOURCES Required)
|
||||
{
|
||||
DPRINT1("MiWriteFilePage(%x,%x)\n", Required->Page[Required->Offset], Required->FileOffset.LowPart);
|
||||
|
||||
return MiWriteBackPage
|
||||
(Required->Context,
|
||||
&Required->FileOffset,
|
||||
PAGE_SIZE,
|
||||
Required->Page[Required->Offset]);
|
||||
}
|
266
reactos/ntoskrnl/cache/section/sptab.c
vendored
Normal file
266
reactos/ntoskrnl/cache/section/sptab.c
vendored
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/mm/section.c
|
||||
* PURPOSE: Section object page tables
|
||||
*
|
||||
* PROGRAMMERS: arty
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newmm.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#define DPRINTC DPRINT
|
||||
|
||||
/* TYPES *********************************************************************/
|
||||
|
||||
extern KSPIN_LOCK MiSectionPageTableLock;
|
||||
|
||||
static
|
||||
PVOID
|
||||
NTAPI
|
||||
MiSectionPageTableAllocate(PRTL_GENERIC_TABLE Table, CLONG Bytes)
|
||||
{
|
||||
PVOID Result;
|
||||
Result = ExAllocatePoolWithTag(NonPagedPool, Bytes, 'MmPt');
|
||||
DPRINT("MiSectionPageTableAllocate(%d) => %p\n", Bytes, Result);
|
||||
return Result;
|
||||
}
|
||||
|
||||
static
|
||||
VOID
|
||||
NTAPI
|
||||
MiSectionPageTableFree(PRTL_GENERIC_TABLE Table, PVOID Data)
|
||||
{
|
||||
DPRINT("MiSectionPageTableFree(%p)\n", Data);
|
||||
ExFreePoolWithTag(Data, 'MmPt');
|
||||
}
|
||||
|
||||
static
|
||||
RTL_GENERIC_COMPARE_RESULTS
|
||||
NTAPI
|
||||
MiSectionPageTableCompare(PRTL_GENERIC_TABLE Table, PVOID PtrA, PVOID PtrB)
|
||||
{
|
||||
PLARGE_INTEGER A = PtrA, B = PtrB;
|
||||
BOOLEAN Result = (A->QuadPart < B->QuadPart) ? GenericLessThan :
|
||||
(A->QuadPart == B->QuadPart) ? GenericEqual : GenericGreaterThan;
|
||||
|
||||
DPRINT
|
||||
("Compare: %08x%08x vs %08x%08x => %s\n",
|
||||
A->u.HighPart, A->u.LowPart,
|
||||
B->u.HighPart, B->u.LowPart,
|
||||
Result == GenericLessThan ? "GenericLessThan" :
|
||||
Result == GenericGreaterThan ? "GenericGreaterThan" :
|
||||
"GenericEqual");
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static
|
||||
PCACHE_SECTION_PAGE_TABLE
|
||||
NTAPI
|
||||
MiSectionPageTableGet
|
||||
(PRTL_GENERIC_TABLE Table,
|
||||
PLARGE_INTEGER FileOffset)
|
||||
{
|
||||
LARGE_INTEGER SearchFileOffset;
|
||||
PCACHE_SECTION_PAGE_TABLE PageTable;
|
||||
SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE);
|
||||
PageTable = RtlLookupElementGenericTable(Table, &SearchFileOffset);
|
||||
DPRINT
|
||||
("MiSectionPageTableGet(%08x,%08x%08x)\n",
|
||||
Table,
|
||||
FileOffset->HighPart,
|
||||
FileOffset->LowPart);
|
||||
return PageTable;
|
||||
}
|
||||
|
||||
static
|
||||
PCACHE_SECTION_PAGE_TABLE
|
||||
NTAPI
|
||||
MiSectionPageTableGetOrAllocate
|
||||
(PRTL_GENERIC_TABLE Table,
|
||||
PLARGE_INTEGER FileOffset)
|
||||
{
|
||||
LARGE_INTEGER SearchFileOffset;
|
||||
PCACHE_SECTION_PAGE_TABLE PageTableSlice =
|
||||
MiSectionPageTableGet(Table, FileOffset);
|
||||
if (!PageTableSlice)
|
||||
{
|
||||
CACHE_SECTION_PAGE_TABLE SectionZeroPageTable = { };
|
||||
SearchFileOffset.QuadPart = ROUND_DOWN(FileOffset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE);
|
||||
SectionZeroPageTable.FileOffset = SearchFileOffset;
|
||||
SectionZeroPageTable.Refcount = 1;
|
||||
PageTableSlice = RtlInsertElementGenericTable
|
||||
(Table, &SectionZeroPageTable, sizeof(SectionZeroPageTable), NULL);
|
||||
DPRINT
|
||||
("Allocate page table %x (%08x%08x)\n",
|
||||
PageTableSlice,
|
||||
PageTableSlice->FileOffset.u.HighPart,
|
||||
PageTableSlice->FileOffset.u.LowPart);
|
||||
if (!PageTableSlice) return NULL;
|
||||
}
|
||||
return PageTableSlice;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiInitializeSectionPageTable(PMM_CACHE_SECTION_SEGMENT Segment)
|
||||
{
|
||||
RtlInitializeGenericTable
|
||||
(&Segment->PageTable,
|
||||
MiSectionPageTableCompare,
|
||||
MiSectionPageTableAllocate,
|
||||
MiSectionPageTableFree,
|
||||
NULL);
|
||||
DPRINT("MiInitializeSectionPageTable(%p)\n", &Segment->PageTable);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
_MiSetPageEntryCacheSectionSegment
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
PLARGE_INTEGER Offset,
|
||||
ULONG Entry,
|
||||
const char *file,
|
||||
int line)
|
||||
{
|
||||
ULONG PageIndex, OldEntry;
|
||||
PCACHE_SECTION_PAGE_TABLE PageTable;
|
||||
PageTable =
|
||||
MiSectionPageTableGetOrAllocate(&Segment->PageTable, Offset);
|
||||
if (!PageTable) return STATUS_NO_MEMORY;
|
||||
ASSERT(MiSectionPageTableGet(&Segment->PageTable, Offset));
|
||||
PageTable->Segment = Segment;
|
||||
PageIndex =
|
||||
(Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE;
|
||||
OldEntry = PageTable->PageEntries[PageIndex];
|
||||
if (OldEntry && !IS_SWAP_FROM_SSE(OldEntry)) {
|
||||
MmDeleteSectionAssociation(PFN_FROM_SSE(OldEntry));
|
||||
}
|
||||
if (Entry && !IS_SWAP_FROM_SSE(Entry)) {
|
||||
MmSetSectionAssociation(PFN_FROM_SSE(Entry), Segment, Offset);
|
||||
}
|
||||
PageTable->PageEntries[PageIndex] = Entry;
|
||||
DPRINT
|
||||
("MiSetPageEntrySectionSegment(%p,%08x%08x,%x) %s:%d\n",
|
||||
Segment, Offset->u.HighPart, Offset->u.LowPart, Entry, file, line);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
_MiGetPageEntryCacheSectionSegment
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment,
|
||||
PLARGE_INTEGER Offset,
|
||||
const char *file,
|
||||
int line)
|
||||
{
|
||||
LARGE_INTEGER FileOffset;
|
||||
ULONG PageIndex, Result;
|
||||
PCACHE_SECTION_PAGE_TABLE PageTable;
|
||||
|
||||
FileOffset.QuadPart =
|
||||
ROUND_DOWN(Offset->QuadPart, ENTRIES_PER_ELEMENT * PAGE_SIZE);
|
||||
PageTable = MiSectionPageTableGet(&Segment->PageTable, &FileOffset);
|
||||
if (!PageTable) return 0;
|
||||
PageIndex =
|
||||
(Offset->QuadPart - PageTable->FileOffset.QuadPart) / PAGE_SIZE;
|
||||
Result = PageTable->PageEntries[PageIndex];
|
||||
#if 0
|
||||
DPRINTC
|
||||
("MiGetPageEntrySectionSegment(%p,%08x%08x) => %x %s:%d\n",
|
||||
Segment,
|
||||
FileOffset.u.HighPart,
|
||||
FileOffset.u.LowPart + PageIndex * PAGE_SIZE,
|
||||
Result,
|
||||
file, line);
|
||||
#endif
|
||||
return Result;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MiFreePageTablesSectionSegment
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment, FREE_SECTION_PAGE_FUN FreePage)
|
||||
{
|
||||
PCACHE_SECTION_PAGE_TABLE Element;
|
||||
DPRINT("MiFreePageTablesSectionSegment(%p)\n", &Segment->PageTable);
|
||||
while ((Element = RtlGetElementGenericTable(&Segment->PageTable, 0))) {
|
||||
DPRINT
|
||||
("Delete table for %x -> %08x%08x\n",
|
||||
Segment,
|
||||
Element->FileOffset.u.HighPart,
|
||||
Element->FileOffset.u.LowPart);
|
||||
if (FreePage)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < ENTRIES_PER_ELEMENT; i++)
|
||||
{
|
||||
ULONG Entry;
|
||||
LARGE_INTEGER Offset;
|
||||
Offset.QuadPart = Element->FileOffset.QuadPart + i * PAGE_SIZE;
|
||||
Entry = Element->PageEntries[i];
|
||||
if (Entry && !IS_SWAP_FROM_SSE(Entry))
|
||||
{
|
||||
DPRINTC("Freeing page %x:%x @ %x\n", Segment, Entry, Offset.LowPart);
|
||||
FreePage(Segment, &Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
DPRINT("Remove memory\n");
|
||||
RtlDeleteElementGenericTable(&Segment->PageTable, Element);
|
||||
}
|
||||
DPRINT("Done\n");
|
||||
}
|
||||
|
||||
PMM_CACHE_SECTION_SEGMENT
|
||||
NTAPI
|
||||
MmGetSectionAssociation(PFN_NUMBER Page, PLARGE_INTEGER Offset)
|
||||
{
|
||||
ULONG RawOffset;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment = NULL;
|
||||
PCACHE_SECTION_PAGE_TABLE PageTable;
|
||||
|
||||
PageTable = (PCACHE_SECTION_PAGE_TABLE)MmGetSegmentRmap(Page, &RawOffset);
|
||||
if (PageTable)
|
||||
{
|
||||
Segment = PageTable->Segment;
|
||||
Offset->QuadPart = PageTable->FileOffset.QuadPart + (RawOffset << PAGE_SHIFT);
|
||||
}
|
||||
|
||||
return(Segment);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmSetSectionAssociation(PFN_NUMBER Page, PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER Offset)
|
||||
{
|
||||
PCACHE_SECTION_PAGE_TABLE PageTable;
|
||||
ULONG ActualOffset;
|
||||
PageTable = MiSectionPageTableGet(&Segment->PageTable, Offset);
|
||||
ASSERT(PageTable);
|
||||
ActualOffset = (ULONG)(Offset->QuadPart - PageTable->FileOffset.QuadPart);
|
||||
MmInsertRmap(Page, (PEPROCESS)PageTable, (PVOID)(RMAP_SEGMENT_MASK | (ActualOffset >> PAGE_SHIFT)));
|
||||
return STATUS_SUCCESS;
|
||||
}
|
508
reactos/ntoskrnl/cache/section/swapout.c
vendored
Normal file
508
reactos/ntoskrnl/cache/section/swapout.c
vendored
Normal file
|
@ -0,0 +1,508 @@
|
|||
/*
|
||||
* Copyright (C) 1998-2005 ReactOS Team (and the authors from the programmers section)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
*
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/mm/section/fault.c
|
||||
* PURPOSE: Consolidate fault handlers for sections
|
||||
*
|
||||
* PROGRAMMERS: Arty
|
||||
* Rex Jolliff
|
||||
* David Welch
|
||||
* Eric Kohl
|
||||
* Emanuele Aliberti
|
||||
* Eugene Ingerman
|
||||
* Casper Hornstrup
|
||||
* KJK::Hyperion
|
||||
* Guido de Jong
|
||||
* Ge van Geldorp
|
||||
* Royce Mitchell III
|
||||
* Filip Navara
|
||||
* Aleksey Bragin
|
||||
* Jason Filby
|
||||
* Thomas Weidenmueller
|
||||
* Gunnar Andre' Dalsnes
|
||||
* Mike Nordell
|
||||
* Alex Ionescu
|
||||
* Gregor Anich
|
||||
* Steven Edwards
|
||||
* Herve Poussineau
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "newmm.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
#define DPRINTC DPRINT
|
||||
|
||||
extern KEVENT MmWaitPageEvent;
|
||||
extern FAST_MUTEX RmapListLock;
|
||||
|
||||
FAST_MUTEX GlobalPageOperation;
|
||||
|
||||
PFN_NUMBER
|
||||
NTAPI
|
||||
MmWithdrawSectionPage
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER FileOffset, BOOLEAN *Dirty)
|
||||
{
|
||||
ULONG Entry;
|
||||
|
||||
DPRINT("MmWithdrawSectionPage(%x,%08x%08x,%x)\n", Segment, FileOffset->HighPart, FileOffset->LowPart, Dirty);
|
||||
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
Entry = MiGetPageEntryCacheSectionSegment(Segment, FileOffset);
|
||||
|
||||
*Dirty = !!IS_DIRTY_SSE(Entry);
|
||||
|
||||
DPRINT("Withdraw %x (%x) of %wZ\n", FileOffset->LowPart, Entry, Segment->FileObject ? &Segment->FileObject->FileName : NULL);
|
||||
|
||||
if (!Entry)
|
||||
{
|
||||
DPRINT("Stoeled!\n");
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
return 0;
|
||||
}
|
||||
else if (MM_IS_WAIT_PTE(Entry))
|
||||
{
|
||||
DPRINT("WAIT\n");
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
return MM_WAIT_ENTRY;
|
||||
}
|
||||
else if (Entry && !IS_SWAP_FROM_SSE(Entry))
|
||||
{
|
||||
DPRINT("Page %x\n", PFN_FROM_SSE(Entry));
|
||||
*Dirty |= (Entry & 2);
|
||||
MiSetPageEntryCacheSectionSegment(Segment, FileOffset, MAKE_SWAP_SSE(MM_WAIT_ENTRY));
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
return PFN_FROM_SSE(Entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT1("SWAP ENTRY?! (%x:%08x%08x)\n", Segment, FileOffset->HighPart, FileOffset->LowPart);
|
||||
ASSERT(FALSE);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmFinalizeSectionPageOut
|
||||
(PMM_CACHE_SECTION_SEGMENT Segment, PLARGE_INTEGER FileOffset, PFN_NUMBER Page,
|
||||
BOOLEAN Dirty)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
BOOLEAN WriteZero = FALSE, WritePage = FALSE;
|
||||
SWAPENTRY Swap = MmGetSavedSwapEntryPage(Page);
|
||||
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
(void)InterlockedIncrementUL(&Segment->ReferenceCount);
|
||||
|
||||
if (Dirty)
|
||||
{
|
||||
DPRINT("Finalize (dirty) Segment %x Page %x\n", Segment, Page);
|
||||
DPRINT("Segment->FileObject %x\n", Segment->FileObject);
|
||||
DPRINT("Segment->Flags %x\n", Segment->Flags);
|
||||
|
||||
WriteZero = TRUE;
|
||||
WritePage = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteZero = TRUE;
|
||||
}
|
||||
|
||||
DPRINT("Status %x\n", Status);
|
||||
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
|
||||
if (WritePage)
|
||||
{
|
||||
DPRINT("MiWriteBackPage(Segment %x FileObject %x Offset %x)\n", Segment, Segment->FileObject, FileOffset->LowPart);
|
||||
Status = MiWriteBackPage(Segment->FileObject, FileOffset, PAGE_SIZE, Page);
|
||||
}
|
||||
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
|
||||
if (WriteZero && NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Setting page entry in segment %x:%x to swap %x\n", Segment, FileOffset->LowPart, Swap);
|
||||
MiSetPageEntryCacheSectionSegment(Segment, FileOffset, Swap ? MAKE_SWAP_SSE(Swap) : 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("Setting page entry in segment %x:%x to page %x\n", Segment, FileOffset->LowPart, Page);
|
||||
MiSetPageEntryCacheSectionSegment
|
||||
(Segment, FileOffset, Page ? (Dirty ? DIRTY_SSE(MAKE_PFN_SSE(Page)) : MAKE_PFN_SSE(Page)) : 0);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("Removing page %x for real\n", Page);
|
||||
MmSetSavedSwapEntryPage(Page, 0);
|
||||
// Note: the other one is held by MmTrimUserMemory
|
||||
if (MmGetReferenceCountPage(Page) != 2) {
|
||||
DPRINT1("ALERT: Page %x about to be evicted with ref count %d\n", Page, MmGetReferenceCountPage(Page));
|
||||
}
|
||||
MmDereferencePage(Page);
|
||||
}
|
||||
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
|
||||
if (InterlockedDecrementUL(&Segment->ReferenceCount) == 0)
|
||||
{
|
||||
MmFinalizeSegment(Segment);
|
||||
}
|
||||
|
||||
/* Note: Writing may evict the segment... Nothing is guaranteed from here down */
|
||||
MiSetPageEvent(Segment, FileOffset->LowPart);
|
||||
|
||||
DPRINT("Status %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmPageOutCacheSection
|
||||
(PMMSUPPORT AddressSpace,
|
||||
MEMORY_AREA* MemoryArea,
|
||||
PVOID Address,
|
||||
PMM_REQUIRED_RESOURCES Required)
|
||||
{
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
ULONG Entry;
|
||||
BOOLEAN Dirty = FALSE;
|
||||
PEPROCESS Process = MmGetAddressSpaceOwner(AddressSpace);
|
||||
LARGE_INTEGER TotalOffset;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment;
|
||||
PVOID PAddress = MM_ROUND_DOWN(Address, PAGE_SIZE);
|
||||
|
||||
TotalOffset.QuadPart = (ULONG_PTR)PAddress - (ULONG_PTR)MemoryArea->StartingAddress +
|
||||
MemoryArea->Data.CacheData.ViewOffset.QuadPart;
|
||||
|
||||
Segment = MemoryArea->Data.CacheData.Segment;
|
||||
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
|
||||
|
||||
Dirty = MmIsDirtyPageRmap(Required->Page[0]);
|
||||
Entry = MiGetPageEntryCacheSectionSegment(Segment, &TotalOffset);
|
||||
|
||||
if (Dirty)
|
||||
{
|
||||
PFN_NUMBER OurPage;
|
||||
MiSetPageEntryCacheSectionSegment(Segment, &TotalOffset, DIRTY_SSE(Entry));
|
||||
MmDeleteRmap(Required->Page[0], Process, Address);
|
||||
MmDeleteVirtualMapping(Process, Address, FALSE, &Dirty, &OurPage);
|
||||
ASSERT(OurPage == Required->Page[0]);
|
||||
} else {
|
||||
/* Just unmap if the page wasn't dirty */
|
||||
PFN_NUMBER OurPage;
|
||||
MmDeleteRmap(Required->Page[0], Process, Address);
|
||||
MmDeleteVirtualMapping(Process, Address, FALSE, &Dirty, &OurPage);
|
||||
DPRINT("OurPage %x ThePage %x\n", OurPage, Required->Page[0]);
|
||||
ASSERT(OurPage == Required->Page[0]);
|
||||
}
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
MmDereferencePage(Required->Page[0]);
|
||||
}
|
||||
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
MiSetPageEvent(Process, Address);
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MmpPageOutPhysicalAddress(PFN_NUMBER Page)
|
||||
{
|
||||
BOOLEAN ProcRef = FALSE;
|
||||
PFN_NUMBER SectionPage = 0;
|
||||
PMM_RMAP_ENTRY entry;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment = NULL;
|
||||
LARGE_INTEGER FileOffset;
|
||||
PMEMORY_AREA MemoryArea;
|
||||
PMMSUPPORT AddressSpace = MmGetKernelAddressSpace();
|
||||
BOOLEAN Dirty = FALSE;
|
||||
PVOID Address = NULL;
|
||||
PEPROCESS Process = NULL;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
MM_REQUIRED_RESOURCES Resources = { 0 };
|
||||
|
||||
DPRINTC("Page out %x (ref ct %x)\n", Page, MmGetReferenceCountPage(Page));
|
||||
|
||||
ExAcquireFastMutex(&GlobalPageOperation);
|
||||
if ((Segment = MmGetSectionAssociation(Page, &FileOffset)))
|
||||
{
|
||||
DPRINT1("Withdrawing page (%x) %x:%x\n", Page, Segment, FileOffset.LowPart);
|
||||
SectionPage = MmWithdrawSectionPage(Segment, &FileOffset, &Dirty);
|
||||
DPRINTC("SectionPage %x\n", SectionPage);
|
||||
|
||||
if (SectionPage == MM_WAIT_ENTRY || SectionPage == 0)
|
||||
{
|
||||
DPRINT1("In progress page out %x\n", SectionPage);
|
||||
ExReleaseFastMutex(&GlobalPageOperation);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(SectionPage == Page);
|
||||
}
|
||||
Resources.State = Dirty ? 1 : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
DPRINT("No segment association for %x\n", Page);
|
||||
}
|
||||
|
||||
|
||||
Dirty = MmIsDirtyPageRmap(Page);
|
||||
|
||||
DPRINTC("Trying to unmap all instances of %x\n", Page);
|
||||
ExAcquireFastMutex(&RmapListLock);
|
||||
entry = MmGetRmapListHeadPage(Page);
|
||||
|
||||
// Entry and Segment might be null here in the case that the page
|
||||
// is new and is in the process of being swapped in
|
||||
if (!entry && !Segment)
|
||||
{
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
DPRINT1("Page %x is in transit\n", Page);
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
while (entry != NULL && NT_SUCCESS(Status))
|
||||
{
|
||||
Process = entry->Process;
|
||||
Address = entry->Address;
|
||||
|
||||
DPRINTC("Process %x Address %x Page %x\n", Process, Address, Page);
|
||||
|
||||
if (RMAP_IS_SEGMENT(Address)) {
|
||||
entry = entry->Next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Process && Address < MmSystemRangeStart)
|
||||
{
|
||||
// Make sure we don't try to page out part of an exiting process
|
||||
if (PspIsProcessExiting(Process))
|
||||
{
|
||||
DPRINT("bail\n");
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
goto bail;
|
||||
}
|
||||
Status = ObReferenceObject(Process);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("bail\n");
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
goto bail;
|
||||
}
|
||||
ProcRef = TRUE;
|
||||
AddressSpace = &Process->Vm;
|
||||
}
|
||||
else
|
||||
{
|
||||
AddressSpace = MmGetKernelAddressSpace();
|
||||
}
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
|
||||
RtlZeroMemory(&Resources, sizeof(Resources));
|
||||
|
||||
if ((((ULONG_PTR)Address) & 0xFFF) != 0)
|
||||
{
|
||||
KeBugCheck(MEMORY_MANAGEMENT);
|
||||
}
|
||||
|
||||
if (!MmTryToLockAddressSpace(AddressSpace))
|
||||
{
|
||||
DPRINT1("Could not lock address space for process %x\n", MmGetAddressSpaceOwner(AddressSpace));
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
goto bail;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
MemoryArea = MmLocateMemoryAreaByAddress(AddressSpace, Address);
|
||||
if (MemoryArea == NULL ||
|
||||
MemoryArea->DeleteInProgress)
|
||||
{
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
DPRINTC("bail\n");
|
||||
goto bail;
|
||||
}
|
||||
|
||||
DPRINTC
|
||||
("Type %x (%x -> %x)\n",
|
||||
MemoryArea->Type,
|
||||
MemoryArea->StartingAddress,
|
||||
MemoryArea->EndingAddress);
|
||||
|
||||
Resources.DoAcquisition = NULL;
|
||||
|
||||
Resources.Page[0] = Page;
|
||||
|
||||
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
|
||||
|
||||
DPRINT("%x:%x, page %x %x\n", Process, Address, Page, Resources.Page[0]);
|
||||
Status = MmPageOutCacheSection
|
||||
(AddressSpace, MemoryArea, Address, &Resources);
|
||||
DPRINT("%x\n", Status);
|
||||
|
||||
ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
|
||||
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
|
||||
if (Status == STATUS_SUCCESS + 1)
|
||||
{
|
||||
// Wait page ... the other guy has it, so we'll just fail for now
|
||||
DPRINTC("Wait entry ... can't continue\n");
|
||||
Status = STATUS_UNSUCCESSFUL;
|
||||
goto bail;
|
||||
}
|
||||
else if (Status == STATUS_MORE_PROCESSING_REQUIRED)
|
||||
{
|
||||
DPRINTC("DoAcquisition %x\n", Resources.DoAcquisition);
|
||||
Status = Resources.DoAcquisition(AddressSpace, MemoryArea, &Resources);
|
||||
DPRINTC("Status %x\n", Status);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("bail\n");
|
||||
goto bail;
|
||||
}
|
||||
else Status = STATUS_MM_RESTART_OPERATION;
|
||||
}
|
||||
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
}
|
||||
while (Status == STATUS_MM_RESTART_OPERATION);
|
||||
Dirty |= Resources.State & 1; // Accumulate dirty
|
||||
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
|
||||
if (ProcRef)
|
||||
{
|
||||
ObDereferenceObject(Process);
|
||||
ProcRef = FALSE;
|
||||
}
|
||||
|
||||
ExAcquireFastMutex(&RmapListLock);
|
||||
ASSERT(!MM_IS_WAIT_PTE(MmGetPfnForProcess(Process, Address)));
|
||||
entry = MmGetRmapListHeadPage(Page);
|
||||
|
||||
DPRINTC("Entry %x\n", entry);
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
|
||||
bail:
|
||||
DPRINTC("BAIL %x\n", Status);
|
||||
|
||||
if (Segment)
|
||||
{
|
||||
DPRINTC("About to finalize section page %x (%x:%x) Status %x %s\n", Page, Segment, FileOffset.LowPart, Status, Dirty ? "dirty" : "clean");
|
||||
|
||||
if (!NT_SUCCESS(Status) ||
|
||||
!NT_SUCCESS
|
||||
(Status = MmFinalizeSectionPageOut
|
||||
(Segment, &FileOffset, Page, Dirty)))
|
||||
{
|
||||
DPRINTC
|
||||
("Failed to page out %x, replacing %x at %x in segment %x\n",
|
||||
SectionPage, FileOffset.LowPart, Segment);
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
MiSetPageEntryCacheSectionSegment(Segment, &FileOffset, Dirty ? MAKE_PFN_SSE(Page) : DIRTY_SSE(MAKE_PFN_SSE(Page)));
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
}
|
||||
|
||||
// Alas, we had the last reference
|
||||
ULONG RefCount;
|
||||
if ((RefCount = InterlockedDecrementUL(&Segment->ReferenceCount)) == 0)
|
||||
MmFinalizeSegment(Segment);
|
||||
}
|
||||
|
||||
if (ProcRef)
|
||||
{
|
||||
DPRINTC("Dereferencing process...\n");
|
||||
ObDereferenceObject(Process);
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&GlobalPageOperation);
|
||||
DPRINTC("%s %x %x\n", NT_SUCCESS(Status) ? "Evicted" : "Spared", Page, Status);
|
||||
return NT_SUCCESS(Status) ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
ULONG
|
||||
NTAPI
|
||||
MiCacheEvictPages(PVOID BaseAddress, ULONG Target)
|
||||
{
|
||||
ULONG i, Entry, Result = 0;
|
||||
NTSTATUS Status;
|
||||
PFN_NUMBER Page;
|
||||
PMEMORY_AREA MemoryArea;
|
||||
LARGE_INTEGER Offset;
|
||||
PMM_CACHE_SECTION_SEGMENT Segment;
|
||||
|
||||
MmLockAddressSpace(MmGetKernelAddressSpace());
|
||||
MemoryArea = MmLocateMemoryAreaByAddress
|
||||
(MmGetKernelAddressSpace(),
|
||||
BaseAddress);
|
||||
|
||||
ASSERT(MemoryArea);
|
||||
ASSERT(MemoryArea->Type == MEMORY_AREA_CACHE);
|
||||
|
||||
Segment = MemoryArea->Data.CacheData.Segment;
|
||||
|
||||
ASSERT(Segment);
|
||||
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
|
||||
for (i = 0;
|
||||
i < Segment->Length.QuadPart -
|
||||
MemoryArea->Data.CacheData.ViewOffset.QuadPart &&
|
||||
Result < Target;
|
||||
i += PAGE_SIZE) {
|
||||
Offset.QuadPart = MemoryArea->Data.CacheData.ViewOffset.QuadPart + i;
|
||||
Entry = MiGetPageEntryCacheSectionSegment(Segment, &Offset);
|
||||
if (Entry && !IS_SWAP_FROM_SSE(Entry)) {
|
||||
Page = PFN_FROM_SSE(Entry);
|
||||
MmReferencePage(Page);
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
Status = MmpPageOutPhysicalAddress(Page);
|
||||
if (NT_SUCCESS(Status))
|
||||
Result++;
|
||||
MmLockCacheSectionSegment(Segment);
|
||||
MmLockAddressSpace(MmGetKernelAddressSpace());
|
||||
MmReleasePageMemoryConsumer(MC_CACHE, Page);
|
||||
}
|
||||
}
|
||||
|
||||
MmUnlockCacheSectionSegment(Segment);
|
||||
MmUnlockAddressSpace(MmGetKernelAddressSpace());
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
|
@ -248,6 +248,8 @@ typedef struct _ROS_SECTION_OBJECT
|
|||
};
|
||||
} ROS_SECTION_OBJECT, *PROS_SECTION_OBJECT;
|
||||
|
||||
struct _MM_CACHE_SECTION_SEGMENT;
|
||||
|
||||
typedef struct _MEMORY_AREA
|
||||
{
|
||||
PVOID StartingAddress;
|
||||
|
@ -270,6 +272,11 @@ typedef struct _MEMORY_AREA
|
|||
PMM_SECTION_SEGMENT Segment;
|
||||
LIST_ENTRY RegionListHead;
|
||||
} SectionData;
|
||||
struct
|
||||
{
|
||||
LARGE_INTEGER ViewOffset;
|
||||
struct _MM_CACHE_SECTION_SEGMENT *Segment;
|
||||
} CacheData;
|
||||
struct
|
||||
{
|
||||
LIST_ENTRY RegionListHead;
|
||||
|
@ -1286,6 +1293,14 @@ VOID
|
|||
NTAPI
|
||||
MmRawDeleteVirtualMapping(PVOID Address);
|
||||
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmGetPageFileMapping(
|
||||
struct _EPROCESS *Process,
|
||||
PVOID Address,
|
||||
SWAPENTRY* SwapEntry);
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmDeletePageFileMapping(
|
||||
|
|
|
@ -399,6 +399,10 @@ PsChargeProcessPageFileQuota(
|
|||
IN SIZE_T Amount
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
PspIsProcessExiting(IN PEPROCESS Process);
|
||||
|
||||
//
|
||||
// Global data inside the Process Manager
|
||||
//
|
||||
|
|
|
@ -465,6 +465,18 @@ MmDeleteVirtualMapping(PEPROCESS Process, PVOID Address, BOOLEAN FreePage,
|
|||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmGetPageFileMapping(PEPROCESS Process, PVOID Address,
|
||||
SWAPENTRY* SwapEntry)
|
||||
/*
|
||||
* FUNCTION: Get a page file mapping
|
||||
*/
|
||||
{
|
||||
ULONG Entry = MmGetPageEntryForProcess(Process, Address);
|
||||
*SwapEntry = Entry >> 1;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmDeletePageFileMapping(PEPROCESS Process, PVOID Address,
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
/* INCLUDES *******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#ifdef NEWCC
|
||||
#include "../cache/section/newmm.h"
|
||||
#endif
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
|
@ -85,6 +88,18 @@ MmpAccessFault(KPROCESSOR_MODE Mode,
|
|||
Status = STATUS_ACCESS_VIOLATION;
|
||||
break;
|
||||
|
||||
#ifdef NEWCC
|
||||
case MEMORY_AREA_CACHE:
|
||||
// This code locks for itself to keep from having to break a lock
|
||||
// passed in.
|
||||
if (!FromMdl)
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
Status = MmAccessFaultCacheSection(Mode, Address, Locked);
|
||||
if (!FromMdl)
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
Status = STATUS_ACCESS_VIOLATION;
|
||||
break;
|
||||
|
@ -175,6 +190,18 @@ MmNotPresentFault(KPROCESSOR_MODE Mode,
|
|||
Locked);
|
||||
break;
|
||||
|
||||
#ifdef NEWCC
|
||||
case MEMORY_AREA_CACHE:
|
||||
// This code locks for itself to keep from having to break a lock
|
||||
// passed in.
|
||||
if (!FromMdl)
|
||||
MmUnlockAddressSpace(AddressSpace);
|
||||
Status = MmNotPresentFaultCacheSection(Mode, Address, Locked);
|
||||
if (!FromMdl)
|
||||
MmLockAddressSpace(AddressSpace);
|
||||
break;
|
||||
#endif
|
||||
|
||||
default:
|
||||
Status = STATUS_ACCESS_VIOLATION;
|
||||
break;
|
||||
|
|
|
@ -302,7 +302,11 @@ MmMpwThreadMain(PVOID Ignored)
|
|||
|
||||
PagesWritten = 0;
|
||||
|
||||
#ifndef NEWCC
|
||||
// XXX arty -- we flush when evicting pages or destorying cache
|
||||
// sections.
|
||||
CcRosFlushDirtyPages(128, &PagesWritten);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "../cache/section/newmm.h"
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
|
@ -21,8 +22,8 @@
|
|||
|
||||
/* GLOBALS ******************************************************************/
|
||||
|
||||
static FAST_MUTEX RmapListLock;
|
||||
static NPAGED_LOOKASIDE_LIST RmapLookasideList;
|
||||
FAST_MUTEX RmapListLock;
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
|
@ -55,6 +56,8 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page)
|
|||
ULONG Offset;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
ASSERT(FALSE);
|
||||
|
||||
ExAcquireFastMutex(&RmapListLock);
|
||||
entry = MmGetRmapListHeadPage(Page);
|
||||
if (entry == NULL)
|
||||
|
@ -65,6 +68,7 @@ MmPageOutPhysicalAddress(PFN_NUMBER Page)
|
|||
Process = entry->Process;
|
||||
|
||||
Address = entry->Address;
|
||||
|
||||
if ((((ULONG_PTR)Address) & 0xFFF) != 0)
|
||||
{
|
||||
KeBugCheck(MEMORY_MANAGEMENT);
|
||||
|
@ -193,8 +197,9 @@ MmSetCleanAllRmaps(PFN_NUMBER Page)
|
|||
}
|
||||
while (current_entry != NULL)
|
||||
{
|
||||
MmSetCleanPage(current_entry->Process, current_entry->Address);
|
||||
current_entry = current_entry->Next;
|
||||
if (!RMAP_IS_SEGMENT(current_entry->Address))
|
||||
MmSetCleanPage(current_entry->Process, current_entry->Address);
|
||||
current_entry = current_entry->Next;
|
||||
}
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
}
|
||||
|
@ -214,7 +219,8 @@ MmSetDirtyAllRmaps(PFN_NUMBER Page)
|
|||
}
|
||||
while (current_entry != NULL)
|
||||
{
|
||||
MmSetDirtyPage(current_entry->Process, current_entry->Address);
|
||||
if (!RMAP_IS_SEGMENT(current_entry->Address))
|
||||
MmSetDirtyPage(current_entry->Process, current_entry->Address);
|
||||
current_entry = current_entry->Next;
|
||||
}
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
|
@ -235,7 +241,8 @@ MmIsDirtyPageRmap(PFN_NUMBER Page)
|
|||
}
|
||||
while (current_entry != NULL)
|
||||
{
|
||||
if (MmIsDirtyPage(current_entry->Process, current_entry->Address))
|
||||
if (!RMAP_IS_SEGMENT(current_entry->Address) &&
|
||||
MmIsDirtyPage(current_entry->Process, current_entry->Address))
|
||||
{
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
return(TRUE);
|
||||
|
@ -255,7 +262,8 @@ MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process,
|
|||
PMM_RMAP_ENTRY new_entry;
|
||||
ULONG PrevSize;
|
||||
|
||||
Address = (PVOID)PAGE_ROUND_DOWN(Address);
|
||||
if (!RMAP_IS_SEGMENT(Address))
|
||||
Address = (PVOID)PAGE_ROUND_DOWN(Address);
|
||||
|
||||
new_entry = ExAllocateFromNPagedLookasideList(&RmapLookasideList);
|
||||
if (new_entry == NULL)
|
||||
|
@ -272,7 +280,8 @@ MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process,
|
|||
#endif
|
||||
#endif
|
||||
|
||||
if (MmGetPfnForProcess(Process, Address) != Page)
|
||||
if (!RMAP_IS_SEGMENT(Address) &&
|
||||
MmGetPfnForProcess(Process, Address) != Page)
|
||||
{
|
||||
DPRINT1("Insert rmap (%d, 0x%.8X) 0x%.8X which doesn't match physical "
|
||||
"address 0x%.8X\n", Process->UniqueProcessId, Address,
|
||||
|
@ -302,17 +311,21 @@ MmInsertRmap(PFN_NUMBER Page, PEPROCESS Process,
|
|||
#endif
|
||||
MmSetRmapListHeadPage(Page, new_entry);
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
if (Process == NULL)
|
||||
|
||||
if (!RMAP_IS_SEGMENT(Address))
|
||||
{
|
||||
Process = PsInitialSystemProcess;
|
||||
}
|
||||
if (Process)
|
||||
{
|
||||
PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
|
||||
if (PrevSize >= Process->Vm.PeakWorkingSetSize)
|
||||
{
|
||||
Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
|
||||
}
|
||||
if (Process == NULL)
|
||||
{
|
||||
Process = PsInitialSystemProcess;
|
||||
}
|
||||
if (Process)
|
||||
{
|
||||
PrevSize = InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, PAGE_SIZE);
|
||||
if (PrevSize >= Process->Vm.PeakWorkingSetSize)
|
||||
{
|
||||
Process->Vm.PeakWorkingSetSize = PrevSize + PAGE_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,21 +352,28 @@ MmDeleteAllRmaps(PFN_NUMBER Page, PVOID Context,
|
|||
{
|
||||
previous_entry = current_entry;
|
||||
current_entry = current_entry->Next;
|
||||
if (DeleteMapping)
|
||||
{
|
||||
DeleteMapping(Context, previous_entry->Process,
|
||||
previous_entry->Address);
|
||||
}
|
||||
Process = previous_entry->Process;
|
||||
ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
|
||||
if (Process == NULL)
|
||||
{
|
||||
Process = PsInitialSystemProcess;
|
||||
}
|
||||
if (Process)
|
||||
{
|
||||
(void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
|
||||
}
|
||||
if (!RMAP_IS_SEGMENT(current_entry->Address))
|
||||
{
|
||||
if (DeleteMapping)
|
||||
{
|
||||
DeleteMapping(Context, previous_entry->Process,
|
||||
previous_entry->Address);
|
||||
}
|
||||
Process = previous_entry->Process;
|
||||
ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
|
||||
if (Process == NULL)
|
||||
{
|
||||
Process = PsInitialSystemProcess;
|
||||
}
|
||||
if (Process)
|
||||
{
|
||||
(void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ExFreeToNPagedLookasideList(&RmapLookasideList, previous_entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,14 +403,16 @@ MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process,
|
|||
}
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
|
||||
if (Process == NULL)
|
||||
{
|
||||
Process = PsInitialSystemProcess;
|
||||
}
|
||||
if (Process)
|
||||
{
|
||||
(void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
|
||||
}
|
||||
if (!RMAP_IS_SEGMENT(Address)) {
|
||||
if (Process == NULL)
|
||||
{
|
||||
Process = PsInitialSystemProcess;
|
||||
}
|
||||
if (Process)
|
||||
{
|
||||
(void)InterlockedExchangeAddUL(&Process->Vm.WorkingSetSize, -PAGE_SIZE);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
previous_entry = current_entry;
|
||||
|
@ -398,3 +420,61 @@ MmDeleteRmap(PFN_NUMBER Page, PEPROCESS Process,
|
|||
}
|
||||
KeBugCheck(MEMORY_MANAGEMENT);
|
||||
}
|
||||
|
||||
PVOID
|
||||
NTAPI
|
||||
MmGetSegmentRmap(PFN_NUMBER Page, PULONG RawOffset)
|
||||
{
|
||||
PCACHE_SECTION_PAGE_TABLE Result = NULL;
|
||||
PMM_RMAP_ENTRY current_entry, previous_entry;
|
||||
|
||||
ExAcquireFastMutex(&RmapListLock);
|
||||
previous_entry = NULL;
|
||||
current_entry = MmGetRmapListHeadPage(Page);
|
||||
while (current_entry != NULL)
|
||||
{
|
||||
if (RMAP_IS_SEGMENT(current_entry->Address))
|
||||
{
|
||||
Result = (PCACHE_SECTION_PAGE_TABLE)current_entry->Process;
|
||||
*RawOffset = (ULONG_PTR)current_entry->Address & ~RMAP_SEGMENT_MASK;
|
||||
InterlockedIncrementUL(&Result->Segment->ReferenceCount);
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
return Result;
|
||||
}
|
||||
previous_entry = current_entry;
|
||||
current_entry = current_entry->Next;
|
||||
}
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
MmDeleteSectionAssociation(PFN_NUMBER Page)
|
||||
{
|
||||
PMM_RMAP_ENTRY current_entry, previous_entry;
|
||||
|
||||
ExAcquireFastMutex(&RmapListLock);
|
||||
previous_entry = NULL;
|
||||
current_entry = MmGetRmapListHeadPage(Page);
|
||||
while (current_entry != NULL)
|
||||
{
|
||||
if (RMAP_IS_SEGMENT(current_entry->Address))
|
||||
{
|
||||
if (previous_entry == NULL)
|
||||
{
|
||||
MmSetRmapListHeadPage(Page, current_entry->Next);
|
||||
}
|
||||
else
|
||||
{
|
||||
previous_entry->Next = current_entry->Next;
|
||||
}
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
ExFreeToNPagedLookasideList(&RmapLookasideList, current_entry);
|
||||
return;
|
||||
}
|
||||
previous_entry = current_entry;
|
||||
current_entry = current_entry->Next;
|
||||
}
|
||||
ExReleaseFastMutex(&RmapListLock);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,9 @@
|
|||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#ifdef NEWCC
|
||||
#include "../cache/section/newmm.h"
|
||||
#endif
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
#include <reactos/exeformat.h>
|
||||
|
@ -745,7 +748,7 @@ MmspCompleteAndReleasePageOp(PMM_PAGEOP PageOp)
|
|||
* ARGUMENTS: PFILE_OBJECT to wait for.
|
||||
* RETURNS: Status of the wait.
|
||||
*/
|
||||
static NTSTATUS
|
||||
NTSTATUS
|
||||
MmspWaitForFileLock(PFILE_OBJECT File)
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
|
@ -979,7 +982,11 @@ MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section,
|
|||
NTSTATUS Status;
|
||||
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
IsDirectMapped = TRUE;
|
||||
#ifndef NEWCC
|
||||
Status = CcRosUnmapCacheSegment(Bcb, FileOffset, Dirty);
|
||||
#else
|
||||
Status = STATUS_SUCCESS;
|
||||
#endif
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("CcRosUnmapCacheSegment failed, status = %x\n", Status);
|
||||
|
@ -1057,6 +1064,7 @@ MmUnsharePageEntrySectionSegment(PROS_SECTION_OBJECT Section,
|
|||
BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea,
|
||||
ULONG SegOffset)
|
||||
{
|
||||
#ifndef NEWCC
|
||||
if (!(MemoryArea->Data.SectionData.Segment->Characteristics & IMAGE_SCN_MEM_SHARED))
|
||||
{
|
||||
PBCB Bcb;
|
||||
|
@ -1069,6 +1077,7 @@ BOOLEAN MiIsPageFromCache(PMEMORY_AREA MemoryArea,
|
|||
return TRUE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -1091,6 +1100,7 @@ MiCopyFromUserPage(PFN_NUMBER DestPage, PVOID SourceAddress)
|
|||
return(STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
#ifndef NEWCC
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiReadPage(PMEMORY_AREA MemoryArea,
|
||||
|
@ -1267,6 +1277,35 @@ MiReadPage(PMEMORY_AREA MemoryArea,
|
|||
}
|
||||
return(STATUS_SUCCESS);
|
||||
}
|
||||
#else
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
MiReadPage(PMEMORY_AREA MemoryArea,
|
||||
ULONG SegOffset,
|
||||
PPFN_NUMBER Page)
|
||||
/*
|
||||
* FUNCTION: Read a page for a section backed memory area.
|
||||
* PARAMETERS:
|
||||
* MemoryArea - Memory area to read the page for.
|
||||
* Offset - Offset of the page to read.
|
||||
* Page - Variable that receives a page contains the read data.
|
||||
*/
|
||||
{
|
||||
MM_REQUIRED_RESOURCES Resources = { };
|
||||
|
||||
Resources.Context = MemoryArea->Data.SectionData.Section->FileObject;
|
||||
Resources.FileOffset.QuadPart = SegOffset +
|
||||
MemoryArea->Data.SectionData.Segment->FileOffset;
|
||||
Resources.Consumer = MC_USER;
|
||||
Resources.Amount = PAGE_SIZE;
|
||||
|
||||
DPRINT1("%S, offset %x, len %d, page %x\n", ((PFILE_OBJECT)Resources.Context)->FileName.Buffer, Resources.FileOffset.LowPart, Resources.Amount, Resources.Page[0]);
|
||||
|
||||
NTSTATUS Status = MiReadFilePage(NULL, NULL, &Resources);
|
||||
*Page = Resources.Page[0];
|
||||
return Status;
|
||||
}
|
||||
#endif
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
|
@ -1388,6 +1427,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
|
|||
if (!MmIsPagePresent(Process, Address))
|
||||
{
|
||||
Entry = MmGetPageEntrySectionSegment(Segment, Offset);
|
||||
DPRINT1("Entry %x\n", Entry);
|
||||
HasSwapEntry = MmIsPageSwapEntry(Process, (PVOID)PAddress);
|
||||
|
||||
if (PAGE_FROM_SSE(Entry) == 0 || HasSwapEntry)
|
||||
|
@ -1587,6 +1627,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
|
|||
{
|
||||
DPRINT1("MmRequestPageMemoryConsumer failed (Status %x)\n", Status);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1624,7 +1665,7 @@ MmNotPresentFaultSectionView(PMMSUPPORT AddressSpace,
|
|||
if (Entry != Entry1)
|
||||
{
|
||||
DPRINT1("Someone changed ppte entry while we slept\n");
|
||||
KeBugCheck(MEMORY_MANAGEMENT);
|
||||
KeBugCheck(MEMORY_MANAGEMENT);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2151,7 +2192,11 @@ MmPageOutSectionView(PMMSUPPORT AddressSpace,
|
|||
Address);
|
||||
KeBugCheck(MEMORY_MANAGEMENT);
|
||||
}
|
||||
#ifndef NEWCC
|
||||
Status = CcRosUnmapCacheSegment(Bcb, FileOffset, FALSE);
|
||||
#else
|
||||
Status = STATUS_SUCCESS;
|
||||
#endif
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("CCRosUnmapCacheSegment failed, status = %x\n", Status);
|
||||
|
@ -2429,7 +2474,9 @@ MmWritePageSectionView(PMMSUPPORT AddressSpace,
|
|||
if (DirectMapped && !Private)
|
||||
{
|
||||
ASSERT(SwapEntry == 0);
|
||||
#ifndef NEWCC
|
||||
CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
|
||||
#endif
|
||||
PageOp->Status = STATUS_SUCCESS;
|
||||
MmspCompleteAndReleasePageOp(PageOp);
|
||||
return(STATUS_SUCCESS);
|
||||
|
@ -2717,7 +2764,9 @@ MmpDeleteSection(PVOID ObjectBody)
|
|||
}
|
||||
if (Section->FileObject != NULL)
|
||||
{
|
||||
#ifndef NEWCC
|
||||
CcRosDereferenceCache(Section->FileObject);
|
||||
#endif
|
||||
ObDereferenceObject(Section->FileObject);
|
||||
Section->FileObject = NULL;
|
||||
}
|
||||
|
@ -3122,7 +3171,9 @@ MmCreateDataFileSection(PROS_SECTION_OBJECT *SectionObject,
|
|||
MmUnlockSectionSegment(Segment);
|
||||
Section->FileObject = FileObject;
|
||||
Section->MaximumSize = MaximumSize;
|
||||
#ifndef NEWCC
|
||||
CcRosReferenceCache(FileObject);
|
||||
#endif
|
||||
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
|
||||
*SectionObject = Section;
|
||||
return(STATUS_SUCCESS);
|
||||
|
@ -3853,11 +3904,15 @@ MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
|
|||
Section->SectionPageProtection = SectionPageProtection;
|
||||
Section->AllocationAttributes = AllocationAttributes;
|
||||
|
||||
#ifndef NEWCC
|
||||
/*
|
||||
* Initialized caching for this file object if previously caching
|
||||
* was initialized for the same on disk file
|
||||
*/
|
||||
Status = CcTryToInitializeFileCache(FileObject);
|
||||
#else
|
||||
Status = STATUS_SUCCESS;
|
||||
#endif
|
||||
|
||||
if (!NT_SUCCESS(Status) || FileObject->SectionObjectPointer->ImageSectionObject == NULL)
|
||||
{
|
||||
|
@ -3950,7 +4005,9 @@ MmCreateImageSection(PROS_SECTION_OBJECT *SectionObject,
|
|||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
Section->FileObject = FileObject;
|
||||
#ifndef NEWCC
|
||||
CcRosReferenceCache(FileObject);
|
||||
#endif
|
||||
//KeSetEvent((PVOID)&FileObject->Lock, IO_NO_INCREMENT, FALSE);
|
||||
*SectionObject = Section;
|
||||
return(Status);
|
||||
|
@ -4062,7 +4119,9 @@ MmFreeSectionPage(PVOID Context, MEMORY_AREA* MemoryArea, PVOID Address,
|
|||
{
|
||||
FileObject = MemoryArea->Data.SectionData.Section->FileObject;
|
||||
Bcb = FileObject->SectionObjectPointer->SharedCacheMap;
|
||||
#ifndef NEWCC
|
||||
CcRosMarkDirtyCacheSegment(Bcb, Offset + Segment->FileOffset);
|
||||
#endif
|
||||
ASSERT(SwapEntry == 0);
|
||||
}
|
||||
}
|
||||
|
@ -4749,7 +4808,9 @@ MmFlushImageSection (IN PSECTION_OBJECT_POINTERS SectionObjectPointer,
|
|||
{
|
||||
return FALSE;
|
||||
}
|
||||
#ifndef NEWCC
|
||||
CcRosSetRemoveOnClose(SectionObjectPointer);
|
||||
#endif
|
||||
return TRUE;
|
||||
case MmFlushForWrite:
|
||||
break;
|
||||
|
|
|
@ -14,6 +14,9 @@
|
|||
<if property="_ELF_" value="1">
|
||||
<define name="_ELF_" />
|
||||
</if>
|
||||
<if property="NEWCC" value="1">
|
||||
<define name="NEWCC" />
|
||||
</if>
|
||||
<include base="cmlib">.</include>
|
||||
<include base="ntoskrnl">include</include>
|
||||
<include base="ntoskrnl" root="intermediate"></include>
|
||||
|
@ -130,14 +133,35 @@
|
|||
<file>timerobj.c</file>
|
||||
<file>wait.c</file>
|
||||
</directory>
|
||||
<directory name="cc">
|
||||
<if property="NEWCC" value="0">
|
||||
<directory name="cc">
|
||||
<file>cacheman.c</file>
|
||||
<file>copy.c</file>
|
||||
<file>fs.c</file>
|
||||
<file>mdl.c</file>
|
||||
<file>pin.c</file>
|
||||
<file>view.c</file>
|
||||
</directory>
|
||||
</directory>
|
||||
</if>
|
||||
<if property="NEWCC" value="1">
|
||||
<directory name="cache">
|
||||
<file>cachesub.c</file>
|
||||
<file>copysup.c</file>
|
||||
<file>fssup.c</file>
|
||||
<file>lazyrite.c</file>
|
||||
<file>logsup.c</file>
|
||||
<file>mdlsup.c</file>
|
||||
<file>pinsup.c</file>
|
||||
<directory name="section">
|
||||
<file>data.c</file>
|
||||
<file>fault.c</file>
|
||||
<file>io.c</file>
|
||||
<file>reqtools.c</file>
|
||||
<file>sptab.c</file>
|
||||
<file>swapout.c</file>
|
||||
</directory>
|
||||
</directory>
|
||||
</if>
|
||||
<directory name="config">
|
||||
<if property="ARCH" value="i386">
|
||||
<directory name="i386">
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#ifdef NEWCC
|
||||
#include "../cache/newcc.h"
|
||||
#endif
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
||||
|
||||
|
@ -154,6 +157,10 @@ PopGracefulShutdown(IN PVOID Context)
|
|||
IoShutdownSystem(1);
|
||||
CcWaitForCurrentLazyWriterActivity();
|
||||
|
||||
#ifdef NEWCC
|
||||
CcShutdownSystem();
|
||||
#endif
|
||||
|
||||
/* Note that here, we should broadcast the power IRP to devices */
|
||||
|
||||
/* In this step, the HAL disables any wake timers */
|
||||
|
|
|
@ -744,8 +744,10 @@ NtSetSystemPowerState(IN POWER_ACTION SystemAction,
|
|||
/* Check if we're still in an invalid status */
|
||||
if (!NT_SUCCESS(Status)) break;
|
||||
|
||||
#ifndef NEWCC
|
||||
/* Flush dirty cache pages */
|
||||
CcRosFlushDirtyPages(-1, &Dummy);
|
||||
#endif
|
||||
|
||||
/* Flush all volumes and the registry */
|
||||
DPRINT1("Flushing volumes, cache flushed %d pages\n", Dummy);
|
||||
|
|
|
@ -1012,6 +1012,13 @@ PspTerminateThreadByPointer(IN PETHREAD Thread,
|
|||
return Status;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
NTAPI
|
||||
PspIsProcessExiting(IN PEPROCESS Process)
|
||||
{
|
||||
return Process->Flags & PSF_PROCESS_EXITING_BIT;
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
PspExitProcess(IN BOOLEAN LastThread,
|
||||
|
|
Loading…
Reference in a new issue