mirror of
https://github.com/reactos/reactos.git
synced 2025-05-20 17:45:06 +00:00
[NTOSKRNL] Implement support for deferred writes in Cc.
Namely, implement CcCanIWrite() (very basic, and likely wrong). And implement CcDeferWrite() which will queue the write operation. In CciLazyWriter() (which may be renamed CcWorkerThread() ;-)), handle the queued write operations one by one. This is likely not to be accurate, but, given we have only on FS supporting this for now (NFS / RDBSS / Shares), this is OK. CORE-14235
This commit is contained in:
parent
07e6e9c9c1
commit
9a07c71eef
3 changed files with 101 additions and 2 deletions
|
@ -378,6 +378,22 @@ CcCanIWrite (
|
|||
CCTRACE(CC_API_DEBUG, "FileObject=%p BytesToWrite=%lu Wait=%d Retrying=%d\n",
|
||||
FileObject, BytesToWrite, Wait, Retrying);
|
||||
|
||||
/* We cannot write if dirty pages count is above threshold */
|
||||
if (CcTotalDirtyPages > CcDirtyPageThreshold)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* We cannot write if dirty pages count will bring use above
|
||||
* XXX: Might not be accurate
|
||||
*/
|
||||
if (CcTotalDirtyPages + (BytesToWrite / PAGE_SIZE) > CcDirtyPageThreshold)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* FIXME: Handle per-file threshold */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -442,7 +458,7 @@ CcCopyWrite (
|
|||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
* @implemented
|
||||
*/
|
||||
VOID
|
||||
NTAPI
|
||||
|
@ -454,10 +470,43 @@ CcDeferWrite (
|
|||
IN ULONG BytesToWrite,
|
||||
IN BOOLEAN Retrying)
|
||||
{
|
||||
PROS_DEFERRED_WRITE_CONTEXT Context;
|
||||
|
||||
CCTRACE(CC_API_DEBUG, "FileObject=%p PostRoutine=%p Context1=%p Context2=%p BytesToWrite=%lu Retrying=%d\n",
|
||||
FileObject, PostRoutine, Context1, Context2, BytesToWrite, Retrying);
|
||||
|
||||
/* Try to allocate a context for queueing the write operation */
|
||||
Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(ROS_DEFERRED_WRITE_CONTEXT), 'CcDw');
|
||||
/* If it failed, immediately execute the operation! */
|
||||
if (Context == NULL)
|
||||
{
|
||||
PostRoutine(Context1, Context2);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, initialize the context */
|
||||
Context->FileObject = FileObject;
|
||||
Context->PostRoutine = PostRoutine;
|
||||
Context->Context1 = Context1;
|
||||
Context->Context2 = Context2;
|
||||
Context->BytesToWrite = BytesToWrite;
|
||||
Context->Retrying = Retrying;
|
||||
|
||||
/* And queue it */
|
||||
if (Retrying)
|
||||
{
|
||||
/* To the top, if that's a retry */
|
||||
ExInterlockedInsertHeadList(&CcDeferredWrites,
|
||||
&Context->CcDeferredWritesEntry,
|
||||
&CcDeferredWriteSpinLock);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* To the bottom, if that's a first time */
|
||||
ExInterlockedInsertTailList(&CcDeferredWrites,
|
||||
&Context->CcDeferredWritesEntry,
|
||||
&CcDeferredWriteSpinLock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -60,9 +60,13 @@ ULONG CcLazyWriteIos = 0;
|
|||
/* Internal vars (MS):
|
||||
* - Threshold above which lazy writer will start action
|
||||
* - Amount of dirty pages
|
||||
* - List for deferred writes
|
||||
* - Spinlock when dealing with the deferred list
|
||||
*/
|
||||
ULONG CcDirtyPageThreshold = 0;
|
||||
ULONG CcTotalDirtyPages = 0;
|
||||
LIST_ENTRY CcDeferredWrites;
|
||||
KSPIN_LOCK CcDeferredWriteSpinLock;
|
||||
|
||||
/* Internal vars (ROS):
|
||||
* - Event to notify lazy writer to shutdown
|
||||
|
@ -308,6 +312,7 @@ CciLazyWriter(PVOID Unused)
|
|||
while (TRUE)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PLIST_ENTRY ListEntry;
|
||||
ULONG Target, Count = 0;
|
||||
|
||||
/* One per second or until we have to stop */
|
||||
|
@ -342,6 +347,34 @@ CciLazyWriter(PVOID Unused)
|
|||
|
||||
/* Inform people waiting on us that we're done */
|
||||
KeSetEvent(&iLazyWriterNotify, IO_DISK_INCREMENT, FALSE);
|
||||
|
||||
/* Likely not optimal, but let's handle one deferred write now! */
|
||||
ListEntry = ExInterlockedRemoveHeadList(&CcDeferredWrites, &CcDeferredWriteSpinLock);
|
||||
if (ListEntry != NULL)
|
||||
{
|
||||
PROS_DEFERRED_WRITE_CONTEXT Context;
|
||||
|
||||
/* Extract the context */
|
||||
Context = CONTAINING_RECORD(ListEntry, ROS_DEFERRED_WRITE_CONTEXT, CcDeferredWritesEntry);
|
||||
|
||||
/* Can we write now? */
|
||||
if (CcCanIWrite(Context->FileObject, Context->BytesToWrite, FALSE, Context->Retrying))
|
||||
{
|
||||
/* Yes! Do it, and destroy the associated context */
|
||||
Context->PostRoutine(Context->Context1, Context->Context2);
|
||||
ExFreePoolWithTag(Context, 'CcDw');
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, requeue it, but in tail, so that it doesn't block others
|
||||
* This is clearly to improve, but given the poor algorithm used now
|
||||
* It's better than nothing!
|
||||
*/
|
||||
ExInterlockedInsertTailList(&CcDeferredWrites,
|
||||
&Context->CcDeferredWritesEntry,
|
||||
&CcDeferredWriteSpinLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1358,6 +1391,8 @@ CcInitView (
|
|||
|
||||
InitializeListHead(&DirtyVacbListHead);
|
||||
InitializeListHead(&VacbLruListHead);
|
||||
InitializeListHead(&CcDeferredWrites);
|
||||
KeInitializeSpinLock(&CcDeferredWriteSpinLock);
|
||||
KeInitializeGuardedMutex(&ViewLock);
|
||||
ExInitializeNPagedLookasideList(&iBcbLookasideList,
|
||||
NULL,
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
//
|
||||
extern ULONG CcRosTraceLevel;
|
||||
extern LIST_ENTRY DirtyVacbListHead;
|
||||
extern ULONG CcDirtyPageThreshold;
|
||||
extern ULONG CcTotalDirtyPages;
|
||||
extern LIST_ENTRY CcDeferredWrites;
|
||||
extern KSPIN_LOCK CcDeferredWriteSpinLock;
|
||||
|
||||
typedef struct _PF_SCENARIO_ID
|
||||
{
|
||||
|
@ -193,6 +197,17 @@ typedef struct _ROS_VACB
|
|||
/* Pointer to the next VACB in a chain. */
|
||||
} ROS_VACB, *PROS_VACB;
|
||||
|
||||
typedef struct _ROS_DEFERRED_WRITE_CONTEXT
|
||||
{
|
||||
LIST_ENTRY CcDeferredWritesEntry;
|
||||
PFILE_OBJECT FileObject;
|
||||
PCC_POST_DEFERRED_WRITE PostRoutine;
|
||||
PVOID Context1;
|
||||
PVOID Context2;
|
||||
ULONG BytesToWrite;
|
||||
BOOLEAN Retrying;
|
||||
} ROS_DEFERRED_WRITE_CONTEXT, *PROS_DEFERRED_WRITE_CONTEXT;
|
||||
|
||||
typedef struct _INTERNAL_BCB
|
||||
{
|
||||
/* Lock */
|
||||
|
|
Loading…
Reference in a new issue