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.

你可能感兴趣的:(thread,IO,object,null,buffer,extension)