字符设备与块设备

阅读本文之前需要掌握基本的计算机体系结构,可以清楚的将冯诺依曼体系结构阐述清楚,明白系统分层的基本思想等,可阅读文章《计算机体系结构变迁》了解。


1.概述

需要明白输入输出设备是非常多的,为了更好的处理,通常会为每一个设备设计设备控制器,这样就屏蔽了各个硬件设备之间的差异,CPU直接通过对寄存器的读写来控制硬件(通过特殊汇编指令,如in/out实现),当然会有一些设备可能需要大批量写入数据到内存,此时会在设备控制器上设置缓冲区(内存映射IO)的方法减少IO次数。而DMA的出现是为了解决大量IO情况下CPU需要多次参与下发指令的问题,CPU通过对DMA控制器下发写/读指令之后,DMA控制器会负责完成相应操作,然后发中断通知CPU。
由于各个设备控制器之间存在较大的差异,故先向上提供了更为抽象的设备驱动程序来操作设备控制器,而当使用设备驱动程序的时候只需要使用insmod将对应驱动程序加载如内核就可以了。在这之后我们又期望文件系统可以较为简单的使用硬件资源而不用花费较大的功夫去设计和规划,所以设计了通用设备层,这样文件系统在调用相关操作时直接调用通用设备层的接口就可以了。然而以上所述仍然对用户是不够友好的,因为文件系统可能也是较多的,所以在上面又封装了一层VFS。

2.常见的字符设备驱动程序

输入字符设备——鼠标

//linux-4.13.16\drivers\input\mouse\logibm.c
/*
 * Logitech Bus Mouse Driver for Linux
 */
module_init(logibm_init);
module_exit(logibm_exit);

输出字符设备——打印机

/*
 * Generic parallel printer driver
linux-4.13.16\drivers\char\lp.c     */
module_init(lp_init_module);
module_exit(lp_cleanup_module);

3.打开字符设备要经过那些步骤

  • 使用insmod命令加载设备驱动程序模块至内核(本质上就是向内核注册设备驱动程序)
  • 使用mknod在/dev目录之下创建一个设备文件,之后就可以基于fd像普通文件那样去访问对应的字符设备了。

4.设备驱动程序应该包含的内容

  • 头文件
  • 定义相关的函数,用于处理内核模块的主要逻辑。如打开,读取等
  • 定义一个file_operations。实现和文件系统的关联,当创建一个设备文件之后会将对应struct file上的file_operations指针指向对应设备驱动程序的file_operations。
  • 定义模块的初始化与退出函数,用于加载和卸载的时候调用。
  • 定义module_init与module_exit函数(统一接口),分别指向上面的初始化与退出函数
  • 声明lisense,调用MODULE_LICENSE

5.块设备

所谓块设备就是指硬盘、U盘等,它们常常会被格式化为文件系统,这就是我们常常熟悉的ext3,4的来源。那么它是怎样做到的哩?其实它和字符设备都差不多的处理逻辑,只不过走的是不同的流水线罢了。

作为软件开发人员应该对块设备了解的基本概念

  • 明白一个硬盘怎样变为我们熟悉的文件系统,又是怎样挂载到某一个系统文件夹下的?
  • 内核是如何驱动硬盘(块设备)的,即read/write系统调用更深层次的实现?

(1)如何将块设备变为熟悉的文件系统

  • 加载设备驱动程序
  • 在/dev下的devtmpfs中为块设备分配inode
  • 调用当前块设备对应的文件系统的mount操作,如若为ext4,则调用ext4_mount挂到某个文件夹下

(2)命令

  • /sys/block/*da/queue/scheduler可以查看磁盘的调度算法
  • iostat -d -x中的avgqu-sz表示设备平均IO队列长度
  • 常见磁盘调度算法:noop(fifo)、deadline(避免饥饿算法)、cfs(完全公平)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章