• 基本介绍

    • 块设备驱动程序通过主传动固定大小数据的随机访问设备
    • Linux核心Visual块设备作为基本设备和不同的字符设备类型
    • Linux块设备驱动程序接口,使块设备最大限度地发挥其效用。一个问题
    • 一个数据块指的是固定大小的数据,而大小的值由内核确定
    • 数据块的大小一般是4096个字节。可是能够依据体系结构和所使用的文件系统进行改变
    • 与数据块相应的是扇区,它是由底层硬件决定大小的一个块,内核所处理的设备扇区大小是512字节
    • 假设要使用不同的硬件扇区大小。用户必须对内核的扇区数做相应的改动
  • 注冊
    • 注冊块设备驱动程序

      • <linux/fs.h>
      • int register_blkdev(unsigned int major, const char *name);
        • 假设须要的话分配一个动态的主设备号
        • 在/proc/devices中创建一个入口项
      • int unregister_blkdev(unsigned int major, const char *name);
    • 注冊磁盘
      • struct block_device_operations

        • int (*open) (struct inode *inode, struct file *filp);
        • int (*release) (struct inode *inode, struct file *filp);
        • int (*ioctl) (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
        • int (*media_changed) (struct gendisk *gd);
        • int (*revalidate_disk) (struct gendisk *gd);
        • struct module *owner;
      • gendisk结构
        • <linux/genhd.h>
        • struct gendisk
          • int major;
          • int first_minor;
          • int minors;
            • 常取16
          • char disk_name[32]
            • 显示在/proc/partitions和sysfs中
          • struct block_device_operations *fops;
          • struct request_queue *queue;
          • int flags;
          • sector_t capacity;
          • void *private_data;
        • struct gendisk *alloc_disk(int minors);
        • void del_gendisk(struct gendisk *gd);
        • void add_disk(struct gendisk *gd);
  • 块设备操作

    • open和release函数

      • 对于那些操作实际硬件设备的驱动程序,open和release函数可以设置驱动程序和硬件的状态。这些操作包含使磁盘開始或者停止旋转,锁住可移动介质的仓门以及分配DMA缓存等
      • 有一些操作可以让块设备在用户空间内被直接打开,这些操作包含给磁盘分区。或者在分区上创建文件系统,或者执行文件系统检查程序
    • 对可移动介质的支持
      • 调用media_changed函数以检查介质是否被改变
      • 在介质改变后将调用revalideate函数
    • ioctl函数
      • 高层的块设备子系统在驱动程序获得ioctl命令前。已经截取了大量的命令
      • 实际上在一个现代驱动程序中。很多ioctl命令根本就不用实现
  • 请求处理
    • 每一个块设备驱动程序的核心是它的请求函数
    • 驱动程序所须要知道的不论什么关于请求的信息。都包括在通过请求队列传递给我们的结构中
    • request函数介绍
      • void request(request_queue_t *queue);

        • 当内核须要驱动程序处理读取、写入以及其它对设备的操作时。就会调用该函数
      • 每一个设备都有一个请求队列
        • dev->queue = blk_init_queue(test_request, &dev->lock);
      • 对request函数的调用是与用户空间进程中的动作全然异步的
    • 一个简单的request函数
      • struct request * elv_next_request(request_queue_t queue);
      • void end_request(struct request *req, int succeeded);
      • struct request
        • sector_t secotr;
        • unsigned long nr_sectors;
        • char *buffer
        • rq_data_dir(struct request *req);
    • 请求队列
      • 一个块设备请求队列能够这样描写叙述:包括块设备I/O请求的序列
      • 请求队列跟踪未完毕的块设备的I/O请求
      • 请求队列还实现了插件接口
      • I/O调度器还负责合并邻近的请求
      • 请求队列拥有request_queue或request_queue_t结构类型
      • <linux/blkdev.h>
      • 队列的创建与删除
        • request_queue_t *blk_init_queue(request_fn_proc *request, spinlock_t *lock);
        • void blk_cleanup_queue(request_queue_t *queue);
      • 队列函数
        • struct request *elv_next_request(request_queue_t *queue);
        • void blkdev_dequeue_request(struct request *req);
        • void elv_requeue_request(request_queue_t *queue, struct request *req);
      • 队列控制函数
        • void blk_stop_queue(request_queue_t *queue);
        • void blk_start_queue(request_queue_t *queue);
        • void blk_queue_bounce_limit(request_queue_t *queue, u64 dma_addr);
        • void blk_queue_max_sectors(request_queue_t *queue, unsigned short max);
        • void blk_queue_max_phys_segments(request_queue_t *queue, unsigned short max);
        • void blk_queue_max_hw_segments(request_queue_t *queue, unsigned short max);
        • void blk_queue_max_segment_size(request_queue_t *queue, unsigned short max);
        • void blk_queue_segment_boundary(request_queue_t *queue, unsigned long mask);
        • void blk_queue_dma_alignment(request_queue_t *queue, int mask);
        • void blk_queue_hardsect_size(request_queue_t *queue, unsigned short max);
      • 请求过程剖析
        • 从本质上讲,一个request结构是作为一个bio结构的链表实现的
        • bio结构
          • bio结构包括了驱动程序运行请求的所有信息,而不必与初始化这个请求的用户空间的进程相关联
          • <linux/bio.h>
          • struct bio
            • sector_t bi_sector;
            • unsigned int bi_size;
              • 以字节为单位所须要传输的数据大小
            • unsigned long bi_flags;
            • unsigned short bio_phys_segments;
            • unsigned short bio_hw_segments;
            • struct bio_vec *bi_io_vec
          • struct bio_vec
            • struct page *vb_page;
            • unsigned int bv_len;
            • unsigned int bv_offset;
          • example
            • int segno;
            • struct bio_vec *bvec;
            • bio_for_each_segment(bvec, bio, segno)
            • {
              • /* 使用该段进行一定的操作 */
            • }
          • char *__bio_kmap_atomic(struct bio *bio, int i, enum km_type type);
          • void __bio_kunmap_atomic(char *buffer, enum km_type type):
          • struct page *bio_page(struct bio *bio);
          • int bio_offset(struct bio *bio);
          • int bio_cur_sectors(struct bio *bio);
          • char *bio_data(struct bio *bio);
          • char *bio_kmap_irq(struct bio *bio, unsigned long *flags);
          • void bio_kunmap_irq(char *buffer, unsigned long *flags);
        • request结构成员
          • struct request

            • sector_t hard_sector;
            • unsigned long hard_nr_sectors;
            • unsigned int hard_cur_sectors;
            • struct bio *bio;
            • char *buffer;
            • unsigned short nr_phys_segments;
            • struct list_head queuelist;
        • 屏障请求
          • 在驱动程序接收到请求前。块设备层又一次组合了请求以提高I/O性能
          • 出于相同的目的,驱动程序也能够又一次组合请求
          • 但在无限制又一次组合请求时面临了一个问题:一些应用程序的某些操作。要在另外一些操作開始前完毕
          • 2.6版本号的块设备层使用屏障(barrier)请求来解决问题
          • 假设一个请求被设置了REQ_HARDBARRER标志。那么在其它兴许请求被初始化前,它必须被写入驱动器
          • void blk_queue_ordered(request_queue_t *queue, int flag);
          • int blk_barrier_rq(sruct request *req);
            • 假设返回一个非零值,该请求是一个屏障请求
        • 不可重试请求
          • int blk_noretry_request(struct request *req);
      • 请求完毕函数
        • int end_that_request_first(struct request *req, int success, int count);
        • void end_that_request_last(struct request *req);
        • example
          • void end_request(struct request *req, int uptodate)
          • {
            • if (!end_that_request(req, uptodate, req->hard_cur_sectors)
            • {
              • add_disk_randomness(req->rq_disk);
              • blkdev_dequeue_request(req);
              • end_that_request_last(req);
            • }
          • }
        • 使用bio
          • example

            • struct request *req
            • struct bio *bio;
            • rq_for_each_bio(bio, req)
            • {
              • /* 使用该bio结构进行一定的操作 */
            • }
        • 块设备请求和DMA
          • int blk_rq_map_sg(request_queue_t *queue, struct request *req, struct scatterlist *list);
          • clear_bit(QUEUE_FLAG_CLEAR, &queue->queue_flags);
        • 不使用请求队列
          • typedef int (make_request_fn) (request_queue_t *q, struct bio *bio);
          • void bio_endio(struct bio *bio, unsigned int bytes, int error);
          • request_queue_t *blk_alloc_queue(int flags);
            • 并未真正地建立一个保存请求的队列
          • void blk_queue_make_request(request_queue_t *queue, make_request_fn *func);
          • drivers/block/ll_rw_block.c
  • 其它一些细节
    • 命令预处理

      • typedef int (prep_rq_fn) (request_queue_t *queue, struct request *req);

        • 该函数要能返回以下的值之中的一个

          • BLKPREP_OK
          • BLKPREP_KILL
          • BLKPREP_DEFER
      • void blk_queue_prep_rq(request_queue_t *queue, prep_rq_fn *func);
    • 标记命令队列
      • 同一时候拥有多个活动请求的硬件通常支持某种形式的标记命令队列(Tagged Command Queueing, TCQ)
      • TCQ仅仅是为每一个请求加入一个整数(标记)的技术,这样当驱动器完毕它们中的一个请求后,它就能够告诉驱动程序完毕的是哪个
      • int blk_queue_int_tags(request_queue_t *queue, int depth, struct blk_queue_tag *tags);
      • int blk_queue_resize_tags(request_queue_t *queue, int new_depth);
      • int blk_queue_start_tag(request_queue_t *queue, struct request *req);
      • void blk_queue_end_tag(request_queue_t *queue, struct request *req);
      • struct request *blk_queue_find_tag(request_queue_t *queue, int tag);
      • void blk_queue_invalidate_tags(request_queue_t *queue);

版权声明:本文博客原创文章,博客,未经同意,不得转载。

《Linux Device Drivers》第十六章 块设备驱动程序——note相关推荐

  1. 《Linux Device Drivers》第六章 高级字符驱动程序操作——note

    ioctl 支持的操作,例如 简单数据传输 控制动作,例如用户空间发起弹出介质动作 反馈硬件的状态,例如报告错误信息 参数配置,例如改变波特率 执行自破坏 用户空间的ioctl方法原型:int ioc ...

  2. 【Linux命令】《鸟哥Linux基础》第十六章 进程管理与SELinux初探

    第十六章 进程管理与SELinux初探 16.1 什么是进程(process) Linux下的所有命令与你能够执行的操作 ===>都与权限有关 如何判断权限? 账号管理中的UID.GID:文件属 ...

  3. linux驱动编写之十六(块驱动设备初识)

    系统中能够随机访问固定大小数据片(chunk)的设备被称作块设备,这些数据片就称作块.块设备文件都是以安装文件系统的方式使用,此也是块设备通常的访问方式.块设备的访问方式是随机的,也就是可以在访问设备 ...

  4. 《Essential Linux Device Drivers》 第2章 A Peek Inside the Kernel

    第 2 章 内核一瞥 在我们开始步入 Linux 设备驱动的神秘世界之前,让我们先熟悉一些从驱动开发人员应该理解的基本的内核概念.我们将学习到内核定时器.同步机制以及内存分配方法,但是,先让我们从顶层 ...

  5. 《Essential Linux Device Drivers》第2章

    第 2 章 内核一瞥 在我们开始步入 Linux 设备驱动的神秘世界之前,让我们先熟悉一些从驱动开发人员应该理解的基本的内核概念.我们将学习到内核定时器.同步机制以及内存分配方法,但是,先让我们从顶层 ...

  6. Essential Linux Device Drivers 中文版第2章

    By 宋宝华 / 本系列文章交流与讨论:@宋宝华Barry 在开始步入Linux设备驱动程序的神秘世界之前,让我们从驱动程序开发人员的角度看几个内核构成要素,熟悉一些基本的内核概念.我们将学习内核定 ...

  7. 鸟哥的Linux私房菜(基础篇)- 第二十六章、Linux 核心编译与管理

    第二十六章.Linux核心编译与管理 最近升级日期:2009/09/18 我们说的 Linux 其实指的就是核心 (kernel) 而已.这个核心控制你主机的所有硬件并提供系统所有的功能,所以说,他重 ...

  8. 鸟哥的Linux私房菜(服务器)- 第十六章、文件服务器之二: SAMBA 服务器

    第十六章.文件服务器之二: SAMBA 服务器 最近更新日期:2011/07/29 如果想要共享档案,在 Linux 对 Linux 的环境下,最简单的方法就是透过 NIS 这玩意儿了!至于 Wind ...

  9. 第二十六章、Linux 核心编译与管理

    我们说的 Linux 其实指的就是核心 (kernel) 而已.这个核心控制你主机的所有硬件并提供系统所有的功能, 所以说,他重不重要啊!我们启动的时候其实就是利用启动管理程序加载这个核心文件来侦测硬 ...

最新文章

  1. Python与Java之间的相互调用——Jython
  2. LeetCode Algorithm 面试题 10.05. 稀疏数组搜索
  3. 详解vue项目和普通项目如何解决开发环境与生产环境下的跨域问题
  4. linux操作系统权限详解,Linux权限详解
  5. C语言 ##__VA_ARGS__ - C语言零基础入门教程
  6. java表达式的类型_java – 此表达式的目标类型必须是功能界面
  7. mysql数据库中文乱码解决
  8. grep 二进制文件grep AMI 2012-11-23.log Binary file 2012-11-23.log matches
  9. Leetcode之整数反转
  10. 数据库删除表中多列语法总结
  11. 2016年,你要学习这些移动开发技术
  12. 如何实现 Linux + Windows 双系统启动
  13. 计算机怎么进入用户模式,Win7系统怎么进入电脑安全模式?
  14. Docker 高级篇
  15. coq形式化验证学习进阶
  16. 姬魔恋战纪服务器维护,姬魔恋战纪闪退、进不去、黑屏不能玩的原因和解决办法[图]...
  17. mysql建库建表全过程20201215
  18. 网站自动弹出QQ对话框
  19. 【渝粤教育】广东开放大学 电子支付与安全 形成性考核 (59)
  20. 【LeetCode】IPO(使用贪心求解)

热门文章

  1. SharePoint 上传附件
  2. 小白设计模式:责任链模式
  3. pthread_join来接收线程的返回参数
  4. C++_选择结构_单行if语句_多行if语句_多条件if语句_嵌套if语句_三目运算符---C++语言工作笔记016
  5. k8s集群部署项目_JAVA项目(制作镜像)---K8S_Google工作笔记0060
  6. Android学习笔记---26_网络通信之资讯客户端,使用pull解析器,解析,从网络中获得的自定义xml文件
  7. hibernate集合类型映射
  8. 将一副完整的位图均分成n块位图显示
  9. 3d激光雷达开发(字符串输出和实体绘制)
  10. 盘绕过苹果id方法_如何更换苹果ID?