编写虚拟Storport小端口驱动程序

<!-- @page { margin: 2cm } P { margin-bottom: 0.21cm } STRONG.ctl { font-weight: normal } -->

Writing a Virtual Storport Miniport Driver
The NT Insider, Volume 16, Issue 3, Sept-Oct 2009 | Published: 29-Sep-09| Modified: 29-Sep-09

 

 

编写虚拟 Storport 小端口驱动程序

 

 

The NT Insider 》第16 卷第3 2009

Storport is a welcome relief to storage driver writers wishing to develop a driver that exports a virtual device. Until the advent of Storport, driver writers were forced to either modify/hack a SCSIport miniport driver or create a full SCSI port driver. The miniport approach was complicated (due to locking issues), unsupported, hard to maintain, and mostly provided poor performance. The full SCSI port driver approach had the advantage of providing good performance, but was exceptionally difficult to write and was also neither supported nor eligible for the Designed for Windows logo. Thus, development in this area was limited to companies and individuals who were willing to take chances, accept the inherent complexities, and forgo WHQL certification.

在开发具备导出虚拟设备功能的驱动程序时, Storport 由于能够减轻开发负担而被存储驱动开发人员欢迎。在 Storport 出现前,驱动程序开发人员在面对以上任务时只有两种选择,一种是修改或者 Hack 一个 SCSIport 小端口驱动程序,要不就是创建一个完整的 SCSI 端口程序。小端口程序的方案比较复杂,无法得到支持,难于维护的,并且可能性能也不好。完全编写 SCSI 驱动的方案具有高性能的优势,但是存杂在意想不到的困难,并且对于 Windows 徽标计划,也是既不可相信也不支持的。因此,在这个领域的开发一直限制在那些愿意承受风险、接受与生俱来的复杂度,并且不考虑 WHQL 认证。

Storport, introduced in Windows Server 2003, was created to deliver the performance needed in RAID and SAN environments that the existing SCSIport driver was not capable of. As of Windows Vista SP1 and Server 2008, Microsoft provided an update to Storport, which enabled support for Storport virtual miniport drivers. This addition allows storage driver developers to finally have a supported model for exporting virtual devices.

Storport 首先出现在 Windows Server 2003 中,可以提供 RAID SAN 环境下需要的高性能,而之前的 SCSIport 驱动是无法获得该这种性能的。在 Windows Vista SP1 Windows Server2008 中,微软对 Storport 进一步升级,可以支持 Storport 虚拟小端口程序,该扩展使得 Storport 驱动开发人员最终获得一种导出虚拟设备的支持模型。

