提交IO传输请求

    技术2024-07-22  63

    1.4.3 提交I/O传输请求

    好了,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_sizebi_sector值,然后调用biobi_end_io方法。

     

    如果没有超过,那么进入一个循环,通过3057行的bdev_get_queue函数获取与块设备相关的请求队列q;其中地址存放在bio的块设备描述符bi_bdevbd_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_sectorsreads值或write_sectorswrites值。

    b) 调整bio->bi_sector值使得把相对于分区的起始扇区号转变为相对于整有盘的扇区号。

    c) bio->bi_bdev设置为整个磁盘的块设备描述符(bio->bd_contains)。

     

    从现在开始,通用块层、I/O调度程序以及设备驱动程序将忘记磁盘分区的存在,直接作用于整个磁盘。

     

    最终,3095行调用q->make_request_fn方法进入块设备的I/O调度层,将bio请求插入请求队列q中。

     

    最新回复(0)