summaryrefslogtreecommitdiff
path: root/filesys/cdfs/workque.c
diff options
context:
space:
mode:
authorDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
committerDave Wilson <[email protected]>2015-03-17 19:50:07 -0700
commit97cf5197cf5b882b2c689d8dc2b555f2edf8f418 (patch)
tree46f3701832d70b420eb0fc0eb93261f9da45db3f /filesys/cdfs/workque.c
parentef1905bf1e8825bb31120dfb27e0daf3154d859a (diff)
Initial publish
Diffstat (limited to 'filesys/cdfs/workque.c')
-rw-r--r--filesys/cdfs/workque.c416
1 files changed, 416 insertions, 0 deletions
diff --git a/filesys/cdfs/workque.c b/filesys/cdfs/workque.c
new file mode 100644
index 00000000..ee548826
--- /dev/null
+++ b/filesys/cdfs/workque.c
@@ -0,0 +1,416 @@
+/*++
+
+Copyright (c) 1989-2000 Microsoft Corporation
+
+Module Name:
+
+ WorkQue.c
+
+Abstract:
+
+ This module implements the Work queue routines for the Cdfs File
+ system.
+
+
+--*/
+
+#include "CdProcs.h"
+
+//
+// The Bug check file id for this module
+//
+
+#define BugCheckFileId (CDFS_BUG_CHECK_WORKQUE)
+
+//
+// The following constant is the maximum number of ExWorkerThreads that we
+// will allow to be servicing a particular target device at any one time.
+//
+
+#define FSP_PER_DEVICE_THRESHOLD (2)
+
+//
+// Local support routines
+//
+
+VOID
+CdAddToWorkque (
+ _Inout_ PIRP_CONTEXT IrpContext,
+ _Inout_ PIRP Irp
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, CdFsdPostRequest)
+#pragma alloc_text(PAGE, CdOplockComplete)
+#pragma alloc_text(PAGE, CdPrePostIrp)
+#endif
+
+
+_Requires_lock_held_(_Global_critical_region_)
+NTSTATUS
+CdFsdPostRequest (
+ _Inout_ PIRP_CONTEXT IrpContext,
+ _Inout_ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine enqueues the request packet specified by IrpContext to the
+ work queue associated with the FileSystemDeviceObject. This is a FSD
+ routine.
+
+Arguments:
+
+ IrpContext - Pointer to the IrpContext to be queued to the Fsp.
+
+ Irp - I/O Request Packet.
+
+Return Value:
+
+ STATUS_PENDING
+
+--*/
+
+{
+ PAGED_CODE();
+
+ ASSERT_IRP_CONTEXT( IrpContext );
+ ASSERT_IRP( Irp );
+
+ //
+ // Posting is a three step operation. First lock down any buffers
+ // in the Irp. Next cleanup the IrpContext for the post and finally
+ // add this to a workque.
+ //
+
+ CdPrePostIrp( IrpContext, Irp );
+
+ CdAddToWorkque( IrpContext, Irp );
+
+ //
+ // And return to our caller
+ //
+
+ return STATUS_PENDING;
+}
+
+
+
+_Requires_lock_held_(_Global_critical_region_)
+VOID
+CdPrePostIrp (
+ _Inout_ PIRP_CONTEXT IrpContext,
+ _Inout_ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs any neccessary work before STATUS_PENDING is
+ returned with the Fsd thread. This routine is called within the
+ filesystem and by the oplock package.
+
+Arguments:
+
+ Context - Pointer to the IrpContext to be queued to the Fsp
+
+ Irp - I/O Request Packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+ BOOLEAN RemovedFcb;
+
+ PAGED_CODE();
+
+ ASSERT_IRP_CONTEXT( IrpContext );
+ ASSERT_IRP( Irp );
+
+ //
+ // Case on the type of the operation.
+ //
+
+ switch (IrpContext->MajorFunction) {
+
+ case IRP_MJ_CREATE :
+
+ //
+ // If called from the oplock package then there is an
+ // Fcb to possibly teardown. We will call the teardown
+ // routine and release the Fcb if still present. The cleanup
+ // code in create will know not to release this Fcb because
+ // we will clear the pointer.
+ //
+
+ if ((IrpContext->TeardownFcb != NULL) &&
+ *(IrpContext->TeardownFcb) != NULL) {
+
+ CdTeardownStructures( IrpContext, *(IrpContext->TeardownFcb), &RemovedFcb );
+
+ if (!RemovedFcb) {
+
+ _Analysis_assume_lock_held_((*IrpContext->TeardownFcb)->FcbNonpaged->FcbResource);
+ CdReleaseFcb( IrpContext, *(IrpContext->TeardownFcb) );
+ }
+
+ *(IrpContext->TeardownFcb) = NULL;
+ IrpContext->TeardownFcb = NULL;
+ }
+
+ break;
+
+ //
+ // We need to lock the user's buffer, unless this is an MDL read/write,
+ // in which case there is no user buffer.
+ //
+
+ case IRP_MJ_READ :
+
+ if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
+
+ CdLockUserBuffer( IrpContext, IrpSp->Parameters.Read.Length, IoWriteAccess );
+ }
+
+ break;
+
+ case IRP_MJ_WRITE :
+
+ if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
+
+ CdLockUserBuffer( IrpContext, IrpSp->Parameters.Read.Length, IoReadAccess );
+ }
+
+ break;
+
+ //
+ // We also need to check whether this is a query file operation.
+ //
+
+ case IRP_MJ_DIRECTORY_CONTROL :
+
+ if (IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
+
+ CdLockUserBuffer( IrpContext, IrpSp->Parameters.QueryDirectory.Length, IoWriteAccess );
+ }
+
+ break;
+ }
+
+ //
+ // Cleanup the IrpContext for the post.
+ //
+
+ SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_MORE_PROCESSING );
+ CdCleanupIrpContext( IrpContext, TRUE );
+
+ //
+ // Mark the Irp to show that we've already returned pending to the user.
+ //
+
+ IoMarkIrpPending( Irp );
+
+ return;
+}
+
+
+
+_Requires_lock_held_(_Global_critical_region_)
+VOID
+CdOplockComplete (
+ _Inout_ PIRP_CONTEXT IrpContext,
+ _Inout_ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by the oplock package when an oplock break has
+ completed, allowing an Irp to resume execution. If the status in
+ the Irp is STATUS_SUCCESS, then we queue the Irp to the Fsp queue.
+ Otherwise we complete the Irp with the status in the Irp.
+
+ If we are completing due to an error then check if there is any
+ cleanup to do.
+
+Arguments:
+
+ Irp - I/O Request Packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BOOLEAN RemovedFcb;
+
+ PAGED_CODE();
+
+ //
+ // Check on the return value in the Irp. If success then we
+ // are to post this request.
+ //
+
+ if (Irp->IoStatus.Status == STATUS_SUCCESS) {
+
+ //
+ // Check if there is any cleanup work to do.
+ //
+
+ switch (IrpContext->MajorFunction) {
+
+ case IRP_MJ_CREATE :
+
+ //
+ // If called from the oplock package then there is an
+ // Fcb to possibly teardown. We will call the teardown
+ // routine and release the Fcb if still present. The cleanup
+ // code in create will know not to release this Fcb because
+ // we will clear the pointer.
+ //
+
+ if (IrpContext->TeardownFcb != NULL) {
+
+ CdTeardownStructures( IrpContext, *(IrpContext->TeardownFcb), &RemovedFcb );
+
+ if (!RemovedFcb) {
+
+ _Analysis_assume_lock_held_((*IrpContext->TeardownFcb)->FcbNonpaged->FcbResource);
+ CdReleaseFcb( IrpContext, *(IrpContext->TeardownFcb) );
+ }
+
+ *(IrpContext->TeardownFcb) = NULL;
+ IrpContext->TeardownFcb = NULL;
+ }
+
+ break;
+ }
+
+ //
+ // Insert the Irp context in the workqueue.
+ //
+
+ CdAddToWorkque( IrpContext, Irp );
+
+ //
+ // Otherwise complete the request.
+ //
+
+ } else {
+
+ CdCompleteRequest( IrpContext, Irp, Irp->IoStatus.Status );
+ }
+
+ return;
+}
+
+
+//
+// Local support routine
+//
+
+VOID
+CdAddToWorkque (
+ _Inout_ PIRP_CONTEXT IrpContext,
+ _Inout_ PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to acually store the posted Irp to the Fsp
+ workque.
+
+Arguments:
+
+ IrpContext - Pointer to the IrpContext to be queued to the Fsp
+
+ Irp - I/O Request Packet.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PVOLUME_DEVICE_OBJECT Vdo;
+ KIRQL SavedIrql;
+ PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
+
+ //
+ // Check if this request has an associated file object, and thus volume
+ // device object.
+ //
+
+ if (IrpSp->FileObject != NULL) {
+
+
+ Vdo = CONTAINING_RECORD( IrpSp->DeviceObject,
+ VOLUME_DEVICE_OBJECT,
+ DeviceObject );
+
+ //
+ // Check to see if this request should be sent to the overflow
+ // queue. If not, then send it off to an exworker thread.
+ //
+
+ KeAcquireSpinLock( &Vdo->OverflowQueueSpinLock, &SavedIrql );
+
+ if (Vdo->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
+
+ //
+ // We cannot currently respond to this IRP so we'll just enqueue it
+ // to the overflow queue on the volume.
+ //
+
+ InsertTailList( &Vdo->OverflowQueue,
+ &IrpContext->WorkQueueItem.List );
+
+ Vdo->OverflowQueueCount += 1;
+
+ KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
+
+ return;
+
+ } else {
+
+ //
+ // We are going to send this Irp to an ex worker thread so up
+ // the count.
+ //
+
+ Vdo->PostedRequestCount += 1;
+
+ KeReleaseSpinLock( &Vdo->OverflowQueueSpinLock, SavedIrql );
+ }
+ }
+
+ //
+ // Send it off.....
+ //
+
+#pragma prefast(suppress:28155, "the function prototype is correct")
+ ExInitializeWorkItem( &IrpContext->WorkQueueItem,
+ CdFspDispatch,
+ IrpContext );
+
+#pragma prefast(suppress: 28159, "prefast believes this routine is obsolete, but it is ok for CDFS to continue using it")
+ ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
+
+ return;
+}
+
+
+