[转载]关于文件系统和磁盘驱动的一点学习心得

原文地址:http://hi.baidu.com/weolar/blog/item/34a8ff19be316572dbb4bd4f.html

 

今天看到sudami同学问起这些东西,好久没搞了,很生疏,所以重新学习了一下,有点小小心得:

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

(应用层)DeleteFileA --> DeleteFileW --> ntdll.ZwSetInformationFil->(驱动 层)nt!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的。

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

的流程的。

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)
        |              |                       |
       atapi.sys -> dev --> dev --> ... --> dev (DR0)  
        |
        |
       ...       

另外AZY说过: 读写IRP->IdePortDispatch->IoStartPacket->IdePortStartIo,到这里分两支有 DMA能力的走: BmSetup->BmReceiveScatterGatherList->IdePortAllocateAccessToken->xxx 无DMA能力的 走:IdePortAllocateAccessToken->CallIdeStartIoSynchronized->IdeStartIoSynchronized->AtapiStartIo->IO 端口xxx pnp管理器 ->ACPI某设备->PCI总线->ACPI某设备->PCIIDE->ACPI某设备 ->atapi->ACPI某设备->DISK->partmgr

 

还有,zzzevazzz大侠说过,“ftdisk是位于ntfs这类filesystem以下..disk这类storage driver以上的一个value added的驱动程序
他在partmgr的帮助下完成一下value added的功能
比如disk mirror等等
至于ftdisk跟disk的联系跟filesystem的联系都不是使用attach的方式完成的...

跟filesystem的联系是通过vpb来完成的
跟disk这是通过io control传递device object的指针完成的

发送到ftdisk的fdo的irp大部分是io control
而发送到ftdisk的pdo的irp则几乎都是read write

系统引导以后..disk.sys被加载..成功以后windows向其发送一个query bus relationship的irp...这个irp首先到达的驱动不是disk.sys而是作为disk的class的upperfilter加载的驱 动...partmgr.sys

partmgr.sys在这个irp上设置一个完成routine然后传递下去...disk会为其每一个分区创建一个pdo..

irp完成的时候..partmgr.sys的完成routine调用..对irp作进一步的处理

他解析返回的device relation结构
对于里面返回的每一个device object..如果是以前没有的现在新出现了..则构造一个volume arrival的iocontrol发送到ftdisk.
如果是以前有的而现在却没有了则发送一个volume removal到ftdisk
完成这些操作了以后ftdisk设置device relation的count成员为0...这样windows并不认为disk返回了很多pdo..以至于windows并不发送诸如start stop这类pnp的irp到disk为每个分区创建的pdo..当然这个工作是有人来完成的..partmgr会发送这些irp到disk去
要验证这个说法很简单..构造一个query bus relation发送到disk.sys就能看到pdo.而发送到partmgr.sys就什么都看不到
windows也不承认disk创建的设备是pdo.因为windows会为每个pdo创建device node.而这些设备并没有对应的device node

ftdisk接受到用disk本身的pdo跟disk创建的分区的pdo作为input产生的volume arrival的时候就创建一个pdo.并且保持这两个指针.这个新创建得pdo是一个FILE_DEVICE_DISK类型的pdo.windows在 IoCreateDevice的检查这种类型.为其创建一个vpb结构.并关联上去.同时ftdisk为这个新创建的pdo注册一个特别的device interface...系统里面的mountmgr.sys在这个device interface上注册了一个notification..mountmgr.sys得到运行.为这个pdo分配一个盘符.并创建符号连 接/dosdevices/c:这样的到ftdisk创建的pdo上...

在第一次访问这个新创建的pdo的时候.比如某程序要读取c:/boot.txt...windows解析这个名字发现c:是一个符号链接.重定向 到ftdisk的pdo上.再检查这个pdo.发现附加得有vpb.再检查vpb发现没有filesystem mount在上面.于是通知各个系统里面注册了得filesystem开始尝试mount这个新的volume.mount成功以后修改vpb的一个指针 指向filesystem在mount过程中为这个即将要使用的新分区所创建的一个device上面.这样就通过vpb把filesystem跟 ftdisk连接到了一起.

大致的情况就是如此.其中disk.sys是有源代码的.fastfat也是有源代码的.”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值