linux 块设备驱动(二)——块设备数据结构

时间:2021-09-16 11:15:52

本文来源于:

1. http://www.cnblogs.com/dyllove98/archive/2013/07/01/3165567.html

块设备相关的数据结构以及接口:

      块设备接口则相对复杂,读写API没有直接到块设备层,而是直接到文件系统层,然后再由文件系统层发起读写请求。

一: block_device:  block_device结构代表了内核中的一个块设备。它可以表示整个磁盘或一个特定的分区。当这个结构代表一个分区时,它的bd_contains成员指向包含这个分区的设备,bd_part成员指向设备的分区结构。当这个结构代表一个块设备时,bd_disk成员指向设备的gendisk结构。

struct block_device {  
    dev_t           bd_dev;  
    struct inode *  bd_inode;   /*分区结点*/  
    int         bd_openers;  
    struct semaphore    bd_sem; /*打开/关闭锁*/  
    struct semaphore    bd_mount_sem;   /* 加载互斥锁*/  
    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;  
    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;  
    unsigned long   bd_private;  
};  
 
 
二:gendisk是一个单独的磁盘驱动器的内核表示。内核还使用gendisk来表示分区。
struct gendisk {  
    int major;          //主设备号  
    int first_minor;     
    int minors;         //最大的次设备号数量,如果设备不能分区,该值为1                                   
    char disk_name[32]; //主设备名  
    struct hd_struct **part;    //分区信息,有minors个  
    struct block_device_operations *fops;//设备操作  
    struct request_queue *queue;    //设备管理I/O请求  
    void *private_data;  
    sector_t capacity;  
    int flags;  
    char devfs_name[64];  
    int number;  
    struct device *driverfs_dev;  
    struct kobject kobj;  
    struct timer_rand_state *random;  
    int policy;  
    atomic_t sync_io;     
    unsigned long stamp, stamp_idle;  
    int in_flight;  
#ifdef  CONFIG_SMP  
    struct disk_stats *dkstats;  
#else  
    struct disk_stats dkstats;  
#endif  
};  
gendisk结构的操作函数包括以下几个:
struct gendisk *alloc_disk(int minors);     //分配磁盘  
void add_disk(struct gendisk *disk);        //增加磁盘信息  
void unlink_gendisk(struct gendisk *disk)   //删除磁盘信息  
void delete_partition(struct gendisk *disk, int part);  //删除分区  
void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags);//添加分区  
 
 
三: block_device_operations结构是块设备对应的操作接口,是连接抽象的块设备操作与具体块设备操作之间的枢纽。
 
struct block_device_operations {  
    int (*open) (struct inode *, struct file *);  
    int (*release) (struct inode *, struct file *);  
    int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);  
    long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);  
    long (*compat_ioctl) (struct file *, unsigned, unsigned long);  
    int (*direct_access) (struct block_device *, sector_t, unsigned long *);  
    int (*media_changed) (struct gendisk *);  
    int (*revalidate_disk) (struct gendisk *);  
    int (*getgeo)(struct block_device *, struct hd_geometry *);  
    struct module *owner;  
};  
block_device_operations并不能完全提供文件操作全部的API,实际上只提供了open、release等函数,其他的文件操作依赖于def_blk_fops:
const struct file_operations def_blk_fops = {  
    .open   = blkdev_open,  
    .release    = blkdev_close,  
    .llseek = block_llseek,  
    .read       = do_sync_read,  
    .write  = do_sync_write,  
    .aio_read   = generic_file_aio_read,  
    .aio_write= generic_file_aio_write_nolock,  
    .mmap   = generic_file_mmap,  
    .fsync  = block_fsync,  
    .unlocked_ioctl = block_ioctl,  
#ifdef CONFIG_COMPAT  
    .compat_ioctl   = compat_blkdev_ioctl,  
#endif  
    .splice_read        = generic_file_splice_read,  
    .splice_write   = generic_file_splice_write,  
}; 

 

四: 系统对块设备进行读写操作时,通过块设备通用的读写操作函数将一个请求保存在该设备的操作请求队列(request queue)中,然后调用这个块设备的底层处理函数,对请求队列中的操作请求进行逐一执行。request_queue结构描述了块设备的请求队列,该结构定义如下:

struct request_queue  
{  
    struct list_head    queue_head;  
    struct request      *last_merge;  
    elevator_t      elevator;  
    /*请求队列列表*/  
    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;  
    /*自动卸载状态*/  
    struct timer_list   unplug_timer;  
    int         unplug_thresh;    
    unsigned long       unplug_delay;   /*自动卸载延时*/  
    struct work_struct  unplug_work;  
    struct backing_dev_info backing_dev_info;  
    void                *queuedata;  
    void                *activity_data;  
    unsigned long       bounce_pfn;  
    int             bounce_gfp;  
    unsigned long       queue_flags;//各种队列标志  
    /*保护队列结构,避免重入*/  
    spinlock_t          *queue_lock;  
    /* 请求的核心结构*/  
    struct kobject kobj;  
    /*请求的配置*/  
    unsigned long       nr_requests;    /* 请求的最大数*/  
    unsigned int        nr_congestion_on;  
    unsigned int        nr_congestion_off;  
    unsigned short      max_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 参数配置*/  
    unsigned int        sg_timeout;  
    unsigned int        sg_reserved_size;  
};  
请求队列相关的处理函数包括:
//创建队列时提供了一个自旋锁。  
request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock);  
//获得队列中第一个未完成的请求。  
struct request *elv_next_request(request_queue_t *q);  
void end_request(struct request *req, int uptodate);//请求完成  
void blk_stop_queue(request_queue_t *queue); //停止请求  
void blk_start_queue(request_queue_t *queue); //开始请求  
void blk_cleanup_queue(request_queue_t *);//清除请求队列 

 

五:向内核注册和注销一个块设备可使用如下函数:

int register_blkdev(unsigned int major, const char *name);  
int unregister_blkdev(unsigned int major, const char *name);