diff --git a/reactos/config.template.rbuild b/reactos/config.template.rbuild index d8a130414d9..5e20dd5fd55 100644 --- a/reactos/config.template.rbuild +++ b/reactos/config.template.rbuild @@ -99,4 +99,9 @@ --> + + + diff --git a/reactos/include/ndk/inline_ntcurrentteb.h b/reactos/include/ndk/inline_ntcurrentteb.h new file mode 100644 index 00000000000..ffda4d96924 --- /dev/null +++ b/reactos/include/ndk/inline_ntcurrentteb.h @@ -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 + +#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_ diff --git a/reactos/include/ndk/psfuncs.h b/reactos/include/ndk/psfuncs.h index 327af5a99b6..4b0a96f52af 100644 --- a/reactos/include/ndk/psfuncs.h +++ b/reactos/include/ndk/psfuncs.h @@ -329,35 +329,7 @@ NtCreateThread( IN BOOLEAN CreateSuspended ); -#ifndef NTOS_MODE_USER -#if defined(_M_IX86) -FORCEINLINE -PTEB -NtCurrentTeb(VOID) -{ -#ifndef __GNUC__ - return (PTEB)(ULONG_PTR)__readfsdword(0x18); -#else - struct _TEB *ret; - - __asm__ __volatile__ ( - "movl %%fs:0x18, %0\n" - : "=r" (ret) - : /* no inputs */ - ); - - return ret; -#endif -} -#elif defined (_M_AMD64) -FORCEINLINE struct _TEB * NtCurrentTeb(VOID) -{ - return (struct _TEB *)__readgsqword(FIELD_OFFSET(NT_TIB, Self)); -} -#endif -#else -struct _TEB * NtCurrentTeb(void); -#endif +#include "inline_ntcurrentteb.h" NTSYSCALLAPI NTSTATUS diff --git a/reactos/include/psdk/winnt.h b/reactos/include/psdk/winnt.h index 441660a894f..7967047c4d1 100644 --- a/reactos/include/psdk/winnt.h +++ b/reactos/include/psdk/winnt.h @@ -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 - -#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()); diff --git a/reactos/ntoskrnl/cache/cachesub.c b/reactos/ntoskrnl/cache/cachesub.c new file mode 100644 index 00000000000..fb9d9e31eb9 --- /dev/null +++ b/reactos/ntoskrnl/cache/cachesub.c @@ -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 +#include "newcc.h" +#include "section/newmm.h" +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/cache/copysup.c b/reactos/ntoskrnl/cache/copysup.c new file mode 100644 index 00000000000..2f8a954e846 --- /dev/null +++ b/reactos/ntoskrnl/cache/copysup.c @@ -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 +#include "newcc.h" +#include "section/newmm.h" +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/cache/fssup.c b/reactos/ntoskrnl/cache/fssup.c new file mode 100644 index 00000000000..8646513e3b0 --- /dev/null +++ b/reactos/ntoskrnl/cache/fssup.c @@ -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 +#include "newcc.h" +#include "section/newmm.h" +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/cache/lazyrite.c b/reactos/ntoskrnl/cache/lazyrite.c new file mode 100644 index 00000000000..4dcbb5d8a36 --- /dev/null +++ b/reactos/ntoskrnl/cache/lazyrite.c @@ -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 +#include "newcc.h" +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/cache/logsup.c b/reactos/ntoskrnl/cache/logsup.c new file mode 100644 index 00000000000..b06432fc394 --- /dev/null +++ b/reactos/ntoskrnl/cache/logsup.c @@ -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 +#include "newcc.h" +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/cache/mdlsup.c b/reactos/ntoskrnl/cache/mdlsup.c new file mode 100644 index 00000000000..6e558d5aa4c --- /dev/null +++ b/reactos/ntoskrnl/cache/mdlsup.c @@ -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 +#include "newcc.h" +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/cache/newcc.h b/reactos/ntoskrnl/cache/newcc.h new file mode 100644 index 00000000000..5e0bd2608eb --- /dev/null +++ b/reactos/ntoskrnl/cache/newcc.h @@ -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); diff --git a/reactos/ntoskrnl/cache/pinsup.c b/reactos/ntoskrnl/cache/pinsup.c new file mode 100644 index 00000000000..5531bbb9720 --- /dev/null +++ b/reactos/ntoskrnl/cache/pinsup.c @@ -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 +#include "newcc.h" +#include "section/newmm.h" +#define NDEBUG +#include + +/* 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 */ diff --git a/reactos/ntoskrnl/cache/section/data.c b/reactos/ntoskrnl/cache/section/data.c new file mode 100644 index 00000000000..89cdf74c5de --- /dev/null +++ b/reactos/ntoskrnl/cache/section/data.c @@ -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 +#include "newmm.h" +#include "../newcc.h" +#define NDEBUG +#include + +#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 */ diff --git a/reactos/ntoskrnl/cache/section/fault.c b/reactos/ntoskrnl/cache/section/fault.c new file mode 100644 index 00000000000..81d6a0171e2 --- /dev/null +++ b/reactos/ntoskrnl/cache/section/fault.c @@ -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 +#include "newmm.h" +#define NDEBUG +#include + +#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); +} diff --git a/reactos/ntoskrnl/cache/section/io.c b/reactos/ntoskrnl/cache/section/io.c new file mode 100644 index 00000000000..254c25c38a6 --- /dev/null +++ b/reactos/ntoskrnl/cache/section/io.c @@ -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 +#include "newmm.h" +#define NDEBUG +#include +#include + +#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; +} diff --git a/reactos/ntoskrnl/cache/section/newmm.h b/reactos/ntoskrnl/cache/section/newmm.h new file mode 100644 index 00000000000..43fd3fe7cef --- /dev/null +++ b/reactos/ntoskrnl/cache/section/newmm.h @@ -0,0 +1,454 @@ +#pragma once + +#include + +/* 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); diff --git a/reactos/ntoskrnl/cache/section/reqtools.c b/reactos/ntoskrnl/cache/section/reqtools.c new file mode 100644 index 00000000000..68056d49ec9 --- /dev/null +++ b/reactos/ntoskrnl/cache/section/reqtools.c @@ -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 +#include "newmm.h" +#define NDEBUG +#include + +#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]); +} diff --git a/reactos/ntoskrnl/cache/section/sptab.c b/reactos/ntoskrnl/cache/section/sptab.c new file mode 100644 index 00000000000..0b71764b865 --- /dev/null +++ b/reactos/ntoskrnl/cache/section/sptab.c @@ -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 +#include "newmm.h" +#define NDEBUG +#include + +#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; +} diff --git a/reactos/ntoskrnl/cache/section/swapout.c b/reactos/ntoskrnl/cache/section/swapout.c new file mode 100644 index 00000000000..685104e3d64 --- /dev/null +++ b/reactos/ntoskrnl/cache/section/swapout.c @@ -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 +#include "newmm.h" +#define NDEBUG +#include + +#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; +} + diff --git a/reactos/ntoskrnl/include/internal/mm.h b/reactos/ntoskrnl/include/internal/mm.h index 25360af7416..9da455b0779 100644 --- a/reactos/ntoskrnl/include/internal/mm.h +++ b/reactos/ntoskrnl/include/internal/mm.h @@ -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( diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h index 1d55e3068ff..bf18cf818b3 100644 --- a/reactos/ntoskrnl/include/internal/ps.h +++ b/reactos/ntoskrnl/include/internal/ps.h @@ -399,6 +399,10 @@ PsChargeProcessPageFileQuota( IN SIZE_T Amount ); +BOOLEAN +NTAPI +PspIsProcessExiting(IN PEPROCESS Process); + // // Global data inside the Process Manager // diff --git a/reactos/ntoskrnl/mm/i386/page.c b/reactos/ntoskrnl/mm/i386/page.c index e096fcf3f56..f3e43d9fed8 100644 --- a/reactos/ntoskrnl/mm/i386/page.c +++ b/reactos/ntoskrnl/mm/i386/page.c @@ -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, diff --git a/reactos/ntoskrnl/mm/mmfault.c b/reactos/ntoskrnl/mm/mmfault.c index bf8b2e014c7..9a3ecf9f0ef 100644 --- a/reactos/ntoskrnl/mm/mmfault.c +++ b/reactos/ntoskrnl/mm/mmfault.c @@ -9,6 +9,9 @@ /* INCLUDES *******************************************************************/ #include +#ifdef NEWCC +#include "../cache/section/newmm.h" +#endif #define NDEBUG #include @@ -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; diff --git a/reactos/ntoskrnl/mm/mminit.c b/reactos/ntoskrnl/mm/mminit.c index df2140c9cc7..55233979f65 100644 --- a/reactos/ntoskrnl/mm/mminit.c +++ b/reactos/ntoskrnl/mm/mminit.c @@ -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 } } diff --git a/reactos/ntoskrnl/mm/rmap.c b/reactos/ntoskrnl/mm/rmap.c index aa2f96ee3b4..c7bd744f25f 100644 --- a/reactos/ntoskrnl/mm/rmap.c +++ b/reactos/ntoskrnl/mm/rmap.c @@ -10,6 +10,7 @@ /* INCLUDES *****************************************************************/ #include +#include "../cache/section/newmm.h" #define NDEBUG #include @@ -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); +} diff --git a/reactos/ntoskrnl/mm/section.c b/reactos/ntoskrnl/mm/section.c index 5dad201e343..6e226d4b84c 100644 --- a/reactos/ntoskrnl/mm/section.c +++ b/reactos/ntoskrnl/mm/section.c @@ -45,6 +45,9 @@ /* INCLUDES *****************************************************************/ #include +#ifdef NEWCC +#include "../cache/section/newmm.h" +#endif #define NDEBUG #include #include @@ -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; diff --git a/reactos/ntoskrnl/ntoskrnl-generic.rbuild b/reactos/ntoskrnl/ntoskrnl-generic.rbuild index 74fdf0b4531..6056698c2b2 100644 --- a/reactos/ntoskrnl/ntoskrnl-generic.rbuild +++ b/reactos/ntoskrnl/ntoskrnl-generic.rbuild @@ -14,6 +14,9 @@ + + + . include @@ -130,14 +133,35 @@ timerobj.c wait.c - + + cacheman.c copy.c fs.c mdl.c pin.c view.c - + + + + + cachesub.c + copysup.c + fssup.c + lazyrite.c + logsup.c + mdlsup.c + pinsup.c + + data.c + fault.c + io.c + reqtools.c + sptab.c + swapout.c + + + diff --git a/reactos/ntoskrnl/po/poshtdwn.c b/reactos/ntoskrnl/po/poshtdwn.c index dd5113e1bb3..919ffd4eefb 100644 --- a/reactos/ntoskrnl/po/poshtdwn.c +++ b/reactos/ntoskrnl/po/poshtdwn.c @@ -9,6 +9,9 @@ /* INCLUDES ******************************************************************/ #include +#ifdef NEWCC +#include "../cache/newcc.h" +#endif #define NDEBUG #include @@ -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 */ diff --git a/reactos/ntoskrnl/po/power.c b/reactos/ntoskrnl/po/power.c index a163b98bc48..cb343125edc 100644 --- a/reactos/ntoskrnl/po/power.c +++ b/reactos/ntoskrnl/po/power.c @@ -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); diff --git a/reactos/ntoskrnl/ps/kill.c b/reactos/ntoskrnl/ps/kill.c index b1ea95fb361..7efbc761ad7 100644 --- a/reactos/ntoskrnl/ps/kill.c +++ b/reactos/ntoskrnl/ps/kill.c @@ -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,