16.4.3 Using Zone Buffers

NT drivers that set up zone buffers for fast allocation of fixed-size blocks (also called entries) should use that memory economically.

NT driver writers who use the Ex..Zone routines should follow these design guidelines:

·Set up a modestly sized zone buffer. That is, make the zone buffer large enough for the driver to handle an average I/O demand for its device in a typical Windows NT machine, rather than setting up a fixed-size zone buffer large enough to handle a worst-case I/O-demand scenario on a high-end Windows NT platform.

When it initializes, the driver can call MmQuerySystemSize and MmIsThisAnNtAsSystem to get an estimate for sizing a zone buffer. MmQuerySystemSize returns a system-defined enumerated type, indicating whether the machine has a small, medium, or large amount of available memory. MmIsThisAnNtAsSystem returns TRUE if the current machine is a Windows NT server, which is likely both to have more memory available and to require a larger zone buffer to handle the I/O demand on the underlying driver(s)' device(s).

·If the driver allocates and frees zone buffer entries using the ExInterlocked..Zone routines, it must provide storage for an excutive spin lock and initialize the spin lock in its DriverEntry routine, as mentioned in Section 16.2.

·The driver should always call ExIsFullZone immediately preceding a call to ExInterlockedAllocateFromZone. Otherwise, the driver might tie up a processor for an extended interval by trying to acquire the spin lock that protects a zone with no free blocks.

·If the driver's call to ExAllocateFromZone returns a NULL pointer or its call to ExIsFullZone returns TRUE, the driver should call ExAllocatePool or ExAllocatePoolWithTag to obtain additional memory to use as zone entries. The driver can use this memory temporarily until some zone entries have been released by calls to ExFreeToZone or ExInterlockedFreeToZone. Then, the driver can call ExFreePool to release its temporary pool allocation since its zone buffer has free blocks again.

·The driver should not call ExExtendZone or ExInterlockedExtendZone, except possibly under the following circumstances:

·Its originally allocated zone buffer has no free blocks.

·It has already called ExAllocatePool or ExAllocatePoolWithTag more than once, but the driver is still using all the additional memory it has allocated from pool for zone entries.

Such a condition indicates a very heavy I/O demand for the driver's device, so extending its zone buffer might be worthwhile. That is, the performance gain from allocating additional zone blocks might allow the driver to process requests fast enough to compensate for its additional "permanent" demand on nonpaged pool, especially if extending the zone allows the driver to release some of the temporary memory it allocated with ExAllocatePool or ExAllocatePoolWithTag.

Note that an NT driver's successful call to ExExtendZone or ExInterlockedExtendZone allocates nonpaged pool that remains allocated to the driver until the system is rebooted. Consequently, any NT driver that calls ExExtendZone or ExInterlockedExtendZone whenever its zone buffer becomes full (that is, all entries are currently allocated), can eventually run out of nonpaged pool. Such a driver also can put the system into a low-memory state such that all I/O throughput becomes very slow, including the "memory-hogging" driver's.

For routine-specific information about the Ex..Zone routines, see the Kernel-Mode Driver Reference.