The previous chapter focuses on a series of questions about request queues. The following describes the request functions. First, let's talk about the hardware block device's request function.
The request function can return if all requests in the Request queue are not completed, or if one request is not completed.
The following is a routine of the Request function:
Static int simp_blkdev_make_request (struct request_queue * q, struct bio * bio) {struct bio_vec * bvec; int I; void * dsk_mem; If (bio-> bi_sector <9) + bio-> bi_size> simp_blkdev_bytes) {printk (kern_err simp_blkdev_diskname ": Bad request: block = % LlU, Count = % u \ n", (unsigned long) bio-> bi_sector, bio-> bi_size); // This condition is used to determine the current running kernel version. # If linux_version_code <kernel_version (2, 6, 24) bio_endio (Bio, 0,-EIO); # else bio_endio (Bio,-EIO); # endif return 0 ;} dsk_mem = simp_blkdev_data + (bio-> bi_sector <9); // traverse bio_for_each_segment (bvec, bio, I) {void * iovec_mem; Switch (bio_rw (bio )) {Case read: Case reada: iovec_mem = kmap (bvec-> bv_page) + bvec-> bv_offset; memcpy (iovec_mem, dsk_mem, bvec-> bv_len ); kunmap (bvec-> bv_page); break; Case write: iovec_mem = kmap (bvec-> bv_page) + bvec-> bv_offset; memcpy (dsk_mem, iovec_mem, bvec-> bv_len ); kunmap (bvec-> bv_page); break; default: printk (kern_err simp_blkdev_diskname ": unknown value of bio_rw: % lu \ n", bio_rw (bio )); # If linux_version_code <kernel_version (2, 6, 24) bio_endio (Bio, 0,-EIO); # else bio_endio (Bio,-EIO); # endif return 0 ;} dsk_mem + = bvec-> bv_len;} # If linux_version_code <kernel_version (2, 6, 24) bio_endio (Bio, bio-> bi_size, 0); # else bio_endio (Bio, 0); # endif return 0 ;}
The first is the continuous detection of a while large loop:
while ((req = elv_next_request(q)) != NULL)
This while large loop is constantly being detected. At the same time, the function of elv_next_request is used to obtain the first unfinished request in the queue. In fact, it is actually traversing the request in the queue. Elv_next_request is used to obtain the first unfinished request in the queue. The parameter is Q. Here, Q is the function pointer of request_queue in the Request queue.
Another important function is end_request (req, 0 );
In this function, if the parameter passed to the end_request function is 0, the request fails. If 1 is passed, the request is processed successfully.
Here, the end_request function is very important. Its prototype is as follows:
void end_request(struct request *req, int uptodate){ if (!end_that_request_first(req, uptodate, req->hard_cur_sectors)){ add_disk_randomness (req->rq_disk); blkdev_dequeue_request (req); end_that_request_last(req); }}
When the device has completed the transfer of one or all of the I/O requests, it must advertise the block device layer, and the 4th line in the above Code completes this work.
The prototype of the end_that_request_first () function is:
int end_that_request_first(struct request *req, int success, int count);
This function informs the block device layer that the block device driver has completed the transfer of Count slice.
The return value of end_that_request_first () is a flag indicating whether all sectors in the request have been transferred. If the returned value is 0, all sectors have been transferred and the request is completed. After that, we must use blkdev_dequeue_request () to clear the request from the queue.
Finally, pass the request to the end_that_request_last () function:
Void end_that_request_last (struct Request * req );
End_that_request_last () indicates that all object requests waiting for the request to be completed have been completed and the request structure has been recycled.
The add_disk_randomness () function of Row 3 contributes entropy to the random number pool of the system using block I/O Request timing, without affecting the drive of the block device. However, it should be called only when the disk operation time is really random (as most mechanical devices do.
LDD describes a complex request function:
The code for this request function is as follows:
Static void xxx_full_request (request_queue_t * q) {struct Request * req; int sectors_xferred; struct xxx_dev * Dev = Q-> queuedata; /* traverse each request */while (req = elv_next_request (q ))! = NULL) {If (! Blk_fs_request (req) {printk (kern_notice "Skip non-Fs Request \ n"); end_request (req, 0); continue;} sectors_xferred = xxx_xfer_request (Dev, req ); if (! End_that_request_first (req, 1, sectors_xferred) {response (req); Response (req) ;}}/ * request processing */static int xxx_xfer_request (struct xxx_dev * Dev, struct Request * req) {struct bio * bio; int nsect = 0;/* traverse each bio */rq_for_each_bio (Bio, req) {xxx_xfer_bio (Dev, bio) in the request ); nsect + = bio-> bi_size/kernel_sector_size;} return nsect;}/* bio Processing */static int xxx_xfer_bio (struct xxx_dev * Dev, struct bio * bio) {int I; struct bio_vec * bvec; sector_t sector = bio-> bi_sector;/* traverse each segment */bio_for_each_segment (bvec, bio, I) {char * buffer = _ bio_kmap_atomic (Bio, i, km_user0); xxx_transfer (Dev, sector, bio_cur_sectors (bio), buffer, bio_data_dir (bio) = write); sector + = bio_cur_sectors (bio ); _ bio_kunmap_atomic (Bio, km_user0);} return 0 ;}
The complex structure of the Request function is as follows:
Devices such as SD card and USB flash drive support the no-Request queue mode. LDD says that to use this mode, the driver must provide a manufacturing request function instead of a request function.
Although the first parameter is still a request queue, this request queue does not actually contain any request, because the block layer does not need to adjust bio to a request, so the main parameter used to create the request is the bio structure. Bio_endio: the notification termination handler.
Whether the processing is successful or not, the manufacturing request function should return 0. If a non-zero number is returned, the Bio request will be submitted again.
Finally, an important function for creating request functions:
void bio_endio(struct bio *bio, int error){if (error)clear_bit(BIO_UPTODATE, &bio->bi_flags);else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))error = -EIO;if (bio->bi_end_io)bio->bi_end_io(bio, error);}