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)
29 #pragma alloc_text(PAGE, FatFsdPostRequest)
44 This routine is called by the oplock package when an oplock break has
45 completed, allowing an Irp to resume execution. If the status in
46 the Irp is STATUS_SUCCESS, then we queue the Irp to the Fsp queue.
47 Otherwise we complete the Irp with the status in the Irp.
51 Context - Pointer to the IrpContext to be queued to the Fsp
53 Irp - I/O Request Packet.
65 // Check on the return value in the Irp.
68 if (Irp
->IoStatus
.Status
== STATUS_SUCCESS
) {
71 // Insert the Irp context in the workqueue.
74 FatAddToWorkque( (PIRP_CONTEXT
) Context
, Irp
);
77 // Otherwise complete the request.
82 FatCompleteRequest( (PIRP_CONTEXT
) Context
, Irp
, Irp
->IoStatus
.Status
);
100 This routine performs any neccessary work before STATUS_PENDING is
101 returned with the Fsd thread. This routine is called within the
102 filesystem and by the oplock package.
106 Context - Pointer to the IrpContext to be queued to the Fsp
108 Irp - I/O Request Packet.
117 PIO_STACK_LOCATION IrpSp
;
118 PIRP_CONTEXT IrpContext
;
123 // If there is no Irp, we are done.
131 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
133 IrpContext
= (PIRP_CONTEXT
) Context
;
136 // If there is a STACK FatIoContext pointer, clean and NULL it.
139 if ((IrpContext
->FatIoContext
!= NULL
) &&
140 FlagOn(IrpContext
->Flags
, IRP_CONTEXT_STACK_IO_CONTEXT
)) {
142 ClearFlag(IrpContext
->Flags
, IRP_CONTEXT_STACK_IO_CONTEXT
);
143 IrpContext
->FatIoContext
= NULL
;
147 // We need to lock the user's buffer, unless this is an MDL-read,
148 // in which case there is no user buffer.
150 // **** we need a better test than non-MDL (read or write)!
152 if (IrpContext
->MajorFunction
== IRP_MJ_READ
||
153 IrpContext
->MajorFunction
== IRP_MJ_WRITE
) {
156 // If not an Mdl request, lock the user's buffer.
159 if (!FlagOn( IrpContext
->MinorFunction
, IRP_MN_MDL
)) {
161 FatLockUserBuffer( IrpContext
,
163 (IrpContext
->MajorFunction
== IRP_MJ_READ
) ?
164 IoWriteAccess
: IoReadAccess
,
165 (IrpContext
->MajorFunction
== IRP_MJ_READ
) ?
166 IrpSp
->Parameters
.Read
.Length
: IrpSp
->Parameters
.Write
.Length
);
170 // We also need to check whether this is a query file operation.
173 } else if (IrpContext
->MajorFunction
== IRP_MJ_DIRECTORY_CONTROL
174 && IrpContext
->MinorFunction
== IRP_MN_QUERY_DIRECTORY
) {
176 FatLockUserBuffer( IrpContext
,
179 IrpSp
->Parameters
.QueryDirectory
.Length
);
182 // We also need to check whether this is a query ea operation.
185 } else if (IrpContext
->MajorFunction
== IRP_MJ_QUERY_EA
) {
187 FatLockUserBuffer( IrpContext
,
190 IrpSp
->Parameters
.QueryEa
.Length
);
193 // We also need to check whether this is a set ea operation.
196 } else if (IrpContext
->MajorFunction
== IRP_MJ_SET_EA
) {
198 FatLockUserBuffer( IrpContext
,
201 IrpSp
->Parameters
.SetEa
.Length
);
204 // These two FSCTLs use neither I/O, so check for them.
207 } else if ((IrpContext
->MajorFunction
== IRP_MJ_FILE_SYSTEM_CONTROL
) &&
208 (IrpContext
->MinorFunction
== IRP_MN_USER_FS_REQUEST
) &&
209 ((IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_GET_VOLUME_BITMAP
) ||
210 (IrpSp
->Parameters
.FileSystemControl
.FsControlCode
== FSCTL_GET_RETRIEVAL_POINTERS
))) {
212 FatLockUserBuffer( IrpContext
,
215 IrpSp
->Parameters
.FileSystemControl
.OutputBufferLength
);
219 // Mark that we've already returned pending to the user
222 IoMarkIrpPending( Irp
);
230 IN PIRP_CONTEXT IrpContext
,
238 This routine enqueues the request packet specified by IrpContext to the
239 Ex Worker threads. This is a FSD routine.
243 IrpContext - Pointer to the IrpContext to be queued to the Fsp
245 Irp - I/O Request Packet, or NULL if it has already been completed.
257 NT_ASSERT( ARGUMENT_PRESENT(Irp
) );
258 NT_ASSERT( IrpContext
->OriginatingIrp
== Irp
);
260 FatPrePostIrp( IrpContext
, Irp
);
262 FatAddToWorkque( IrpContext
, Irp
);
265 // And return to our caller
268 return STATUS_PENDING
;
273 // Local support routine.
278 IN PIRP_CONTEXT IrpContext
,
286 This routine is called to acually store the posted Irp to the Fsp
291 IrpContext - Pointer to the IrpContext to be queued to the Fsp
293 Irp - I/O Request Packet.
303 PIO_STACK_LOCATION IrpSp
;
305 IrpSp
= IoGetCurrentIrpStackLocation( Irp
);
308 // Check if this request has an associated file object, and thus volume
312 if ( IrpSp
->FileObject
!= NULL
) {
314 PVOLUME_DEVICE_OBJECT Vdo
;
316 Vdo
= CONTAINING_RECORD( IrpSp
->DeviceObject
,
317 VOLUME_DEVICE_OBJECT
,
321 // Check to see if this request should be sent to the overflow
322 // queue. If not, then send it off to an exworker thread.
325 KeAcquireSpinLock( &Vdo
->OverflowQueueSpinLock
, &SavedIrql
);
327 if ( Vdo
->PostedRequestCount
> FSP_PER_DEVICE_THRESHOLD
) {
330 // We cannot currently respond to this IRP so we'll just enqueue it
331 // to the overflow queue on the volume.
334 InsertTailList( &Vdo
->OverflowQueue
,
335 &IrpContext
->WorkQueueItem
.List
);
337 Vdo
->OverflowQueueCount
+= 1;
339 KeReleaseSpinLock( &Vdo
->OverflowQueueSpinLock
, SavedIrql
);
346 // We are going to send this Irp to an ex worker thread so up
350 Vdo
->PostedRequestCount
+= 1;
352 KeReleaseSpinLock( &Vdo
->OverflowQueueSpinLock
, SavedIrql
);
360 ExInitializeWorkItem( &IrpContext
->WorkQueueItem
,
365 #pragma prefast( suppress:28159, "prefast indicates this is an obsolete API but it is ok for fastfat to keep using it." )
367 ExQueueWorkItem( &IrpContext
->WorkQueueItem
, CriticalWorkQueue
);