1099 lines
36 KiB
C
1099 lines
36 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
InnerIo.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the read, write, and lockctrl routines for the local minirdr
|
||
Author:
|
||
|
||
Joe Linn [JoeLinn] 11-Oct-1994
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
//
|
||
// The Bug check file id for this module
|
||
//
|
||
|
||
#define BugCheckFileId (RDBSS_BUG_CHECK_LOCAL_INNERIO)
|
||
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_READ)
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#endif
|
||
|
||
PIRP
|
||
MRxLocalBuildAsynchronousFsdRequest(
|
||
IN ULONG MajorFunction,
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PFILE_OBJECT FileObject,
|
||
IN PETHREAD UsersThread,
|
||
IN OUT PVOID Buffer OPTIONAL,
|
||
IN ULONG Length OPTIONAL,
|
||
IN PLARGE_INTEGER StartingOffset OPTIONAL,
|
||
IN ULONG Key OPTIONAL,
|
||
IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine builds an I/O Request Packet (IRP) suitable for a File System
|
||
Driver (FSD) to use in requesting an I/O operation from a device driver.
|
||
The request must be one of the following request codes:
|
||
|
||
IRP_MJ_READ
|
||
IRP_MJ_WRITE
|
||
IRP_MJ_FLUSH_BUFFERS
|
||
IRP_MJ_SHUTDOWN
|
||
|
||
This routine provides a simple, fast interface to the device driver w/o
|
||
having to put the knowledge of how to build an IRP into all of the FSDs
|
||
(and device drivers) in the system.
|
||
|
||
This is just lifted from io\iosubs.c plus the addition of the fileobject stuff.
|
||
plus the completion routine and context.
|
||
|
||
Arguments:
|
||
|
||
MajorFunction - Function to be performed; see previous list.
|
||
|
||
DeviceObject - Pointer to device object on which the I/O will be performed.
|
||
|
||
FileObject - Pointer to the file object on the device object.
|
||
|
||
Buffer - Pointer to buffer to get data from or write data into. This
|
||
parameter is required for read/write, but not for flush or shutdown
|
||
functions.
|
||
|
||
Length - Length of buffer in bytes. This parameter is required for
|
||
read/write, but not for flush or shutdown functions.
|
||
|
||
StartingOffset - Pointer to the offset on the disk to read/write from/to.
|
||
This parameter is required for read/write, but not for flush or
|
||
shutdown functions.
|
||
|
||
Key - the key to be used....required for read/write.
|
||
|
||
CompletionRoutine - the IrpCompletionRoutine
|
||
Context - context of the completion routine
|
||
|
||
Return Value:
|
||
|
||
The function value is a pointer to the IRP representing the specified
|
||
request.
|
||
|
||
--*/
|
||
|
||
{
|
||
PIRP irp;
|
||
PIO_STACK_LOCATION irpSp;
|
||
|
||
//
|
||
// Begin by allocating the IRP for this request. Do not charge quota to
|
||
// the current process for this IRP.
|
||
//
|
||
|
||
irp = IoAllocateIrp( DeviceObject->StackSize, FALSE ); //joejoe ???
|
||
if (!irp) {
|
||
return irp;
|
||
}
|
||
|
||
//
|
||
// Set current thread for IoSetHardErrorOrVerifyDevice.
|
||
//
|
||
|
||
irp->Tail.Overlay.Thread = UsersThread;
|
||
|
||
//
|
||
// Get a pointer to the stack location of the first driver which will be
|
||
// invoked. This is where the function codes and the parameters are set.
|
||
//
|
||
|
||
irpSp = IoGetNextIrpStackLocation( irp ); //ok4ioget
|
||
irpSp->FileObject = FileObject; //ok4->FileObj
|
||
{ BOOLEAN EnableCalls = CompletionRoutine!=NULL;
|
||
|
||
IoSetCompletionRoutine(irp, CompletionRoutine, Context,
|
||
EnableCalls,EnableCalls,EnableCalls);
|
||
}
|
||
|
||
|
||
//
|
||
// Set the major function code.
|
||
//
|
||
|
||
irpSp->MajorFunction = (UCHAR) MajorFunction;
|
||
|
||
if (MajorFunction != IRP_MJ_FLUSH_BUFFERS && MajorFunction != IRP_MJ_SHUTDOWN) {
|
||
|
||
//
|
||
// Now allocate a buffer or lock the pages of the caller's buffer into
|
||
// memory based on whether the target device performs direct or buffered
|
||
// I/O operations.
|
||
//
|
||
|
||
if (DeviceObject->Flags & DO_BUFFERED_IO) {
|
||
|
||
//
|
||
// The target device supports buffered I/O operations. Allocate a
|
||
// system buffer and, if this is a write, fill it in. Otherwise,
|
||
// the copy will be done into the caller's buffer in the completion
|
||
// code. Also note that the system buffer should be deallocated on
|
||
// completion. Also, set the parameters based on whether this is a
|
||
// read or a write operation.
|
||
//
|
||
|
||
irp->AssociatedIrp.SystemBuffer = RxAllocatePoolWithTag( NonPagedPoolCacheAligned,
|
||
Length,
|
||
'oIxR' );
|
||
if (irp->AssociatedIrp.SystemBuffer == NULL) {
|
||
IoFreeIrp( irp );
|
||
return (PIRP) NULL;
|
||
}
|
||
|
||
if (MajorFunction == IRP_MJ_WRITE) {
|
||
RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, Buffer, Length );
|
||
irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
|
||
} else {
|
||
irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
|
||
irp->UserBuffer = Buffer;
|
||
}
|
||
|
||
} else if (DeviceObject->Flags & DO_DIRECT_IO) {
|
||
|
||
//
|
||
// The target device supports direct I/O operations. Allocate
|
||
// an MDL large enough to map the buffer and lock the pages into
|
||
// memory.
|
||
//
|
||
|
||
irp->MdlAddress = IoAllocateMdl( Buffer,
|
||
Length,
|
||
FALSE,
|
||
FALSE,
|
||
(PIRP) NULL );
|
||
if (irp->MdlAddress == NULL) {
|
||
IoFreeIrp( irp );
|
||
return (PIRP) NULL;
|
||
}
|
||
|
||
MmProbeAndLockPages( irp->MdlAddress,
|
||
KernelMode,
|
||
(LOCK_OPERATION) (MajorFunction == IRP_MJ_READ ? IoWriteAccess : IoReadAccess) );
|
||
|
||
} else {
|
||
|
||
//
|
||
// The operation is neither buffered nor direct. Simply pass the
|
||
// address of the buffer in the packet to the driver.
|
||
//
|
||
|
||
irp->UserBuffer = Buffer;
|
||
}
|
||
|
||
//
|
||
// Set the parameters according to whether this is a read or a write
|
||
// operation. Notice that these parameters must be set even if the
|
||
// driver has not specified buffered or direct I/O.
|
||
//
|
||
|
||
if (MajorFunction == IRP_MJ_WRITE) {
|
||
irpSp->Parameters.Write.Length = Length;
|
||
irpSp->Parameters.Write.Key = Key;
|
||
irpSp->Parameters.Write.ByteOffset = *StartingOffset;
|
||
} else {
|
||
irpSp->Parameters.Read.Length = Length;
|
||
irpSp->Parameters.Read.Key = Key;
|
||
irpSp->Parameters.Read.ByteOffset = *StartingOffset;
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Finally, return a pointer to the IRP.
|
||
//
|
||
|
||
return irp;
|
||
}
|
||
|
||
RXSTATUS
|
||
MRxLocalCalldownReadCompletion (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP CalldownIrp,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the I/O completion routine for calldown reads. we just call the lowio completion
|
||
and exit
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to target device object for the request.
|
||
|
||
CalldownIrp - Pointer to I/O request packet used to call down to the underlying filesystem
|
||
|
||
Context - Irpcontext of the original request to the rdbss
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - If RxStatus(MORE_PROCESSING_REQUIRED) is returned.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PRX_CONTEXT RxContext = Context;
|
||
RxCaptureRequestPacket;
|
||
|
||
RxDbgTrace ( 0, Dbg, ( "MRxLocalCalldownReadCompletion\n"));
|
||
RxLog(('XRz',0));
|
||
//DbgBreakPoint();
|
||
if (CalldownIrp->PendingReturned){
|
||
capReqPacket->IoStatus = CalldownIrp->IoStatus;
|
||
RxDbgTrace ( 0, Dbg, ( "MRxLocalCalldownReadCompletion iostat=%08lx/%08lx\n",
|
||
capReqPacket->IoStatus.Status, capReqPacket->IoStatus.Information));
|
||
RxLog(('YRz',2, capReqPacket->IoStatus.Status, capReqPacket->IoStatus.Information ));
|
||
RxContext->StoredStatus = CalldownIrp->IoStatus.Status;
|
||
IoFreeIrp(CalldownIrp);
|
||
RxLowIoCompletion(RxContext);
|
||
}
|
||
//don't call unless pended RxLowIoCompletion(RxContext);
|
||
|
||
RxLog(('ZRz',0));
|
||
return(RxStatus(MORE_PROCESSING_REQUIRED));
|
||
}
|
||
|
||
|
||
RXSTATUS
|
||
MRxLocalRead (
|
||
IN PRX_CONTEXT RxContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements local read call. we fill in the info and stuff here BUT we
|
||
do not complete the Irp.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - Returns the status for the read
|
||
|
||
--*/
|
||
|
||
{
|
||
RXSTATUS Status;
|
||
RxCaptureRequestPacket;
|
||
PIRP CalldownIrp;
|
||
RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
|
||
PSRV_OPEN SrvOpen = capFobx->SrvOpen;
|
||
PMRX_LOCAL_SRV_OPEN localSrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;
|
||
PVOID Buffer;
|
||
LARGE_INTEGER ByteOffsetAsLI;
|
||
|
||
BOOLEAN Wait = FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT)!=0;
|
||
|
||
|
||
ByteOffsetAsLI.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxRead.... ByteCount = %08lx, ByteOffset = %08lx %08lx\n",
|
||
LowIoContext->ParamsFor.ReadWrite.ByteCount,
|
||
ByteOffsetAsLI.LowPart, ByteOffsetAsLI.HighPart));
|
||
|
||
RxLog(('dRz',3,SrvOpen,LowIoContext->ParamsFor.ReadWrite.ByteCount,
|
||
ByteOffsetAsLI.LowPart));
|
||
//ASSERT (Wait); //we can try without this
|
||
ASSERT (localSrvOpen->UnderlyingFileObject);
|
||
|
||
Buffer = RxLowIoGetBufferAddress(RxContext);
|
||
RxDbgTrace ( 0, Dbg, ( "MRxRead.... ->Buffer = %8lx\n", Buffer));
|
||
|
||
CalldownIrp = MRxLocalBuildAsynchronousFsdRequest(
|
||
IRP_MJ_READ, // IN ULONG MajorFunction,
|
||
localSrvOpen->UnderlyingDeviceObject, // IN PDEVICE_OBJECT DeviceObject,
|
||
localSrvOpen->UnderlyingFileObject, // IN PFILE_OBJECT FileObject,
|
||
capReqPacket->Tail.Overlay.Thread, //IN PTHREAD UsersThread,
|
||
Buffer, // IN OUT PVOID Buffer OPTIONAL,
|
||
LowIoContext->ParamsFor.ReadWrite.ByteCount, // IN ULONG Length OPTIONAL,
|
||
&ByteOffsetAsLI, // IN PLARGE_INTEGER StartingOffset OPTIONAL,
|
||
capPARAMS->Parameters.Read.Key, // IN ULONG Key OPTIONAL,
|
||
MRxLocalCalldownReadCompletion, // IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
|
||
RxContext // IN PVOID Context
|
||
);
|
||
|
||
if (!CalldownIrp){
|
||
Status = RxContext->StoredStatus = RxStatus(INSUFFICIENT_RESOURCES);
|
||
return(Status);
|
||
}
|
||
|
||
Status = IoCallDriver(
|
||
localSrvOpen->UnderlyingDeviceObject,
|
||
CalldownIrp
|
||
);
|
||
|
||
if (Status != RxStatus(PENDING)) {
|
||
//copy up the status
|
||
capReqPacket->IoStatus = CalldownIrp->IoStatus;
|
||
IoFreeIrp(CalldownIrp);
|
||
RxContext->StoredStatus = Status;
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, ("MRxRead.... ---->Initial Status = %08lx, Initial Block status/Info = %08lx %08lx \n",
|
||
Status, capReqPacket->IoStatus.Status, capReqPacket->IoStatus.Information));
|
||
|
||
return(Status);
|
||
}
|
||
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#undef Dbg
|
||
#define Dbg (DEBUG_TRACE_WRITE)
|
||
|
||
|
||
|
||
RXSTATUS
|
||
MRxLocalCalldownWriteCompletion (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP CalldownIrp,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the I/O completion routine for calldown writes. we just call the lowio completion
|
||
and exit. it is almost identical to reads BUT separate for debugging.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to target device object for the request.
|
||
|
||
CalldownIrp - Pointer to I/O request packet used to call down to the underlying filesystem
|
||
|
||
Context - Irpcontext of the original request to the rdbss
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - If RxStatus(MORE_PROCESSING_REQUIRED) is returned.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PRX_CONTEXT RxContext = Context;
|
||
RxCaptureRequestPacket;
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
PNON_PAGED_FCB NonPagedFcb;
|
||
PERESOURCE Resource;
|
||
|
||
RxDbgTrace ( 0, Dbg, ("MRxLocalCalldownWriteCompletion = %08lx\n", 0));
|
||
RxLog(('XWz',0));
|
||
//DbgBreakPoint();
|
||
if (CalldownIrp->PendingReturned){
|
||
capReqPacket->IoStatus = CalldownIrp->IoStatus;
|
||
RxLog(('YWz',2, capReqPacket->IoStatus.Status, capReqPacket->IoStatus.Information ));
|
||
RxContext->StoredStatus = CalldownIrp->IoStatus.Status;
|
||
IoFreeIrp(CalldownIrp);
|
||
}
|
||
|
||
//
|
||
// If this was a special async write, decrement the count. Set the
|
||
// event if this was the final outstanding I/O for the file. Also, release the resource
|
||
|
||
NonPagedFcb = LowIoContext->ParamsFor.ReadWrite.NonPagedFcb;
|
||
if (NonPagedFcb){
|
||
if ((ExInterlockedAddUlong( &NonPagedFcb->OutstandingAsyncWrites,
|
||
0xffffffff,
|
||
&RxStrucSupSpinLock ) == 1)) {
|
||
|
||
KeSetEvent( NonPagedFcb->OutstandingAsyncEvent, 0, FALSE );
|
||
}
|
||
|
||
|
||
Resource = LowIoContext->Resource;
|
||
|
||
if (Resource != NULL) {
|
||
|
||
ExReleaseResourceForThread( Resource,
|
||
LowIoContext->ResourceThreadId );
|
||
}
|
||
}
|
||
|
||
|
||
RxLowIoCompletion(RxContext);
|
||
|
||
RxLog(('ZWz',0));
|
||
return(RxStatus(MORE_PROCESSING_REQUIRED));
|
||
}
|
||
|
||
|
||
RXSTATUS
|
||
MRxLocalWrite (
|
||
IN PRX_CONTEXT RxContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements local write call. we fill in the info and stuff here BUT we
|
||
do not complete the Irp.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - Returns the status for the write
|
||
|
||
--*/
|
||
|
||
{
|
||
RXSTATUS Status;
|
||
RxCaptureRequestPacket;
|
||
PIRP CalldownIrp;
|
||
RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
|
||
PSRV_OPEN SrvOpen = capFobx->SrvOpen;
|
||
PMRX_LOCAL_SRV_OPEN localSrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;
|
||
PVOID Buffer;
|
||
LARGE_INTEGER ByteOffsetAsLI;
|
||
|
||
BOOLEAN Wait = FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT)!=0;
|
||
|
||
|
||
ByteOffsetAsLI.QuadPart = LowIoContext->ParamsFor.ReadWrite.ByteOffset;
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxWrite.... ByteCount = %08lx, ByteOffset = %08lx %08lx\n",
|
||
LowIoContext->ParamsFor.ReadWrite.ByteCount,
|
||
ByteOffsetAsLI.LowPart, ByteOffsetAsLI.HighPart));
|
||
RxLog(('rWz',3,SrvOpen,LowIoContext->ParamsFor.ReadWrite.ByteCount,
|
||
ByteOffsetAsLI.LowPart));
|
||
|
||
//ASSERT (Wait); //we can try without this
|
||
ASSERT (localSrvOpen->UnderlyingFileObject);
|
||
|
||
Buffer = RxLowIoGetBufferAddress(RxContext);
|
||
RxDbgTrace ( 0, Dbg, (" ->Buffer = %8lx\n", Buffer));
|
||
|
||
CalldownIrp = MRxLocalBuildAsynchronousFsdRequest(
|
||
IRP_MJ_WRITE, // IN ULONG MajorFunction,
|
||
localSrvOpen->UnderlyingDeviceObject, // IN PDEVICE_OBJECT DeviceObject,
|
||
localSrvOpen->UnderlyingFileObject, // IN PFILE_OBJECT FileObject,
|
||
capReqPacket->Tail.Overlay.Thread, //IN PTHREAD UsersThread,
|
||
Buffer, // IN OUT PVOID Buffer OPTIONAL,
|
||
LowIoContext->ParamsFor.ReadWrite.ByteCount, // IN ULONG Length OPTIONAL,
|
||
&ByteOffsetAsLI, // IN PLARGE_INTEGER StartingOffset OPTIONAL,
|
||
capPARAMS->Parameters.Read.Key, // IN ULONG Key OPTIONAL,
|
||
MRxLocalCalldownWriteCompletion, // IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
|
||
RxContext // IN PVOID Context
|
||
);
|
||
|
||
if (!CalldownIrp){
|
||
Status = RxContext->StoredStatus = RxStatus(INSUFFICIENT_RESOURCES);
|
||
return(Status);
|
||
}
|
||
|
||
Status = IoCallDriver(
|
||
localSrvOpen->UnderlyingDeviceObject,
|
||
CalldownIrp
|
||
);
|
||
|
||
if (Status != RxStatus(PENDING)) {
|
||
//copy up the status
|
||
capReqPacket->IoStatus = CalldownIrp->IoStatus;
|
||
RxContext->StoredStatus = Status;
|
||
IoFreeIrp(CalldownIrp);
|
||
}
|
||
|
||
RxDbgTrace(-1, Dbg, (" ---->Initial Status = %08lx, Initial Block status/Info = %08lx %08lx \n",
|
||
Status, capReqPacket->IoStatus.Status, capReqPacket->IoStatus.Information));
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
|
||
RXSTATUS
|
||
MRxLocalExtendForCache(
|
||
IN PRX_CONTEXT RxContext,
|
||
IN OUT PFCB Fcb,
|
||
IN PLONGLONG pNewFileSize
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine extends the file allocation so that the we can do a copywrite. the fcb lock
|
||
is exclusive here; we will take the opportunity to find out the actual allocation so that
|
||
we'll get the fast path. another minirdr might want to guess instead since it might be actual net ios
|
||
otherwise.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - Returns the status for the set file allocation...could be an error if disk full
|
||
|
||
--*/
|
||
|
||
{
|
||
RXSTATUS Status;
|
||
RxCaptureRequestPacket;
|
||
RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
|
||
PSRV_OPEN SrvOpen = capFobx->SrvOpen;
|
||
PMRX_LOCAL_SRV_OPEN localSrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;
|
||
PFILE_OBJECT UnderlyingFileObject = localSrvOpen->UnderlyingFileObject;
|
||
|
||
PFILE_ALLOCATION_INFORMATION Buffer;
|
||
FILE_ALLOCATION_INFORMATION FileAllocationInformationBuffer;
|
||
ULONG Length;
|
||
|
||
RxDbgTrace(+1, Dbg, ("MRxLocalExtendForCache.. pnewfilesize=%08lx\n", *pNewFileSize));
|
||
RxLog(('4ez',2,SrvOpen,*pNewFileSize));
|
||
ASSERT ( RxIsFcbAcquiredExclusive ( Fcb ) );
|
||
|
||
Buffer = &FileAllocationInformationBuffer;
|
||
Length = sizeof(FILE_ALLOCATION_INFORMATION);
|
||
ASSERT (UnderlyingFileObject);
|
||
|
||
if (capFcb->Header.AllocationSize.QuadPart >= *pNewFileSize) {
|
||
Status = RxStatus(SUCCESS);
|
||
RxDbgTrace(-1, Dbg, (" PlentyAllocation = %08lx\n", Status));
|
||
return(Status);
|
||
}
|
||
|
||
{ LONGLONG CurrentExtend = (*pNewFileSize)-Fcb->Header.AllocationSize.QuadPart;
|
||
Buffer->AllocationSize.QuadPart = Fcb->Header.AllocationSize.QuadPart
|
||
+ 32 * CurrentExtend;
|
||
}
|
||
RxDbgTrace( 0, Dbg, (" Extending to %08lx from %08lx!\n",
|
||
Buffer->AllocationSize.LowPart,
|
||
Fcb->Header.AllocationSize.LowPart));
|
||
Status = IoSetInformation(
|
||
UnderlyingFileObject, //IN PFILE_OBJECT FileObject,
|
||
FileAllocationInformation, //IN FILE_INFORMATION_CLASS FileInformationClass,
|
||
Length, //IN ULONG Length,
|
||
Buffer //IN PVOID FileInformation
|
||
);
|
||
|
||
//joejoe here we should now read it back and see what we actually got; for smallio we will be
|
||
//seeing subcluster extension when, in fact, we get a cluster at a time.
|
||
|
||
if (Status == RxStatus(SUCCESS)) {
|
||
Fcb->Header.AllocationSize = Buffer->AllocationSize;
|
||
RxDbgTrace(-1, Dbg, (" ---->Status = %08lx\n", Status));
|
||
return(Status);
|
||
}
|
||
|
||
RxDbgTrace( 0, Dbg, (" EXTEND1 FAILED!!!!!!%c\n", '!'));
|
||
|
||
//try for exactly what we need
|
||
|
||
Buffer->AllocationSize.QuadPart = *pNewFileSize;
|
||
Status = IoSetInformation(
|
||
UnderlyingFileObject, //IN PFILE_OBJECT FileObject,
|
||
FileAllocationInformation, //IN FILE_INFORMATION_CLASS FileInformationClass,
|
||
Length, //IN ULONG Length,
|
||
Buffer //IN PVOID FileInformation
|
||
);
|
||
|
||
|
||
if (Status == RxStatus(SUCCESS)) {
|
||
Fcb->Header.AllocationSize = Buffer->AllocationSize;
|
||
RxDbgTrace(-1, Dbg, (" ---->Status = %08lx\n", Status));
|
||
return(Status);
|
||
}
|
||
|
||
RxDbgTrace( 0, Dbg, (" EXTEND1 FAILED!!!!!!%c\n", '!'));
|
||
|
||
RxDbgTrace(-1, Dbg, (" ---->Status = %08lx\n", Status));
|
||
|
||
return(Status);
|
||
}
|
||
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//----------------------------------------------------------------------------------------------
|
||
//
|
||
// The local debug trace level
|
||
//
|
||
|
||
#undef Dbg
|
||
#define Dbg (DEBUG_TRACE_LOCKCTRL)
|
||
|
||
|
||
PIRP
|
||
MRxBuildLockRequest (
|
||
IN PIRP irp OPTIONAL,
|
||
IN PFILE_OBJECT fileObject,
|
||
IN PETHREAD UsersThread,
|
||
IN UCHAR MinorCode,
|
||
IN RXVBO ByteOffset,
|
||
IN PLARGE_INTEGER Length,
|
||
IN ULONG Key,
|
||
IN UCHAR Flags,
|
||
IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
|
||
IN PVOID Context OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function builds an I/O request packet for a lock request.
|
||
|
||
Arguments:
|
||
|
||
Irp - Supplies a pointer to an IRP; allocates one if one is not provided.
|
||
|
||
FileObject - Supplies a pointer the file object to which this
|
||
request is directed. This pointer is copied into the IRP, so
|
||
that the called driver can find its file-based context. NOTE
|
||
THAT THIS IS NOT A REFERENCED POINTER. The caller must ensure
|
||
that the file object is not deleted while the I/O operation is
|
||
in progress. The local minirdr accomplishes this by holding a pointer
|
||
(a REFERENCED ptr) to the fileobject in its srvopen while the fileobject is
|
||
open.
|
||
|
||
Context - Supplies a PVOID value that is passed to the completion
|
||
routine.
|
||
|
||
StartingBlock - the block number of the beginning of the locked
|
||
range.
|
||
|
||
ByteOffset - the offset within block of the beginning of the locked
|
||
range.
|
||
|
||
Length - the length of the locked range.
|
||
|
||
Key - the key value to be associated with the lock.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PDEVICE_OBJECT deviceObject;
|
||
PIO_STACK_LOCATION irpSp;
|
||
|
||
PAGED_CODE( );
|
||
|
||
deviceObject = IoGetRelatedDeviceObject( fileObject );
|
||
|
||
//
|
||
// Allocate and initialize the I/O Request Packet (IRP) for this operation.
|
||
// The allocation is performed with an exception handler in case the
|
||
// caller does not have enough quota to allocate the packet.
|
||
|
||
if (irp) {
|
||
ASSERT( irp->StackCount >= deviceObject->StackSize );
|
||
} else {
|
||
irp = IoAllocateIrp( deviceObject->StackSize, TRUE ); //joejoe should i charge quota??
|
||
}
|
||
|
||
if (!irp) {
|
||
|
||
//
|
||
// An IRP could not be allocated.
|
||
|
||
return NULL;
|
||
}
|
||
|
||
// we have to make sure that the thread that takes the lock is the same as the one that reads
|
||
irp->Tail.Overlay.Thread = UsersThread;
|
||
irp->RequestorMode = KernelMode;
|
||
|
||
//
|
||
// Get a pointer to the stack location for the first driver. This will be
|
||
// used to pass the original function codes and parameters.
|
||
//
|
||
|
||
irpSp = IoGetNextIrpStackLocation( irp );
|
||
|
||
{ BOOLEAN EnableCalls = CompletionRoutine!=NULL;
|
||
|
||
IoSetCompletionRoutine(irp, CompletionRoutine, Context,
|
||
EnableCalls,EnableCalls,EnableCalls);
|
||
}
|
||
|
||
|
||
|
||
irpSp->MajorFunction = IRP_MJ_LOCK_CONTROL;
|
||
irpSp->MinorFunction = MinorCode;
|
||
irpSp->FileObject = fileObject; //ok4->FileObj
|
||
irpSp->DeviceObject = deviceObject;
|
||
|
||
irpSp->Flags = Flags;
|
||
|
||
irpSp->Parameters.LockControl.Length = Length;
|
||
irpSp->Parameters.LockControl.Key = Key;
|
||
irpSp->Parameters.LockControl.ByteOffset.QuadPart = ByteOffset;
|
||
|
||
return irp;
|
||
|
||
}
|
||
|
||
RXSTATUS
|
||
MRxLocalCalldownLockCompletion (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP CalldownIrp,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the I/O completion routine for calldown lock requests. we just call the lowio completion
|
||
and exit
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to target device object for the request.
|
||
|
||
CalldownIrp - Pointer to I/O request packet used to call down to the underlying filesystem
|
||
|
||
Context - Irpcontext of the original request to the rdbss
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - RxStatus(MORE_PROCESSING_REQUIRED) is returned.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PRX_CONTEXT RxContext = Context;
|
||
|
||
RxDbgTrace ( 0, Dbg, ("MRxLocalCalldownLockCompletion = %08lx\n", 0));
|
||
//DbgBreakPoint();
|
||
if (CalldownIrp->PendingReturned){
|
||
RxContext->CurrentIrp->IoStatus = CalldownIrp->IoStatus;
|
||
RxContext->StoredStatus = CalldownIrp->IoStatus.Status;
|
||
}
|
||
RxLowIoCompletion(RxContext);
|
||
|
||
IoFreeIrp(CalldownIrp);
|
||
return(RxStatus(MORE_PROCESSING_REQUIRED));
|
||
}
|
||
|
||
|
||
RXSTATUS
|
||
MRxLocalLocks (
|
||
IN PRX_CONTEXT RxContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements local read call. we fill in the info and stuff here BUT we
|
||
do not complete the Irp.
|
||
|
||
Arguments:
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - Returns the status for the read
|
||
|
||
--*/
|
||
|
||
{
|
||
RXSTATUS Status;
|
||
RxCaptureRequestPacket;
|
||
PIRP CalldownIrp;
|
||
RxCaptureFcb; RxCaptureFobx; RxCaptureParamBlock;
|
||
PLOWIO_CONTEXT LowIoContext = &RxContext->LowIoContext;
|
||
|
||
PSRV_OPEN SrvOpen = capFobx->SrvOpen;
|
||
PMRX_LOCAL_SRV_OPEN localSrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;
|
||
|
||
BOOLEAN Wait = FlagOn(RxContext->Flags,RX_CONTEXT_FLAG_WAIT)!=0;
|
||
PLARGE_INTEGER LengthAsLI = (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.Length;
|
||
PLARGE_INTEGER OffsetAsLI = (PLARGE_INTEGER)&LowIoContext->ParamsFor.Locks.ByteOffset;
|
||
|
||
char *whichop;
|
||
|
||
switch (LowIoContext->Operation) {
|
||
case LOWIO_OP_SHAREDLOCK: whichop = "SHAREDLOCK"; break;
|
||
case LOWIO_OP_EXCLUSIVELOCK: whichop = "EXCLUSIVELOCK"; break;
|
||
case LOWIO_OP_UNLOCK: whichop = "UNLOCK"; break;
|
||
case LOWIO_OP_UNLOCKALL: whichop = "UNLOCKALL"; break;
|
||
case LOWIO_OP_UNLOCKALLBYKEY: whichop = "UNLOCKALLBYKEY"; break;
|
||
}
|
||
|
||
RxDbgTrace (+1, Dbg, ("MRxExclusiveLock...%s, Flags = %08lx, Key = %08lx\n", whichop,
|
||
LowIoContext->ParamsFor.Locks.Flags,
|
||
LowIoContext->ParamsFor.Locks.Key));
|
||
RxDbgTrace( 0, Dbg, (" ->Length = %08lx %08lx\n",
|
||
LengthAsLI->LowPart,
|
||
LengthAsLI->HighPart));
|
||
RxDbgTrace( 0, Dbg, (" ->ByteOffset = %08lx %08lx\n",
|
||
OffsetAsLI->LowPart,
|
||
OffsetAsLI->HighPart));
|
||
RxLog(('kLz',3,SrvOpen, LengthAsLI->LowPart, OffsetAsLI->LowPart));
|
||
|
||
ASSERT (localSrvOpen->UnderlyingFileObject);
|
||
|
||
CalldownIrp = MRxBuildLockRequest (
|
||
NULL ,//IN PIRP irp OPTIONAL,
|
||
localSrvOpen->UnderlyingFileObject ,//IN PFILE_OBJECT fileObject,
|
||
capReqPacket->Tail.Overlay.Thread ,//IN PTHREAD UsersThread,
|
||
capPARAMS->MinorFunction ,//IN UCHAR MinorCode,
|
||
LowIoContext->ParamsFor.Locks.ByteOffset,//IN RXVBO ByteOffset,
|
||
LengthAsLI ,//IN PLARGE_INTEGER Length,
|
||
LowIoContext->ParamsFor.Locks.Key ,//IN ULONG Key,
|
||
(UCHAR)LowIoContext->ParamsFor.Locks.Flags ,//IN UCHAR Flags,
|
||
MRxLocalCalldownLockCompletion ,//IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
|
||
RxContext //IN PVOID Context OPTIONAL
|
||
);
|
||
|
||
|
||
if (!CalldownIrp){
|
||
Status = RxContext->StoredStatus = RxStatus(INSUFFICIENT_RESOURCES);
|
||
return(Status);
|
||
}
|
||
|
||
Status = RxContext->StoredStatus =
|
||
IoCallDriver(
|
||
localSrvOpen->UnderlyingDeviceObject,
|
||
CalldownIrp
|
||
);
|
||
|
||
if (Status != RxStatus(PENDING)) {
|
||
//copy up the status
|
||
capReqPacket->IoStatus = CalldownIrp->IoStatus;
|
||
}
|
||
|
||
RxDbgTrace ( 0, Dbg, (" ---->Initial Status = %08lx\n", Status));
|
||
RxDbgTrace(-1, Dbg, (" ------> Initial Block status/Info = %08lx %08lx\n",
|
||
capReqPacket->IoStatus.Status, capReqPacket->IoStatus.Information));
|
||
|
||
return(Status);
|
||
}
|
||
|
||
|
||
RXSTATUS
|
||
MRxLocalAssertLockCompletion (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP CalldownIrp,
|
||
IN PVOID Context
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the I/O completion routine for calldown ios like querydirectory. the rub is that we
|
||
turned synchronous opens into async opens. what we do here is set an event (in the case of a pended
|
||
packet for a sync that we turned async) OR copyup the status;complete;free in the case of a call
|
||
that was always async.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Pointer to target device object for the request.
|
||
|
||
CalldownIrp - Pointer to I/O request packet used to call down to the underlying filesystem
|
||
|
||
Context - Irpcontext of the original request to the rdbss
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - If RxStatus(MORE_PROCESSING_REQUIRED) is returned.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PKEVENT Event = Context;
|
||
|
||
RxDbgTrace ( 0, Dbg, (" MRxLocalAssertLockCompletion = %08lx\n", 0));
|
||
|
||
if (CalldownIrp->PendingReturned){
|
||
KeSetEvent( Event, 0, FALSE );
|
||
}
|
||
|
||
return(RxStatus(MORE_PROCESSING_REQUIRED));
|
||
}
|
||
|
||
|
||
RXSTATUS
|
||
MRxLocalAssertBufferedFileLocks (
|
||
IN PSRV_OPEN SrvOpen
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called to assert all buffered file locks on a srvopen.
|
||
|
||
|
||
Arguments:
|
||
|
||
SrvOpen - Supplies the file whose locks are to be asserted.
|
||
|
||
|
||
Return Value:
|
||
|
||
RXSTATUS - Status of operation.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
RXSTATUS Status;
|
||
PFILE_LOCK_INFO FileLock;
|
||
PFCB Fcb = SrvOpen->Fcb;
|
||
|
||
PIRP CalldownIrp = NULL;
|
||
|
||
PMRX_LOCAL_SRV_OPEN localSrvOpen = (PMRX_LOCAL_SRV_OPEN)SrvOpen;
|
||
|
||
UCHAR Flags;
|
||
BOOLEAN Wait = TRUE;
|
||
|
||
PKEVENT Event;
|
||
|
||
PAGED_CODE();
|
||
|
||
RxDbgTrace (+1, Dbg, ("MRxLocalAssertBufferedFileLocks SrvOpen = %08lx", SrvOpen));
|
||
ASSERT (localSrvOpen->UnderlyingFileObject);
|
||
|
||
Event = RxAllocatePoolWithTag( NonPagedPool, sizeof(KEVENT), 'LAxR' );
|
||
if (!CalldownIrp){
|
||
Status = RxStatus(INSUFFICIENT_RESOURCES);
|
||
return(Status);
|
||
}
|
||
|
||
try {
|
||
for (FileLock = FsRtlGetNextFileLock(&Fcb->Specific.Fcb.FileLock, TRUE);
|
||
FileLock != NULL;
|
||
FileLock = FsRtlGetNextFileLock(&Fcb->Specific.Fcb.FileLock, FALSE)) {
|
||
|
||
RxDbgTrace (0, Dbg, ("MRxLocalAssertBufferedFileLocks Exclusive = %08lx, Key = %08lx\n",
|
||
FileLock->ExclusiveLock,
|
||
FileLock->Key));
|
||
RxDbgTrace( 0, Dbg, (" ->Length = %08lx %08lx\n",
|
||
FileLock->Length.LowPart,
|
||
FileLock->Length.HighPart));
|
||
RxDbgTrace( 0, Dbg, (" ->ByteOffset = %08lx %08lx\n",
|
||
FileLock->StartingByte.LowPart,
|
||
FileLock->StartingByte.HighPart));
|
||
|
||
if (FileLock->ExclusiveLock) {
|
||
Flags = SL_EXCLUSIVE_LOCK | SL_FAIL_IMMEDIATELY;
|
||
} else {
|
||
Flags = SL_FAIL_IMMEDIATELY;
|
||
}
|
||
|
||
//joejoe we should reuse the irp.........
|
||
CalldownIrp = MRxBuildLockRequest (
|
||
NULL ,//IN PIRP irp OPTIONAL,
|
||
localSrvOpen->UnderlyingFileObject ,//IN PFILE_OBJECT fileObject,
|
||
localSrvOpen->OriginalThread ,//IN PTHREAD UsersThread,
|
||
IRP_MN_LOCK ,//IN UCHAR MinorCode,
|
||
FileLock->StartingByte.QuadPart ,//IN RXVBO ByteOffset,
|
||
&FileLock->Length ,//IN PLARGE_INTEGER Length,
|
||
FileLock->Key ,//IN ULONG Key,
|
||
Flags ,//IN UCHAR Flags,
|
||
MRxLocalAssertLockCompletion ,//IN PIO_COMPLETION_ROUTINE CompletionRoutine OPTIONAL,
|
||
&Event //IN PVOID Context OPTIONAL
|
||
);
|
||
|
||
if (!CalldownIrp){
|
||
Status = RxStatus(INSUFFICIENT_RESOURCES);
|
||
try_return(Status);
|
||
}
|
||
|
||
CalldownIrp->Flags |= IRP_SYNCHRONOUS_API;
|
||
|
||
KeInitializeEvent( Event, SynchronizationEvent, FALSE );
|
||
|
||
Status = IoCallDriver(
|
||
localSrvOpen->UnderlyingDeviceObject,
|
||
CalldownIrp
|
||
);
|
||
|
||
if (Status == RxStatus(PENDING)) {
|
||
KeWaitForSingleObject(Event, UserRequest, KernelMode, FALSE, NULL);
|
||
Status = CalldownIrp->IoStatus.Status;
|
||
}
|
||
|
||
RxDbgTrace ( 0, Dbg, (" ---->PerLock Status = %08lx\n", Status));
|
||
|
||
}
|
||
|
||
try_exit:
|
||
NOTHING;
|
||
|
||
} finally {
|
||
|
||
ExFreePool(Event);
|
||
if (CalldownIrp) {
|
||
IoFreeIrp(CalldownIrp);
|
||
}
|
||
}
|
||
|
||
RxDbgTrace (-1, Dbg, ("--------->Final Status = %08lx\n", Status));
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
|