Something went wrong. Try again.
Reactos
Something went wrong. Try again.
8.2 kB · 375 lines
C
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376/*++
Copyright (c) 1989-2000 Microsoft Corporation
Module Name:
WorkQue.c
Abstract:
This module implements the Work queue routines for the Fat File system.
--*/
#include "fatprocs.h"
//// 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)
#ifdef ALLOC_PRAGMA#pragma alloc_text(PAGE, FatOplockComplete)#pragma alloc_text(PAGE, FatPrePostIrp)#pragma alloc_text(PAGE, FatFsdPostRequest)#endif
VOIDNTAPIFatOplockComplete ( IN PVOID Context, IN 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.
Arguments:
Context - Pointer to the IrpContext to be queued to the Fsp
Irp - I/O Request Packet.
Return Value:
None.
--*/
{ PAGED_CODE();
// // Check on the return value in the Irp. //
if (Irp->IoStatus.Status == STATUS_SUCCESS) {
// // Insert the Irp context in the workqueue. //
FatAddToWorkque( (PIRP_CONTEXT) Context, Irp );
// // Otherwise complete the request. //
} else {
FatCompleteRequest( (PIRP_CONTEXT) Context, Irp, Irp->IoStatus.Status ); }
return;}
VOIDNTAPIFatPrePostIrp ( IN PVOID Context, IN 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; PIRP_CONTEXT IrpContext;
PAGED_CODE();
// // If there is no Irp, we are done. //
if (Irp == NULL) {
return; }
IrpSp = IoGetCurrentIrpStackLocation( Irp );
IrpContext = (PIRP_CONTEXT) Context;
// // If there is a STACK FatIoContext pointer, clean and NULL it. //
if ((IrpContext->FatIoContext != NULL) && FlagOn(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT)) {
ClearFlag(IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT); IrpContext->FatIoContext = NULL; }
// // We need to lock the user's buffer, unless this is an MDL-read, // in which case there is no user buffer. // // **** we need a better test than non-MDL (read or write)!
if (IrpContext->MajorFunction == IRP_MJ_READ || IrpContext->MajorFunction == IRP_MJ_WRITE) {
// // If not an Mdl request, lock the user's buffer. //
if (!FlagOn( IrpContext->MinorFunction, IRP_MN_MDL )) {
FatLockUserBuffer( IrpContext, Irp, (IrpContext->MajorFunction == IRP_MJ_READ) ? IoWriteAccess : IoReadAccess, (IrpContext->MajorFunction == IRP_MJ_READ) ? IrpSp->Parameters.Read.Length : IrpSp->Parameters.Write.Length ); }
// // We also need to check whether this is a query file operation. //
} else if (IrpContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && IrpContext->MinorFunction == IRP_MN_QUERY_DIRECTORY) {
FatLockUserBuffer( IrpContext, Irp, IoWriteAccess, IrpSp->Parameters.QueryDirectory.Length );
// // We also need to check whether this is a query ea operation. //
} else if (IrpContext->MajorFunction == IRP_MJ_QUERY_EA) {
FatLockUserBuffer( IrpContext, Irp, IoWriteAccess, IrpSp->Parameters.QueryEa.Length );
// // We also need to check whether this is a set ea operation. //
} else if (IrpContext->MajorFunction == IRP_MJ_SET_EA) {
FatLockUserBuffer( IrpContext, Irp, IoReadAccess, IrpSp->Parameters.SetEa.Length );
// // These two FSCTLs use neither I/O, so check for them. //
} else if ((IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) && (IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST) && ((IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_VOLUME_BITMAP) || (IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_GET_RETRIEVAL_POINTERS))) {
FatLockUserBuffer( IrpContext, Irp, IoWriteAccess, IrpSp->Parameters.FileSystemControl.OutputBufferLength ); }
// // Mark that we've already returned pending to the user //
IoMarkIrpPending( Irp );
return;}
NTSTATUSFatFsdPostRequest( IN PIRP_CONTEXT IrpContext, IN PIRP Irp )
/*++
Routine Description:
This routine enqueues the request packet specified by IrpContext to the Ex Worker threads. This is a FSD routine.
Arguments:
IrpContext - Pointer to the IrpContext to be queued to the Fsp
Irp - I/O Request Packet, or NULL if it has already been completed.
Return Value:
STATUS_PENDING
--*/
{ PAGED_CODE();
NT_ASSERT( ARGUMENT_PRESENT(Irp) ); NT_ASSERT( IrpContext->OriginatingIrp == Irp );
FatPrePostIrp( IrpContext, Irp );
FatAddToWorkque( IrpContext, Irp );
// // And return to our caller //
return STATUS_PENDING;}
//// Local support routine.//
VOID#ifdef __REACTOS__NTAPI#endifFatAddToWorkque ( IN PIRP_CONTEXT IrpContext, IN 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.
--*/
{ KIRQL SavedIrql; PIO_STACK_LOCATION IrpSp;
IrpSp = IoGetCurrentIrpStackLocation( Irp );
// // Check if this request has an associated file object, and thus volume // device object. //
if ( IrpSp->FileObject != NULL ) {
PVOLUME_DEVICE_OBJECT Vdo;
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..... //
ExInitializeWorkItem( &IrpContext->WorkQueueItem, FatFspDispatch, IrpContext );
#ifdef _MSC_VER#pragma prefast( suppress:28159, "prefast indicates this is an obsolete API but it is ok for fastfat to keep using it." )#endif ExQueueWorkItem( &IrpContext->WorkQueueItem, CriticalWorkQueue );
return;}