天天看點

《Windows NT FileSystem Internals》學習筆記之IO_STACK_LOCATION的結構

NTDDK定義的Stack Location結構體由以下幾個字段組成:

MajorFunction:

該字段定義了一個函數功能集,核心模式驅動可以實作其中的每一個函數。每一個函數由一個函數代碼對應。

當核心模式驅動接收到一個IRP時,驅動首先檢查目前StackLocation中的MajorFunction字段,得出驅動将要執行的功能,可能的MajorFunction功能代碼如下:

#define IRP_MJ_CREATE                   0x00

#define IRP_MJ_CREATE_NAMED_PIPE        0x01

#define IRP_MJ_CLOSE                    0x02

#define IRP_MJ_READ                     0x03

#define IRP_MJ_WRITE                    0x04

#define IRP_MJ_QUERY_INFORMATION        0x05

#define IRP_MJ_SET_INFORMATION          0x06

#define IRP_MJ_QUERY_EA                 0x07

#define IRP_MJ_SET_EA                   0x08

#define IRP_MJ_FLUSH_BUFFERS            0x09

#define IRP_MJ_QUERY_VOLUME_INFORMATION 0x 0a

#define IRP_MJ_SET_VOLUME_INFORMATION   0x0b

#define IRP_MJ_DIRECTORY_CONTROL        0x 0c

#define IRP_MJ_FILE_SYSTEM_CONTROL      0x0d

#define IRP_MJ_DEVICE_CONTROL           0x0e

#define IRP_MJ_INTERNAL_DEVICE_CONTROL  0x 0f

#define IRP_MJ_SHUTDOWN                 0x10

#define IRP_MJ_LOCK_CONTROL             0x11

#define IRP_MJ_CLEANUP                  0x12

#define IRP_MJ_CREATE_MAILSLOT          0x13

#define IRP_MJ_QUERY_SECURITY           0x14

#define IRP_MJ_SET_SECURITY             0x15

#define IRP_MJ_POWER                    0x16

#define IRP_MJ_SYSTEM_CONTROL           0x17

#define IRP_MJ_DEVICE_CHANGE            0x18

#define IRP_MJ_QUERY_QUOTA              0x19

#define IRP_MJ_SET_QUOTA                0x 1a

#define IRP_MJ_PNP                      0x1b

#define IRP_MJ_PNP_POWER                IRP_MJ_PNP      // Obsolete....

#define IRP_MJ_MAXIMUM_FUNCTION         0x1b

MinorFunction

MinorFunction提供了MajorFunction更詳細的資訊

Flags

      Flags提供了函數期望驅動執行的附加資訊

Control

       當核心驅動異步處理IRP時,驅動可以通過調用IoMarkIrpPending()将IRP标記為Pending狀态,以排隊IRP處理。IoMarkIrpPending實際上隻是将目前Stack Location的Control字段設定為SL_PENDING_RETURNED。核心驅動可以檢查該字段查詢是否有該标記。

DeviceObject

     當調用IoCallDriver()時,NT I/O管理器設定該字段,該字段的内容被設定為目标裝置對象的指針。

Win2K源代碼中可以看出上面的過程:

NTSTATUS

FASTCALL

IopfCallDriver(

    IN PDEVICE_OBJECT DeviceObject,

    IN OUT PIRP Irp

    )

{

    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)

{

        KeBugCheckEx( NO_MORE_IRP_STACK_LOCATIONS, (ULONG_PTR) Irp, 0, 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;

    PERFINFO_DRIVER_MAJORFUNCTION_CALL(Irp, irpSp, driverObject);

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

                                                              Irp );

    PERFINFO_DRIVER_MAJORFUNCTION_RETURN(Irp, irpSp, driverObject);

    return status;

}

FileObject

       I/O管理器将該字段設定為指向I/O操作的目标檔案對象

CompletionRoutine

       當調用IoSetCompletionRoutine()函數時,設定該字段。I/O管理器在IRP處理完成時,要進行一系列的事後處理,其中就包括檢查CompletionRoutine。如果指定了CompletionRoutine,該函數就将在執行事後處理的線程中調用;一般情況下就是調用IoCompleteRequest()函數的線程上下文中。

       CompletionRoutine采用堆棧順序調用,即最後指定的CompletionRoutine最先調用,是以最高層驅動的完成函數最後被調用。如果某個驅動CompletionRoutine傳回了STATUS_MORE_PROCESSING_REQUIRED,I/O管理器将立即停止IRP事後處理。傳回STATUS_MORE_PROCESSING_REQUIRED的驅動有責任釋放IRP占用的記憶體。

       如果你開發一個高層的驅動程式,例如檔案系統驅動或者過濾驅動,并且指定了一個Completion Routine。記得使用以下代碼:

if(PtrIrp->PendingReturned)

{

IoMarkIrpPending(PtrIrp);

}

否則的話IRP處理将會出現錯誤。

Context

       該字段為Completion Routine提供參數

繼續閱讀