The bio structureThe basic container for block I/O within the kernel is the bio structure, which is defined in <linux/bio.h>. This structure represents block I/O operations that are in flight (active) as a list of segments. A segment is a chunk of a buffer that is contiguous in memory. Thus, individual buffers need not be contiguous in memory. By allowing the buffers to be described in chunks, the bio structure provides the capability for the kernel to perform block I/O operations of even a single buffer from multiple locations in memory. Vector I/O such as this is called scatter-gather I/O. Here is struct bio, defined in <linux/bio.h>, with comments added for each field: struct bio { sector_t bi_sector; /* associated sector on disk */ struct bio *bi_next; /* list of requests */ struct block_device *bi_bdev; /* associated block device */ unsigned long bi_flags; /* status and command flags */ unsigned long bi_rw; /* read or write? */ unsigned short bi_vcnt; /* number of bio_vecs off */ unsigned short bi_idx; /* current index in bi_io_vec */ unsigned short bi_phys_segments; /* number of segments after coalescing */ unsigned short bi_hw_segments; /* number of segments after remapping */ unsigned int bi_size; /* I/O count */ unsigned int bi_hw_front_size; /* size of the first mergeable segment */ unsigned int bi_hw_back_size; /* size of the last mergeable segment */ unsigned int bi_max_vecs; /* maximum bio_vecs possible */ struct bio_vec *bi_io_vec; /* bio_vec list */ bio_end_io_t *bi_end_io; /* I/O completion method */ atomic_t bi_cnt; /* usage counter */ void *bi_private; /* owner-private method */ bio_destructor_t *bi_destructor; /* destructor method */ }; The primary purpose of a bio structure is to represent an in-flight block I/O operation. To this end, the majority of the fields in the structure are housekeeping related. The most important fields are bi_io_vecs, bi_vcnt, and bi_idx. Figure 13.2 shows the relationship between the bio structure and its friends. Figure 13.2. Relationship between struct bio, struct bio_vec, and struct page.The bi_io_vecs field points to an array of bio_vec structures. These structures are used as lists of individual segments in this specific block I/O operation. Each bio_vec is treated as a vector of the form <page, offset, len>, which describes a specific segment: the physical page on which it lies, the location of the block as an offset into the page, and the length of the block starting from the given offset. The full array of these vectors describes the entire buffer. The bio_vec structure is defined in <linux/bio.h>: struct bio_vec { /* pointer to the physical page on which this buffer resides */ struct page *bv_page; /* the length in bytes of this buffer */ unsigned int bv_len; /* the byte offset within the page where the buffer resides */ unsigned int bv_offset; }; In each given block I/O operation, there are bi_vcnt vectors in the bio_vec array starting with bi_io_vecs. As the block I/O operation is carried out, the bi_idx field is used to point to the current index into the array. In summary, each block I/O request is represented by a bio structure. Each request comprises one or more blocks, which are stored in an array of bio_vec structures. These structures act as vectors and describe each segment's location in a physical page in memory. The first segment in the I/O operation is pointed to by b_io_vec. Each additional segment follows after the first, for a total of bi_vcnt segments in the list. As the block I/O layer submits segments in the request, the bi_idx field is updated to point to the current segment. The bi_idx field is used to point to the current bio_vec in the list, which helps the block I/O layer keep track of partially completed block I/O operations. A more important usage, however, is to allow the splitting of bio structures. With this feature, drivers such as RAID (Redundant Array of Inexpensive Disks, a hard disk setup that allows single volumes to span multiple disks for performance and reliability purposes) can take a single bio structure, initially intended for a single device, and split it up among the multiple hard drives in the RAID array. All the RAID driver needs to do is copy the bio structure and update the bi_idx field to point to where the individual drive should start its operation. The bio structure maintains a usage count in the bi_cnt field. When this field reaches zero, the structure is destroyed and the backing memory is freed. Two functions, which follow, manage the usage counters for you. void bio_get(struct bio *bio) void bio_put(struct bio *bio) The former increments the usage count, whereas the latter decrements the usage count (and, if the count reaches zero, destroys the bio structure). Before manipulating an in-flight bio structure, be sure to increment its usage count to make sure it does not complete and deallocate out from under you. When you're finished, decrement the usage count in turn. Finally, the bi_private field is a private field for the owner (that is, creator) of the structure. As a rule, you can read or write this field only if you allocated the bio structure. The Old Versus the NewThe difference between buffer heads and the new bio structure is important. The bio structure represents an I/O operation, which may include one or more pages in memory. On the other hand, the buffer_head structure represents a single buffer, which describes a single block on the disk. Because buffer heads are tied to a single disk block in a single page, buffer heads result in the unnecessary dividing of requests into block-sized chunks, only to later reassemble them. Because the bio structure is lightweight, it can describe discontiguous blocks, and does not unnecessarily split I/O operations. Switching from struct buffer_head to struct bio provided other benefits, as well:
The concept of buffer heads is still required, however; buffer heads function as descriptors, mapping disk blocks to pages. The bio structure does not contain any information about the state of a bufferit is simply an array of vectors describing one or more segments of data for a single block I/O operation, plus related information. In the current setup, the buffer_head structure is still needed to contain information about buffers while the bio structure describes in-flight I/O. Keeping the two structures separate allows each to remain as small as possible. |