第九章输入输出子系统 输入/输出子系统(简称O子系统)的功能就是使进程 能够与外部设备进行通讯,设备驱动程序是输入输出子 系统中的核心模块,并且与设备类型一一对应。 每一种类型的设备都有特定的设备驱动程序;而每一种 设备驱动程序控制这种类型的所有设备。 1
第九章 输入/输出子系统 输入/输出子系统(简称I/O子系统)的功能就是使进程 能够与外部设备进行通讯,设备驱动程序是输入/输出子 系统中的核心模块,并且与设备类型一一对应。 每一种类型的设备都有特定的设备驱动程序;而每一种 设备驱动程序控制这种类型的所有设备。 1
9.1设备驱动程序接口 UNIX系统中把设备分为两大类: 块设备一 以块为单位进行数据的输入输出,如硬盘、软 盘、磁带、光盘等设备。 字符设备(原始设备,raw设备)一以字节为单位进行数 据的输入输出,如终端、打印机、绘图仪、调制解调器、网卡 等。 每个设备都有一个文件名(节点)相对应,用于标识该设备 的属性: 1 root system 14, 0 Mar 27 2009 cdo C上U-上w-上W- 1 root system 15, 0Max272009 clone 1 root system 4, 0Har27■ 2009 console C上-上-xwT 1 O▣t system 49, 0 Mar 28 2009 d1c8023 巴r-上订-上wT 1x00t system 48, 0Hax282009 dlcether CrW-上W-xwT 1 root system 47, 0Hax282009 dlcfddi Cr-上W-xwT 1 上0▣t system 46, 0 Mar 28 2009 dlcqllc C上W-上订-上T 1上oot system 45, 0Hax282009 dlcsdlc C上W-上-上T 1r00t system 44, 0Har282009 dlctoken C上订-上对-上 1 上oot system 15,34Har27 2009 echo 1 root system 6 0 Aug 28 10:05 error 1 root system 6, 1Har272009 errorctl 与上订一上可-工W一 1 root system 19, 0Har272009 fdo
9.1 设备驱动程序接口 UNIX系统中把设备分为两大类: 块设备 —— 以块为单位进行数据的输入输出,如硬盘、软 盘、磁带、光盘等设备。 字符设备(原始设备,raw设备)—— 以字节为单位进行数 据的输入输出,如终端、打印机、绘图仪、调制解调器、网卡 等。 每个设备都有一个文件名(i节点)相对应,用于标识该设备 的属性: 2
1、系统配置 系统配置就是告诉核心,当前系统中包含哪些设备,以及这些 设备的“地址”一建立设备文件、联接设备驱动程序,例如: mknod /dev/tty15 c 2 15 核心与驱动程序的接口是由块设备开关表和字符设备开关表 来描述的。 每一种设备类型在开关表中都有若干表项,这些表项在系统 调用时引导核心转向适当的驱动程序接口。 硬件与驱动程序的接口,是由与机器相关的控制寄存器或操 作设备的O指令以及中断向量组成:当一个设备发出中断时,系 统识别发出中断的设备,并调用适当的中断处理程序。 3
1、系统配置 系统配置就是告诉核心,当前系统中包含哪些设备,以及这些 设备的“地址” —— 建立设备文件、联接设备驱动程序,例如: mknod /dev/tty15 c 2 15 核心与驱动程序的接口是由块设备开关表和字符设备开关表 来描述的。 每一种设备类型在开关表中都有若干表项,这些表项在系统 调用时引导核心转向适当的驱动程序接口。 硬件与驱动程序的接口,是由与机器相关的控制寄存器或操 作设备的I/O指令以及中断向量组成:当一个设备发出中断时,系 统识别发出中断的设备,并调用适当的中断处理程序。 3
设备开关表示例 块设备开关表 表项 open close strategy 0 gdopen gdclose gdstrategy 1 gtopen gtclose gtstrategy 字符设备开关表 表项 open close read write ioctl 0 conopen conclose conread conwrite conioctl 1 dzbopen dzbclose dzbread dzbwrite dzbioctl 2 syopen nulldev syread sywrite syioctl 3 nulldev nulldev mmread mmwrite nodev 4 gdopen gdclose gdread gdwrite nodev 5 gtopen gtclose gtread gtwrite nodev 4
块 设 备 开 关 表 表项 open close strategy 0 gdopen gdclose gdstrategy 1 gtopen gtclose gtstrategy 字 符 设 备 开 关 表 表项 open close read write ioctl 0 conopen conclose conread conwrite conioctl 1 dzbopen dzbclose dzbread dzbwrite dzbioctl 2 syopen nulldev syread sywrite syioctl 3 nulldev nulldev mmread mmwrite nodev 4 gdopen gdclose gdread gdwrite nodev 5 gtopen gtclose gtread gtwrite nodev 设备开关表示例 4
驱动程序入口点 文件子系统 open close open close read write ioctl mount umount read write 高速缓冲调用 字符设备开关表 块设备开关表 open close read write ioctl open close strategy 驱动程序 驱动程序 入口点 驱动程序 设备中断处理程序 设备中断处理程序 中断向量 中断向量 设备中断 5
驱动程序入口点 5 文 件 子 系 统 高速缓冲调用 字 符 设 备 开 关 表 块 设 备 开 关 表 驱 动 程 序 设 备 中 断 处 理 程 序 驱 动 程 序 设 备 中 断 处 理 程 序 中 断 向 量 中 断 向 量 设 备 中 断 open close read write ioctl open close read write ioctl open close mount umount read write open close strategy 驱动程序 入口点
2、系统调用与驱动程序接口 对于使用文件描述符的系统调用的基本操作流程: 核心从用户文件描述符的指针找到系统打开文件表项和文件 的索引节点。 检查文件的类型,根据需要存取块设备或字符设备开关表。 > 从索引节点中抽取主设备号和次设备号。 > 使用主设备号为索引值进入相应的开关表。 > 根据用户所发的系统调用来调用开关表中的对应函数。 6
2、系统调用与驱动程序接口 对于使用文件描述符的系统调用的基本操作流程: 核心从用户文件描述符的指针找到系统打开文件表项和文件 的索引节点。 检查文件的类型,根据需要存取块设备或字符设备开关表。 从索引节点中抽取主设备号和次设备号。 使用主设备号为索引值进入相应的开关表。 根据用户所发的系统调用来调用开关表中的对应函数。 6
2、系统调用与驱动程序接口(续) 对设备文件的系统调用与对正规文件的系统调用之间的一个 重要区别是:当核心执行驱动程序时,对设备文件的索引节点是 不上锁的。 因为驱动程序会频繁地睡眠,以等待硬连接或数据的到来, 因此核心不能确定一个进程要睡眠多长时间。 如果对设备文件的索引节点上锁,则其它存取此节点的进程 (如通过系统调用stat)会因为本进程在驱动程序中睡眠,而无 限期地睡眠(等待)下去。 7
2、系统调用与驱动程序接口(续) 对设备文件的系统调用与对正规文件的系统调用之间的一个 重要区别是:当核心执行驱动程序时,对设备文件的索引节点是 不上锁的。 因为驱动程序会频繁地睡眠,以等待硬连接或数据的到来, 因此核心不能确定一个进程要睡眠多长时间。 如果对设备文件的索引节点上锁,则其它存取此节点的进程 (如通过系统调用stat)会因为本进程在驱动程序中睡眠,而无 限期地睡眠(等待)下去。 7
①算法:open*用于设备驱动程序的open* 输入:路径名,打开方式 输出:文件描述符 { 将路径名转换为索引节点,增加索引节点的引用计数; 与正规文件一样,分配系统打开文件表项和用户文件描述符; 从索引节点取主设备号和次设备号; if(块设备) { 使用主设备号作为查块设备开关表的索引值; 调用该索引值对应的驱动程序打开过程一传递参数为次设备号和打开方式: else*是字符设备*/ f 使用主设备号作为查字符设备开关表的索引值; 调用该索引值对应的驱动程序打开过程一传递参数为次设备号和打开方式: if(open在驱动程序中失败) 减少系统打开文件表项和索引节点的计数值: 8
① 算法:open /* 用于设备驱动程序的open */ 输入:路径名,打开方式 输出:文件描述符 { 将路径名转换为索引节点,增加索引节点的引用计数; 与正规文件一样,分配系统打开文件表项和用户文件描述符; 从索引节点取主设备号和次设备号; if (块设备) { 使用主设备号作为查块设备开关表的索引值; 调用该索引值对应的驱动程序打开过程——传递参数为次设备号和打开方式; } else /* 是字符设备 */ { 使用主设备号作为查字符设备开关表的索引值; 调用该索引值对应的驱动程序打开过程——传递参数为次设备号和打开方式; } if (open在驱动程序中失败) 减少系统打开文件表项和索引节点的计数值; } 8
②、算法:close 断开一个进程与设备的连接 a、搜索系统打开文件表(file表)以确认没有其他进程仍 然打开着这个设备。 既不能仅仅看fle表中的计数值来确认这是该设备的最 后一次关闭操作,因为几个进程可能通过不同的fle表项(读写指 针)来存取该设备; 也不能依靠活动索引节点表(inode表)的计数值来确定 这是否为最后一次关闭操作,因为可能有几个不同的文件代表同 一设备,例如: crw-rw-rw-1 root sys 9,1 Aug 62014 /dev/tty01 crw-rw-rw-1 root unix 9,1 Sep52015 /dev/tty02 虽然上述两个设备的名字不同,但它们的主设备号和此设备 号相同,因此是同一设备。有可能多个进程独立地打开这两个文 件,这些进程存取不同的inode,但却是对同一设备进行操作g
②、算法:close 断开一个进程与设备的连接 a、搜索系统打开文件表(file表)以确认没有其他进程仍 然打开着这个设备。 既不能仅仅看file表中的计数值来确认这是该设备的最 后一次关闭操作,因为几个进程可能通过不同的file表项(读写指 针)来存取该设备; 也不能依靠活动索引节点表(inode表)的计数值来确定 这是否为最后一次关闭操作,因为可能有几个不同的文件代表同 一设备,例如: crw-rw-rw- 1 root sys 9, 1 Aug 6 2014 /dev/tty01 crw-rw-rw- 1 root unix 9, 1 Sep 5 2015 /dev/tty02 虽然上述两个设备的名字不同,但它们的主设备号和此设备 号相同,因此是同一设备。有可能多个进程独立地打开这两个文 件,这些进程存取不同的inode,但却是对同一设备进行操作。9
②、算法:close 断开一个进程与设备的连接(续) b、对于一个字符设备,核心调用该设备对应的cose过程 并返回用户态。 对于一个块设备,首先判断该设备上是否为一个已安装 的文件系统。 如果是已安装的文件系统,则释放索引节点后返回。 如果不是已安装的文件系统,核心要做两件事: 搜索数据缓冲区高速缓冲,看是否有先前安装本 文件系统时遗留下来的数据块以“延迟写”的形式还 在内存中,还没有写回设备。如果有,则先写回这些 数据块。 在关闭本设备后,核心再扫描一次数据缓冲区高 速缓冲,使装有本设备数据块的缓冲区无效(释放到 空闲链表的表头),以使装有有效数据的缓冲区能在 内存中停留更长时间。 10
②、算法:close 断开一个进程与设备的连接(续) b、对于一个字符设备,核心调用该设备对应的close过程 并返回用户态。 对于一个块设备,首先判断该设备上是否为一个已安装 的文件系统。 如果是已安装的文件系统,则释放索引节点后返回。 如果不是已安装的文件系统,核心要做两件事: ① 搜索数据缓冲区高速缓冲,看是否有先前安装本 文件系统时遗留下来的数据块以“延迟写”的形式还 在内存中,还没有写回设备。如果有,则先写回这些 数据块。 ② 在关闭本设备后,核心再扫描一次数据缓冲区高 速缓冲,使装有本设备数据块的缓冲区无效(释放到 空闲链表的表头),以使装有有效数据的缓冲区能在 内存中停留更长时间。 10