3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the Work queue routines for the Cdfs File
20 // The Bug check file id for this module
23 #define BugCheckFileId (CDFS_BUG_CHECK_WORKQUE)
26 // The following constant is the maximum number of ExWorkerThreads that we
27 // will allow to be servicing a particular target device at any one time.
30 #define FSP_PER_DEVICE_THRESHOLD (2)
33 // Local support routines
38 _Inout_ PIRP_CONTEXT IrpContext
,
43 #pragma alloc_text(PAGE, CdFsdPostRequest)
44 #pragma alloc_text(PAGE, CdOplockComplete)
45 #pragma alloc_text(PAGE, CdPrePostIrp)
49 _Requires_lock_held_(_Global_critical_region_
)
52 _Inout_ PIRP_CONTEXT IrpContext
,
60 This routine enqueues the request packet specified by IrpContext to the
61 work queue associated with the FileSystemDeviceObject. This is a FSD
66 IrpContext - Pointer to the IrpContext to be queued to the Fsp.
68 Irp - I/O Request Packet.
79 ASSERT_IRP_CONTEXT( IrpContext
);
83 // Posting is a three step operation. First lock down any buffers
84 // in the Irp. Next cleanup the IrpContext for the post and finally
85 // add this to a workque.
88 CdPrePostIrp( IrpContext
, Irp
);
90 CdAddToWorkque( IrpContext
, Irp
);
93 // And return to our caller
96 return STATUS_PENDING
;
101 _Requires_lock_held_(_Global_critical_region_
)
104 _Inout_ PIRP_CONTEXT IrpContext
,
112 This routine performs any neccessary work before STATUS_PENDING is
113 returned with the Fsd thread. This routine is called within the
114 filesystem and by the oplock package.
118 Context - Pointer to the IrpContext to be queued to the Fsp
120 Irp - I/O Request Packet.
129 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
134 ASSERT_IRP_CONTEXT( IrpContext
);
138 // Case on the type of the operation.
141 switch (IrpContext
->MajorFunction
) {
146 // If called from the oplock package then there is an
147 // Fcb to possibly teardown. We will call the teardown
148 // routine and release the Fcb if still present. The cleanup
149 // code in create will know not to release this Fcb because
150 // we will clear the pointer.
153 if ((IrpContext
->TeardownFcb
!= NULL
) &&
154 *(IrpContext
->TeardownFcb
) != NULL
) {
156 CdTeardownStructures( IrpContext
, *(IrpContext
->TeardownFcb
), &RemovedFcb
);
160 _Analysis_assume_lock_held_((*IrpContext
->TeardownFcb
)->FcbNonpaged
->FcbResource
);
161 CdReleaseFcb( IrpContext
, *(IrpContext
->TeardownFcb
) );
164 *(IrpContext
->TeardownFcb
) = NULL
;
165 IrpContext
->TeardownFcb
= NULL
;
171 // We need to lock the user's buffer, unless this is an MDL read/write,
172 // in which case there is no user buffer.
177 if (!FlagOn( IrpContext
->MinorFunction
, IRP_MN_MDL
)) {
179 CdLockUserBuffer( IrpContext
, IrpSp
->Parameters
.Read
.Length
, IoWriteAccess
);
186 if (!FlagOn( IrpContext
->MinorFunction
, IRP_MN_MDL
)) {
188 CdLockUserBuffer( IrpContext
, IrpSp
->Parameters
.Read
.Length
, IoReadAccess
);
194 // We also need to check whether this is a query file operation.
197 case IRP_MJ_DIRECTORY_CONTROL
:
199 if (IrpContext
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
) {
201 CdLockUserBuffer( IrpContext
, IrpSp
->Parameters
.QueryDirectory
.Length
, IoWriteAccess
);
208 // Cleanup the IrpContext for the post.
211 SetFlag( IrpContext
->Flags
, IRP_CONTEXT_FLAG_MORE_PROCESSING
);
212 CdCleanupIrpContext( IrpContext
, TRUE
);
215 // Mark the Irp to show that we've already returned pending to the user.
218 IoMarkIrpPending( Irp
);
225 _Requires_lock_held_(_Global_critical_region_
)
228 _Inout_ PIRP_CONTEXT IrpContext
,
236 This routine is called by the oplock package when an oplock break has
237 completed, allowing an Irp to resume execution. If the status in
238 the Irp is STATUS_SUCCESS, then we queue the Irp to the Fsp queue.
239 Otherwise we complete the Irp with the status in the Irp.
241 If we are completing due to an error then check if there is any
246 Irp - I/O Request Packet.
260 // Check on the return value in the Irp. If success then we
261 // are to post this request.
264 if (Irp
->IoStatus
.Status
== STATUS_SUCCESS
) {
267 // Check if there is any cleanup work to do.
270 switch (IrpContext
->MajorFunction
) {
275 // If called from the oplock package then there is an
276 // Fcb to possibly teardown. We will call the teardown
277 // routine and release the Fcb if still present. The cleanup
278 // code in create will know not to release this Fcb because
279 // we will clear the pointer.
282 if (IrpContext
->TeardownFcb
!= NULL
) {
284 CdTeardownStructures( IrpContext
, *(IrpContext
->TeardownFcb
), &RemovedFcb
);
288 _Analysis_assume_lock_held_((*IrpContext
->TeardownFcb
)->FcbNonpaged
->FcbResource
);
289 CdReleaseFcb( IrpContext
, *(IrpContext
->TeardownFcb
) );
292 *(IrpContext
->TeardownFcb
) = NULL
;
293 IrpContext
->TeardownFcb
= NULL
;
300 // Insert the Irp context in the workqueue.
303 CdAddToWorkque( IrpContext
, Irp
);
306 // Otherwise complete the request.
311 CdCompleteRequest( IrpContext
, Irp
, Irp
->IoStatus
.Status
);
319 // Local support routine
324 _Inout_ PIRP_CONTEXT IrpContext
,
332 This routine is called to acually store the posted Irp to the Fsp
337 IrpContext - Pointer to the IrpContext to be queued to the Fsp
339 Irp - I/O Request Packet.
348 PVOLUME_DEVICE_OBJECT Vdo
;
350 PIO_STACK_LOCATION IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
353 // Check if this request has an associated file object, and thus volume
357 if (IrpSp
->FileObject
!= NULL
) {
360 Vdo
= CONTAINING_RECORD( IrpSp
->DeviceObject
,
361 VOLUME_DEVICE_OBJECT
,
365 // Check to see if this request should be sent to the overflow
366 // queue. If not, then send it off to an exworker thread.
369 KeAcquireSpinLock( &Vdo
->OverflowQueueSpinLock
, &SavedIrql
);
371 if (Vdo
->PostedRequestCount
> FSP_PER_DEVICE_THRESHOLD
) {
374 // We cannot currently respond to this IRP so we'll just enqueue it
375 // to the overflow queue on the volume.
378 InsertTailList( &Vdo
->OverflowQueue
,
379 &IrpContext
->WorkQueueItem
.List
);
381 Vdo
->OverflowQueueCount
+= 1;
383 KeReleaseSpinLock( &Vdo
->OverflowQueueSpinLock
, SavedIrql
);
390 // We are going to send this Irp to an ex worker thread so up
394 Vdo
->PostedRequestCount
+= 1;
396 KeReleaseSpinLock( &Vdo
->OverflowQueueSpinLock
, SavedIrql
);
404 #pragma prefast(suppress:28155, "the function prototype is correct")
405 ExInitializeWorkItem( &IrpContext
->WorkQueueItem
,
409 #pragma prefast(suppress: 28159, "prefast believes this routine is obsolete, but it is ok for CDFS to continue using it")
410 ExQueueWorkItem( &IrpContext
->WorkQueueItem
, CriticalWorkQueue
);