zoukankan      html  css  js  c++  java
  • Linux中块设备驱动程序分析

    基于《Linux设备驱动程序》书中的sbull程序以对Linux块设备驱动总结分析。


    開始之前先来了解这个块设备中的核心数据结构:

    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 */
    };
    在这个结构中,struct request_queue与 struct gendisk 是这个结构中的重要成员,
    也是块设备中的重要结构,这个文章中的大部分阐述都是基于这两个结构的操作。
    一.流程:
    块设备驱动也是从init函数開始的,所以分析也从这里開始。
    第一步:
        register_blkdev(sbull_major, "sbull");
    先注冊块设备,第一个參数是设备号,为0表完动态分配,第二个为设备名。
    第二步:
        Devices = kmalloc(ndevices*sizeof (struct sbull_dev), GFP_KERNEL);
    创建这个块设备的核心数据结构,也就是这个块设备的对象实体,创建了ndevice这样
    的实体。
    第三步:
        setup_device(Devices + i, i);
    说白了,就是初始化实体,并把它加入到系统的block层中去。这个步骤非常重要,它
    成以下面一些操作:
    1.初始化一个自旋锁。    
        spin_lock_init(&dev->lock);
    2.分配一个请求队列,并用1中的自旋锁来控制对队列的訪问。
        dev->queue = blk_init_queue(sbull_full_request, &dev->lock);
    3.分配,初始化及安装对应的gendisk结构。
        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));
    4.最后add_disk完毕整个初始化过程,这步一定要在初始化的最后再调用,由于
      add_disk后,可能就会调用磁盘的操作函数,假设初始化还没有完毕就会出错。

    二.块设备操作 struct block_device_operations 结构分析:
    sbull模块中的该结构:
    static struct block_device_operations sbull_ops = {
        .owner           = THIS_MODULE,
        .open              = sbull_open,
        .release           = sbull_release,
        .media_changed   = sbull_media_changed,
        .revalidate_disk = sbull_revalidate,
        .ioctl             = sbull_ioctl
    };
    open与release这两个函数就不再详细分析,它们有一个重要功能就是添加用户计数和
    降低用户计数。media_changed 和revalidata_disk即是对可移动介质的支持,像u盘等
    等这些可移动,即插即用的设备就应该实现这两个函数。media_changed是检查介质是
    否改变,发迹即返回非零,revalidate_disk即介质改变后运行。它们之间怎样联系我
    们不用管,我们主要实现这个函数的实体就可以。
    ioctl函数,ioctl函数的功能也简化了,可实际的磁盘设备大多也主要是实现对磁盘信
    息的查询。
    三.请求处理。
        块设备驱动程序的核心是请求处理部分,是块设备驱动的难点。设计得好否直接关
    系到设备的性能。
        我们看在安装块设备实体的时候,初始化了一个请求队列:
        dev->queue = blk_init_queue(sbull_full_request, &dev->lock);
    这个操作就是把生成的请求队列dev->queue与请求函数sbull_full_request绑定在一
    起。sbull中的request函数:
    static void sbull_full_request(request_queue_t *q)
    {
        struct request *req;
        int sectors_xferred;
        struct sbull_dev *dev = q->queuedata;
        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 = sbull_xfer_request(dev, req);
            if (! end_that_request_first(req, 1, sectors_xferred)) {
                blkdev_dequeue_request(req);
                end_that_request_last(req);
            }
        }
    }
    req = elv_next_request(q) 获取队列中第一个未完毕的请求,两次调用而没有
    执行end_that_request_last或者end_request时得到的是同样的结果,由于它不会删除
    队列中的请求。仅仅有结束该请求,才会得到下一个请求。sbull_xfer_request在这里即
    是实际的传输数据。
    一个实际的块设备请求处理要这些要复杂得多,那就要更深入了解request结构,bio结

    构,队列结构等等。但在这里先不深入去讨论。

  • 相关阅读:
    Kvm virsh
    lvs tunl
    django表单使用
    django上传图片
    django框架admin使用
    django模板的使用
    django数据库操作
    django数据库交互
    django数据库中
    django之类视图
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4354415.html
Copyright © 2011-2022 走看看