LDD3块设备代码分析

    技术2022-05-20  64

    整个块设备抽象的数据结构

    struct sbull_dev {

            int size;                       /* Device size in sectors */

            u8 *data;                       /* The data array */

            short users;                    /* How many users */

            short media_change;             /* Flag a media change? */

            spinlock_t lock;                /* For mutual exclusion */

            struct request_queue *queue;    /* The device request queue */请求队列

            struct gendisk *gd;             /* The gendisk structure */              /块设备数据结构

            struct timer_list timer;        /* For simulated media changes */

    };

    //模块初始化函数

    static int __init sbull_init(void)

    {

    int i;

    /*

    * Get registered.

    */

    sbull_major = register_blkdev(sbull_major, "sbull");//自动分配主设备号

    if (sbull_major <= 0) {

    printk(KERN_WARNING "sbull: unable to get major number/n");

    return -EBUSY;

    }

    /*

    * Allocate the device array, and initialize each one.

    */

    Devices = kmalloc(ndevices*sizeof (struct sbull_dev), GFP_KERNEL);//分配每个块设备的数据结构

    if (Devices == NULL)

    goto out_unregister;

    for (i = 0; i < ndevices; i++) 

    setup_device(Devices + i, i);

     

    return 0;

     

      out_unregister:

    unregister_blkdev(sbull_major, "sbd");

    return -ENOMEM;

    }

     

    static void setup_device(struct sbull_dev *dev, int which)

    {

    /*

    * Get some memory.

    */

    memset (dev, 0, sizeof (struct sbull_dev));

    dev->size = nsectors*hardsect_size;

    dev->data = vmalloc(dev->size);

    if (dev->data == NULL) {

    printk (KERN_NOTICE "vmalloc failure./n");

    return;

    }

    spin_lock_init(&dev->lock);

     

    /*

    * The timer which "invalidates" the device.

    */

    init_timer(&dev->timer);

    dev->timer.data = (unsigned long) dev;

    dev->timer.function = sbull_invalidate;//初始化超时定时器

     

    /*

    * The I/O queue, depending on whether we are using our own

    * make_request function or not.

    */

    switch (request_mode) {

       case RM_NOQUEUE:

    dev->queue = blk_alloc_queue(GFP_KERNEL);

    if (dev->queue == NULL)

    goto out_vfree;

    blk_queue_make_request(dev->queue, sbull_make_request);

    break;

     

       case RM_FULL:

    dev->queue = blk_init_queue(sbull_full_request, &dev->lock);

    if (dev->queue == NULL)

    goto out_vfree;

    break;

     

       default:

    printk(KERN_NOTICE "Bad request mode %d, using simple/n", request_mode);

             /* fall into.. */

     

       case RM_SIMPLE:

    dev->queue = blk_init_queue(sbull_request, &dev->lock);//向系统动态申请请求队列

    if (dev->queue == NULL)                                                    //sbull_request为个人实习的请求队列处理函数

    goto out_vfree;

    break;

    }

    blk_queue_hardsect_size(dev->queue, hardsect_size);

    dev->queue->queuedata = dev;

    /*

    * And the gendisk structure.

    */

    dev->gd = alloc_disk(SBULL_MINORS);//申请块设备数据结构

    if (! dev->gd) {

    printk (KERN_NOTICE "alloc_disk failure/n");

    goto out_vfree;

    }

    dev->gd->major = sbull_major;

    dev->gd->first_minor = which*SBULL_MINORS;

    dev->gd->fops = &sbull_ops;

    dev->gd->queue = dev->queue;//将请求队列与块设备绑定

    dev->gd->private_data = dev;

    snprintf (dev->gd->disk_name, 32, "sbull%c", which + 'a');

    set_capacity(dev->gd, nsectors*(hardsect_size/KERNEL_SECTOR_SIZE));

    add_disk(dev->gd);//最后添加到系统

    return;

     

      out_vfree:

    if (dev->data)

    vfree(dev->data);

    }

     

     

    static void sbull_exit(void)

    {

    int i;

     

    for (i = 0; i < ndevices; i++) {

    struct sbull_dev *dev = Devices + i;

     

    del_timer_sync(&dev->timer);

    if (dev->gd) {

    del_gendisk(dev->gd);

    put_disk(dev->gd);

    }

    if (dev->queue) {

    if (request_mode == RM_NOQUEUE)

    blk_put_queue(dev->queue);

    else

    blk_cleanup_queue(dev->queue);//返回请求队列

    }

    if (dev->data)

    vfree(dev->data);

    }

    unregister_blkdev(sbull_major, "sbull");//返回设备号

    kfree(Devices);

    }

    最简单的处理请求队列模型

    static void sbull_request(request_queue_t *q)

    {

    struct request *req;

     

    while ((req = elv_next_request(q)) != NULL) {//elv_next_request获得请求队列中的下一个请求

    struct sbull_dev *dev = req->rq_disk->private_data;

    if (! blk_fs_request(req)) {

    printk (KERN_NOTICE "Skip non-fs request/n");

    end_request(req, 0);

    continue;

    }

        //     printk (KERN_NOTICE "Req dev %d dir %ld sec %ld, nr %d f %lx/n",

        //     dev - Devices, rq_data_dir(req),

        //     req->sector, req->current_nr_sectors,

        //     req->flags);

        //req->sector 要传输的下一个缓冲区

        //req->current_nr_sectors 当前要传输的扇区数目

        //req->buffer 数据应当从这个缓冲区来或者去

        //rq_data_dir 可获得这个请求的数据传送方向

    sbull_transfer(dev, req->sector, req->current_nr_sectors,

    req->buffer, rq_data_dir(req));

    end_request(req, 1);

    }

    }

    //传输数据

    static void sbull_transfer(struct sbull_dev *dev, unsigned long sector,

    unsigned long nsect, char *buffer, int write)          

    {

                              //此次传输的偏移量

    unsigned long offset = sector*KERNEL_SECTOR_SIZE;     //req->sector 要传输的下一个扇区

    unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;//nsect = req->current_nr_sectors 当前要传输的扇区数目

                           //nbytes 此次要传输的字节数目

     

    if ((offset + nbytes) > dev->size) {

    printk (KERN_NOTICE "Beyond-end write (%ld %ld)/n", offset, nbytes);

    return;

    }

    if (write)

    memcpy(dev->data + offset, buffer, nbytes);

    else

    memcpy(buffer, dev->data + offset, nbytes);

    }

     

    每一个块设备的IO请求数据都是通过bio结构体表示,每个请求包含一个或者多个块(即是struct bio 中的数组)

    块设备IO请求由结构体 struct request表示,因为一个请求可能包含多个连续磁盘块,所以可能包含多个struct bio结构体。

    多个struct request 再链接成 struct request_queue。request_queue再与每个磁盘的gendisk捆绑在一起。

     

    struct bio{

    struct bio_vec *bi_io_vec;//指向数组的首地址

    unsigned short bi_idx;//数组的标号

    unsigned short bi_vcnt;//总共的片段数量

    .......

    }

    struct bio_vec{//一个数据结构代表一个缓存片段

    struct page *bv_page;//被缓存的内存页

    unsigned int bv_len;//数据长度

    unsigned int bv_offset;//页内偏移

    }


    最新回复(0)