现在的位置: 首页 > 综合 > 正文

简单说点对文件系统、分层驱动、文件读写的理解

2013年06月23日 ⁄ 综合 ⁄ 共 4096字 ⁄ 字号 评论关闭

write by http://hi.baidu.com/weolar/blog/item...2dbb4bd4f.html


今天看到sudami同学学习起这些东西,好久没搞了,很生疏,所以重新学习了一下,有点小小心得(仅仅是心得,有不少错误,希望大家斧正
 ):


在我的理解中,设备对象(drevobj)相当于驱动对象(drvobj)创建的子对象,用来形成设备链,从而接受、处理数据的。设备对象挂到设备链中,
接受到了被设备管理器派遣的IRP时(记得某本书上好像说,没有真正所谓的设备管理器,只是一组派遣例程,如IopfCallDriver就是将IRP派
遣的。通过hook这个函数能得到很多我们想要的东西),这时设备对象的母对象--驱动对象组建的IRP派遣函数,(即
DriverObject->MajorFunction[IRP_MJ_CREATE]         = DispatchCreate;形
式的函数)将会接受IRP并处理。而设备堆栈则是每次IRP下发时辅助IRP找到相应派遣函数并存储一些可重用参数的地方。
    废话说了这么多,那么我们平时访问、删除文件是怎么回事呢?比如我们删除一个文件,那么系统的流程就是:

(应用层)DeleteFileA 
--> 
DeleteFileW 
--> 
ntdll.ZwSetInformationFil
->
(驱动层)NtSetInformationFile
->
SrSetInformationFile
->
NtfsNtSetInformationFile
->
NtfsCommonSetInformationFile
->
NtfsSetDispositionInfo 
->
MmFlushImageSection 
->
MiCleanSection

到了驱动层,windows就是通过IRP来传递了。上面的流程
中,nt!NtSetInformationFile->SrSetInformationFile->NtfsNtSetInformationFile->NtfsCommonSetInformationFile 几
个此时虽然也有IRP的传送,但都还是直接调用,不是IopfCallDriver的形式。而IRP起到传递参数的作用。它体内保持着将要下发的设备对
象。现在来看接下来某个IRP(并非删除文件)在设备链中的传递:

nt!NtFlushBuffersFile
->

nt!IopSynchronousServiceTail
->

sr!SrPassThrough
->

Ntfs!NtfsFsdFlushBuffers
->

Ntfs!LfsFlushToLsn
->

Ntfs!LfsFlushToLsnPriv
->

Ntfs!LfsFlushLbcb
->

Ntfs!LfsFlushLfcb
->

sr!SrWrite
->

Ntfs!NtfsCommonWrite
->

Ntfs!NtfsNonCachedIo
->

Ntfs!NtfsSingleAsync
->

VolSnap!VolSnapWrite
->

ftdisk!FtDiskReadWrite
->

CLASSPNP!ClassReadWrite
->

CLASSPNP!ServiceTransferRequest
->

CLASSPNP!SubmitTransferPacket
->

atapi!IdePortDispatch
(/Driver/atapi / IdeDeviceP0T0L0-3)->

atapi!IdePortInsertByKeyDeviceQueue
->

atapi!StartIo Packet
->

HAL->

Io 端口……
也就是说:IRP是从Ntfs ->ftdisk (卷设备) -> class(classpnp )-> atapi -> hal -> IO
的流向的。

那么//./Physical Drive%d 啊,/Device/Harddisk%d/Partition0啊~ 是表示什么呢?通过DeviceTree和winobj可以得知,
//./PhysicalDrive 只是Device/Harddisk%d/Partition0的符号连接,

而Device/Harddisk0/Partition0是/Device/Harddisk0/DR0的符号链接。

Device/Harddisk0/Partition1、2……则是Device/HarddiskVolume1、2的符号连接。

那么设备堆栈是怎么回事呢,原来从上到下是这样:

FS DRIVER--->>

Volsnap--->>>

ftdisk(Device/HarddiskVolume1)--->>

partmgr(Ipartmgr )--->>

disk(Device/Harddisk%d/Partition0/ DR0)--->>

acpi--->>>

atapi( IdeDeviceP0T0L0-3)

每层都是attached到上一层,所以形成设备链的。括号内表示驱动对象创建的设备对象,用来形成设备堆栈并接受IRP的。
(所以过滤驱动挂载到任意一层时遍能拦截到数据,这也是微软提倡的“HOOK”方式)

这也就对应了微软的说法,IRP是从文件系统->卷驱动 -> 磁盘驱动-> 类驱动-> 端口驱动-> 微端口驱动的流程的。

而Device/Harddisk%d/Partition0/ DR0则是disk驱动对象创建用来处理ClassReadWrite等IRP的设备对
象了。我看了disk的IRP_MJ_READ确实是CLASSPNP!ClassReadWrite,这就可以接受为什么IRP到了disk这层反而到
了classpnp中去处理IRP了。

另外,MJ前辈还说过:
1.文件系统设备站和storage设备站使用同一个irp,到了atapi,这个MINIPORT,就换成pkt中的另一个Irp,
2.如果中间没有人重新转发IRP(例如DISKF)的话,从FSD到ATAPI都是用的同一个IRP。IdePortDispatch 没有源代码,而
classpnp是开源的(wdk就有),可参考classpnp中的ServiceTransferRequest和
SetupReadWriteTransferPacket。

IRP再往下会到哪呢?原来通过在ATAPI中通过IdePortInsertByKeyDeviceQueue将IRP入队列,再往下就是ATAPI的
StartIo 了。StartIo 再往下就没有IRP的概念了,便到达HAL(硬件抽象)层,再往下就是端口IO了!

下面是大米同学的图,画的很好,先引用一下^_^:
IRP |     
        |         
        |           attach dev               attach dev 
        |               |                       |
   ntfs/fat32.sys  --> dev --> dev --> ... --> dev 
        |               |                       |
        |           attach dev               attach dev
        |               |
        |              ...    
        |
        |
        |   
        |              ...
        |               |
      partmgr.sys  --> dev --> dev --> ... --> dev
        |               |                         
        |              ... 
        |
        |
        |                                     dev ( /driver/partmgr)
        |              |                       |
       disk.sys   --> dev --> dev --> ... --> dev (DR0) 
        |              |
      
        |
        |                                   dev ( /driver/partmgr)
        |                                      |
        |                                    dev (DR0)   (/driver/disk)                     
        |              |                       |
       atapi.sys  ->  dev --> dev --> ... --> dev
        |
        |
       ...
另外AZY前辈也说过:

读写IRP->IdePortDispatch->IoStartPacket->IdePortStartIo,到这里分两支
有DMA能力的走: BmSetup->BmReceiveScatterGatherList->IdePortAllocateAccessToken->xxx
无DMA能力的走:IdePortAllocateAccessToken->CallIdeStartIoSynchronized->IdeStartIoSynchronized->AtapiStartIo->IO端口xxx

抱歉!评论已关闭.