reactos/ntoskrnl/include/internal/cc.h
Pierre Schweitzer c5139563db
[NTOSKRNL] Bring an initial (and not perfect ;-)) implementation of read ahead to our Cc!
This halfplements CcScheduleReadAhead() which is responsible for finding the next reads
to perform given last read and previous reads. I made it very basic for now, at least
to test the whole process.
This also introduces the CcExpressWorkQueue in the lazy writer which is responsible
for dealing with read ahead items and which is dealt with before the regular queue.
In CcCopyData(), if read was fine, schedule read ahead so that it can happen in background
without the FSD to notice it! Also, update the read history so that scheduling as a
bit of data.
Implement (à la "old Cc" ;-)) CcPerformReadAhead() which is responsible for performing
the read. It's only to be called by the worker thread.

Side note on the modifications done in CcRosReleaseFileCache(). Private cache map
is tied to a handle. If it goes away, private cache map gets deleted. Read ahead
can run after the handle was closed (and thus, private cache map deleted), so
it is mandatory to always lock the master lock before accessing the structure in
read ahead or before deleting it in CcRosReleaseFileCache(). Otherwise, you'll
just break everything. You've been warned!

This commit also partly reverts f8b5d27.

CORE-14312
2018-02-09 10:14:11 +01:00

509 lines
11 KiB
C

