reactos/drivers/filesystems/fastfat_new/workque.c
2020-12-31 17:14:04 +01:00

375 lines
8 KiB
C

/*++
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
VOID
NTAPI
FatOplockComplete (
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;
}
VOID
NTAPI
FatPrePostIrp (
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;
}
NTSTATUS
FatFsdPostRequest(
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
#endif
FatAddToWorkque (
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;
}