免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 16895 | 回复: 14
打印 上一主题 下一主题

看块设备驱动部分的笔记 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-06-04 16:30 |只看该作者 |倒序浏览
对于块设备,首先明确几个基本的概念:

扇区(Sectors): 通常是512 bytes.  是硬件设备传输数据的基本单位.

块(Blocks):     通常是1, 2, 4, 8, .... 个扇区,并且小于一个page.   是内核(VFS和文件系统)传送数据的基本单位.

段(Segments):   是若干相邻的块. 是一个内存页或者内存页的一部分. 一般由块设备驱动程序来处理.

每个缓冲区与一个块对应,相当于磁盘块在内存中的表示.


引用ULK3中的一张图来说明它们的关系:





对于整个块设备驱动的层次架构,ULK3中的一张图能够很好的说明这些:

论坛徽章:
0
2 [报告]
发表于 2008-06-04 16:30 |只看该作者
bio

相关数据结构:

/*
* main unit of I/O for the block layer and lower layers (ie drivers and
* stacking drivers)
*/
struct bio {
        sector_t                bi_sector;
        struct bio                *bi_next;        /* request queue link */
        struct block_device        *bi_bdev;
        unsigned long                bi_flags;        /* status, command, etc */
        unsigned long                bi_rw;                /* bottom bits READ/WRITE,
                                                 * top bits priority
                                                 */

        unsigned short                bi_vcnt;        /* how many bio_vec's */
        unsigned short                bi_idx;                /* current index into bvl_vec */

        /* Number of segments in this BIO after
         * physical address coalescing is performed.
         */
        unsigned short                bi_phys_segments;

        /* Number of segments after physical and DMA remapping
         * hardware coalescing is performed.
         */
        unsigned short                bi_hw_segments;

        unsigned int                bi_size;        /* residual I/O count */

        /*
         * To keep track of the max hw size, we account for the
         * sizes of the first and last virtually mergeable segments
         * in this bio
         */
        unsigned int                bi_hw_front_size;
        unsigned int                bi_hw_back_size;

        unsigned int                bi_max_vecs;        /* max bvl_vecs we can hold */

        struct bio_vec                *bi_io_vec;        /* the actual vec list */

        bio_end_io_t                *bi_end_io;
        atomic_t                bi_cnt;                /* pin count */

        void                        *bi_private;

        bio_destructor_t        *bi_destructor;        /* destructor */
        struct bio_set                *bi_set;        /* memory pools set */
};




/*
* was unsigned short, but we might as well be ready for > 64kB I/O pages
*/
struct bio_vec {
        struct page        *bv_page;
        unsigned int        bv_len;
        unsigned int        bv_offset;
};


bio是 Generic block layer(通用块层) 的核心数据结构。

bio中的段(segment)是由bio_vec数据结构表示的。 bio相关的段被放在bio_vec的数组中,他们的关系表示如下:




其中bio的bi_idx字段会不断保持更新,内核中提供了宏 bio_for_each_segment 用来遍历bio中的bio_vec

论坛徽章:
0
3 [报告]
发表于 2008-06-04 16:31 |只看该作者
gendisk

相关数据结构:

struct gendisk {
        int major;                        /* major number of driver */
        int first_minor;
        int minors;                     /* maximum number of minors, =1 for
                                         * disks that can't be partitioned. */
        char disk_name[32];                /* name of major driver */
        struct hd_struct **part;        /* [indexed by minor] */
        struct block_device_operations *fops;
        struct request_queue *queue;
        void *private_data;
        sector_t capacity;

        int flags;
        char devfs_name[64];                /* devfs crap */
        int number;                        /* more of the same */
        struct device *driverfs_dev;
        struct kobject kobj;

        struct timer_rand_state *random;
        int policy;

        atomic_t sync_io;                /* RAID */
        unsigned long stamp, stamp_idle;
        int in_flight;
#ifdef        CONFIG_SMP
        struct disk_stats *dkstats;
#else
        struct disk_stats dkstats;
#endif
};



struct hd_struct {
        sector_t start_sect;
        sector_t nr_sects;
        struct kobject kobj;
        unsigned reads, read_sectors, writes, write_sectors;
        int policy, partno;
};




磁盘由gendisk对象来表示。
磁盘的分区用hd_struct对象表示。

磁盘的分区是通过设备的次设备号(minor)来区分的,例如
                                                                           


                                                                           
hda1就是第一个分区,hda2就是第二个分区。

