[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:
Pierre Schweitzer 2018-01-23 22:56:23 +01:00
parent 07e6e9c9c1
commit 9a07c71eef
No known key found for this signature in database
GPG key ID: 7545556C3D585B0B
3 changed files with 101 additions and 2 deletions

View file

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

View file

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

View file

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