mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
cf4138fa24
Fix crash when the function was called concurrently for the same file by BTRFS driver. CORE-19664
516 lines
11 KiB
C
516 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;
|
|
|
|
//
|
|
// Counters
|
|
//
|
|
extern ULONG CcLazyWritePages;
|
|
extern ULONG CcLazyWriteIos;
|
|
extern ULONG CcMapDataWait;
|
|
extern ULONG CcMapDataNoWait;
|
|
extern ULONG CcPinReadWait;
|
|
extern ULONG CcPinReadNoWait;
|
|
extern ULONG CcPinMappedDataCount;
|
|
extern ULONG CcDataPages;
|
|
extern ULONG CcDataFlushes;
|
|
|
|
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;
|
|
LIST_ENTRY BcbList;
|
|
LARGE_INTEGER SectionSize;
|
|
LARGE_INTEGER ValidDataLength;
|
|
PFILE_OBJECT FileObject;
|
|
ULONG DirtyPages;
|
|
LIST_ENTRY SharedCacheMapLinks;
|
|
ULONG Flags;
|
|
PVOID Section;
|
|
PKEVENT CreateEvent;
|
|
PCACHE_MANAGER_CALLBACKS Callbacks;
|
|
PVOID LazyWriteContext;
|
|
LIST_ENTRY PrivateList;
|
|
ULONG DirtyPageThreshold;
|
|
KSPIN_LOCK BcbSpinLock;
|
|
PRIVATE_CACHE_MAP PrivateCacheMap;
|
|
|
|
/* ROS specific */
|
|
LIST_ENTRY CacheMapVacbListHead;
|
|
BOOLEAN PinAccess;
|
|
KSPIN_LOCK CacheMapLock;
|
|
KGUARDED_MUTEX FlushCacheLock;
|
|
#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
|
|
#define SHARED_CACHE_MAP_IN_CREATION 0x4
|
|
#define SHARED_CACHE_MAP_IN_LAZYWRITE 0x8
|
|
|
|
typedef struct _ROS_VACB
|
|
{
|
|
/* Base address of the region where the view's data is mapped. */
|
|
PVOID BaseAddress;
|
|
/* 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;
|
|
/* Number of references. */
|
|
volatile ULONG ReferenceCount;
|
|
/* 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;
|
|
ULONG PinCount;
|
|
CSHORT RefCount; /* (At offset 0x34 on WinNT4) */
|
|
LIST_ENTRY BcbEntry;
|
|
} 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,
|
|
LazyScan = 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
|
|
|
|
CODE_SEG("INIT")
|
|
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
|
|
CcRosFlushVacb(
|
|
_In_ PROS_VACB Vacb,
|
|
_Out_opt_ PIO_STATUS_BLOCK Iosb
|
|
);
|
|
|
|
NTSTATUS
|
|
CcRosGetVacb(
|
|
PROS_SHARED_CACHE_MAP SharedCacheMap,
|
|
LONGLONG FileOffset,
|
|
PROS_VACB *Vacb
|
|
);
|
|
|
|
BOOLEAN
|
|
CcRosEnsureVacbResident(
|
|
_In_ PROS_VACB Vacb,
|
|
_In_ BOOLEAN Wait,
|
|
_In_ BOOLEAN NoRead,
|
|
_In_ ULONG Offset,
|
|
_In_ ULONG Length
|
|
);
|
|
|
|
CODE_SEG("INIT")
|
|
VOID
|
|
NTAPI
|
|
CcInitView(VOID);
|
|
|
|
VOID
|
|
NTAPI
|
|
CcShutdownLazyWriter(VOID);
|
|
|
|
CODE_SEG("INIT")
|
|
BOOLEAN
|
|
CcInitializeCacheManager(VOID);
|
|
|
|
PROS_VACB
|
|
CcRosLookupVacb(
|
|
PROS_SHARED_CACHE_MAP SharedCacheMap,
|
|
LONGLONG FileOffset
|
|
);
|
|
|
|
VOID
|
|
NTAPI
|
|
CcInitCacheZeroPage(VOID);
|
|
|
|
VOID
|
|
CcRosMarkDirtyVacb(
|
|
PROS_VACB Vacb);
|
|
|
|
VOID
|
|
CcRosUnmarkDirtyVacb(
|
|
PROS_VACB Vacb,
|
|
BOOLEAN LockViews);
|
|
|
|
NTSTATUS
|
|
CcRosFlushDirtyPages(
|
|
ULONG Target,
|
|
PULONG Count,
|
|
BOOLEAN Wait,
|
|
BOOLEAN CalledFromLazy
|
|
);
|
|
|
|
VOID
|
|
CcRosDereferenceCache(PFILE_OBJECT FileObject);
|
|
|
|
VOID
|
|
CcRosReferenceCache(PFILE_OBJECT FileObject);
|
|
|
|
NTSTATUS
|
|
CcRosReleaseVacb(
|
|
PROS_SHARED_CACHE_MAP SharedCacheMap,
|
|
PROS_VACB Vacb,
|
|
BOOLEAN Dirty,
|
|
BOOLEAN Mapped
|
|
);
|
|
|
|
NTSTATUS
|
|
CcRosRequestVacb(
|
|
PROS_SHARED_CACHE_MAP SharedCacheMap,
|
|
LONGLONG FileOffset,
|
|
PROS_VACB *Vacb
|
|
);
|
|
|
|
NTSTATUS
|
|
CcRosInitializeFileCache(
|
|
PFILE_OBJECT FileObject,
|
|
PCC_FILE_SIZES FileSizes,
|
|
BOOLEAN PinAccess,
|
|
PCACHE_MANAGER_CALLBACKS CallBacks,
|
|
PVOID LazyWriterContext
|
|
);
|
|
|
|
NTSTATUS
|
|
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);
|
|
|
|
NTSTATUS
|
|
CcRosInternalFreeVacb(
|
|
IN PROS_VACB Vacb);
|
|
|
|
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)
|
|
|
|
#if DBG
|
|
#define CcRosVacbIncRefCount(vacb) CcRosVacbIncRefCount_(vacb,__FILE__,__LINE__)
|
|
#define CcRosVacbDecRefCount(vacb) CcRosVacbDecRefCount_(vacb,__FILE__,__LINE__)
|
|
#define CcRosVacbGetRefCount(vacb) CcRosVacbGetRefCount_(vacb,__FILE__,__LINE__)
|
|
|
|
ULONG
|
|
CcRosVacbIncRefCount_(
|
|
PROS_VACB vacb,
|
|
PCSTR file,
|
|
INT line);
|
|
|
|
ULONG
|
|
CcRosVacbDecRefCount_(
|
|
PROS_VACB vacb,
|
|
PCSTR file,
|
|
INT line);
|
|
|
|
ULONG
|
|
CcRosVacbGetRefCount_(
|
|
PROS_VACB vacb,
|
|
PCSTR file,
|
|
INT line);
|
|
|
|
#else
|
|
#define CcRosVacbIncRefCount(vacb) InterlockedIncrement((PLONG)&(vacb)->ReferenceCount)
|
|
FORCEINLINE
|
|
ULONG
|
|
CcRosVacbDecRefCount(
|
|
PROS_VACB vacb)
|
|
{
|
|
ULONG Refs;
|
|
|
|
Refs = InterlockedDecrement((PLONG)&vacb->ReferenceCount);
|
|
if (Refs == 0)
|
|
{
|
|
CcRosInternalFreeVacb(vacb);
|
|
}
|
|
return Refs;
|
|
}
|
|
#define CcRosVacbGetRefCount(vacb) InterlockedCompareExchange((PLONG)&(vacb)->ReferenceCount, 0, 0)
|
|
#endif
|
|
|
|
BOOLEAN
|
|
CcRosFreeOneUnusedVacb(
|
|
VOID);
|