FileDisk 线程方式进行IRP序列化

      刚看完FileDisk代码,感受颇多,其中采用线程的方式进行IRP序列化更是让人觉得新鲜.在DDK中一般采用StartIo来进行IRP的序列话,其中在入口函数中加入pDriverObject->DriverStartUp = XXXStartIO即可, 当然也没这么简单,其中还要做写处理.

      FileDisk采用了另外一种方法,先来看看代码;

 //为IRP消息而设的双向循环链表结构
InitializeListHead(&device_extension->list_head);
//自旋锁初始化,锁住双向链表,在线程处理中解锁
KeInitializeSpinLock(&device_extension->list_lock);
//设置同步事件
KeInitializeEvent(
&device_extension->request_event,
SynchronizationEvent,//同步事件操作,在每一次wait通过后自动将事件设为未受信状态,
//使下一次wait阻塞.NotificationEvent则不会自动设置,需要手动
FALSE//初始状态为未受信状态
);
//设置线程有效
device_extension->terminate_thread = FALSE;
//建立主线程,实际上一个盘只有一个线程操作
status = PsCreateSystemThread(
&thread_handle,//获得线程句柄
(ACCESS_MASK) 0L,//屏蔽消息
NULL,
NULL,
NULL,
FileDiskThread,//触发磁盘操作线程
device_object
);

    这里可以看出,将FileDisk将IRP包保存在List_head当中,方便于在FileDiskThread线程直接进行处理.接下来看看FileDiskThread线程代码如何实现;

VOID
FileDiskThread (
IN PVOID Context
)
{
PDEVICE_OBJECT device_object;
PDEVICE_EXTENSION device_extension;
PLIST_ENTRY request;//双向链表的IRP栈
PIRP irp;
PIO_STACK_LOCATION io_stack;
PUCHAR system_buffer;
PUCHAR buffer;

ASSERT(Context != NULL);//?

device_object = (PDEVICE_OBJECT) Context;

device_extension = (PDEVICE_EXTENSION) device_object->DeviceExtension;
//设置优先级
KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);

for (;;)//以下为线程的无限循环,当device_extension->terminate_thread设为true时才结束.
{
//等待request_event事件置信,for每循环一次,在这里被阻塞,等待
KeWaitForSingleObject(
&device_extension->request_event,
Executive,
KernelMode,
FALSE,
NULL
);
//如果结束线程标志置位,结束线程
if (device_extension->terminate_thread)
{
PsTerminateSystemThread(STATUS_SUCCESS);
}
//遍历IRP表
while (request = ExInterlockedRemoveHeadList(
&device_extension->list_head,
&device_extension->list_lock
)) //list不为空,则指向下一链表数据
{
irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry); //获取irp基地址,tail是IRP结构里面的一个Union结构,Tail.Overlay.ListEntry说明IRP入栈待处理
////IRP的栈返回形式
io_stack = IoGetCurrentIrpStackLocation(irp);

switch (io_stack->MajorFunction)
{
case IRP_MJ_READ://读数据到内存
system_buffer = (PUCHAR) MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority);//分配MDL虚拟地址空间
if (system_buffer == NULL)
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;//分配失败返回资源不足警告
irp->IoStatus.Information = 0;
break;
}
buffer = (PUCHAR) ExAllocatePool(PagedPool, io_stack->Parameters.Read.Length); //分配空间
if (buffer == NULL)
{
irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
irp->IoStatus.Information = 0;
break;
}
ZwReadFile(
device_extension->file_handle, //读取指定的映像文件
NULL,
NULL,
NULL,
&irp->IoStatus,
buffer, //文件缓冲
io_stack->Parameters.Read.Length,
&io_stack->Parameters.Read.ByteOffset,
NULL
);
RtlCopyMemory(system_buffer, buffer, io_stack->Parameters.Read.Length); //将文件缓冲读入到MDL缓冲
ExFreePool(buffer);//释放文件缓冲
break;

case IRP_MJ_WRITE://内存数据写到设备
if ((io_stack->Parameters.Write.ByteOffset.QuadPart +
io_stack->Parameters.Write.Length) >
device_extension->file_size.QuadPart)//判错处理
{
irp->IoStatus.Status = STATUS_INVALID_PARAMETER;
irp->IoStatus.Information = 0;
}
ZwWriteFile(
device_extension->file_handle,
NULL,
NULL,
NULL,
&irp->IoStatus,
MmGetSystemAddressForMdlSafe(irp->MdlAddress, NormalPagePriority), //从MDL缓冲写入文件
io_stack->Parameters.Write.Length,
&io_stack->Parameters.Write.ByteOffset,
NULL
); //写文件
break;
//下面的是自定义IRP响应
case IRP_MJ_DEVICE_CONTROL:
switch (io_stack->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_FILE_DISK_OPEN_FILE:
//nt未公开函数,应该是权限设置
SeImpersonateClient(device_extension->security_client_context, NULL);

irp->IoStatus.Status = FileDiskOpenFile(device_object, irp);

PsRevertToSelf();//nt未公开函数

break;

case IOCTL_FILE_DISK_CLOSE_FILE:
irp->IoStatus.Status = FileDiskCloseFile(device_object, irp);
break;

default:
irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
}
break;

default:
irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
}

IoCompleteRequest(
irp,
(CCHAR) (NT_SUCCESS(irp->IoStatus.Status) ?
IO_DISK_INCREMENT : IO_NO_INCREMENT)
);
}
}
}

     不得不看看WRITE和READ IRP是怎么处理的,代码如下;

NTSTATUS
FileDiskReadWrite (//完成对虚拟磁盘的读写,对应于主功能代码IRP_MJ_WRITE和IRP_MJ_READ,
//在进行读写之前要先确认设备是否存在。
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION device_extension;
PIO_STACK_LOCATION io_stack;

device_extension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;

if (!device_extension->media_in_device)//虚拟盘内没介质则出错
{
Irp->IoStatus.Status = STATUS_NO_MEDIA_IN_DEVICE;
Irp->IoStatus.Information = 0;

IoCompleteRequest(Irp, IO_NO_INCREMENT);

return STATUS_NO_MEDIA_IN_DEVICE;
}

io_stack = IoGetCurrentIrpStackLocation(Irp);

if (io_stack->Parameters.Read.Length == 0)//如果要求读写长度为0,直接返回
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
//标识IRP已经处理
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//返回成功
return STATUS_SUCCESS;
}
//通知客户端等IRP_MJ_READ/WRITE的响应
IoMarkIrpPending(Irp);
//插入到Irq处理队列链头

ExInterlockedInsertTailList(
&device_extension->list_head,
&Irp->Tail.Overlay.ListEntry,
&device_extension->list_lock
);

//触发线程事件
KeSetEvent(
&device_extension->request_event,
(KPRIORITY) 0,
FALSE
);
//返回等待处理响应
return STATUS_PENDING;
}

     从上面的代码可以方便的看出FileDisk驱动的IRP序列化的实现过程,方法很简单,将IRP包保存在List_head连表中,同时把与之相对应的自反锁保存在list_lock当中,在利用request_event事件通知驱动处理IRP.

时间: 2024-10-22 10:22:53

FileDisk 线程方式进行IRP序列化的相关文章

.NET 三种 序列化方式

1. XML Serializer.这个是 ASP.NET 中 Web Service SOAP 请求的发送和接受默认使用的方式.指序列化对象的公共属性和成员. 2. SOAP Serializer . DotNet Remoting 使用的对象传送方式.这个时候传送的对象要求有 Serializable 标志. 3. BinarySerializer .同2, 只不过是二进制格式. 代码示例: 考虑一个 Person 对象,会有一些属性比如fullname,唯一 ID,电话(最多三个.) [S

Java创建线程的两种方式_java

前言 多线程是我们开发过程中经常遇到的,也是必不可少需要掌握的.当我们知道需要进行多线程开发时首先需要知道的自然是如何实现多线程,也就是我们应该如何创建线程. 在Java中创建线程和创建普通的类的对象操作是一样的,我们可以通过两种方式来创建线程: 1.继承Thread类,并重写run()方法. 2.实现Runnable接口,并实现run()方法. 方法一:继承Thread类 代码非常简单 首先重载一个构造函数,以便我们可以给线程命名. 重写run()方法. 这里我们先让线程输出线程名+start

java常见的序列化方式_java

在远程调用中,需要把参数和返回值通过网络传输,这个使用就要用到序列化将对象转变成字节流,从一端到另一端之后再反序列化回来变成对象. 既然前面有一篇提到了hessian,这里就简单讲讲Java序列化和hessian序列化的区别. 首先,hessian序列化比Java序列化高效很多,而且生成的字节流也要短很多.但相对来说没有Java序列化可靠,而且也不如Java序列化支持的全面.而之所以会出现这样的区别,则要从它们的实现方式来看. 先说Java序列化,具体工作原理就不说了,Java序列化会把要序列化

FileDisk 源代码

转自:http://www.ccgcn.com/bbs/redirect.php?tid=974&goto=lastpost FileDisk.h FileDisk 是把一个镜像文件Mount成一个卷fileDisk.h中包含以下内容1.OPEN_FILE_INFORMATION结构 复制内容到剪贴板 代码: typedef struct _OPEN_FILE_INFORMATION {    LARGE_INTEGER   FileSize;    //镜像文件的大小,并不一定是到文件尾. 

Qt之线程基础

何为线程 线程与并行处理任务息息相关,就像进程一样.那么,线程与进程有什么区别呢?当你在电子表格上进行数据计算的时候,在相同的桌面上可能有一个播放器正在播放你最喜欢的歌曲.这是一个两个进程并行工作的例子:一个进程运行电子表格程序:另一个进程运行一个媒体播放器.这种情况最适合用多任务这个词来描述.进一步观察媒体播放器,你会发现在这个进程内,又存在并行的工作.当媒体播放器向音频驱动发送音乐数据的时候,用户界面上与之相关的信息不断地进行更新.这就是单个进程内的并行线程. 那么,并发是如何实现的呢?在单

Android实现圆形图片的两种方式_Android

在项目中,我们经常会用到圆形图片,但是android本身又没有提供,那我只能我们自己来完成. 第一种方式,自定义CircleImageView: public class CircleImageView extends ImageView { private static final ScaleType SCALE_TYPE = ScaleType.CENTER_CROP; private static final Bitmap.Config BITMAP_CONFIG = Bitmap.Con

如何中断JAVA线程

如何中断JAVA线程 程序是很简易的.然而,在编程人员面前,多线程呈现出了一组新的难题,如果没有被恰当的解决,将导致意外的行为以及细微的.难以发现的错误.       在本篇文章中,我们针对这些难题之一:如何中断一个正在运行的线程.                                                                                      背景     中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切,

Java多线程编程基础之线程对象

在进入java平台的线程对象之前,基于基础篇(一)的一些问题,我先插入两个基本概念. [线程的并发与并行] 在单CPU系统中,系统调度在某一时刻只能让一个线程运行,虽然这种调试机制有多种形式(大多数是时间片轮巡为主),但无论如何,要通过不断切换需要运行的线程让其运行的方式就叫并发(concurrent).而在多CPU系统中,可以让两个以上的线程同时运行,这种可以同时让两个以上线程同时运行的方式叫做并行(parallel). 在上面包括以后的所有论述中,请各位朋友谅解,我无法用最准确的词语来定义储

C#实现远程线程插入

使用.NET可以实现远程线程插入吗? 使用严格的C#,不借助任何其它技术.远程线程插入是不能在.NET平台上实现的.然而在shellcode技术和远程线程插入之代码插入的基础上.完全可以实现基于.NET平台的混合型远程线程插入. 最终效果是这样的:用于将线程插入到其它进程的可执行程序是.NET程序(混合几百字节的机器码),用于被插入到其它进程的DLL或EXE也是纯.NET实现的. 可被插入的对象是所有有权限进程WriteProcessMemory操作的本机进程. 实现C#下的远程线程插入需要的技