好了,bio这个数据我们建立好了,随后调用generic_make_request 函数。这个函数是通用块层的入口点,该层只有这一个函数处理请求:
3020void generic_make_request(struct bio *bio) 3021{ 3022 request_queue_t *q; 3023 sector_t maxsector; 3024 int ret, nr_sectors = bio_sectors(bio); 3025 dev_t old_dev; 3026 3027 might_sleep(); 3028 /* Test device or partition size, when known. */ 3029 maxsector = bio->bi_bdev->bd_inode->i_size >> 9; 3030 if (maxsector) { 3031 sector_t sector = bio->bi_sector; 3032 3033 if (maxsector < nr_sectors || maxsector - nr_sectors < sector) { 3034 /* 3035 * This may well happen - the kernel calls bread() 3036 * without checking the size of the device, e.g., when 3037 * mounting a device. 3038 */ 3039 handle_bad_sector(bio); 3040 goto end_io; 3041 } 3042 } 3043 3044 /* 3045 * Resolve the mapping until finished. (drivers are 3046 * still free to implement/resolve their own stacking 3047 * by explicitly returning 0) 3048 * 3049 * NOTE: we don't repeat the blk_size check for each new device. 3050 * Stacking drivers are expected to know what they are doing. 3051 */ 3052 maxsector = -1; 3053 old_dev = 0; 3054 do { 3055 char b[BDEVNAME_SIZE]; 3056 3057 q = bdev_get_queue(bio->bi_bdev); 3058 if (!q) { 3059 printk(KERN_ERR 3060 "generic_make_request: Trying to access " 3061 "nonexistent block-device %s (%Lu)/n", 3062 bdevname(bio->bi_bdev, b), 3063 (long long) bio->bi_sector); 3064end_io: 3065 bio_endio(bio, bio->bi_size, -EIO); 3066 break; 3067 } 3068 3069 if (unlikely(bio_sectors(bio) > q->max_hw_sectors)) { 3070 printk("bio too big device %s (%u > %u)/n", 3071 bdevname(bio->bi_bdev, b), 3072 bio_sectors(bio), 3073 q->max_hw_sectors); 3074 goto end_io; 3075 } 3076 3077 if (unlikely(test_bit(QUEUE_FLAG_DEAD, &q->queue_flags))) 3078 goto end_io; 3079 3080 /* 3081 * If this device has partitions, remap block n 3082 * of partition p to block n+start(p) of the disk. 3083 */ 3084 blk_partition_remap(bio); 3085 3086 if (maxsector != -1) 3087 blk_add_trace_remap(q, bio, old_dev, bio->bi_sector, 3088 maxsector); 3089 3090 blk_add_trace_bio(q, bio, BLK_TA_QUEUE); 3091 3092 maxsector = bio->bi_sector; 3093 old_dev = bio->bi_bdev->bd_dev; 3094 3095 ret = q->make_request_fn(q, bio); 3096 } while (ret); 3097} |
首先3033行,检查bio->bi_sector没有超过块设备的扇区数。如果超过,则调用handle_bad_sector(bio)函数将bio->bi_flags设置为BIO_EOF标志,然后打印一条内核错误信息。随后跳到end_io标号处执行3065行的bio_endio()函数,并终止。bio_endio()更新bio描述符中的bi_size和bi_sector值,然后调用bio的bi_end_io方法。
如果没有超过,那么进入一个循环,通过3057行的bdev_get_queue函数获取与块设备相关的请求队列q;其中地址存放在bio的块设备描述符bi_bdev的bd_disk字段所指向的gendisk结构中,而该块设备描述符则由bio->bi_bdev指向:
static inline request_queue_t *bdev_get_queue(struct block_device *bdev) { return bdev->bd_disk->queue; } |
其中地址存放在块设备描述符的bd_disk字段所指向的gendisk结构中,而该块设备描述符则由bio->bi_bdev指向。
接下来3084行调用blk_partition_remap()函数检查块设备是否指的是一个磁盘分区(bio->bi_bdev不等于bio->bi_dev->bd_contains)。如果是,则从bio->bi_bdev获取分区的hd_struct描述符,从而执行下面的子操作:
a) 根据数据传送的方向,更新hd_struct描述符中的read_sectors和reads值或write_sectors和writes值。
b) 调整bio->bi_sector值使得把相对于分区的起始扇区号转变为相对于整有盘的扇区号。
c) 将bio->bi_bdev设置为整个磁盘的块设备描述符(bio->bd_contains)。
从现在开始,通用块层、I/O调度程序以及设备驱动程序将忘记磁盘分区的存在,直接作用于整个磁盘。
最终,3095行调用q->make_request_fn方法进入块设备的I/O调度层,将bio请求插入请求队列q中。