MmGetSystemAddressForMdlSafe 有可能返回空----(Crch)

 

快速备份在昨天晚上的测试中 , 有一台机器在启动过程中 , 还在 Native 模式时 , Win32 SubSystem 加载前 , 被断点中断 , 发现 MmGetSystemAddressForMdlSafe 返回了空指针 .

 

Mdl->Flag = 0x42, MmGetSystemAddressForMdlSafe 将用 MmMapLockedPagesSpecifyCache 返回 Read Buffer 的地址 .

 

修改 IP, 重新执行这个函数 ( 中间 , 有其他 IRP 被处理 ),   获得 Buffer 的地址成功 .

 

以前从未发现过 MmGetSystemAddressForMdlSafe 函数返回空指针的情况 . 而且 , 重新执行成功 , 表明其偶然性 .

 

经过分析 , 发现可能的原因 : MmGetSystemAddressForMdlSafe 因为系统虚拟地址空间紧张,而有可能返回 NULL

 

 

此时 , 物理内存还剩约 1.5G, MDL 已经分配到了足够的物理内存 , 但在被映射为虚拟地址时 , 却失败了 .

要求映射的地址范围也比较大 , 0x1409000 Bytes. 可能的原因是因为系统此时无法分配出连续大约 21M 的虚拟地址空间 .

 

查看了此时的驱动运行情况 , 发现 Irp 队列中 , 存在大量的 Irp 同时被执行 ( 多到 Irp 队列的链表在 Watch 窗口中已经无法继续展开 , 展开 10 级以上 ). 因为快速备份的 LBA 重新映射过程 , 分配了大量的内存片段 ( 极有可能超过 1000 ), 可能导致内存被撕为大量零碎的情况 在此种情况请求一个较大的连续虚拟地址空间时 , 由于不允许 Bugcheck, 所以返回空指针 .

 

通常 , 我们在驱动中 , 频繁请求的固定长度的内存是 , 会使用 LookasideList, LookasideList 不能很好的支持大量的请求 , 因为 LookasideList 在发现其链表中没有空闲的 Pool , 仍然会使用 ExAllocatePool 从内存中直接分配 , 只是释放时 , 将其暂时放回 List, 以方便下次使用时 , 直接从链表中取出即可 . LookasideList OS 实现 , 系统有个 Timer 回调 , 会不断的取检查其链表深度和每个 Pool 片段的命中率 , 当发现命中率很低时 , 系统会回收这些片段 . 所以 , 仍然会造成大量内存碎片 . -- 所以, 建议频繁但不量大时, 使用LookasideList是个好主意. 又频繁又量大时, 就要慎重了.

 

由于在 DiskFilter 层几乎不允许有失败的情况 , 所以 , 目前比较投机的解决办法是反复重试 , 直到其不返回为空为止 .

比较彻底的解决办法 : 自己动手 , 丰衣足食 . 自己管理内存 这样 , 不会造成大量碎片 , 而且 , 效率相对较高 . 相对而言 ExAllocatePool 实际上的开销是比较大的 .

 

在测试过程中 , 还发现一些现象 , 算与这个问题有关 , 分享给大家 :

1 绝不要低估系统同时发下来的 IRP 的数量 (NTFS 是量大 )

2 绝不要低估系统 IRP 请求的长度 (FAT32 是单个 IRP 很大 , 不过还好 , 还没有遇到超过 64M )

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值