跟踪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传给了DeviceObject。IoCallDriver有原封不动的调用了IofCallDriver,IofCallDriver又原封不动的调用了IopfCallDriver。IopfCallDriver执行了驱动程序中注册的派遣函数。
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;
}
- 跟踪NtReadFile系统服务的执行过程
- 跟踪sys_execve的执行过程
- 跟踪 root.sh 的 执行过程
- 跟踪sys_mkdir的系统调用过程
- sql语句执行过程的跟踪方法相关介绍
- 简单的执行跟踪
- 跟踪oracle的执行
- Linux内核分析:实验五--使用GDB跟踪系统调用执行过程
- 程序执行过程的跟踪:(用debug来跟踪一个程序的运行过程) 整理总结
- 5_gdb跟踪分析系统调用system_call的处理过程
- 系统调用的初始化过程与系统调用执行过程
- fork系统调用的执行过程
- Linux系统ELF程序的执行过程
- 系统服务的调用过程(SystemService)
- 系统调用执行过程
- 深入剖析MFC基础框架——跟踪MFC单文档程序的执行过程:
- 理解WF的跟踪服务
- dubbo+zipkin的服务跟踪
- 2008年终总结--总结过去,把握现在,展望未来
- 使用 inotify 监控 Linux 文件系统事件
- JS日历
- javascript中正则的使用详解
- 三等功奖章背后的故事
- 跟踪NtReadFile系统服务的执行过程
- String看堆栈
- 关于#pragma warning
- 几个免费的方案(转自云舒大大)
- Java在WEB中如何统计在线人数
- 制作iis自动安装包
- paradox数据库sum后的排序
- 使用 Ttyutils 截获 UNIX/Linux 终端
- 挑选适合自己的乒乓球拍【转】