3 Copyright (c) 1989-2000 Microsoft Corporation
11 This module implements the Work queue routines for the Fat File
20 // The following constant is the maximum number of ExWorkerThreads that we
21 // will allow to be servicing a particular target device at any one time.
24 #define FSP_PER_DEVICE_THRESHOLD (2)
27 #pragma alloc_text(PAGE, FatOplockComplete)
28 #pragma alloc_text(PAGE, FatPrePostIrp)
43 This routine is called by the oplock package when an oplock break has
44 completed, allowing an Irp to resume execution. If the status in
45 the Irp is STATUS_SUCCESS, then we queue the Irp to the Fsp queue.
46 Otherwise we complete the Irp with the status in the Irp.
50 Context - Pointer to the IrpContext to be queued to the Fsp
52 Irp - I/O Request Packet.
62 // Check on the return value in the Irp.
65 if (Irp
->IoStatus
.Status
== STATUS_SUCCESS
) {
68 // Insert the Irp context in the workqueue.
71 FatAddToWorkque( (PIRP_CONTEXT
) Context
, Irp
);
74 // Otherwise complete the request.
79 FatCompleteRequest( (PIRP_CONTEXT
) Context
, Irp
, Irp
->IoStatus
.Status
);
97 This routine performs any neccessary work before STATUS_PENDING is
98 returned with the Fsd thread. This routine is called within the
99 filesystem and by the oplock package.
103 Context - Pointer to the IrpContext to be queued to the Fsp
105 Irp - I/O Request Packet.
114 PIO_STACK_LOCATION IrpSp
;
115 PIRP_CONTEXT IrpContext
;
118 // If there is no Irp, we are done.
126 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
128 IrpContext
= (PIRP_CONTEXT
) Context
;
131 // If there is a STACK FatIoContext pointer, clean and NULL it.
134 if ((IrpContext
->FatIoContext
!= NULL
) &&
135 FlagOn(IrpContext
->Flags
, IRP_CONTEXT_STACK_IO_CONTEXT
)) {
137 ClearFlag(IrpContext
->Flags
, IRP_CONTEXT_STACK_IO_CONTEXT
);
138 IrpContext
->FatIoContext
= NULL
;
142 // We need to lock the user's buffer, unless this is an MDL-read,
143 // in which case there is no user buffer.
145 // **** we need a better test than non-MDL (read or write)!
147 if (IrpContext
->MajorFunction
== IRP_MJ_READ
||
148 IrpContext
->MajorFunction
== IRP_MJ_WRITE
) {
151 // If not an Mdl request, lock the user's buffer.
154 if (!FlagOn( IrpContext
->MinorFunction
, IRP_MN_MDL
)) {
156 FatLockUserBuffer( IrpContext
,
158 (IrpContext
->MajorFunction
== IRP_MJ_READ
) ?
159 IoWriteAccess
: IoReadAccess
,
160 (IrpContext
->MajorFunction
== IRP_MJ_READ
) ?
161 IrpSp
->Parameters
.Read
.Length
: IrpSp
->Parameters
.Write
.Length
);
165 // We also need to check whether this is a query file operation.
168 } else if (IrpContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
169 && IrpContext
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
) {
171 FatLockUserBuffer( IrpContext
,
174 IrpSp
->Parameters
.QueryDirectory
.Length
);
177 // We also need to check whether this is a query ea operation.
180 } else if (IrpContext
->MajorFunction
== IRP_MJ_QUERY_EA
) {
182 FatLockUserBuffer( IrpContext
,
185 IrpSp
->Parameters
.QueryEa
.Length
);
188 // We also need to check whether this is a set ea operation.
191 } else if (IrpContext
->MajorFunction
== IRP_MJ_SET_EA
) {
193 FatLockUserBuffer( IrpContext
,
196 IrpSp
->Parameters
.SetEa
.Length
);
199 // These two FSCTLs use neither I/O, so check for them.
202 } else if ((IrpContext
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
203 (IrpContext
->MinorFunction
== IRP_MN_USER_FS_REQUEST
) &&
204 ((IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_GET_VOLUME_BITMAP
) ||
205 (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_GET_RETRIEVAL_POINTERS
))) {
207 FatLockUserBuffer( IrpContext
,
210 IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
);
214 // Mark that we've already returned pending to the user
217 IoMarkIrpPending( Irp
);
225 IN PIRP_CONTEXT IrpContext
,
233 This routine enqueues the request packet specified by IrpContext to the
234 Ex Worker threads. This is a FSD routine.
238 IrpContext - Pointer to the IrpContext to be queued to the Fsp
240 Irp - I/O Request Packet, or NULL if it has already been completed.
250 ASSERT( ARGUMENT_PRESENT(Irp
) );
251 ASSERT( IrpContext
->OriginatingIrp
== Irp
);
253 FatPrePostIrp( IrpContext
, Irp
);
255 FatAddToWorkque( IrpContext
, Irp
);
258 // And return to our caller
261 return STATUS_PENDING
;
266 // Local support routine.
271 IN PIRP_CONTEXT IrpContext
,
279 This routine is called to acually store the posted Irp to the Fsp
284 IrpContext - Pointer to the IrpContext to be queued to the Fsp
286 Irp - I/O Request Packet.
296 PIO_STACK_LOCATION IrpSp
;
298 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
301 // Check if this request has an associated file object, and thus volume
305 if ( IrpSp
->FileObject
!= NULL
) {
307 PVOLUME_DEVICE_OBJECT Vdo
;
309 Vdo
= CONTAINING_RECORD( IrpSp
->DeviceObject
,
310 VOLUME_DEVICE_OBJECT
,
314 // Check to see if this request should be sent to the overflow
315 // queue. If not, then send it off to an exworker thread.
318 KeAcquireSpinLock( &Vdo
->OverflowQueueSpinLock
, &SavedIrql
);
320 if ( Vdo
->PostedRequestCount
> FSP_PER_DEVICE_THRESHOLD
) {
323 // We cannot currently respond to this IRP so we'll just enqueue it
324 // to the overflow queue on the volume.
327 InsertTailList( &Vdo
->OverflowQueue
,
328 &IrpContext
->WorkQueueItem
.List
);
330 Vdo
->OverflowQueueCount
+= 1;
332 KeReleaseSpinLock( &Vdo
->OverflowQueueSpinLock
, SavedIrql
);
339 // We are going to send this Irp to an ex worker thread so up
343 Vdo
->PostedRequestCount
+= 1;
345 KeReleaseSpinLock( &Vdo
->OverflowQueueSpinLock
, SavedIrql
);
353 ExInitializeWorkItem( &IrpContext
->WorkQueueItem
,
357 ExQueueWorkItem( &IrpContext
->WorkQueueItem
, CriticalWorkQueue
);