gendisk的part指向分区数组的首地址,数组的下标是分区的minor索引(从1开始),即数组的第一个成员是指向minor为1的分区。

论坛徽章:
0
4 [报告]
发表于 2008-06-04 16:32 |只看该作者
request_queue

相关数据结构:

请求队列中两个比较重要的数据结构是: request_queue 和 request

struct request_queue
{
        /*
         * Together with queue_head for cacheline sharing
         */
        struct list_head        queue_head;
        struct request                *last_merge;
        elevator_t                *elevator;

        /*
         * the queue request freelist, one for reads and one for writes
         */
        struct request_list        rq;

        request_fn_proc                *request_fn;
        merge_request_fn        *back_merge_fn;
        merge_request_fn        *front_merge_fn;
        merge_requests_fn        *merge_requests_fn;
        make_request_fn                *make_request_fn;
        prep_rq_fn                *prep_rq_fn;
        unplug_fn                *unplug_fn;
        merge_bvec_fn                *merge_bvec_fn;
        activity_fn                *activity_fn;
        issue_flush_fn                *issue_flush_fn;
        prepare_flush_fn        *prepare_flush_fn;
        end_flush_fn                *end_flush_fn;

        /*
         * Auto-unplugging state
         */
        struct timer_list        unplug_timer;
        int                        unplug_thresh;        /* After this many requests */
        unsigned long                unplug_delay;        /* After this many jiffies */
        struct work_struct        unplug_work;

        struct backing_dev_info        backing_dev_info;

        /*
         * The queue owner gets to use this for whatever they like.
         * ll_rw_blk doesn't touch it.
         */
        void                        *queuedata;

        void                        *activity_data;

        /*
         * queue needs bounce pages for pages above this limit
         */
        unsigned long                bounce_pfn;
        unsigned int                bounce_gfp;

        /*
         * various queue flags, see QUEUE_* below
         */
        unsigned long                queue_flags;

        /*
         * protects queue structures from reentrancy. ->__queue_lock should
         * _never_ be used directly, it is queue private. always use
         * ->queue_lock.
         */
        spinlock_t                __queue_lock;
        spinlock_t                *queue_lock;

        /*
         * queue kobject
         */
        struct kobject kobj;

        /*
         * queue settings
         */
        unsigned long                nr_requests;        /* Max # of requests */
        unsigned int                nr_congestion_on;
        unsigned int                nr_congestion_off;
        unsigned int                nr_batching;

        unsigned short                max_sectors;
        unsigned short                max_hw_sectors;
        unsigned short                max_phys_segments;
        unsigned short                max_hw_segments;
        unsigned short                hardsect_size;
        unsigned int                max_segment_size;

        unsigned long                seg_boundary_mask;
        unsigned int                dma_alignment;

        struct blk_queue_tag        *queue_tags;

        atomic_t                refcnt;

        unsigned int                in_flight;

        /*
         * sg stuff
         */
        unsigned int                sg_timeout;
        unsigned int                sg_reserved_size;

        struct list_head        drain_list;

        /*
         * reserved for flush operations
         */
        struct request                *flush_rq;
        unsigned char                ordered;
};



------------------------------------------------------------------

/*
* try to put the fields that are referenced together in the same cacheline
*/
struct request {
        struct list_head queuelist; /* looking for ->queue? you must _not_
                                     * access it directly, use
                                     * blkdev_dequeue_request! */
        unsigned long flags;                /* see REQ_ bits below */

        /* Maintain bio traversal state for part by part I/O submission.
         * hard_* are block layer internals, no driver should touch them!
         */

        sector_t sector;                /* next sector to submit */
        unsigned long nr_sectors;        /* no. of sectors left to submit */
        /* no. of sectors left to submit in the current segment */
        unsigned int current_nr_sectors;

        sector_t hard_sector;                /* next sector to complete */
        unsigned long hard_nr_sectors;        /* no. of sectors left to complete */
        /* no. of sectors left to complete in the current segment */
        unsigned int hard_cur_sectors;

        struct bio *bio;
        struct bio *biotail;

        void *elevator_private;

        int rq_status;        /* should split this into a few status bits */
        struct gendisk *rq_disk;
        int errors;
        unsigned long start_time;

        /* Number of scatter-gather DMA addr+len pairs after
         * physical address coalescing is performed.
         */
        unsigned short nr_phys_segments;

        /* Number of scatter-gather addr+len pairs after
         * physical and DMA remapping hardware coalescing is performed.
         * This is the number of scatter-gather entries the driver
         * will actually have to deal with after DMA mapping is done.
         */
        unsigned short nr_hw_segments;

