Level 5 · Chapter 2

The I/O Manager

The dispatcher that wraps every kind of I/O request in one standard format, so the same machinery works across files, devices, and pipes alike.

The I/O system introduced the IRP as the standard unit of work. This chapter is about the component that actually creates, routes, and completes them: the I/O Manager.

One request format for wildly different targets

The genuinely useful design decision underneath the I/O Manager: a file read, a write to a named pipe, an ioctl sent to a custom hardware device, and a request to a network driver are all represented the same way — as an IRP, carrying a request type, target device object, buffers, and status. This uniformity is exactly what lets the same core kernel machinery dispatch to filesystems, storage drivers, network drivers, and arbitrary third-party hardware drivers without needing type-specific routing logic for each — the I/O Manager doesn't need to know what a "file" or a "pipe" conceptually is, only how to hand an IRP to the device object responsible for it.

Building, routing, and completing

Concretely, the I/O Manager's job splits into three phases:

  1. Build. Translate a user-mode API call (via Ntdll) into a fully-populated IRP — target device, operation type, buffers, and any relevant flags.
  2. Route. Hand the IRP to the top of the relevant device stack. Each driver in the stack has registered dispatch routines — entry points for specific IRP types — and the I/O Manager calls into whichever one applies, then (depending on what that driver does) either the request completes there or gets forwarded further down the stack.
  3. Complete. Once the request reaches wherever it's actually going to be satisfied, results and status flow back up through the stack via a completion path, eventually reaching the original caller.

Why this design tolerates deep, arbitrary stacking

Because every layer only has to know how to handle the specific IRP types it cares about — forwarding anything else unchanged to the next driver down — Windows can insert new layers into an existing device stack (a filter driver for antivirus scanning, encryption, or auditing, say) without the layers above or below needing any awareness that the new one exists. This is a direct, practical consequence of the I/O Manager's uniform IRP model: a filter driver just becomes one more stop an IRP passes through, indistinguishable in kind from the drivers that were already there.

A worked example: why the same API works across such different targets

ReadFile in Win32 works — with the same function signature and broadly the same semantics — whether the handle refers to an ordinary disk file, a named pipe, or a serial port. That's not a coincidence or convenient overloading in the Win32 layer; it's a direct reflection of the fact that, underneath, all three become the same kind of IRP, routed by the same I/O Manager, to whichever device stack happens to be registered for that particular kind of target. The application-level uniformity is a visible consequence of the kernel-level uniformity described in this chapter.

A common mistake

It's easy to think of the I/O Manager as itself doing the actual work of, say, reading a file — as if it contained filesystem or device-specific logic. It deliberately doesn't: it's exclusively a builder and router. All the actual domain-specific behavior — how NTFS lays out files, how a specific storage controller talks to its hardware — lives in the drivers the I/O Manager hands IRPs to, never in the I/O Manager itself. Conflating "the I/O Manager routed this request" with "the I/O Manager understood or executed this request" misses the entire point of the layering.

Where this connects

  • Drivers & device stacks covers the different roles (bus, function, filter) the drivers receiving these IRPs actually play.
  • File systems is one specific, heavily-used consumer of exactly this IRP-routing machinery.