The Logical Volume Device Driver (LVDD) is a pseudo-device driver that operates on logical volumes through the /dev/lvn special file. Like the physical disk device driver, this pseudo-device driver provides character and block entry points with compatible arguments. Each volume group has an entry in the kernel device switch table. Each entry contains entry points for the device driver and a pointer to the volume group data structure. The logical volumes of a volume group are distinguished by their minor numbers.
Attention: Each logical volume has a control block located in the first 512 bytes. Data begins in the second 512-byte block. Care must be taken when reading and writing directly to the logical volume, such as when using applications that write to raw logical volumes, because the control block is not protected from such writes. If the control block is overwritten, commands that use it can no longer be used.
Character I/O requests are performed by issuing a read or write request on a /dev/rlvn character special file for a logical volume. The read or write is processed by the file system SVC handler, which calls the LVDD ddread or ddwrite entry point. The ddread or ddwrite entry point transforms the character request into a block request. This is done by building a buffer for the request and calling the LVDD ddstrategy entry point.
Block I/O requests are performed by issuing a read or write on a block special file /dev/lvn for a logical volume. These requests go through the SVC handler to the bread or bwrite block I/O kernel services. These services build buffers for the request and call the LVDD ddstrategy entry point. The LVDD ddstrategy entry point then translates the logical address to a physical address (handling bad block relocation and mirroring) and calls the appropriate physical disk device driver.
On completion of the I/O, the physical disk device driver calls the iodone kernel service on the device interrupt level. This service then calls the LVDD I/O completion-handling routine. Once this is completed, the LVDD calls the iodone service again to notify the requester that the I/O is completed.
The LVDD is logically split into top and bottom halves. The top half contains the ddopen, ddclose, ddread, ddwrite, ddioctl, and ddconfig entry points. The bottom half contains the ddstrategy entry point, which contains block read and write code. This is done to isolate the code that must run fully pinned and has no access to user process context. The bottom half of the device driver runs on interrupt levels and is not permitted to page fault. The top half runs in the context of a process address space and can page fault.
The interface to the ddstrategy entry point is one or more logical buf structures in a list. The logical buf structure is defined in the /usr/include/sys/buf.h file and contains all needed information about an I/O request, including a pointer to the data buffer. The ddstrategy entry point associates one or more (if mirrored) physical buf structures (or pbufs) with each logical buf structure and passes them to the appropriate physical device driver.
The pbuf structure is a standard buf structure with some additional fields. The LVDD uses these fields to track the status of the physical requests that correspond to each logical I/O request. A pool of pinned pbuf structures is allocated and managed by the LVDD.
There is one device switch entry for each volume group defined on the system. Each volume group entry contains a pointer to the volume group data structure describing it.
The top half of the LVDD contains the code that runs in the context of a process address space and can page fault. It contains the following entry points:
|ddopen||Called by the file system when a logical volume is mounted, to open the logical volume specified.|
|ddclose||Called by the file system when a logical volume is unmounted, to close the logical volume specified.|
|ddconfig||Initializes data structures for the LVDD.|
|ddread|| Called by the read subroutine to translate character I/O requests to block I/O requests. This entry point verifies that the request is on a 512-byte boundary and is a multiple of 512 bytes in length.
When a character request spans partitions or logical tracks (32 pages of 4K bytes each), the LVDD ddread routine breaks it into multiple requests. The routine then builds a buffer for each request and passes it to the LVDD ddstrategy entry point, which handles logical block I/O requests.
If the ext parameter is set (called by the readx subroutine), the ddread entry point passes this parameter to the LVDD ddstrategy routine in the b_options field of the buffer header.
|ddwrite||Called by the write subroutine to translate character I/O requests to block I/O requests. The LVDD ddwrite routine performs the same processing for a write request as the LVDD ddread routine does for read requests.|
|ddioctl|| Supports the following operations:
The bottom half of the device driver supports the ddstrategy entry point. This entry point processes all logical block requests and performs the following functions:
The bottom half of the LVDD runs on interrupt levels and, as a result, is not permitted to page fault. The bottom half of the LVDD is divided into the following three layers:
Each logical I/O request passes down through the bottom three layers before reaching the physical disk device driver. Once the I/O is complete, the request returns back up through the layers to handle the I/O completion processing at each layer. Finally, control returns to the original requestor.
The strategy layer deals only with logical requests. The ddstrategy entry point is called with one or more logical buf structures. A list of buf structures for requests that are not blocked are passed to the second layer, the scheduler.
The scheduler layer schedules physical requests for logical operations and handles mirroring and the MWC cache. For each logical request the scheduler layer schedules one or more physical requests. These requests involve translating logical addresses to physical addresses, handling mirroring, and calling the LVDD physical layer with a list of physical requests.
When a physical I/O operation is complete for one phase or mirror of a logical request, the scheduler initiates the next phase (if there is one). If no more I/O operations are required for the request, the scheduler calls the strategy termination routine. This routine notifies the originator that the request has been completed.
The scheduler also handles the MWC cache for the volume group. If a logical volume is using mirror write consistency, then requests for this logical volume are held within the scheduling layer until the MWC cache blocks can be updated on the target physical volumes. When the MWC cache blocks have been updated, the request proceeds with the physical data write operations.
When MWC is being used, system performance can be adversely affected. This is caused by the overhead of logging or journalling that a write request is active in a logical track group (LTG) (32 4K-byte pages or 128K bytes). This overhead is for mirrored writes only. It is necessary to guarantee data consistency between mirrors particularly if the system crashes before the write to all mirrors has been completed.
Mirror write consistency can be turned off for an entire logical volume. It can also be inhibited on a request basis by turning on the NO_MWC flag as defined in the /usr/include/sys/lvdd.h file.
The physical layer of the LVDD handles startup and termination of the physical request. The physical layer calls a physical disk device driver's ddstrategy entry point with a list of buf structures linked together. In turn, the physical layer is called by the iodone kernel service when each physical request is completed.
This layer also performs bad-block relocation and detection/correction of bad blocks, when necessary. These details are hidden from the other two layers.
Physical disk device drivers adhere to the following criteria if they are to be accessed by the LVDD:
Note: For write requests, the LVDD attempts to hardware-relocate the bad block. If this is unsuccessful, then the block is software-relocated. For read requests, the information is recorded and the block is relocated on the next write request to that block.
Serial DASD Subsystem Device Driver.
The buf structure.
The lvdd special file.
The write subroutine, readx subroutine.
The iodone kernel service, the bread kernel service, bwrite kernel services.