块设备驱动程序

块设备驱动程序
<1>.块设备和字符设备的区别
 1,读取数据的单元不同,块设备读写数据的基本单元式块,字符设备的基本单元是字节。
 2,块设备可以随机访问,字符设备只能顺序访问。
<2>.linux内核中块设备的描述
 struct gendisk {
  int major;主设备号
  int first_minor;次设备号
  int minors;
  char disk_name[DISK_NAME_LEN];驱动名
  struct block_device_operations *fops;
  struct request_queue *queue; 请求队列
  ………………………………………………
  int node_id;
 };
 设备操作
 struct block_device_operations {
  int (*open)(struct block_device *,fmode_t );
  int (*release)(struct gendisk * ,fmode_t);
  int (*ioctl)(struct block_device *,fmode_t ,unsigned ,unsigned long);
  ………………………………………………………………………………
 }
<3>.设备注册
 void add_disk(struct gendisk *gd);
<4>.IO请求
 linux内核中,使用struct request来表示等待处理的块设备IO请求。
 struct request
 {
  struct list_head queuelist;链表结构
  sector_t sector;要操作的首个扇区
  unsigned long nr_sectors;要操作的扇区个数
  struct bio *bio;请求的bio结构体的链表
  struct bio *biotail;请求的bio结构体的链表尾
  …………………………………………………………
 }
<5>.请求队列
 请求队列就是IO请求request所形成的队列。在linux内核中用struct request_queue来描述。
<6>.队列操作函数
 struct request_queue *blk_init_queue(request_fn_proc *rfn,spinlock_t *lock);
 初始化请求队列,一般在模块加载函数中被调用。
 void blk_cleanup_queue(request_queue *q);
 清除请求队列,完成将请求队列返回给系统任务,一般在模块卸载函数中调用。
 struct request *elv_next_request(request_queue_t *queue);
 返回下一个要处理的请求,如果没有请求则返回NULL。elv_next_request()不会清除请求,仍然把这个请求放到
 队列上,因此,连续调用它两次,会返回同一个请求结构体。
 void blkdev_dequeue_request(struct request *req);从队列中删除一个请求结构体。
<7>.块设备驱动测试
 insmod simple-blk.ko
 ls /dev/simp_blkdev
 mkfs.ext3 /dev/simp_blkdev
 mkdir -p /mnt/blk
 mount
 cp /etc/init.d/* /mnt/blk
 ls /mnt/blk
 umount /mnt/blk
 ls /mnt/blk
<8>.bio结构
 一个struct bio代表一次块设备的IO请求,IO调度器可将连续的bio合并成一个请求struct request。
 struct bio
 {
  sector_t bi_sector; 第一个要访问的扇区
  unsigned int bi_size;以字节为单位要传输的数据大小
  struct bio_vec *bi_io_vec;实际的vector列表
 }
 struct bio_vec
 {
  struct page *bv_page;页指针
  unsigned int bv_len;要传输数据的长度
  unsigned int bv_offset;偏移量
 }
 在_make_request函数中,使用了IO调度器,将多个bio访问顺序进行优化,调整,合并成一个request,然后提交给用户
 指定的处理函数。然而对于U盘,ramdisk,记忆棒之类的设备,并不存在磁盘所需要的寻道时间。因此对这样的设备而言
 一个IO调度器,不但发挥不了作用,而且会浪费很多的内存和CPU资源。
 
 解决方法:驱动程序自己实现request_queue所需要的make_request_fn 函数,不使用_make_request函数。
<9>.请求处理的另一种实现方法。
 分配请求队列。
 request_queue_t *blk_alloc_queue(int fgp_mask);
 对于FLASH,RAM等完全随机访问的非机械设备,并不需要进行复杂的IO调度,这个时候应该使用上述函数分配一个请求队列。
 void blk_queue_make_request(request_queue_t *q,make_request_fn *fn);
 绑定请求队列和制造请求函数

你可能感兴趣的:(块设备驱动程序)