        int tag;
        char *buffer;

        int ref_count;
        request_queue_t *q;
        struct request_list *rl;

        struct completion *waiting;
        void *special;

        /*
         * when request is used as a packet command carrier
         */
        unsigned int cmd_len;
        unsigned char cmd[BLK_MAX_CDB];

        unsigned int data_len;
        void *data;

        unsigned int sense_len;
        void *sense;

        unsigned int timeout;

        /*
         * For Power Management requests
         */
        struct request_pm_state *pm;

        /*
         * completion callback. end_io_data should be folded in with waiting
         */
        rq_end_io_fn *end_io;
        void *end_io_data;
};




每一个对于块设备的请求都用一个request描述符来表示.
而每个请求又包含一个或多个bio结构.

对于一个请求队列(request_queue),其所有的request描述符形成一个双向链表.


论坛徽章:
0
5 [报告]
发表于 2008-06-04 16:33 |只看该作者
block_device

相关数据结构:

struct block_device {
        dev_t                        bd_dev;  /* not a kdev_t - it's a search key */
        struct inode *                bd_inode;        /* will die */
        int                        bd_openers;
        struct semaphore        bd_sem;        /* open/close mutex */
        struct semaphore        bd_mount_sem;        /* mount mutex */
        struct list_head        bd_inodes;
        void *                        bd_holder;
        int                        bd_holders;
        struct block_device *        bd_contains;
        unsigned                bd_block_size;
        struct hd_struct *        bd_part;
        /* number of times partitions within this device have been opened. */
        unsigned                bd_part_count;
        int                        bd_invalidated;
        struct gendisk *        bd_disk;
        struct list_head        bd_list;
        struct backing_dev_info *bd_inode_backing_dev_info;
        /*
         * Private data.  You must have bd_claim'ed the block_device
         * to use this.  NOTE:  bd_claim allows an owner to claim
         * the same device multiple times, the owner must take special
         * care to not mess up bd_private for that case.
         */
        unsigned long                bd_private;
};


每一个块设备都由一个block_device对象来表示.
这里所说的块设备其实是指一个逻辑块设备.
比如一个磁盘由一个block_device对象来表示,而该磁盘又分了三个分区,这三个分区就又是三个逻辑块设备.

block_device中的bd_contains字段指向与整个磁盘相关的block_device对象.
因而,如果如果block_device表示一个磁盘分区,则其bd_contains指向整个磁盘的block_device对象.
如果block_device表示的是一个磁盘,则其bd_contains指向自己.

block_device中有几个比较重要的字段:
bd_disk 指向块设备中磁盘对应的gendisk结构.
bd_part 指向hd_struct分区描述符(如果是整个磁盘的话,bd_part为NULL)



综合前面所有的结构,整体的结构关系如下图所示:

论坛徽章:
0
6 [报告]
发表于 2008-06-04 16:35 |只看该作者

                              
写了个大概.

不过关于块设备驱动这部分内容,还有很多具体的细节问题我还没有搞太清楚.

keep on studying.

论坛徽章:
0
7 [报告]
发表于 2008-10-29 14:42 |只看该作者
写的不错

论坛徽章:
3
金牛座
日期:2014-06-14 22:04:062015年辞旧岁徽章
日期:2015-03-03 16:54:152015年迎新春徽章
日期:2015-03-04 09:49:45
8 [报告]
发表于 2008-10-29 15:54 |只看该作者
感谢分享,学习中……

论坛徽章:
7
丑牛
日期:2013-10-18 14:43:21技术图书徽章
日期:2013-11-03 09:58:03辰龙
日期:2014-01-15 22:57:50午马
日期:2014-09-15 07:04:39丑牛
日期:2014-10-16 14:25:222015年亚洲杯之伊朗
日期:2015-03-16 10:24:352015亚冠之城南
日期:2015-05-31 09:52:32
9 [报告]
发表于 2011-08-21 12:16 |只看该作者
>>这里所说的块设备其实是指一个逻辑块设备.

个人感觉这里思路可以改成, 一个块设备满足块方式的寻址和读写数据即可.
至于具体的读写 , 可以有其自己的实现方式.
这就如同一个物理网卡可以有多个虚拟网卡一样. 虚拟网卡的发送最终调用物理网卡

论坛徽章:
0
10 [报告]
发表于 2011-08-21 12:46 |只看该作者
回复 1# xpl


    bytex,你的sina博客怎么不更新了。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP