跟踪NtReadFile系统服务的执行过程

来源:互联网 发布:悉尼科技大学 知乎 编辑:程序博客网 时间:2024/05/18 00:31

由于马上就要期末考试了,操作系统这么课,关于设备这一块我还是一片狼藉,很是杂乱。由于老师之前说过不懂驱动就不可能懂设备,所以我就找了本驱动开发的书来看。还是有些收获的,至少根据书中的描述,我大致了解了处理一个IO请求的最简单最简单流程。


大概流程是是Win32API——Native API——系统调用陷入——内核内部例程创建IRP——传递给相应驱动程序。至于驱动程序执行完之后的是我就不甚了解了,但是知道有个IoCompleteRequest的函数会完成这个IRP请求,必要的话会唤醒因为执行IO而进入睡眠状态的线程。


下面我就根据WRK提供的源码,进行一下简要的分析:

我们直接从系统调用后进入系统服务函数开始,这里跟踪的是NtReadFile

为了便于阅读,我只把相关函数的我要讲得部分列出来,在文章的最后我会把涉及到的函数的完整实现全部给出。


NTSTATUS

NtReadFile (

   __in HANDLE FileHandle,

   __in_opt HANDLE Event,

   __in_opt PIO_APC_ROUTINE ApcRoutine,

   __in_opt PVOID ApcContext,

   __out PIO_STATUS_BLOCK IoStatusBlock,

   __out_bcount(Length) PVOID Buffer,

   __in ULONG Length,

   __in_opt PLARGE_INTEGER ByteOffset,

   __in_opt PULONG Key

    )

{

……

   status = ObReferenceObjectByHandle( FileHandle,

                                       FILE_READ_DATA,

                                       IoFileObjectType,

                                       requestorMode,

                                        (PVOID*) &fileObject,

                                        NULL );

   if (!NT_SUCCESS( status )) {

       return status;

    }

 

   //

   // Get the address of the target device object.

   //

 

   deviceObject = IoGetRelatedDeviceObject( fileObject );

……

irp = IopAllocateIrp(deviceObject->StackSize, !synchronousIo );

……

   irp->Tail.Overlay.OriginalFileObject = fileObject;

   irp->Tail.Overlay.Thread = CurrentThread;

   irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;

   irp->RequestorMode = requestorMode;

   irp->PendingReturned = FALSE;

   irp->Cancel = FALSE;

   irp->CancelRoutine = (PDRIVER_CANCEL) NULL;

 

   //

   // Fill in the service independent parameters in the IRP.

   //

 

   irp->UserEvent = eventObject;

   irp->UserIosb = IoStatusBlock;

   irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;

   irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;

 

   //

   // Get a pointer to the stack location for the first driver.  This will be

   // used to pass the original function codes and parameters.  Note that

   // setting the major function here also sets:

   //

   //      MinorFunction = 0;

   //      Flags = 0;

   //      Control = 0;

   //

 

   irpSp = IoGetNextIrpStackLocation( irp );

   majorFunction = (PULONG) (&irpSp->MajorFunction);

   *majorFunction = IRP_MJ_READ;

irpSp->FileObject= fileObject;

 

 

   //

   // Now determine whether this device expects to have data buffered to it

   // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO

   // flag in the device object.  Ifthe flag is set, then a system buffer is

   // allocated and the driver's data will be copied into it.  Otherwise, a

   // Memory Descriptor List (MDL) is allocated and the caller's buffer is

   // locked down using it.

   //

 

   irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;

irp->MdlAddress= (PMDL) NULL;

……

 

    status = IopSynchronousServiceTail( deviceObject,

                                         irp,

                                        fileObject,

                                         TRUE,

                                        requestorMode,

                                        synchronousIo,

                                        ReadTransfer );

 

    return status;

}

可以看到,NtReadFile先是获得了文件对象FileObject,然后由FileObject获得了设备对象DeviceObject。这也应证了在Windows中,文件是在设备之上的,在FILE_OBJECT结构中有指针指向DeviceObject,在DEVICE_OBJECT结构中又有指针回指到DriverObject上,这样就找到了驱动程序了(由DrvierObject对象描述的)。

下面的一系列操作是对IRP的初始化,一个IRP代表着一个IO的请求。

最后,NtReadFile调用了一个名为IopSynchronousServiceTail的函数。关于这个函数的功能,MS是这样描述的“Thisroutine is invoked to complete the operation of a system service.It queues theIRP to the thread's queue, updates the transfer count,calls the driver, andfinally synchronizes completion of the I/O.

在这个函数中,有这么一条语句:status = IoCallDriver( DeviceObject, Irp );正是这条语句实现把IRP传给了DeviceObjectIoCallDriver有原封不动的调用了IofCallDriverIofCallDriver又原封不动的调用了IopfCallDriverIopfCallDriver执行了驱动程序中注册的派遣函数。

IopfCallDriver实现如下:
NTSTATUS

FORCEINLINE

IopfCallDriver(

   IN PDEVICE_OBJECT DeviceObject,

   IN OUT PIRP Irp

    )

 

/*++

 

Routine Description:

 

   This routine is invoked to pass an I/O Request Packet (IRP) to another

   driver at its dispatch routine.

 

Arguments:

 

   DeviceObject - Pointer to device object to which the IRP should bepassed.

 

   Irp - Pointer to IRP for request.

 

Return Value:

 

   Return status from driver's dispatch routine.

 

--*/

 

{

   PIO_STACK_LOCATION irpSp;

   PDRIVER_OBJECT driverObject;

   NTSTATUS status;

 

   //

   // Ensure that this is really an I/O Request Packet.

   //

 

   ASSERT( Irp->Type == IO_TYPE_IRP );

 

   //

   // Update the IRP stack to point to the next location.

   //

   Irp->CurrentLocation--;

 

   if (Irp->CurrentLocation <= 0) {

       KiBugCheck3( NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR) Irp, 0, 0 );

    }

 

   irpSp = IoGetNextIrpStackLocation( Irp );

   Irp->Tail.Overlay.CurrentStackLocation = irpSp;

 

   //

   // Save a pointer to the device object for this request so that it can

   // be used later in completion.

   //

 

   irpSp->DeviceObject = DeviceObject;

 

 

   //

   // Invoke the driver at its dispatch routine entry point.

   //

 

   driverObject = DeviceObject->DriverObject;

 

   //

   // Prevent the driver from unloading.

   //

 

 

   status = driverObject->MajorFunction[irpSp->MajorFunction](DeviceObject,

                                                             Irp );

 

   return status;

}

最后那句就是通过DriverObject调用了注册的派遣程序。

通过这一步步跟踪下来,这几个对象之间的关系清楚多了。我看到了期末考试胜利的希望了。

 

以下是涉及的函数的实现:

 

NTSTATUS

NtReadFile (

   __in HANDLE FileHandle,

   __in_opt HANDLE Event,

   __in_opt PIO_APC_ROUTINE ApcRoutine,

   __in_opt PVOID ApcContext,

   __out PIO_STATUS_BLOCK IoStatusBlock,

   __out_bcount(Length) PVOID Buffer,

   __in ULONG Length,

   __in_opt PLARGE_INTEGER ByteOffset,

   __in_opt PULONG Key

    )

 

/*++

 

Routine Description:

 

   This service reads Length bytes of data from the file associated with

   FileHandle starting at ByteOffset and puts the data into the caller's

   Buffer.  If the end of the file isreached before Length bytes have

   been read, then the operation will terminate.  The actual length of

   the data read from the file will be returned in the second longword

   of the IoStatusBlock.

 

Arguments:

 

   FileHandle - Supplies a handle to the file to be read.

 

   Event - Optionally supplies an event to be signaled when the readoperation

       is complete.

 

   ApcRoutine - Optionally supplies an APC routine to be executed when theread

       operation is complete.

 

   ApcContext - Supplies a context parameter to be passed to theApcRoutine, if

       an ApcRoutine was specified.

 

   IoStatusBlock - Address of the caller's I/O status block.

 

   Buffer - Address of buffer to receive the data read from the file.

 

   Length - Supplies the length, in bytes, of the data to read from thefile.

 

   ByteOffset - Optionally specifies the starting byte offset within thefile

       to begin the read operation.  Ifnot specified and the file is open

       for synchronous I/O, then the current file position is used.  If the

       file is not opened for synchronous I/O and the parameter is not

       specified, then it is an error.

 

   Key - Optionally specifies a key to be used if there are locksassociated

       with the file.

 

Return Value:

 

   The status returned is success if the read operation was properly queued

   to the I/O system.  Once the readcompletes the status of the operation

   can be determined by examining the Status field of the I/O status block.

 

--*/

 

{

   PIRP irp;

   NTSTATUS status;

   PFILE_OBJECT fileObject;

   PDEVICE_OBJECT deviceObject;

   PFAST_IO_DISPATCH fastIoDispatch;

   KPROCESSOR_MODE requestorMode;

   PIO_STACK_LOCATION irpSp;

   NTSTATUS exceptionCode;

   BOOLEAN synchronousIo;

   PKEVENT eventObject = (PKEVENT) NULL;

   ULONG keyValue = 0;

   LARGE_INTEGER fileOffset = {0,0};

   PULONG majorFunction;

   PETHREAD CurrentThread;

 

   PAGED_CODE();

 

   //

   // Get the previous mode;  i.e.,the mode of the caller.

   //

 

   CurrentThread = PsGetCurrentThread ();

   requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);

 

   //

   // Reference the file object so the target device can be found.  Note

   // that if the caller does not have read access to the file, theoperation

   // will fail.

   //

 

   status = ObReferenceObjectByHandle( FileHandle,

                                       FILE_READ_DATA,

                                        IoFileObjectType,

                                       requestorMode,

                                        (PVOID*) &fileObject,

                                        NULL );

   if (!NT_SUCCESS( status )) {

       return status;

    }

 

   //

    //Get the address of the target device object.

   //

 

   deviceObject = IoGetRelatedDeviceObject( fileObject );

 

   if (requestorMode != KernelMode) {

 

       //

       // The caller's access mode is not kernel so probe each of the arguments

       // and capture them as necessary. If any failures occur, the condition

       // handler will be invoked to handle them.  It will simply cleanup and

       // return an access violation status code back to the system service

       // dispatcher.

       //

 

       exceptionCode = STATUS_SUCCESS;

 

       try {

 

           //

           // The IoStatusBlock parameter must be writeable by the caller.

           //

 

           ProbeForWriteIoStatus(IoStatusBlock);

 

           //

           // If this is a 32-bit asynchronous IO, then mark the Iosb being sent asso.

           // Note: IopMarkApcRoutineIfAsyncronousIo32 must be called after probing

           //       the IoStatusBlockstructure for write.

           //

 

           IopMarkApcRoutineIfAsyncronousIo32(IoStatusBlock,ApcRoutine,(fileObject->Flags& FO_SYNCHRONOUS_IO));

 

           //

           // The caller's data buffer must be writable from the caller's

           // mode.  This check ensures thatthis is the case.  Since the

           // buffer address is captured, the caller cannot change it,

           // even though he/she can change the protection from another

           // thread.  This error will becaught by the probe/lock or

           // buffer copy operations later.

           //

 

           ProbeForWrite( Buffer, Length, sizeof( UCHAR ) );

 

           //

           // If this file has an I/O completion port associated w/it, then

           // ensure that the caller did not supply an APC routine, as the

           // two are mutually exclusive methods for I/O completion

           // notification.

           //

 

           if (fileObject->CompletionContext && IopApcRoutinePresent(ApcRoutine )) {

                ObDereferenceObject( fileObject);

                returnSTATUS_INVALID_PARAMETER;

           }

 

           //

           // Also ensure that the ByteOffset parameter is readable from

           // the caller's mode and capture it if it is present.

           //

 

           if (ARGUMENT_PRESENT( ByteOffset )) {

                ProbeForReadSmallStructure(ByteOffset,

                                           sizeof( LARGE_INTEGER ),

                                            sizeof( ULONG ) );

                fileOffset = *ByteOffset;

           }

 

           //

           // Check to see whether the caller has opened the file without

           // intermediate buffering.  If so,perform the following Buffer

           // and ByteOffset parameter checks differently.

           //

 

           if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {

 

                //

                // The file was opened withoutintermediate buffering enabled.

                // Check that the Buffer isproperly aligned, and that the

                // length is an integral numberof 512-byte blocks.

                //

 

                if((deviceObject->SectorSize &&

                    (Length &(deviceObject->SectorSize - 1))) ||

                    (ULONG_PTR) Buffer &deviceObject->AlignmentRequirement) {

 

                    //

                    // Check for sector sizesthat are not a power of two.

                    //

 

                    if ((deviceObject->SectorSize&&

                        Length %deviceObject->SectorSize) ||

                        (ULONG_PTR) Buffer& deviceObject->AlignmentRequirement) {

                        ObDereferenceObject(fileObject );

                        return STATUS_INVALID_PARAMETER;

                    }

                }

 

                //

                // If a ByteOffset parameterwas specified, ensure that it

                // is a valid argument.

                //

 

                if (ARGUMENT_PRESENT(ByteOffset )) {

                    if(deviceObject->SectorSize &&

                        (fileOffset.LowPart& (deviceObject->SectorSize - 1))) {

                        ObDereferenceObject(fileObject );

                       returnSTATUS_INVALID_PARAMETER;

                    }

                }

           }

 

           //

           // Finally, ensure that if there is a key parameter specified it

           // is readable by the caller.

           //

 

            if (ARGUMENT_PRESENT( Key )) {

                keyValue = ProbeAndReadUlong(Key );

           }

 

       } except(IopExceptionFilter( GetExceptionInformation(),&exceptionCode )) {

 

           //

           // An exception was incurred while attempting to probe the

           // caller's parameters. Dereference the file object and return

           // an appropriate error status code.

           //

 

           ObDereferenceObject( fileObject );

           return exceptionCode;

 

       }

 

    }else {

 

       //

       // The caller's mode is kernel. Get the same parameters that are

       // required from any other mode.

       //

 

       if (ARGUMENT_PRESENT( ByteOffset )) {

           fileOffset = *ByteOffset;

       }

 

       if (ARGUMENT_PRESENT( Key )) {

           keyValue = *Key;

       }

 

#if DBG

       if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {

 

           //

           // The file was opened without intermediate buffering enabled.

           // Check that the Buffer is properly aligned, and that the

           // length is an integral number of the block size.

           //

 

           if ((deviceObject->SectorSize &&

                (Length &(deviceObject->SectorSize - 1))) ||

                (ULONG_PTR) Buffer &deviceObject->AlignmentRequirement) {

 

                //

                // Check for sector sizes thatare not a power of two.

                //

 

                if((deviceObject->SectorSize &&

                    Length %deviceObject->SectorSize) ||

                    (ULONG_PTR) Buffer &deviceObject->AlignmentRequirement) {

                    ObDereferenceObject(fileObject );

                    ASSERT( FALSE );

                    returnSTATUS_INVALID_PARAMETER;

                }

           }

 

           //

           // If a ByteOffset parameter was specified, ensure that it

           // is a valid argument.

           //

 

           if (ARGUMENT_PRESENT( ByteOffset )) {

                if (deviceObject->SectorSize&&

                    (fileOffset.LowPart &(deviceObject->SectorSize - 1))) {

                    ObDereferenceObject(fileObject );

                    ASSERT( FALSE );

                    returnSTATUS_INVALID_PARAMETER;

                }

           }

       }

#endif // DBG

    }

 

   //

   // Get the address of the event object and set the event to the Not-

   // Signaled state, if an one was specified.  Note here too, that if

   // the handle does not refer to an event, then the reference will fail.

   //

 

   if (ARGUMENT_PRESENT( Event )) {

       status = ObReferenceObjectByHandle( Event,

                                           EVENT_MODIFY_STATE,

                                            ExEventObjectType,

                                           requestorMode,

                                           (PVOID *) &eventObject,

                                           NULL );

       if (!NT_SUCCESS( status )) {

           ObDereferenceObject( fileObject );

           return status;

       } else {

           KeClearEvent( eventObject );

       }

    }

 

   //

   // Get the address of the driver object's Fast I/O dispatch structure.

   //

 

   fastIoDispatch = deviceObject->DriverObject->FastIoDispatch;

 

   //

   // Make a special check here to determine whether this is a synchronous

   // I/O operation.  If it is, thenwait here until the file is owned by

   // the current thread.

    //

 

   if (fileObject->Flags & FO_SYNCHRONOUS_IO) {

 

       BOOLEAN interrupted;

 

       if (!IopAcquireFastLock( fileObject )) {

           status = IopAcquireFileObjectLock( fileObject,

                                              requestorMode,

                                               (BOOLEAN)((fileObject->Flags & FO_ALERTABLE_IO) != 0),

                                              &interrupted );

           if (interrupted) {

                if (eventObject) {

                    ObDereferenceObject(eventObject );

                }

                ObDereferenceObject( fileObject);

                return status;

           }

       }

 

       if (!ARGUMENT_PRESENT( ByteOffset ) ||

           (fileOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&

           fileOffset.HighPart == -1)) {

           fileOffset = fileObject->CurrentByteOffset;

       }

 

       //

       // Turbo read support.  If thefile is currently cached on this

       // file object, then call the Cache Manager directly via FastIoRead

       // and try to successfully complete the request here.  Note if

       // FastIoRead returns FALSE or we get an I/O error, we simply

       // fall through and go the "long way" and create an Irp.

       //

 

       if (fileObject->PrivateCacheMap) {

 

           IO_STATUS_BLOCK localIoStatus;

 

           ASSERT(fastIoDispatch && fastIoDispatch->FastIoRead);

 

           //

           //  Negative file offsets areillegal.

           //

 

           if (fileOffset.HighPart < 0) {

                if (eventObject) {

                    ObDereferenceObject(eventObject );

                }

                IopReleaseFileObjectLock(fileObject );

                ObDereferenceObject( fileObject);

                returnSTATUS_INVALID_PARAMETER;

           }

 

           if (fastIoDispatch->FastIoRead( fileObject,

                                           &fileOffset,

                                           Length,

                                           TRUE,

                                           keyValue,

                                           Buffer,

                                           &localIoStatus,

                                            deviceObject )

 

                    &&

 

                ((localIoStatus.Status ==STATUS_SUCCESS) ||

                 (localIoStatus.Status ==STATUS_BUFFER_OVERFLOW) ||

                 (localIoStatus.Status ==STATUS_END_OF_FILE))) {

 

                //

                // Boost the priority of thecurrent thread so that it appears

                // as if it just did I/O.  This causes background jobs that

                // get cache hits to be moreresponsive in terms of getting

                // more CPU time.

                //

 

                if (IopCacheHitIncrement) {

                    KeBoostPriorityThread(&CurrentThread->Tcb,

                                          IopCacheHitIncrement );

                }

 

                //

                // Carefully return the I/Ostatus.

                //

 

                IopUpdateReadOperationCount( );

                IopUpdateReadTransferCount((ULONG)localIoStatus.Information );

 

                try {

                    *IoStatusBlock =localIoStatus;

                } except(EXCEPTION_EXECUTE_HANDLER ) {

                    localIoStatus.Status =GetExceptionCode();

                    localIoStatus.Information =0;

                }

 

                //

                // If an event was specified,set it.

                //

 

                if (ARGUMENT_PRESENT( Event )){

                    KeSetEvent( eventObject, 0,FALSE );

                    ObDereferenceObject(eventObject );

                }

 

                //

               // Note that the file objectevent need not be set to the

                // Signaled state, as it isalready set.

                //

 

                //

                // Cleanup and return.

                //

 

                IopReleaseFileObjectLock(fileObject );

                ObDereferenceObject( fileObject);

 

                return localIoStatus.Status;

           }

       }

       synchronousIo = TRUE;

 

    }else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags& (FO_NAMED_PIPE | FO_MAILSLOT))) {

 

       //

       // The file is not open for synchronous I/O operations, but the

       // caller did not specify a ByteOffset parameter.

       //

 

       if (eventObject) {

           ObDereferenceObject( eventObject );

       }

       ObDereferenceObject( fileObject );

       return STATUS_INVALID_PARAMETER;

    }else {

       synchronousIo = FALSE;

    }

 

   //

   //  Negative file offsets areillegal.

   //

 

   if (fileOffset.HighPart < 0) {

       if (eventObject) {

           ObDereferenceObject( eventObject );

       }

       if (synchronousIo) {

           IopReleaseFileObjectLock( fileObject );

       }

       ObDereferenceObject( fileObject );

        return STATUS_INVALID_PARAMETER;

    }

 

   //

   // Set the file object to the Not-Signaled state.

   //

 

   KeClearEvent( &fileObject->Event );

 

   //

   // Allocate and initialize the I/O Request Packet (IRP) for thisoperation.

   // The allocation is performed with an exception handler in case the

   // caller does not have enough quota to allocate the packet.

 

   irp = IopAllocateIrp( deviceObject->StackSize, !synchronousIo );

   if (!irp) {

 

       //

       // An IRP could not be allocated. Cleanup and return an appropriate

       // error status code.

       //

 

       IopAllocateIrpCleanup( fileObject, eventObject );

 

       return STATUS_INSUFFICIENT_RESOURCES;

    }

   irp->Tail.Overlay.OriginalFileObject = fileObject;

   irp->Tail.Overlay.Thread = CurrentThread;

   irp->Tail.Overlay.AuxiliaryBuffer = (PVOID) NULL;

   irp->RequestorMode = requestorMode;

   irp->PendingReturned = FALSE;

   irp->Cancel = FALSE;

   irp->CancelRoutine = (PDRIVER_CANCEL) NULL;

 

   //

    // Fill in the service independentparameters in the IRP.

   //

 

   irp->UserEvent = eventObject;

   irp->UserIosb = IoStatusBlock;

   irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;

   irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;

 

   //

   // Get a pointer to the stack location for the first driver.  This will be

   // used to pass the original function codes and parameters.  Note that

   // setting the major function here also sets:

   //

   //      MinorFunction = 0;

   //      Flags = 0;

   //      Control = 0;

   //

 

   irpSp = IoGetNextIrpStackLocation( irp );

   majorFunction = (PULONG) (&irpSp->MajorFunction);

   *majorFunction = IRP_MJ_READ;

   irpSp->FileObject = fileObject;

 

   //

   // Now determine whether this device expects to have data buffered to it

   // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO

   // flag in the device object.  Ifthe flag is set, then a system buffer is

   // allocated and the driver's data will be copied into it.  Otherwise, a

   // Memory Descriptor List (MDL) is allocated and the caller's buffer is

   // locked down using it.

   //

 

   irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;

   irp->MdlAddress = (PMDL) NULL;

 

   if (deviceObject->Flags & DO_BUFFERED_IO) {

 

       //

       // The device does not support direct I/O.  Allocate a system buffer

       // and specify that it should be deallocated on completion.  Also

       // indicate that this is an input operation so the data will be copied

       // into the caller's buffer.  Thisis done using an exception handler

       // that will perform cleanup if the operation fails.  Note that this

       // is only done if the operation has a non-zero length.

       //

 

       if (Length) {

 

           try {

 

                //

                // Allocate the intermediarysystem buffer from nonpaged pool

                // and charge quota for it.

                //

 

                irp->AssociatedIrp.SystemBuffer=

                    ExAllocatePoolWithQuota(NonPagedPoolCacheAligned, Length );

 

           } except(EXCEPTION_EXECUTE_HANDLER) {

 

                //

                // An exception was incurredwhile either probing the caller's

                // buffer or allocating thesystem buffer.  Determine what

                // actually happened, cleaneverything up, and return an

                // appropriate error statuscode.

                //

 

                IopExceptionCleanup(fileObject,

                                     irp,

                                    eventObject,

                                     (PKEVENT)NULL );

 

                return GetExceptionCode();

 

           }

 

           //

           // Remember the address of the caller's buffer so the copy can take

           // place during I/O completion. Also, set the flags so that the

           // completion code knows to do the copy and to deallocate the buffer.

           //

 

            irp->UserBuffer = Buffer;

           irp->Flags = IRP_BUFFERED_IO |

                         IRP_DEALLOCATE_BUFFER|

                         IRP_INPUT_OPERATION;

 

       } else {

 

           //

           // This is a zero-length read. Simply indicate that this is

           // buffered I/O, and pass along the request.  The buffer will

           // not be set to deallocate so the completion path does not

           // have to special-case the length.

           //

 

           irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;

 

       }

 

    }else if (deviceObject->Flags & DO_DIRECT_IO) {

 

       //

       // This is a direct I/O operation. Allocate an MDL and invoke the

       // memory management routine to lock the buffer into memory.  This

       // is done using an exception handler that will perform cleanup if

       // the operation fails.  Note thatno MDL is allocated, nor is any

       // memory probed or locked if the length of the request was zero.

       //

 

       PMDL mdl;

 

       irp->Flags = 0;

 

       if (Length) {

 

           try {

 

                //

                // Allocate an MDL, chargingquota for it, and hang it off of

                // the IRP.  Probe and lock the pages associated with the

                // caller's buffer for writeaccess and fill in the MDL with

                // the PFNs of those pages.

                //

 

                mdl = IoAllocateMdl( Buffer,Length, FALSE, TRUE, irp );

                if (mdl == NULL) {

                    ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES );

                }

                MmProbeAndLockPages( mdl,requestorMode, IoWriteAccess );

 

           } except(EXCEPTION_EXECUTE_HANDLER) {

 

                //

                // An exception was incurredwhile either probing the caller's

                // buffer or allocating theMDL.  Determine what actually

                // happened, clean everythingup, and return an appropriate

                // error status code.

                //

 

                IopExceptionCleanup(fileObject,

                                     irp,

                                    eventObject,

                                     (PKEVENT) NULL );

 

                return GetExceptionCode();

 

           }

 

       }

 

    }else {

 

       //

       // Pass the address of the user's buffer so the driver has access to

       // it.  It is now the driver's responsibilityto do everything.

       //

 

       irp->Flags = 0;

       irp->UserBuffer = Buffer;

    }

 

   //

   // If this read operation is supposed to be performed with cachingdisabled

   // set the disable flag in the IRP so no caching is performed.

   //

 

   if (fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) {

       irp->Flags |= IRP_NOCACHE | IRP_READ_OPERATION |IRP_DEFER_IO_COMPLETION;

    }else {

       irp->Flags |= IRP_READ_OPERATION | IRP_DEFER_IO_COMPLETION;

    }

 

   //

   // Copy the caller's parameters to the service-specific portion of the

   // IRP.

   //

 

   irpSp->Parameters.Read.Length = Length;

   irpSp->Parameters.Read.Key = keyValue;

   irpSp->Parameters.Read.ByteOffset = fileOffset;

 

   //

   // Queue the packet, call the driver, and synchronize appropriately with

   // I/O completion.

   //

 

   status = IopSynchronousServiceTail( deviceObject,

                                         irp,

                                        fileObject,

                                         TRUE,

                                        requestorMode,

                                        synchronousIo,

                                         ReadTransfer);

 

   return status;

}

 


 

NTSTATUS

IopSynchronousServiceTail(

   IN PDEVICE_OBJECT DeviceObject,

   IN PIRP Irp,

   IN PFILE_OBJECT FileObject,

   IN BOOLEAN DeferredIoCompletion,

   IN KPROCESSOR_MODE RequestorMode,

   IN BOOLEAN SynchronousIo,

   IN TRANSFER_TYPE TransferType

    )

 

/*++

 

Routine Description:

 

   This routine is invoked to complete the operation of a system service.

   It queues the IRP to the thread's queue, updates the transfer count,

   calls the driver, and finally synchronizes completion of the I/O.

 

Arguments:

 

   DeviceObject - Device on which the I/O is to occur.

 

   Irp - I/O Request Packet representing the I/O operation.

 

   FileObject - File object for this open instantiation.

 

   DeferredIoCompletion - Indicates whether deferred completion ispossible.

 

   RequestorMode - Mode in which request was made.

 

   SynchronousIo - Indicates whether the operation is to be synchronous.

 

   TransferType - Type of transfer being performed: read, write, or other.

 

Return Value:

 

   The function value is the final status of the operation.

 

--*/

 

{

   NTSTATUS status;

 

   PAGED_CODE();

 

   //

   // Insert the packet at the head of the IRP list for the thread.

   //

 

   if (!SynchronousIo) {

       IopQueueThreadIrp( Irp );

    }

 

   //

   // Update the operation count statistic for the current process.

   //

 

   switch( TransferType ) {

 

   case ReadTransfer:

       IopUpdateReadOperationCount();

       break;

 

   case WriteTransfer:

       IopUpdateWriteOperationCount();

       break;

 

   case OtherTransfer:

       IopUpdateOtherOperationCount();

       break;

    }

 

   //

   // Now simply invoke the driver at its dispatch entry with the IRP.

   //

 

   status = IoCallDriver( DeviceObject, Irp );

 

   //

   // If deferred I/O completion is possible, check for pending returned

   // from the driver.  If the driverdid not return pending, then the

   // packet has not actually been completed yet, so complete it here.

   //

 

   if (DeferredIoCompletion) {

 

       if (status != STATUS_PENDING) {

 

           //

           // The I/O operation was completed without returning a status of

           // pending.  This means that atthis point, the IRP has not been

           // fully completed.  Complete itnow.

           //

 

           PKNORMAL_ROUTINE normalRoutine;

           PVOID normalContext;

           KIRQL irql = PASSIVE_LEVEL; // Just to shut up the compiler

 

           ASSERT( !Irp->PendingReturned );

 

           if (!SynchronousIo) {

                KeRaiseIrql( APC_LEVEL,&irql );

           }

           IopCompleteRequest( &Irp->Tail.Apc,

                               &normalRoutine,

                                &normalContext,

                                (PVOID *)&FileObject,

                               &normalContext );

 

           if (!SynchronousIo) {

                KeLowerIrql( irql );

           }

       }

    }

 

   //

   // If this operation was a synchronous I/O operation, check the return

   // status to determine whether or not to wait on the file object.  If

   // the file object is to be waited on, wait for the operation tocomplete

   // and obtain the final status from the file object itself.

   //

 

   if (SynchronousIo) {

 

       if (status == STATUS_PENDING) {

 

           status = KeWaitForSingleObject( &FileObject->Event,

                                           Executive,

                                           RequestorMode,

                                           (BOOLEAN) ((FileObject->Flags & FO_ALERTABLE_IO) != 0),

                                           (PLARGE_INTEGER) NULL );

 

           if (status == STATUS_ALERTED || status == STATUS_USER_APC) {

 

                //

                // The wait request has endedeither because the thread was alerted

                // or an APC was queued to thisthread, because of thread rundown or

                // CTRL/C processing.  In either case, try to bail out of this I/O

                // request carefully so thatthe IRP completes before this routine

                // exists so thatsynchronization with the file object will remain

                // intact.

                //

 

                IopCancelAlertedRequest(&FileObject->Event, Irp );

 

           }

 

           status = FileObject->FinalStatus;

 

       }

 

       IopReleaseFileObjectLock( FileObject );

 

    }

 

   return status;

}

 

 

NTSTATUS

IoCallDriver(

   IN PDEVICE_OBJECT DeviceObject,

   IN OUT PIRP Irp

    )

{

   return IofCallDriver (DeviceObject, Irp);

}

 

NTSTATUS

FASTCALL

IofCallDriver(

   IN PDEVICE_OBJECT DeviceObject,

   IN OUT PIRP Irp

    )

{

   if (pIofCallDriver != NULL) {

 

       //

       // This routine will either jump immediately to IovCallDriver or

       // IoPerfCallDriver.

       //

       return pIofCallDriver(DeviceObject, Irp, _ReturnAddress());

    }

 

   return IopfCallDriver(DeviceObject, Irp);

}

NTSTATUS

FORCEINLINE

IopfCallDriver(

   IN PDEVICE_OBJECT DeviceObject,

   IN OUT PIRP Irp

    )

 

/*++

 

Routine Description:

 

   This routine is invoked to pass an I/O Request Packet (IRP) to another

   driver at its dispatch routine.

 

Arguments:

 

   DeviceObject - Pointer to device object to which the IRP should bepassed.

 

   Irp - Pointer to IRP for request.

 

Return Value:

 

   Return status from driver's dispatch routine.

 

--*/

 

{

   PIO_STACK_LOCATION irpSp;

   PDRIVER_OBJECT driverObject;

   NTSTATUS status;

 

   //

   // Ensure that this is really an I/O Request Packet.

   //

 

   ASSERT( Irp->Type == IO_TYPE_IRP );

 

   //

   // Update the IRP stack to point to the next location.

   //

   Irp->CurrentLocation--;

 

   if (Irp->CurrentLocation <= 0) {

       KiBugCheck3( NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR) Irp, 0, 0 );

    }

 

   irpSp = IoGetNextIrpStackLocation( Irp );

   Irp->Tail.Overlay.CurrentStackLocation = irpSp;

 

   //

   // Save a pointer to the device object for this request so that it can

   // be used later in completion.

   //

 

   irpSp->DeviceObject = DeviceObject;

 

 

   //

   // Invoke the driver at its dispatch routine entry point.

   //

 

   driverObject = DeviceObject->DriverObject;

 

   //

   // Prevent the driver from unloading.

   //

 

 

   status = driverObject->MajorFunction[irpSp->MajorFunction](DeviceObject,

                                                              Irp);

 

   return status;

}

 
原创粉丝点击