The Storport model is very good model for a virtual miniport driver. It provides I/O queue management (e.g. queue depth, holding off I/Os when queue depth is reached), some I/O error handling (e.g. resets, some retries), all the operations necessary to handle PnP device (LUN) starting and stopping, and all the bus driver duties. One thing that it does not provide is help in hardware management (we're implementing a virtual miniport remember!), since there is no hardware assumed to be present. This means that virtual miniport is totally responsible for handling the I/O request. While this may sound daunting, remember that as a virtual miniport you have the full set of Kernel APIs and other drivers in the system to help you perform your work.

Storport 对于虚拟小端口驱动是一个非常优秀的模型,包括提供 I/O 队列管理 ( 比如当达到队列深度时,停止 I/O),I/O 错误处理 ( 比如 reset,retry), 所有处理 Pnp 设备 (LUN) 启动和停止的必要操作,以及所有总线驱动的工作。该模型不提供对硬件管理的帮助(记住,我们正在实现一个虚拟小端口!),因为假设没有硬件。这就意味着虚拟小端口驱动要负责处理所有 I/O 请求。尽管听起来有点令人气馁,但记住针对虚拟小端口驱动,你可以通过内核 API 全集和系统中的其他驱动来帮助你实现相关工作。

This article "Writing a Virtual Storport Miniport Driver" is based upon the information we have gained at OSR while developing a Storport virtual miniport driver. This topic, which is too big to be described by just one The NT Insider article, will be discussed over a series of articles and will culminate in the presentation of a fully functional Storport virtual miniport driver. This first article in the series describes the architecture, flow of control, and key routines to be implemented when developing a virtual miniport.

这篇文章《编写虚拟 Storport 小端口驱动程序》主要基于 OSR 在开发 Storport 虚拟小端口驱动程序获得的知识。该话题如果作为单篇《 NT Insider 》文章来说篇幅过长,因此将作为一系列文章进行讨论,并且最终展现出一个完整功能的 Storport 虚拟小端口驱动程序。该系列的首篇文章将描述开发一个虚拟端口驱动程序的架构,控制流,以及主要例程。

OSR would like to that James Antognini and Albert Chen from Microsoft for providing us with the information needed to produce the Storport virtual miniport. Without their help it would have taken awhile for information on writing one to be published.

微软的 James Antognini Albert Chen 为我们提供了创建 Storport 虚拟小端口需要的信息, OSR 表示感谢,没有他们的帮助将无法得到相关信息用于编写程序和发布。

Getting Started with Storport

Storport 入门

For those of you who have never worked with Storport before let's go over some basics. When working with the Storport model, we develop a driver that interfaces to the Storport driver (Storport.sys) through a defined set of APIs and data structures; it is not an IRP based interface. Similar to the SCSI port/miniport model, the Storport driver, called a Port Driver, provides the environment that we operate in, and support routines that our miniport driver needs, in order to make our adapter available to the Windows storage subsystem. The adapter is assumed to be a device (virtual or physical), which can control one or more SCSI buses and one or more SCSI devices. We call our driver, developed for this model, a miniport driver. Figure 1 illustrates the Storport model.

对于那些没有使用过 Storport 的人们,首先让我们了解相关基础知识。使用 Storport 模型,我们开发一个驱动程序通过接口实现与 Storport 驱动程序( Storport.sys )的交互,该接口包括一组预先定义的 API 和数据结构,注意这不是基于接口的 IRP 。和 SCSI 端口 / 小端口模型相似, Storport 驱动程序被称为端口驱动程序,提供操作需要的运行环境支持,以及小端口驱动程序需要的支持例程,以实现我们的适配器可以在 Windows 存储子系统中可用的目标。适配器定义为一个设备(虚拟或者物理的),该设备能够控制一到多条 SCSI 总线以及一到多个 SCSI 设备。我们承该模型中开发的驱动程序为小端口驱动程序。图 1 显示了 Storport 模型。

 


 

Figure 1 - Storport Driver Model
Adapted from The Windows Storage Driver Stack in Depth (Microsoft WinHEC 2006)

1 Storport 驱动模型

改编自 < 深入 Windows 存储驱动栈 > (微软 WinHEC2006

A Storport miniport driver must conform to defined Storport rules in order to provide the services that the adapter, whether virtual or physical, offers to the operating system. Storport calls the miniport with SCSI_REQUEST_BLOCKS (SRBs) which describe the operation to be performed. Like an IRP, the SRB contains all the information that the miniport needs in order to perform the operation. It contains an operation code, buffers and parameters that describe the request. The driver performs the operation described in the SRB, puts the completion status into the SRB, and then notifies Storport when the request is completed. Again, this is not unlike how a normal driver handles an IRP.

不管是虚拟还是物理的适配器,为了能够向操作系统提供服务, Storport 小端口驱动必须遵循定义好的 Storport 规则。 Storport 驱动通过 SCSI_REQUEST_BLOCK(SRBs) 调用小端口驱动, SRB 描述了需要执行的操作。就像 IRP SRB 包含了小端口驱动执行操作时需要的所有信息。包括一个描述请求的操作码、缓冲区和参数。驱动程序执行 SRB 中描述的操作,将完成状态放入 SRB 中,然后在请求完成后通知 Storport 驱动。再次提醒,这不像处理 IRP 的普通驱动所做的。

The point here is that Storport does all the operations necessary to interact with the I/O Manager, PnP Manager and Power Manager, in order to make a device available to the system. How that is done is invisible to the miniport driver and it frees the developer to focus on providing the virtual adapter's services to Windows.

为了使得设备可以被系统使用, Storport 驱动封装了与 I/O Manager PnP Manager Power Manager 所有必须的交互操作。对于小端口驱动来说,这些都是不可见的。这将开发人员解脱出来,只需要关注于如何实现虚拟适配器本身的功能。

Designing our Virtual Miniport

虚拟小端口驱动的设计

As with any development project, a good project begins with a good design. Therefore when designing a virtual Storport miniport (we'll just refer to our driver as a miniport from now on), there are a few items that we need to think about, since they will impact how we define our driver. They are:

任何好的开发项目都是从好的设计开始的,因此在设计虚拟 Storport 小端口驱动(我们更愿意称为小端口驱动)时,需要考虑一些影响我们定义驱动的事项,如下:

  • Are the resources that we're exporting accessible locally or remotely?

  • 我们需要导出的可存取资源是本地还是远程的?

  • If remotely, how do we get to it? Via a network, or some other mechanism?

  • 如果是远程的,我们怎样得到它?通过网络,或者一些其他机制?

  • If locally, how do we get to it? Via another driver, kernel APIs, or a user mode entity?

  • 如果是本地,我们如何得到它?通过其他驱动,内核 API ,或者用户态下的实体。

  • Is our resource static or dynamic? If dynamic, how will the miniport be notified that it is present? For example, will the miniport be notified by another driver or some user mode component?

  • 我们的资源是静态还是动态的?如果是动态的,在资源出现是小端口驱动如何被通知?例如,小端口驱动可以被其他驱动或者用户态组件通知。

  • How are we going to process the requests we receive? Do they have to be performed synchronously or asynchronously? Can we use system worker threads, create our own thread pool, or is somebody else processing the request?

  • 我们准备怎样处理收到的请求?是同步还是异步执行?是否要使用系统工作线程,生成自有线程池,还是其他方式处理请求?

  • Handling Failure

  • 错误处理

Let's start a basic discussion of these items.

就这些事项我们展开一个基础讨论。

Accessing Resources

存取资源

While it may be obvious to some, our design is going to based upon how we get access to the resource that our virtual adapter is going to be exporting as a local SCSI device. If the resource is local then we'll have to decide whether we can use kernel APIs to access the resource (Zw calls, memory accesses, or IRP based requests), or if we have to communicate with a user mode application or service to get access to the resource. Likewise, if the resource is remote, we have to decide if we can communicate with it via the network or via some other driver that has access to the resource. That other driver could be for some special device that exports both network and SCSI functionality and exists as a virtual bus driver which creates a virtual PDO that our miniport will be loaded to handle.

尽管可能很明显,我们的设计是基于如何去存取资源,使得我们的虚拟适配器就好像一个本地 SCSI 设备。如果资源是本地的,我们将需要确定是否使用内核 API 去存取资源(通过 zw 调用,内存存取或者 IRP 请求),或者和一个用户态应用程序或者服务通信以存取资源。相反的,如果资源是远程的,我们要确定能够通过网络通信或者一些其他驱动存取资源。其他的驱动可能是针对一些特定表现为网络和 SCSI 功能的设备,并且作为虚拟总线驱动存在。这样虚拟总线驱动可以创建虚拟 PDO ,我们的小端口驱动就可以被装入并进行处理。

Static or Dynamic

静态或者动态

How a resource becomes accessible to Storport is worthy of discussion. There are 2 types of devices, static devices and dynamic devices. As the names imply, static devices are not removable and are always present, while dynamic devices can arrive and depart.

对于 Storport ,资源如何成为可存取是值得讨论的。存在两种类型的设备:静态设备和动态设备。正如名字所表示,静态设备不能被移除、总是存在的,而动态设备可以加入和移除。

If our devices are static then life is easy, and when called upon by Storport to enumerate our devices during initialization, all we have to do is describe our devices to Storport and we're golden. If on the other hand our devices are dynamic, then we'll need to have a way to know when those dynamic devices have arrived or have departed, and notify Storport of those occurrences.

如果我们的设备是静态的,则整个生命周期比较简单,在被 Storport 调用初始化时枚举我们的设备,我们要做得就是向 Storport 驱动描述我们的所有设备就好了。另一方面,如果我们的设备是动态的,我们需要有方法知道这些动态设备什么时候加入,什么时候移除了,并且及时通知 Storport

Processing Requests

处理请求

As with any other type of kernel driver, we need to be concerned about how we handle requests. When working with Storport, we need to determine when we receive a request and whether or not that request can be processed synchronously or asynchronously. If the request can be processed asynchronously, then our driver has to provide the means for this to be accomplished. All this really means is that we either have to use system work items, or create our own worker threads to provide the background processing and this probably implies that some queuing is involved.

对于其他类型的内核驱动,我们需要关心如何处理请求。而与 Storport 驱动协同工作,我们需要确定什么时候接收请求、请求是否同步或者异步处理。如果请求可以被异步处理,那么我们的驱动需要提供完成方式。完成方式可以通过系统工作线程,或者创建我么自己的工作线程在后台处理,那这可能又设计到一些队列处理。

When processing a request, our driver has to be very cognizant of what IRQL it is being called at. Unlike most device stacks, drivers working in the storage stack have to deal with the fact that their entry points can be called at IRQLs less than or equal to DISPATCH_LEVEL . So we have to make sure that the operations we need to be performed can be performed at that IRQL, or there is some way that we can process the request later on at some lower IRQL.

当处理一个请求时,我们的驱动需要非常清楚当前处于什么 IRQL 级别上。与大多数驱动栈不同,存储栈的驱动需要面对一个事实,调用入口点的 IRQL 可能小与等于 DISPATCH_LEVEL 所以我们需要确信执行操作能够在这些 IRQL 级别上运行,或者有其他方法可以晚些时候在较低级别的 IRQL 上处理这些请求。

Finally, we have to determine how the request is going to be performed. Are we performing the operation or are we passing the request to some other entity to perform the operation (e.g., another driver or a user-mode service)?

最后,我们需要确定请求将如何被指向。是我们指向操作好事将请求传递到其他实体上操作(比如其他驱动或者用户态服务)?

Handling Failure

错误处理

Failures in the storage stack are not well tolerated. Thus, when designing our driver we must ensure that we have all the resources necessary to process a request in place before initiating the request. In addition, if the resource is accessed across the network or via some other remote mechanism, we must consider the possibility that we may lose access to our device. Bad things can start happening; "Lost delayed write" messages come to mind....

在存储栈中不能很好的容错,因此在驱动设计时必须确认在初始化请求前已经获得了所有处理请求所需要的资源。另外,如果资源是通过网络或者其他远程机制进行存取的,我们必须考虑存取设备失败的可能。(***)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值