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:
Art Yerkes 2010-11-02 02:32:39 +00:00
parent 7697abf4a2
commit f2e646d5b4
30 changed files with 5908 additions and 125 deletions

View file

@ -99,4 +99,9 @@
-->
<property name="BUILD_MP" value="1" />
<!--
Whether to compile the new cache manager
-->
<property name="NEWCC" value="0" />
</group>

View 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_

View file

@ -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

View file

@ -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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);

View 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
View 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
View 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;
}

View file

@ -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(

View file

@ -399,6 +399,10 @@ PsChargeProcessPageFileQuota(
IN SIZE_T Amount
);
BOOLEAN
NTAPI
PspIsProcessExiting(IN PEPROCESS Process);
//
// Global data inside the Process Manager
//

View file

@ -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,

View file

@ -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;

View file

@ -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
}
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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">

View file

@ -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 */

View file

@ -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);

View file

@ -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,