Common IO Request Types


Common I/O Request Types

The fundamental issue in designing your driver to process I/O is to determine which request types the driver must handle, which request types it sends down the device stack, and which request types the framework can handle on the driver's behalf.

The most common I/O requests that applications issue are create, close, read, write, and device I/O control.

Create Requests

An application typically opens a file, directory, or device by calling the Windows CreateFile function. If the request succeeds, the system returns a file handle through which the application can perform I/O. The file handle is specific to the process-not the thread-that created it. The application provides the file handle in all subsequent I/O requests to identify the target of the request.

Whenever an application attempts to open a file handle, the Windows I/O manager creates a file object and sends a create request to the target device stack. When WDF receives the create request, it typically creates a WDF file object that corresponds to the I/O manager's file object. Neither the WDF file object nor the I/O manager's file object necessarily represents a file on the physical device, despite the name. Instead, the file object provides a way for the driver to track the established session with the application and for the application to specify which device interface to open.

A driver can opt to receive and handle create requests or it can let the framework handle them on the driver's behalf. Remember that multiple processes can have handles to the same file object, so more than one process can use a file simultaneously. A file can have multiple simultaneous users if a child process inherits a handle from its parent process or if a process duplicates a handle from another process. However, the file handle still represents a single session. An application that shares a file handle shares its session with another application.

Cleanup and Close Requests

An application typically calls the Windows CloseHandle function when it no longer requires a file handle. In response, the I/O manager decrements the handle count for the associated file object. After all handles to the file object have been closed, the I/O manager sends a cleanup request to the driver. In response to the cleanup request, the driver should cancel all outstanding I/O requests for the file object. Although no handles remain open when the driver receives the cleanup request, outstanding references might still exist on the file object, such as those caused by a pending IRP.

After the object's reference count reaches zero and all the I/O for the file is complete, the I/O manager sends a close request to the driver.

image from book
CloseHandle and Cleanup

To user-mode developers, it sometimes comes as a surprise that CloseHandle does not result in a close request in their driver, but instead results in a cleanup request. I wish there was a different name for IRP_MJ_CLOSE to avoid this confusion-say IRP_MJ_FINALIZE.

When the application closes the handle (assuming this was the only outstanding handle), your driver receives a cleanup request, which just means that the file object has no more outstanding clients. So all the I/O for that file object can be canceled. Thus, cleanup serves as a bulk cancel to give the driver the opportunity to efficiently cancel all outstanding I/O for a file.

When all the I/O for the file has completed and the reference count on the file object is zero, the driver receives a close request, at which point the driver can safely deallocate any resources that it allocated for the file.

For kernel-mode drivers, there is another reason why Windows supports both cleanup and close. The cleanup request is guaranteed to arrive in the context of the calling process, so that driver can perform cleanup actions in the session's context space. The context in which close requests arrive is completely arbitrary.
-Praveen Rao, Windows Driver Foundation Team, Microsoft

image from book

Read and Write Requests

An application typically issues a read request by calling the Windows ReadFile function and issues a write request by calling the WriteFile function. An application issues read and write requests to retrieve data from, or provide data to, a device through a particular file handle. Each read request includes a buffer in which the driver returns the requested data, and each write request includes a buffer that contains the data to be written. The application describes each data buffer by specifying a pointer to the buffer and the buffer's length in bytes.

The I/O manager builds an IRP that describes the request and sets up buffers for buffered or direct I/O, depending on the I/O transfer type for the device stack. The device's drivers then handle the request.

Because some devices can satisfy a read or write request by transferring fewer bytes than the application's data buffer specifies, the system returns to the application the number of bytes that were transferred as a result of a successful read or write operation.

Device I/O Control Requests

Applications issue device I/O control requests by using the Windows DeviceIoControl function. Such requests are also called "device controls," "I/O controls," or simply "IOCTLs." Kernel-mode components can also define and use internal device I/O control requests-sometimes called private IOCTLs. User-mode applications and drivers cannot issue internal device I/O control requests.

Device I/O control requests describe operations that cannot be easily represented in terms of read or write requests. For example, a driver for a CD-ROM device might provide a way for an application to open or close the drive door. Similarly, the Fx2_Driver and Osrusbfx2 samples support a request through which an application can control the light bar on the USB Fx2 device.

