windows-nt/Source/XPSP1/NT/admin/pchealth/sr/kernel/srio.c
2020-09-26 16:20:57 +08:00

1148 lines
31 KiB
C

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
srio.c
Abstract:
This files contains the routines that generate IO
for the SR filter driver.
Author:
Molly Brown (MollyBro) 07-Nov-2000
Revision History:
Added routines to post & wait for ops - ravisp 12/6/2000
--*/
#include "precomp.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, SrQueryInformationFile )
#pragma alloc_text( PAGE, SrSetInformationFile )
#pragma alloc_text( PAGE, SrQueryVolumeInformationFile )
#pragma alloc_text( PAGE, SrQueryEaFile )
#pragma alloc_text( PAGE, SrQuerySecurityObject )
#pragma alloc_text( PAGE, SrFlushBuffers )
#pragma alloc_text( PAGE, SrSyncOpWorker )
#pragma alloc_text( PAGE, SrPostSyncOperation )
#endif // ALLOC_PRAGMA
NTSTATUS
SrSyncIoCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT Event
)
/*++
Routine Description:
This routine does the cleanup necessary once the IO request
is completed by the file system.
Arguments:
DeviceObject - This will be NULL since we originated this
Irp.
Irp - The io request structure containing the information
about the current state of our file name query.
Event - The event to signal to notify the
originator of this request that the operation is
complete.
Return Value:
Returns STATUS_MORE_PROCESSING_REQUIRED so that IO Manager
will not try to free the Irp again.
--*/
{
UNREFERENCED_PARAMETER( DeviceObject );
//
// Make sure that the Irp status is copied over to the user's
// IO_STATUS_BLOCK so that the originator of this irp will know
// the final status of this operation.
//
ASSERT( NULL != Irp->UserIosb );
*Irp->UserIosb = Irp->IoStatus;
//
// Signal SynchronizingEvent so that the originator of this
// Irp know that the operation is completed.
//
KeSetEvent( Event, IO_NO_INCREMENT, FALSE );
//
// We are now done, so clean up the irp that we allocated.
//
IoFreeIrp( Irp );
//
// If we return STATUS_SUCCESS here, the IO Manager will
// perform the cleanup work that it thinks needs to be done
// for this IO operation. This cleanup work includes:
// * Copying data from the system buffer to the user's buffer
// if this was a buffered IO operation.
// * Freeing any MDLs that are in the Irp.
// * Copying the Irp->IoStatus to Irp->UserIosb so that the
// originator of this irp can see the final status of the
// operation.
// * If this was an asynchronous request or this was a
// synchronous request that got pending somewhere along the
// way, the IO Manager will signal the Irp->UserEvent, if one
// exists, otherwise it will signal the FileObject->Event.
// (This can have REALLY bad implications if the irp originator
// did not an Irp->UserEvent and the irp originator is not
// waiting on the FileObject->Event. It would not be that
// farfetched to believe that someone else in the system is
// waiting on FileObject->Event and who knows who will be
// awoken as a result of the IO Manager signaling this event.
//
// Since some of these operations require the originating thread's
// context (e.g., the IO Manager need the UserBuffer address to
// be valid when copy is done), the IO Manager queues this work
// to an APC on the Irp's orginating thread.
//
// Since SR allocated and initialized this irp, we know
// what cleanup work needs to be done. We can do this cleanup
// work more efficiently than the IO Manager since we are handling
// a very specific case. Therefore, it is better for us to
// perform the cleanup work here then free the irp than passing
// control back to the IO Manager to do this work.
//
// By returning STATUS_MORE_PROCESS_REQUIRED, we tell the IO Manager
// to stop processing this irp until it is told to restart processing
// with a call to IoCompleteRequest. Since the IO Manager has
// already performed all the work we want it to do on this
// irp, we do the cleanup work, return STATUS_MORE_PROCESSING_REQUIRED,
// and ask the IO Manager to resume processing by calling
// IoCompleteRequest.
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
SrQueryInformationFile (
IN PDEVICE_OBJECT NextDeviceObject,
IN PFILE_OBJECT FileObject,
OUT PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass,
OUT PULONG LengthReturned OPTIONAL
)
/*++
Routine Description:
This routine returns the requested information about a specified file.
The information returned is determined by the FileInformationClass that
is specified, and it is placed into the caller's FileInformation buffer.
This routine only supports the following FileInformationClasses:
FileBasicInformation
FileStandardInformation
FileStreamInformation
FileAlternateNameInformation
FileNameInformation
Arguments:
NextDeviceObject - Supplies the device object where this IO should start
in the device stack.
FileObject - Supplies the file object about which the requested
information should be returned.
FileInformation - Supplies a buffer to receive the requested information
returned about the file. This must be a buffer allocated from kernel
space.
Length - Supplies the length, in bytes, of the FileInformation buffer.
FileInformationClass - Specifies the type of information which should be
returned about the file.
LengthReturned - the number of bytes returned if the operation was
successful.
Return Value:
The status returned is the final completion status of the operation.
--*/
{
PIRP irp = NULL;
PIO_STACK_LOCATION irpSp = NULL;
IO_STATUS_BLOCK ioStatusBlock;
KEVENT event;
NTSTATUS status;
PAGED_CODE();
//
// In DBG builds, make sure that we have valid parameters before we do
// any work here.
//
ASSERT( NULL != NextDeviceObject );
ASSERT( NULL != FileObject );
ASSERT( NULL != FileInformation );
ASSERT( (FileInformationClass == FileBasicInformation) ||
(FileInformationClass == FileStandardInformation) ||
(FileInformationClass == FileStreamInformation) ||
(FileInformationClass == FileAlternateNameInformation) ||
(FileInformationClass == FileNameInformation) ||
(FileInformationClass == FileInternalInformation) );
//
// The parameters look ok, so setup the Irp.
//
KeInitializeEvent( &event, NotificationEvent, FALSE );
ioStatusBlock.Status = STATUS_SUCCESS;
ioStatusBlock.Information = 0;
irp = IoAllocateIrp( NextDeviceObject->StackSize, FALSE );
if (irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Set our current thread as the thread for this
// irp so that the IO Manager always knows which
// thread to return to if it needs to get back into
// the context of the thread that originated this
// irp.
//
irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Set that this irp originated from the kernel so that
// the IO Manager knows that the buffers do not
// need to be probed.
//
irp->RequestorMode = KernelMode;
//
// Initialize the UserIosb and UserEvent in the
irp->UserIosb = &ioStatusBlock;
irp->UserEvent = NULL;
//
// Set the IRP_SYNCHRONOUS_API to denote that this
// is a synchronous IO request.
//
irp->Flags = IRP_SYNCHRONOUS_API;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
irpSp->FileObject = FileObject;
//
// Setup the parameters for IRP_MJ_QUERY_INFORMATION. These
// were supplied by the caller of this routine.
// The buffer we want to be filled in should be placed in
// the system buffer.
//
irp->AssociatedIrp.SystemBuffer = FileInformation;
irpSp->Parameters.QueryFile.Length = Length;
irpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass;
//
// Set up the completion routine so that we know when our
// request for the file name is completed. At that time,
// we can free the irp.
//
IoSetCompletionRoutine( irp,
SrSyncIoCompletion,
&event,
TRUE,
TRUE,
TRUE );
status = IoCallDriver( NextDeviceObject, irp );
(VOID) KeWaitForSingleObject( &event,
Executive,
KernelMode,
FALSE,
NULL );
if (LengthReturned != NULL) {
*LengthReturned = (ULONG) ioStatusBlock.Information;
}
#if DBG
if (STATUS_OBJECT_NAME_NOT_FOUND == ioStatusBlock.Status ||
STATUS_INVALID_PARAMETER == ioStatusBlock.Status)
{
return ioStatusBlock.Status;
}
#endif
RETURN( ioStatusBlock.Status );
}
NTSTATUS
SrSetInformationFile (
IN PDEVICE_OBJECT NextDeviceObject,
IN PFILE_OBJECT FileObject,
IN PVOID FileInformation,
IN ULONG Length,
IN FILE_INFORMATION_CLASS FileInformationClass
)
/*++
Routine Description:
This routine changes the provided information about a specified file. The
information that is changed is determined by the FileInformationClass that
is specified. The new information is taken from the FileInformation buffer.
Arguments:
NextDeviceObject - Supplies the device object where this IO should start
in the device stack.
FileObject - Supplies the file object about which the requested
information should be changed.
FileInformation - Supplies a buffer containing the information which should
be changed on the file.
Length - Supplies the length, in bytes, of the FileInformation buffer.
FileInformationClass - Specifies the type of information which should be
changed about the file.
Return Value:
The status returned is the final completion status of the operation.
--*/
{
PIRP irp;
PIO_STACK_LOCATION irpSp;
IO_STATUS_BLOCK ioStatusBlock;
KEVENT event;
NTSTATUS status;
PAGED_CODE();
//
// In DBG builds, make sure the parameters are valid.
//
ASSERT( NULL != NextDeviceObject );
ASSERT( NULL != FileObject );
ASSERT( NULL != FileInformation );
//
// The parameters look ok, so setup the Irp.
//
KeInitializeEvent( &event, NotificationEvent, FALSE );
ioStatusBlock.Status = STATUS_SUCCESS;
ioStatusBlock.Information = 0;
irp = IoAllocateIrp( NextDeviceObject->StackSize, FALSE );
if (irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Set our current thread as the thread for this
// irp so that the IO Manager always knows which
// thread to return to if it needs to get back into
// the context of the thread that originated this
// irp.
//
irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Set that this irp originated from the kernel so that
// the IO Manager knows that the buffers do not
// need to be probed.
//
irp->RequestorMode = KernelMode;
//
// Initialize the UserIosb and UserEvent in the
irp->UserIosb = &ioStatusBlock;
irp->UserEvent = NULL;
//
// Set the IRP_SYNCHRONOUS_API to denote that this
// is a synchronous IO request.
//
irp->Flags = IRP_SYNCHRONOUS_API;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
irpSp->FileObject = FileObject;
//
// Setup the parameters for IRP_MJ_QUERY_INFORMATION. These
// were supplied by the caller of this routine.
// The buffer we want to be filled in should be placed in
// the system buffer.
//
irp->AssociatedIrp.SystemBuffer = FileInformation;
irpSp->Parameters.SetFile.Length = Length;
irpSp->Parameters.SetFile.FileInformationClass = FileInformationClass;
irpSp->Parameters.SetFile.FileObject = NULL;
irpSp->Parameters.SetFile.DeleteHandle = NULL;
//
// Set up the completion routine so that we know when our
// request for the file name is completed. At that time,
// we can free the irp.
//
IoSetCompletionRoutine( irp,
SrSyncIoCompletion,
&event,
TRUE,
TRUE,
TRUE );
status = IoCallDriver( NextDeviceObject, irp );
(VOID) KeWaitForSingleObject( &event,
Executive,
KernelMode,
FALSE,
NULL );
#if DBG
if (ioStatusBlock.Status == STATUS_CANNOT_DELETE ||
ioStatusBlock.Status == STATUS_DIRECTORY_NOT_EMPTY)
{
//
// bug#186511: STATUS_CANNOT_DELETE can be returned for some crazy
// reason by the fsd if the file is already deleted. it should return
// already deleted or simple return success, but it returns this
// instead. callers of this function know to test for this.
// don't DbgBreak.
//
return ioStatusBlock.Status;
}
#endif
RETURN( ioStatusBlock.Status );
}
NTSTATUS
SrQueryVolumeInformationFile (
IN PDEVICE_OBJECT NextDeviceObject,
IN PFILE_OBJECT FileObject,
OUT PVOID FsInformation,
IN ULONG Length,
IN FS_INFORMATION_CLASS FsInformationClass,
OUT PULONG LengthReturned OPTIONAL
)
/*++
Routine Description:
This routine returns information about the volume associated with the
FileObject parameter. The information returned in the buffer is defined
by the FsInformationClass parameter. The legal values for this parameter
are as follows:
o FileFsVolumeInformation
o FileFsSizeInformation
o FileFsDeviceInformation
o FileFsAttributeInformation
Note: Currently this routine only supports the following
FsInformationClasses:
FileFsVolumeInformation
FileFsSizeInformation
Arguments:
NextDeviceObject - Supplies the device object where this IO should start
in the device stack.
FileObject - Supplies a fileobject to an open volume, directory, or file
for which information about the volume is returned.
FsInformation - Supplies a buffer to receive the requested information
returned about the volume. This must be a buffer allocated from
kernel space.
Length - Supplies the length, in bytes, of the FsInformation buffer.
FsInformationClass - Specifies the type of information which should be
returned about the volume.
LengthReturned - The number of bytes returned if the operation was
successful.
Return Value:
The status returned is the final completion status of the operation.
--*/
{
PIRP irp = NULL;
PIO_STACK_LOCATION irpSp = NULL;
IO_STATUS_BLOCK ioStatusBlock;
KEVENT event;
NTSTATUS status;
PAGED_CODE();
//
// In DBG builds, make sure that we have valid parameters before
// we do any work here.
//
ASSERT( NextDeviceObject != NULL );
ASSERT( FileObject != NULL );
ASSERT( FsInformation != NULL );
ASSERT( (FsInformationClass == FileFsVolumeInformation) ||
(FsInformationClass == FileFsSizeInformation) ||
(FsInformationClass == FileFsAttributeInformation) );
//
// The parameters look ok, so setup the Irp.
//
KeInitializeEvent( &event, NotificationEvent, FALSE );
ioStatusBlock.Status = STATUS_SUCCESS;
ioStatusBlock.Information = 0;
irp = IoAllocateIrp( NextDeviceObject->StackSize, FALSE );
if (irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Set our current thread as the thread for this
// irp so that the IO Manager always knows which
// thread to return to if it needs to get back into
// the context of the thread that originated this
// irp.
//
irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Set that this irp originated from the kernel so that
// the IO Manager knows that the buffers do not
// need to be probed.
//
irp->RequestorMode = KernelMode;
//
// Initialize the UserIosb and UserEvent in the
irp->UserIosb = &ioStatusBlock;
irp->UserEvent = NULL;
//
// Set the IRP_SYNCHRONOUS_API to denote that this
// is a synchronous IO request.
//
irp->Flags = IRP_SYNCHRONOUS_API;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
irpSp->FileObject = FileObject;
//
// Setup the parameters for IRP_MJ_QUERY_VOLUME_INFORMATION. These
// were supplied by the caller of this routine.
// The buffer we want to be filled in should be placed in
// the system buffer.
//
irp->AssociatedIrp.SystemBuffer = FsInformation;
irpSp->Parameters.QueryVolume.Length = Length;
irpSp->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
//
// Set up the completion routine so that we know when our
// request for the file name is completed. At that time,
// we can free the irp.
//
IoSetCompletionRoutine( irp,
SrSyncIoCompletion,
&event,
TRUE,
TRUE,
TRUE );
status = IoCallDriver( NextDeviceObject, irp );
(VOID) KeWaitForSingleObject( &event,
Executive,
KernelMode,
FALSE,
NULL );
if (LengthReturned != NULL) {
*LengthReturned = (ULONG) ioStatusBlock.Information;
}
RETURN( ioStatusBlock.Status );
}
NTSTATUS
SrQueryEaFile (
IN PDEVICE_OBJECT NextDeviceObject,
IN PFILE_OBJECT FileObject,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG LengthReturned OPTIONAL
)
/*++
Routine Description:
This routine returns the Extended Attributes (EAs) associated with the
file specified by the FileObject parameter. The amount of information
returned is based on the size of the EAs, and the size of the buffer.
That is, either all of the EAs are written to the buffer, or the buffer
is filled with complete EAs if the buffer is not large enough to contain
all of the EAs. Only complete EAs are ever written to the buffer; no
partial EAs will ever be returned.
NOTE: This routine will always return EAs starting at the being of the
file's EA List. It will also always return as many EAs as possible in the
buffer. THIS BEHAVIOR IS A LIMITED VERSION OF ZwQueryEaFile.
Arguments:
NextDeviceObject - Supplies the device object where this IO should start
in the device stack.
FileObject - Supplies a fileobject to the file for which the EAs are returned.
IoStatusBlock - Address of the caller's I/O status block.
Buffer - Supplies a buffer to receive the EAs for the file.
Length - Supplies the length, in bytes, of the buffer.
LengthReturned - The number of bytes returned if the operation is
successful.
Return Value:
The status returned is the final completion status of the operation.
--*/
{
PIRP irp = NULL;
PIO_STACK_LOCATION irpSp = NULL;
IO_STATUS_BLOCK ioStatusBlock;
KEVENT event;
NTSTATUS status;
PAGED_CODE();
//
// In DBG builds, make sure that we have valid parameters before we do
// any work here.
//
ASSERT( NULL != NextDeviceObject );
ASSERT( NULL != FileObject );
ASSERT( NULL != Buffer );
//
// The parameters look ok, so setup the Irp.
//
KeInitializeEvent( &event, NotificationEvent, FALSE );
ioStatusBlock.Status = STATUS_SUCCESS;
ioStatusBlock.Information = 0;
irp = IoAllocateIrp( NextDeviceObject->StackSize, FALSE );
if (NULL == irp) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Set our current thread as the thread for this
// irp so that the IO Manager always knows which
// thread to return to if it needs to get back into
// the context of the thread that originated this
// irp.
//
irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Set that this irp originated from the kernel so that
// the IO Manager knows that the buffers do not
// need to be probed.
//
irp->RequestorMode = KernelMode;
//
// Initialize the UserIosb and UserEvent in the
irp->UserIosb = &ioStatusBlock;
irp->UserEvent = NULL;
//
// Set the IRP_SYNCHRONOUS_API to denote that this
// is a synchronous IO request.
//
irp->Flags = IRP_SYNCHRONOUS_API;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_QUERY_EA;
irpSp->FileObject = FileObject;
//
// Setup the parameters for IRP_MJ_QUERY_EA. These
// were supplied by the caller of this routine.
// The buffer we want to be filled in should be placed in
// the user buffer.
//
irp->UserBuffer = Buffer;
irpSp->Parameters.QueryEa.Length = Length;
irpSp->Parameters.QueryEa.EaList = NULL;
irpSp->Parameters.QueryEa.EaListLength = 0;
irpSp->Parameters.QueryEa.EaIndex = 0;
irpSp->Flags = SL_RESTART_SCAN;
//
// Set up the completion routine so that we know when our
// request for the file name is completed. At that time,
// we can free the irp.
//
IoSetCompletionRoutine( irp,
SrSyncIoCompletion,
&event,
TRUE,
TRUE,
TRUE );
status = IoCallDriver( NextDeviceObject, irp );
(VOID) KeWaitForSingleObject( &event,
Executive,
KernelMode,
FALSE,
NULL );
if (LengthReturned != NULL) {
*LengthReturned = (ULONG) ioStatusBlock.Information;
}
RETURN( ioStatusBlock.Status );
}
NTSTATUS
SrQuerySecurityObject (
IN PDEVICE_OBJECT NextDeviceObject,
IN PFILE_OBJECT FileObject,
IN SECURITY_INFORMATION SecurityInformation,
OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
IN ULONG Length,
OUT PULONG LengthNeeded
)
/*++
Routine Description:
This routine is used to invoke an object's security routine. It
is used to set the object's security state.
Arguments:
NextDeviceObject - Supplies the device object where this IO should start
in the device stack.
FileObject - Supplies the file object for the object being modified
SecurityInformation - Indicates the type of information we are
interested in getting. e.g., owner, group, dacl, or sacl.
SecurityDescriptor - Supplies a pointer to where the information
should be returned. This must be a buffer allocated from kernel
space.
Length - Supplies the size, in bytes, of the output buffer
LengthNeeded - Receives the length, in bytes, needed to store
the output security descriptor
Return Value:
An appropriate NTSTATUS value
--*/
{
PIRP irp = NULL;
PIO_STACK_LOCATION irpSp = NULL;
IO_STATUS_BLOCK ioStatusBlock;
KEVENT event;
NTSTATUS status;
PAGED_CODE();
//
// Make sure that we have valid parameters before we do any work here.
//
ASSERT( NextDeviceObject != NULL );
ASSERT( FileObject != NULL );
ASSERT( SecurityDescriptor != NULL );
ASSERT( LengthNeeded != NULL );
//
// The parameters look ok, so setup the Irp.
//
KeInitializeEvent( &event, NotificationEvent, FALSE );
ioStatusBlock.Status = STATUS_SUCCESS;
ioStatusBlock.Information = 0;
irp = IoAllocateIrp( NextDeviceObject->StackSize, FALSE );
if (irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Set our current thread as the thread for this
// irp so that the IO Manager always knows which
// thread to return to if it needs to get back into
// the context of the thread that originated this
// irp.
//
irp->Tail.Overlay.Thread = PsGetCurrentThread();
//
// Set that this irp originated from the kernel so that
// the IO Manager knows that the buffers do not
// need to be probed.
//
irp->RequestorMode = KernelMode;
//
// Initialize the UserIosb and UserEvent in the
irp->UserIosb = &ioStatusBlock;
irp->UserEvent = NULL;
//
// Set the IRP_SYNCHRONOUS_API to denote that this
// is a synchronous IO request.
//
irp->Flags = IRP_SYNCHRONOUS_API;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_QUERY_SECURITY;
irpSp->FileObject = FileObject;
//
// Setup the parameters for IRP_MJ_QUERY_SECURITY_INFORMATION. These
// were supplied by the caller of this routine.
// The buffer we want to be filled in should be placed in
// the User buffer.
//
irp->UserBuffer = SecurityDescriptor;
irpSp->Parameters.QuerySecurity.SecurityInformation = SecurityInformation;
irpSp->Parameters.QuerySecurity.Length = Length;
//
// Set up the completion routine so that we know when our
// request for the file name is completed. At that time,
// we can free the irp.
//
IoSetCompletionRoutine( irp,
SrSyncIoCompletion,
&event,
TRUE,
TRUE,
TRUE );
status = IoCallDriver( NextDeviceObject, irp );
(VOID) KeWaitForSingleObject( &event,
Executive,
KernelMode,
FALSE,
NULL );
status = ioStatusBlock.Status;
if (status == STATUS_BUFFER_OVERFLOW) {
status = STATUS_BUFFER_TOO_SMALL;
//
// The buffer was too small, so return the size needed for the
// security descriptor.
//
*LengthNeeded = (ULONG) ioStatusBlock.Information;
}
#if DBG
if (status == STATUS_BUFFER_TOO_SMALL) {
return status;
}
#endif
RETURN( status );
}
NTSTATUS
SrFlushBuffers (
PDEVICE_OBJECT NextDeviceObject,
PFILE_OBJECT FileObject
)
{
PIRP irp = NULL;
PIO_STACK_LOCATION irpSp = NULL;
IO_STATUS_BLOCK ioStatusBlock;
KEVENT event;
NTSTATUS status;
PAGED_CODE();
//
// Make sure that we have valid parameters before we do any work here.
//
ASSERT( NextDeviceObject != NULL );
ASSERT( FileObject != NULL );
//
// The parameters look ok, so setup the Irp.
//
KeInitializeEvent( &event, NotificationEvent, FALSE );
ioStatusBlock.Status = STATUS_SUCCESS;
ioStatusBlock.Information = 0;
irp = IoBuildAsynchronousFsdRequest( IRP_MJ_FLUSH_BUFFERS,
NextDeviceObject,
NULL,
0,
NULL,
&ioStatusBlock );
if (irp == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->FileObject = FileObject;
//
// Set up the completion routine so that we know when our
// request for the file name is completed. At that time,
// we can free the irp.
//
IoSetCompletionRoutine( irp,
SrSyncIoCompletion,
&event,
TRUE,
TRUE,
TRUE );
status = IoCallDriver( NextDeviceObject, irp );
if (status == STATUS_PENDING)
{
(VOID) KeWaitForSingleObject( &event,
Executive,
KernelMode,
FALSE,
NULL );
}
RETURN( ioStatusBlock.Status );
}
//
//++
// Function:
// SrSyncOpWorker
//
// Description:
// This function is the generic worker routine
// that calls the real caller-passed work routine,
// and sets the event for synchronization with the main
// thread
//
// Arguments:
//
// Context
//
// Return Value:
//
// None
//--
//
VOID
SrSyncOpWorker(
IN PSR_WORK_CONTEXT WorkContext
)
{
PAGED_CODE();
ASSERT(WorkContext != NULL);
ASSERT(WorkContext->SyncOpRoutine != NULL);
//
// Call the 'real' posted routine
//
WorkContext->Status = (*WorkContext->SyncOpRoutine)(WorkContext->Parameter);
//
// Signal the main-thread about completion
//
KeSetEvent(&WorkContext->SyncEvent,
EVENT_INCREMENT,
FALSE);
}
//++
// Function:
// SrPostSyncOperation
//
// Description:
// This function posts work to a worker thread
// and waits for completion
//
// WARNING: Be VERY careful about acquiring locks in the
// operation that is being posted. This may lead to deadlocks.
//
//
// Arguments:
//
// Pointer to worker routine that handles the work
// Context to be passed to worker routine
//
// Return Value:
// This function returns status of the work routine
//--
NTSTATUS
SrPostSyncOperation(
IN PSR_SYNCOP_ROUTINE SyncOpRoutine,
IN PVOID Parameter
)
{
SR_WORK_CONTEXT workContext;
NTSTATUS status;
PAGED_CODE();
//
// Initialize the workContext
//
workContext.SyncOpRoutine = SyncOpRoutine;
workContext.Parameter = Parameter;
KeInitializeEvent(&workContext.SyncEvent,
NotificationEvent,
FALSE);
//
// Initialize and queue off the SyncOp Worker
//
ExInitializeWorkItem(&workContext.WorkItem,
SrSyncOpWorker,
&workContext);
ExQueueWorkItem(&workContext.WorkItem,
CriticalWorkQueue );
//
// Now just wait for the worker to fire and complete
//
status = KeWaitForSingleObject(&workContext.SyncEvent,
Executive,
KernelMode,
FALSE,
NULL);
ASSERT(status == STATUS_SUCCESS);
//
// We're done free the work context and return the status of the
// operation.
//
return workContext.Status;
}