#pragma once
//
// Define this if you want debugging support
//
#define _CC_DEBUG_ 0x00
//
// These define the Debug Masks Supported
//
#define CC_API_DEBUG 0x01
//
// Debug/Tracing support
//
#if _CC_DEBUG_
#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented
#define CCTRACE(x, ...) \
{ \
DbgPrintEx("%s [%.16s] - ", \
__FUNCTION__, \
PsGetCurrentProcess()->ImageFileName); \
DbgPrintEx(__VA_ARGS__); \
}
#else
#define CCTRACE(x, ...) \
if (x & CcRosTraceLevel) \
{ \
DbgPrint("%s [%.16s] - ", \
__FUNCTION__, \
PsGetCurrentProcess()->ImageFileName); \
DbgPrint(__VA_ARGS__); \
}
#endif
#else
#define CCTRACE(x, fmt, ...) DPRINT(fmt, ##__VA_ARGS__)
#endif
//
// Global Cc Data
//
extern ULONG CcRosTraceLevel;
extern LIST_ENTRY DirtyVacbListHead;
extern ULONG CcDirtyPageThreshold;
extern ULONG CcTotalDirtyPages;
extern LIST_ENTRY CcDeferredWrites;
extern KSPIN_LOCK CcDeferredWriteSpinLock;
extern ULONG CcNumberWorkerThreads;
extern LIST_ENTRY CcIdleWorkerThreadList;
extern LIST_ENTRY CcExpressWorkQueue;
extern LIST_ENTRY CcRegularWorkQueue;
extern LIST_ENTRY CcPostTickWorkQueue;
extern NPAGED_LOOKASIDE_LIST CcTwilightLookasideList;
extern LARGE_INTEGER CcIdleDelay;
typedef struct _PF_SCENARIO_ID
{
WCHAR ScenName[30];
ULONG HashId;
} PF_SCENARIO_ID, *PPF_SCENARIO_ID;
typedef struct _PF_LOG_ENTRY
{
ULONG FileOffset:30;
ULONG Type:2;
union
{
ULONG FileKey;
ULONG FileSequenceNumber;
};
} PF_LOG_ENTRY, *PPF_LOG_ENTRY;
typedef struct _PFSN_LOG_ENTRIES
{
LIST_ENTRY TraceBuffersLink;
LONG NumEntries;
LONG MaxEntries;
PF_LOG_ENTRY Entries[ANYSIZE_ARRAY];
} PFSN_LOG_ENTRIES, *PPFSN_LOG_ENTRIES;
typedef struct _PF_SECTION_INFO
{
ULONG FileKey;
ULONG FileSequenceNumber;
ULONG FileIdLow;
ULONG FileIdHigh;
} PF_SECTION_INFO, *PPF_SECTION_INFO;
typedef struct _PF_TRACE_HEADER
{
ULONG Version;
ULONG MagicNumber;
ULONG Size;
PF_SCENARIO_ID ScenarioId;
ULONG ScenarioType; // PF_SCENARIO_TYPE
ULONG EventEntryIdxs[8];
ULONG NumEventEntryIdxs;
ULONG TraceBufferOffset;
ULONG NumEntries;
ULONG SectionInfoOffset;
ULONG NumSections;
ULONG FaultsPerPeriod[10];
LARGE_INTEGER LaunchTime;
ULONGLONG Reserved[5];
} PF_TRACE_HEADER, *PPF_TRACE_HEADER;
typedef struct _PFSN_TRACE_DUMP
{
LIST_ENTRY CompletedTracesLink;
PF_TRACE_HEADER Trace;
} PFSN_TRACE_DUMP, *PPFSN_TRACE_DUMP;
typedef struct _PFSN_TRACE_HEADER
{
ULONG Magic;
LIST_ENTRY ActiveTracesLink;
PF_SCENARIO_ID ScenarioId;
ULONG ScenarioType; // PF_SCENARIO_TYPE
ULONG EventEntryIdxs[8];
ULONG NumEventEntryIdxs;
PPFSN_LOG_ENTRIES CurrentTraceBuffer;
LIST_ENTRY TraceBuffersList;
ULONG NumTraceBuffers;
KSPIN_LOCK TraceBufferSpinLock;
KTIMER TraceTimer;
LARGE_INTEGER TraceTimerPeriod;
KDPC TraceTimerDpc;
KSPIN_LOCK TraceTimerSpinLock;
ULONG FaultsPerPeriod[10];
LONG LastNumFaults;
LONG CurPeriod;
LONG NumFaults;
LONG MaxFaults;
PEPROCESS Process;
EX_RUNDOWN_REF RefCount;
WORK_QUEUE_ITEM EndTraceWorkItem;
LONG EndTraceCalled;
PPFSN_TRACE_DUMP TraceDump;
NTSTATUS TraceDumpStatus;
LARGE_INTEGER LaunchTime;
PPF_SECTION_INFO SectionInfo;
ULONG SectionInfoCount;
} PFSN_TRACE_HEADER, *PPFSN_TRACE_HEADER;
typedef struct _PFSN_PREFETCHER_GLOBALS
{
LIST_ENTRY ActiveTraces;
KSPIN_LOCK ActiveTracesLock;
PPFSN_TRACE_HEADER SystemWideTrace;
LIST_ENTRY CompletedTraces;
FAST_MUTEX CompletedTracesLock;
LONG NumCompletedTraces;
PKEVENT CompletedTracesEvent;
LONG ActivePrefetches;
} PFSN_PREFETCHER_GLOBALS, *PPFSN_PREFETCHER_GLOBALS;
typedef struct _ROS_SHARED_CACHE_MAP
{
CSHORT NodeTypeCode;
CSHORT NodeByteSize;
ULONG OpenCount;
LARGE_INTEGER FileSize;
LARGE_INTEGER SectionSize;
PFILE_OBJECT FileObject;
ULONG DirtyPages;
LIST_ENTRY SharedCacheMapLinks;
ULONG Flags;
PCACHE_MANAGER_CALLBACKS Callbacks;
PVOID LazyWriteContext;
LIST_ENTRY PrivateList;
ULONG DirtyPageThreshold;
/* ROS specific */
LIST_ENTRY CacheMapVacbListHead;
ULONG TimeStamp;
BOOLEAN PinAccess;
KSPIN_LOCK CacheMapLock;
#if DBG
BOOLEAN Trace; /* enable extra trace output for this cache map and it's VACBs */
#endif
} ROS_SHARED_CACHE_MAP, *PROS_SHARED_CACHE_MAP;
#define READAHEAD_DISABLED 0x1
#define WRITEBEHIND_DISABLED 0x2
typedef struct _ROS_VACB
{
/* Base address of the region where the view's data is mapped. */
PVOID BaseAddress;
/* Memory area representing the region where the view's data is mapped. */
struct _MEMORY_AREA* MemoryArea;
/* Are the contents of the view valid. */
BOOLEAN Valid;
/* Are the contents of the view newer than those on disk. */
BOOLEAN Dirty;
/* Page out in progress */
BOOLEAN PageOut;
ULONG MappedCount;
/* Entry in the list of VACBs for this shared cache map. */
LIST_ENTRY CacheMapVacbListEntry;
/* Entry in the list of VACBs which are dirty. */
LIST_ENTRY DirtyVacbListEntry;
/* Entry in the list of VACBs. */
LIST_ENTRY VacbLruListEntry;
/* Offset in the file which this view maps. */
LARGE_INTEGER FileOffset;
/* Mutex */
KMUTEX Mutex;
/* Number of references. */
ULONG ReferenceCount;
/* How many times was it pinned? */
_Guarded_by_(Mutex)
LONG PinCount;
/* Pointer to the shared cache map for the file which this view maps data for. */
PROS_SHARED_CACHE_MAP SharedCacheMap;
/* Pointer to the next VACB in a chain. */
} ROS_VACB, *PROS_VACB;
typedef struct _INTERNAL_BCB
{
/* Lock */
ERESOURCE Lock;
PUBLIC_BCB PFCB;
PROS_VACB Vacb;
BOOLEAN Dirty;
BOOLEAN Pinned;
CSHORT RefCount; /* (At offset 0x34 on WinNT4) */
} INTERNAL_BCB, *PINTERNAL_BCB;
typedef struct _LAZY_WRITER
{
LIST_ENTRY WorkQueue;
KDPC ScanDpc;
KTIMER ScanTimer;
BOOLEAN ScanActive;
BOOLEAN OtherWork;
BOOLEAN PendingTeardown;
} LAZY_WRITER, *PLAZY_WRITER;
typedef struct _WORK_QUEUE_ENTRY
{
LIST_ENTRY WorkQueueLinks;
union
{
struct
{
FILE_OBJECT *FileObject;
} Read;
struct
{
SHARED_CACHE_MAP *SharedCacheMap;
} Write;
struct
{
KEVENT *Event;
} Event;
struct
{
unsigned long Reason;
} Notification;
} Parameters;
unsigned char Function;
} WORK_QUEUE_ENTRY, *PWORK_QUEUE_ENTRY;
typedef enum _WORK_QUEUE_FUNCTIONS
{
ReadAhead = 1,
WriteBehind = 2,
LazyWrite = 3,
SetDone = 4,
} WORK_QUEUE_FUNCTIONS, *PWORK_QUEUE_FUNCTIONS;
extern LAZY_WRITER LazyWriter;
#define NODE_TYPE_DEFERRED_WRITE 0x02FC
#define NODE_TYPE_PRIVATE_MAP 0x02FE
#define NODE_TYPE_SHARED_MAP 0x02FF
VOID
NTAPI
CcPfInitializePrefetcher(
VOID
);
VOID
NTAPI
CcMdlReadComplete2(
IN PFILE_OBJECT FileObject,
IN PMDL MemoryDescriptorList
);
VOID
NTAPI
CcMdlWriteComplete2(
IN PFILE_OBJECT FileObject,
IN PLARGE_INTEGER FileOffset,
IN PMDL MdlChain
);
NTSTATUS
NTAPI
CcRosFlushVacb(PROS_VACB Vacb);
NTSTATUS
NTAPI
CcRosGetVacb(
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset,
PLONGLONG BaseOffset,
PVOID *BaseAddress,
PBOOLEAN UptoDate,
PROS_VACB *Vacb
);
VOID
NTAPI
CcInitView(VOID);
VOID
NTAPI
CcShutdownLazyWriter(VOID);
NTSTATUS
NTAPI
CcReadVirtualAddress(PROS_VACB Vacb);
NTSTATUS
NTAPI
CcWriteVirtualAddress(PROS_VACB Vacb);
BOOLEAN
NTAPI
CcInitializeCacheManager(VOID);
NTSTATUS
NTAPI
CcRosUnmapVacb(
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset,
BOOLEAN NowDirty
);
PROS_VACB
NTAPI
CcRosLookupVacb(
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset
);
VOID
NTAPI
CcInitCacheZeroPage(VOID);
NTSTATUS
NTAPI
CcRosMarkDirtyFile(
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset
);
VOID
NTAPI
CcRosMarkDirtyVacb(
PROS_VACB Vacb);
VOID
NTAPI
CcRosUnmarkDirtyVacb(
PROS_VACB Vacb,
BOOLEAN LockViews);
NTSTATUS
NTAPI
CcRosFlushDirtyPages(
ULONG Target,
PULONG Count,
BOOLEAN Wait,
BOOLEAN CalledFromLazy
);
VOID
NTAPI
CcRosDereferenceCache(PFILE_OBJECT FileObject);
VOID
NTAPI
CcRosReferenceCache(PFILE_OBJECT FileObject);
VOID
NTAPI
CcRosRemoveIfClosed(PSECTION_OBJECT_POINTERS SectionObjectPointer);
NTSTATUS
NTAPI
CcRosReleaseVacb(
PROS_SHARED_CACHE_MAP SharedCacheMap,
PROS_VACB Vacb,
BOOLEAN Valid,
BOOLEAN Dirty,
BOOLEAN Mapped
);
NTSTATUS
NTAPI
CcRosRequestVacb(
PROS_SHARED_CACHE_MAP SharedCacheMap,
LONGLONG FileOffset,
PVOID* BaseAddress,
PBOOLEAN UptoDate,
PROS_VACB *Vacb
);
NTSTATUS
NTAPI
CcRosInitializeFileCache(
PFILE_OBJECT FileObject,
PCC_FILE_SIZES FileSizes,
BOOLEAN PinAccess,
PCACHE_MANAGER_CALLBACKS CallBacks,
PVOID LazyWriterContext
);
NTSTATUS
NTAPI
CcRosReleaseFileCache(
PFILE_OBJECT FileObject
);
VOID
NTAPI
CcShutdownSystem(VOID);
VOID
NTAPI
CcWorkerThread(PVOID Parameter);
VOID
NTAPI
CcScanDpc(
PKDPC Dpc,
PVOID DeferredContext,
PVOID SystemArgument1,
PVOID SystemArgument2);
VOID
CcScheduleLazyWriteScan(BOOLEAN NoDelay);
VOID
CcPostDeferredWrites(VOID);
VOID
CcPostWorkQueue(
IN PWORK_QUEUE_ENTRY WorkItem,
IN PLIST_ENTRY WorkQueue);
VOID
CcPerformReadAhead(
IN PFILE_OBJECT FileObject);
FORCEINLINE
NTSTATUS
CcRosAcquireVacbLock(
_Inout_ PROS_VACB Vacb,
_In_ PLARGE_INTEGER Timeout)
{
NTSTATUS Status;
Status = KeWaitForSingleObject(&Vacb->Mutex,
Executive,
KernelMode,
FALSE,
Timeout);
return Status;
}
FORCEINLINE
VOID
CcRosReleaseVacbLock(
_Inout_ PROS_VACB Vacb)
{
KeReleaseMutex(&Vacb->Mutex, FALSE);
}
FORCEINLINE
BOOLEAN
DoRangesIntersect(
_In_ LONGLONG Offset1,
_In_ LONGLONG Length1,
_In_ LONGLONG Offset2,
_In_ LONGLONG Length2)
{
if (Offset1 + Length1 <= Offset2)
return FALSE;
if (Offset2 + Length2 <= Offset1)
return FALSE;
return TRUE;
}
FORCEINLINE
BOOLEAN
IsPointInRange(
_In_ LONGLONG Offset1,
_In_ LONGLONG Length1,
_In_ LONGLONG Point)
{
return DoRangesIntersect(Offset1, Length1, Point, 1);
}
#define CcBugCheck(A, B, C) KeBugCheckEx(CACHE_MANAGER, BugCheckFileId | ((ULONG)(__LINE__)), A, B, C)