When an application issues a device I/O control request, it supplies a control code that identifies the operation to perform. Windows defines numerous standard control codes, which are typically specific to a particular device class. For example, Windows defines standard control codes for controlling CD and DVD devices, including opening and closing their drive doors. Drivers can also define custom control codes that can be used to control nonstandard devices or to control nonstandard aspects of a standard device's behavior. For example:

  • The Fx2_Driver and Osrusbfx2 samples are examples of a driver for a nonstandard device that defines custom control codes to allow an application to control various aspects of its device's behavior.

  • A CD-ROM driver that provides custom control codes to control a unique set of lights or indicators is an example of a driver for a standard device that would use custom control codes.

Device I/O control requests are different from read and write requests in several important ways in addition to the control code previously mentioned:

  • The I/O transfer type is encoded into the control code and is not required to be the same for every I/O control request that a driver supports.

    All read and write requests for a device must use the same transfer type.

  • An application can specify both an input buffer and an output buffer for each request.

    Although device I/O control requests always have parameters for both input and output buffers, not every control code requires both buffers to be specified. In fact, some device I/O control codes-such as the standard control code used to close the door on a CD or DVD device-do not require any buffers at all.

  • The output buffer on a device I/O control request can be used for additional input instead of output in some circumstances.

image from book
Validating I/O Control Codes

In my early days, when I was working on the disk and CD-ROM drivers, I changed some code in the storage class driver to handle device I/O controls more gracefully. The storage I/O controls had some duplication, and the same command was defined as an I/O control for both a disk and a CD-ROM. The control code includes the device type, so the control codes weren't the same numerical value, which made the processing harder.

So I split the I/O control code up into its component parts (method, function, access, and device) and then threw away the "device" portion and proceeded to check based only on function code.

This introduced a security bug. An attacker could open the device for no access, and then issue a storage I/O control with the access flags zeroed in the code. The I/O manager would allow the command through-because the control code indicated that it didn't require any privileges-but my driver would still process it.

I'm happy that we found this before we shipped the system. It's the sort of mistake you only make once.
-Peter Wieland, Windows Driver Foundation Team, Microsoft

image from book

Summary of I/O Request Types

Each I/O request type is associated with an IRP major function code. When the system receives a request from an application, the I/O manager packages the request into an IRP and sends the IRP to the drivers for the device. I/O requests from applications always start at the top of the device stack for a device, so that all drivers in the stack have the opportunity to process them.

The Windows I/O manager uses IRPs to transmit other types of requests in addition to requests for device I/O. WDF supports the most common IRPs. Table 8-1 lists all the types of IRPs that WDF supports.

Table 8-1: Types of IRPs that WDF Supports
Open table as spreadsheet

WDM IRP major function code

Comments

IRP_MJ_CLEANUP

Supported through immediate callbacks on a file object; not queued.

IRP_MJ_CLOSE

Supported through immediate callbacks on a file object; not queued.

IRP_MJ_CREATE

Supported through queues for both KMDF and UMDF, and through immediate callbacks on a device object for KMDF only.

IRP_MJ_DEVICE_CONTROL

Supported through queues.

IRP_MJ_INTERNAL_DEVICE_CONTROL

Supported through queues for KMDF only.

IRP_MJ_PNP

Supported through state-specific callbacks on a device object.

IRP_MJ_POWER

Supported through state-specific callbacks on a device object.

IRP_MJ_READ

Supported through queues.

IRP_MJ_SHUTDOWN

Supported for control (non-Plug and Play) device objects in KMDF only.

IRP_MJ_SYSTEM_CONTROL

Supported through WMI objects in KMDF only.

IRP_MJ_WRITE

Supported through queues.

Chapter 7, "Plug and Play and Power Management," describes state-specific callbacks on a device object. Chapter 14, "Beyond the Frameworks," describes how KMDF drivers can handle additional types of IRPs by escaping from the framework.




Developing Drivers with the Microsoft Windows Driver Foundation
Developing Drivers with the Windows Driver Foundation (Pro Developer)
ISBN: 0735623740
EAN: 2147483647
Year: 2007
Pages: 224

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net