设为首页 收藏本站
查看: 854|回复: 0

Windows文件系统过滤驱动开发教程(7)

[复制链接]

尚未签到

发表于 2015-5-11 12:51:27 | 显示全部楼层 |阅读模式
Windows文件系统过滤驱动开发教程


7.IRP完成函数,中断级,如何超越中断级别的限制

先讨论一下Volumne设备是如何得到的.首先看以下几个函数:

// ------------------wdf.h 中的内容 -------------------------
typedef VPB wd_vpb;
_inline wd_vpb * wd_dev_vbp(wd_dev *dev)
{
return dev->Vpb;
}

_inline wd_dev * wd_vbp_dev(wd_vpb *vpb)
{
return vpb->DeviceObject;
}


VPB是Volume parameter block.一个数据结构.它的主要作用是把实际存储媒介设备对象和文件系统上的卷设备对象联系起来.

wd_dev_vbp可以让你从一个Storage Device Object得到一个VPB,而wd_vbp_dev这个函数可以得到这个VPB所对应的Volmue设备.

现在首先要得到Storage Device Object.实际上这个东西保存在当前IO_STACK_LOCATION中.

// ------------------wdf.h 中的内容 -----------------------
_inline wd_dev *wd_irpsp_mount_storage(wd_io_stack *irpsp)
{
return irpsp->Parameters.MountVolume.Vpb->RealDevice;
};

那么,从irp出发,我最终可以通过以下的方式得到Volumue设备:

wd_irpsp *irpsp = wd_cur_io_stack(irp);
wd_dev *storage_dev = wd_irpsp_mount_storage(irp);
wd_vpb *vpb = wd_dev_vbp(storage_dev);
wd_dev *volume_dev = wd_vbp_dev(vpb);

不过实际情况并不这么简单.这里的IRP是一个MOUNT请求.而volume设备对象实际上是这个请求完成之后的返回结果.因此,在这个请求还没有完成之前,我们就试图去获得Volume设备对象,当然是竹篮打水一场空了.

这里,你可以直接拷贝当前IO_STACK_LOCATION,然后向下发送请求,但在此之前,要先给irp分配一个完成函数.irp一旦完成,你的完成函数将被调用.这样的话,你可以在完成函数中得到Volume设备,并实施你的绑定过程.

这里要讨论一下中断级别的问题.常常碰到人问某函数只能在Passive Level调用是什么意思.总之我们的任何代码执行的时候,总是处在某个当前的中断级之中.某些系统调用只能在低级别中断级中执行.请注意,如果一个调用 可以在高处运行,那么它能在低处运行,反过来则不行.

我们需要知道的只是我们关心Passive Level和Dispatch Level.而且Dispatch Level的中断级较高.一般ddk上都会标明,如果注明irq level>=dispatch,那么你就不能在passive level的代码中调用它们了.

那么你如何判断当前的代码在哪个中断级别中呢?我一般是这么判断的:如果你的代码执行是由于应用程序(或者说上层)的调用而引发的,那么应该在Passive Level.如果你的代码执行是由于下层硬件而引发的,那么则可能在dispatch level.

希望不要机械的理解我的话!以上只是极为粗略的便于记忆的理解方法.实际的应用应该是这样的:所有的dispatch functions由于是上层发来的irp而导致的调用,所以应该都是Passive Level,在其中你可以调用绝大多数系统调用.而如网卡的OnReceive,硬盘读写完毕,返回而导致的完成函数,都有可能在Dispatch级.注 意都是有可能,而不是绝对是.但是一旦有可能,我们就应该按就是考虑.

好,现在我们发现,我们已经注册了完成函数,并且这个函数执行中可能是dispatch level.

现在面临的问题是,我们已经决定在完成函数中调用 IoAttachDeviceToDeviceStack来绑定Volume.而DDK说明有:Callers of IoAttachDeviceToDeviceStack must be running at IRQL WorkerRoutine)(item->Parameter);
}

任务是一个数据结构,已经被我重定义为wd_work_item,wd_work_init能初始化它.初始化的时候你只需要填写一个你的任务的函数.同时一个context用来记录上下相关参数.(这是个空指针,你可以只想你任何想要的参数类型).

一般这个任务会自动执行,但是有时我们也想不插入队列,我们自己执行它.那么调用wd_work_run即可.

然后调用wd_work_queque插入工作者队列,之后会被执行.插入类型这里选择wd_work_delay.

希望你没有被这一串东西搞糊涂.现在我会写一个"设置完成函数"的函数.执行后,自动在Passive Level级执行你的完成函数.希望不会把你搞得晕头转向的:).

// 完成例程上下文。好几个fsctl需要注册完成例程。而例程中的工作可能
// 只能在passive level中运行,因此不得不加入一个work_item,把任务塞
// 入工作线程等待完成
typedef struct _my_fsctl_comp_con
{
wd_work_item work;
wd_dev *dev;
wd_irp *irp;
wd_dev *new_dev; // 这个元素仅仅用于mount的时候。因为我
// 们要生成一个新设备来绑定vdo.
} my_fsctl_comp_con;

wd_bool my_fsctl_set_comp(wd_dev *dev,
wd_irp *irp,
wd_dev *new_dev,
wd_irp_comp_func complete,
wd_work_func work_complete)
{
my_fsctl_comp_con *context;
context = (wdff_fsctl_comp_con *)wd_malloc(wd_false,
sizeof(wdff_fsctl_comp_con));
if(context == NULL)
{
wd_printf0("fsctl set comp: failed to malloc context.\r\n");
return wd_false;
}

// 初始化工作细节
wd_work_init(&context->work,
work_complete,
context);

context->dev = dev;
context->irp = irp;
context->new_dev = new_dev;

// 设置irp完成例程
wd_irp_comp(irp,complete,context);

return wd_true;
}

// 以下函数作为以上complete的参数被使用
wd_stat my_fsctl_comp(in wd_dev *dev,
in wd_irp *irp,
in wd_void *context)
{
wd_printf0("fsctl_comp: come in!!!\r\n");
UNREFERENCED_PARAMETER(dev);
UNREFERENCED_PARAMETER(irp);
// 判断当前中断级
if(wd_get_cur_irql() > wd_irql_passive)
{
wd_printf0("fsctl_comp:into quque!!!\r\n");
// 如果在passive更低的中断级别,必须插入延迟队列中运行
wd_work_queue((wd_work_item *)context,wd_work_delay);
}
else
{
// 否则可以直接执行
wd_printf0("fsctl_comp:run directly!!!\r\n");
wd_work_run((wd_work_item *)context);
}
return wd_stat_more_processing;
}

我想以上的过程应该已经可以理解了!注册了基本的完成历程complete函数(也就是我最后写的函数my_fsctl_comp后),irp执行完毕回 调my_fsctl_comp,而我事先已经把已经做好的任务(wd_work_item)写在上下文指针中(context)中.一回调这个函数,我就 wd_work_queque插入队列.结果wd_work_item中记录的work_complete函数显然会在Passive level中执行.我们的系统也将保持稳定.

work_complete函数将从context上下文指针中得到足够的参数,来完成对Volume的绑定.

希望你没有被弄昏头:),我们下回再分解.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-65852-1-1.html 上篇帖子: 《Windows核心编程》学习笔记(7)– 详解线程 下篇帖子: TechEd 2010微软技术大会 Windows Phone 7 相关课程预告
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表