https://git.reactos.org/?p=reactos.git;a=commitdiff;h=303f17f884513ebf89d4c…
commit 303f17f884513ebf89d4c10744219382fea1d1d1
Author: Thomas Faber <thomas.faber(a)reactos.org>
AuthorDate: Sun Oct 18 15:23:52 2020 +0200
Commit: Thomas Faber <thomas.faber(a)reactos.org>
CommitDate: Sat Oct 24 19:53:36 2020 +0200
[FASTFAT] Implement the overflow queue. CORE-17344 CORE-17328
This avoids blocking all Ex worker threads in fastfat, thereby making Cc
unable to issue the lazy writes that would unblock those workers.
This is more or less directly taken from fastfat_new.
---
drivers/filesystems/fastfat/fsctl.c | 5 ++
drivers/filesystems/fastfat/misc.c | 92 ++++++++++++++++++++++++++++++++++---
drivers/filesystems/fastfat/vfat.h | 6 +++
3 files changed, 97 insertions(+), 6 deletions(-)
diff --git a/drivers/filesystems/fastfat/fsctl.c b/drivers/filesystems/fastfat/fsctl.c
index a8cbca4670f..6764a67d329 100644
--- a/drivers/filesystems/fastfat/fsctl.c
+++ b/drivers/filesystems/fastfat/fsctl.c
@@ -600,6 +600,11 @@ VfatMount(
DeviceExt->HashTableSize = HashTableSize;
DeviceExt->VolumeDevice = DeviceObject;
+ KeInitializeSpinLock(&DeviceExt->OverflowQueueSpinLock);
+ InitializeListHead(&DeviceExt->OverflowQueue);
+ DeviceExt->OverflowQueueCount = 0;
+ DeviceExt->PostedRequestCount = 0;
+
/* use same vpb as device disk */
DeviceObject->Vpb = Vpb;
DeviceToMount->Vpb = Vpb;
diff --git a/drivers/filesystems/fastfat/misc.c b/drivers/filesystems/fastfat/misc.c
index 443ad290817..76b17f1db36 100644
--- a/drivers/filesystems/fastfat/misc.c
+++ b/drivers/filesystems/fastfat/misc.c
@@ -336,12 +336,53 @@ static
VOID
NTAPI
VfatDoRequest(
- PVOID IrpContext)
+ PVOID Context)
{
+ PVFAT_IRP_CONTEXT IrpContext = Context;
+ PDEVICE_EXTENSION DeviceExt;
+ KIRQL OldIrql;
+
InterlockedDecrement(&QueueCount);
- DPRINT("VfatDoRequest(IrpContext %p), MajorFunction %x, %d\n",
- IrpContext, ((PVFAT_IRP_CONTEXT)IrpContext)->MajorFunction, QueueCount);
- VfatDispatchRequest((PVFAT_IRP_CONTEXT)IrpContext);
+
+ if (IrpContext->Stack->FileObject != NULL)
+ {
+ DeviceExt = IrpContext->Stack->DeviceObject->DeviceExtension;
+ ObReferenceObject(DeviceExt->VolumeDevice);
+ }
+
+ do
+ {
+ DPRINT("VfatDoRequest(IrpContext %p), MajorFunction %x, %d\n",
+ IrpContext, IrpContext->MajorFunction, QueueCount);
+ VfatDispatchRequest(IrpContext);
+ IrpContext = NULL;
+
+ /* Now process any overflow items */
+ if (DeviceExt != NULL)
+ {
+ KeAcquireSpinLock(&DeviceExt->OverflowQueueSpinLock, &OldIrql);
+ if (DeviceExt->OverflowQueueCount != 0)
+ {
+ IrpContext =
CONTAINING_RECORD(RemoveHeadList(&DeviceExt->OverflowQueue),
+ VFAT_IRP_CONTEXT,
+ WorkQueueItem.List);
+ DeviceExt->OverflowQueueCount--;
+ DPRINT("Processing overflow item for IRP %p context %p
(%lu)\n",
+ IrpContext->Irp, IrpContext,
DeviceExt->OverflowQueueCount);
+ }
+ else
+ {
+ ASSERT(IsListEmpty(&DeviceExt->OverflowQueue));
+ DeviceExt->PostedRequestCount--;
+ }
+ KeReleaseSpinLock(&DeviceExt->OverflowQueueSpinLock, OldIrql);
+ }
+ } while (IrpContext != NULL);
+
+ if (DeviceExt != NULL)
+ {
+ ObDereferenceObject(DeviceExt->VolumeDevice);
+ }
}
static
@@ -349,6 +390,10 @@ NTSTATUS
VfatQueueRequest(
PVFAT_IRP_CONTEXT IrpContext)
{
+ PDEVICE_EXTENSION DeviceExt;
+ KIRQL OldIrql;
+ BOOLEAN Overflow;
+
InterlockedIncrement(&QueueCount);
DPRINT("VfatQueueRequest(IrpContext %p), %d\n", IrpContext, QueueCount);
@@ -357,10 +402,41 @@ VfatQueueRequest(
ASSERT(!(IrpContext->Flags & IRPCONTEXT_QUEUE) &&
(IrpContext->Flags & IRPCONTEXT_COMPLETE));
+ Overflow = FALSE;
IrpContext->Flags |= IRPCONTEXT_CANWAIT;
IoMarkIrpPending(IrpContext->Irp);
- ExInitializeWorkItem(&IrpContext->WorkQueueItem, VfatDoRequest, IrpContext);
- ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
+
+ /* We should not block more than two worker threads per volume,
+ * or we might stop Cc from doing the work to unblock us.
+ * Add additional requests into the overflow queue instead and process
+ * them all in an existing worker thread (see VfatDoRequest above).
+ */
+ if (IrpContext->Stack->FileObject != NULL)
+ {
+ DeviceExt = IrpContext->Stack->DeviceObject->DeviceExtension;
+ KeAcquireSpinLock(&DeviceExt->OverflowQueueSpinLock, &OldIrql);
+ if (DeviceExt->PostedRequestCount > 2)
+ {
+ DeviceExt->OverflowQueueCount++;
+ DPRINT("Queue overflow. Adding IRP %p context %p to overflow queue
(%lu)\n",
+ IrpContext->Irp, IrpContext, DeviceExt->OverflowQueueCount);
+ InsertTailList(&DeviceExt->OverflowQueue,
+ &IrpContext->WorkQueueItem.List);
+ Overflow = TRUE;
+ }
+ else
+ {
+ DeviceExt->PostedRequestCount++;
+ }
+ KeReleaseSpinLock(&DeviceExt->OverflowQueueSpinLock, OldIrql);
+ }
+
+ if (!Overflow)
+ {
+ ExInitializeWorkItem(&IrpContext->WorkQueueItem, VfatDoRequest,
IrpContext);
+ ExQueueWorkItem(&IrpContext->WorkQueueItem, CriticalWorkQueue);
+ }
+
return STATUS_PENDING;
}
@@ -552,6 +628,10 @@ VfatCheckForDismount(
vfatDestroyFCB(Fcb);
}
+ ASSERT(DeviceExt->OverflowQueueCount == 0);
+ ASSERT(IsListEmpty(&DeviceExt->OverflowQueue));
+ ASSERT(DeviceExt->PostedRequestCount == 0);
+
/*
* Now that the closing of the internal opened meta-files has been
* handled, we can now set the VPB's DeviceObject to NULL.
diff --git a/drivers/filesystems/fastfat/vfat.h b/drivers/filesystems/fastfat/vfat.h
index fcb3a25cca7..943c6b76ab1 100644
--- a/drivers/filesystems/fastfat/vfat.h
+++ b/drivers/filesystems/fastfat/vfat.h
@@ -330,6 +330,12 @@ typedef struct DEVICE_EXTENSION
struct _VFATFCB *RootFcb;
PSTATISTICS Statistics;
+ /* Overflow request queue */
+ KSPIN_LOCK OverflowQueueSpinLock;
+ LIST_ENTRY OverflowQueue;
+ ULONG OverflowQueueCount;
+ ULONG PostedRequestCount;
+
/* Pointers to functions for manipulating FAT. */
PGET_NEXT_CLUSTER GetNextCluster;
PFIND_AND_MARK_AVAILABLE_CLUSTER FindAndMarkAvailableCluster;