I/O Request Packet (IRP)

An I/O Request Packet (IRP) is a data structure that the I/O Manager uses to manage I/O operations. It contains all the information necessary to perform an I/O operation, from the time a user-mode application initiates the request to the time the request is completed by a device driver.

Structure of an IRP

An IRP is a complex structure that can be thought of as a container for I/O-related information. Key components include:

IRP Stack Location

Each driver that processes an IRP is given a "stack location" within the IRP. This stack location contains:

Common IRP Major Function Codes

The following table lists some of the most common IRP major function codes:

Code Name Description
IRP_MJ_CREATE Create Creates a new file or opens an existing one.
IRP_MJ_READ Read Reads data from a device.
IRP_MJ_WRITE Write Writes data to a device.
IRP_MJ_DEVICE_CONTROL Device Control Performs device-specific operations.
IRP_MJ_CLOSE Close Closes a file or handle.
IRP_MJ_CLEANUP Cleanup Performs cleanup operations before closing a file.
IRP_MJ_PNP Plug and Play Handles Plug and Play events.
IRP_MJ_POWER Power Management Handles power management events.
Note: Drivers typically handle a subset of these function codes relevant to their functionality. The I/O Manager passes the IRP down the driver stack.

IRP Processing Flow

  1. An application or system component initiates an I/O request.
  2. The I/O Manager creates an IRP and populates its initial stack location for the top-most driver.
  3. The I/O Manager passes the IRP to the driver's dispatch routine.
  4. The driver processes the request, potentially performs some work, and then passes the IRP down to the next driver in the stack using IoCallDriver.
  5. This continues until the lowest driver in the stack completes the operation.
  6. As the IRP returns up the stack, each driver can perform post-processing or call its completion routine.
  7. Finally, the I/O Manager marks the IRP as completed and informs the requesting application.

Creating and Managing IRPs

Kernel-mode drivers use functions provided by the I/O Manager to create, allocate, and manage IRPs. Key functions include:

Example: Allocating an IRP

PIRP AllocateAndInitializeIrp(
    IN CCHAR StackSize
)
{
    PIRP Irp;
    PIO_STACK_LOCATION IrpSp;

    Irp = IoAllocateIrp(StackSize, NULL);
    if (Irp == NULL) {
        return NULL;
    }

    IrpSp = IoGetNextIrpStackLocation(Irp);

    // Initialize Stack Location parameters here...
    // IrpSp->MajorFunction = IRP_MJ_READ;
    // IrpSp->Parameters.Read.Length = ...;
    // IrpSp->Parameters.Read.Key = ...;
    // IrpSp->Parameters.Read.ByteOffset = ...;

    return Irp;
}
                

Canceling IRPs

Drivers can implement cancellation logic to abort I/O operations that are in progress. This is typically done by setting a CancelRoutine in the IRP's stack location and calling IoSetCancelRoutine.

Understanding IRPs is fundamental to developing robust and efficient device drivers in the Windows kernel.