📄 00000009.htm
字号:
将挂起请求者并将此进程放置到等待队列中直到系统中有足够的物理内存为止。 <BR>不是所有的设备驱动(或者真正的Linux核心代码)都会经历这个过程,所以 <BR>如分配核心内存的请求不能立刻得到满足,则此请求可能会失败。如果设备驱 <BR>动希望在此内存中进行DMA,那么它必须将此内存设置为DMA使能的。这也是为 <BR>什么是Linux核心而不是设备驱动需要了解系统中的DMA使能内存的原因。 <BR>8.4 设备驱动与核心的接口 <BR>Linux核心与设备驱动之间必须有一个以标准方式进行互操作的接口。每一类 <BR>设备驱动:字符设备、块设备及网络设备都提供了通用接口以便在需要时为核 <BR>心提供服务。这种通用接口使得核心可以以相同的方式来对待不同的设备及设 <BR>备驱动。如SCSI和IDE硬盘的区别很大但Linux对它们使用相同的接口。 <BR>Linux动态性很强。每次Linux核心启动时如遇到不同的物理设备将需要不同的 <BR>物理设备驱动。Linux允许通过配置脚本在核心重建时将设备驱动包含在内。设 <BR>备驱动在启动初始化时可能会发现系统中根本没有任何硬件需要控制。其它设 <BR>备驱动可以在必要时作为核心模块动态加载到。为了处理设备驱动的动态属性, <BR>设备驱动在初始化时将其注册到核心中去。Linux维护着已注册设备驱动表作为 <BR>和设备驱动的接口。这些表中包含支持此类设备例程的指针和相关信息。 <BR>8.4.1 字符设备 <BR>字符设备是Linux设备中最简单的一种。应用程序可以和存取文件相同的 <BR>系统调用来打开、读写及关闭它。即使此设备是将Linux系统连接到网络 <BR>中的PPP后台进程的modem也是如此。字符设备初始化时,它的设备驱动通 <BR>过在device_struct结构的chrdevs数组中添加一个入口来将其注册到Linux <BR>核心上。设备的主设备标志符用来对此数组进行索引(如对tty设备的索引 <BR>4)。设备的主设备标志符是固定的。 <BR>chrdevs数组每个入口中的device_struct数据结构包含两个元素;一个指 <BR>向已注册的设备驱动名称,另一个则是指向一组文件操作指针。它们是位 <BR>于此字符设备驱动内部的文件操作例程的地址指针,用来处理相关的文件 <BR>操作如打开、读写与关闭。/proc/devices中字符设备的内容来自chrdevs <BR>数组。 <BR>当打开代表字符设备的字符特殊文件时(如/dev/cua0),核心必须作好准 <BR>备以便调用相应字符设备驱动的文件操作例程。与普通的目录和文件一样, <BR>每个字符特殊文件用一个VFS节点表示。每个字符特殊文件使用的VFS inode <BR>和所有设备特殊文件一样,包含着设备的主从标志符。这个VFS inode由底 <BR>层的文件系统来建立(比如EXT2),其信息来源于设备相关文件名称所在文 <BR>件系统。 <BR>每个VFS inode和一组文件操作相关联,它们根据inode代表的文件系统对 <BR>象变化而不同。当创建一个代表字符相关文件的VFS inode时,其文件操 <BR>作被设置为缺省的字符设备操作。 <BR>字符设备只有一个文件操作:打开文件操作。当应用打开字符特殊文件时, <BR>通用文件打开操作使用设备的主标志符来索引此chrdevs数组,以便得到那 <BR>些文件操作函数指针。同时建立起描叙此字符特殊文件的file结构,使其文 <BR>件操作指针指向此设备驱动中的文件操作指针集合。这样所有应用对它进行 <BR>的文件操作都被映射到此字符设备的文件操作集合上。 <BR>8.4.2 块设备 <BR>块设备也支持以文件方式访问。系统对块设备特殊文件提供了非常类似于 <BR>字符特殊文件的文件操作机制。Linux在blkdevs数组中维护所有已注册的 <BR>块设备。象chrdevs数组一样,blkdevs也使用设备的主设备号进行索引。 <BR>其入口也是device_struct结构。和字符设备不同的是系统有几类块设备。 <BR>SCSI设备是一类而IDE设备则是另外一类。它们将以各自类别登记到Linux <BR>核心中并为核心提供文件操作功能。某类块设备的设备驱动为此类型设备 <BR>提供了类别相关的接口。如SCSI设备驱动必须为SCSI子系统提供接口以便 <BR>SCSI子系统能用它来为核心提供对此设备的文件操作。 <BR>和普通文件操作接口一样, 每个块设备驱动必须为buffer <BR>cache提供接口。每个块设备驱动将填充其在blk_dev数组中的blk_dev_struct <BR>结构入口。数组的索引值还是此设备的主设备号。这个blk_dev_struct结 <BR>构包含请求过程的地址以及指向请求数据结构链表的指针,每个代表一个 <BR>从buffercache中来让设备进行数据读写的请求。 <BR>每当buffer cache希望从一个已注册设备中读写数据块时,它会将request <BR>结构添加到其blk_dev_struct中。图8.2表示每个请求有指向一个或多个 <BR>buffer_hear结构的指针,每个请求读写一块数据。如buffer cache对 <BR>buffer_head结构上锁,则进程会等待到对此缓冲的块操作完成。每个 <BR>request结构都从静态链表all_requests中分配。如果此请求被加入到空 <BR>请求链表中,则将调用驱动请求函数以启动此请求队列的处理,否则该设备 <BR>驱动将简单地处理请求链表上的request。 <BR>一旦设备驱动完成了请求则它必须将每个buffer_heard结构从request结 <BR>构中清除,将它们标记成已更新状态并解锁之。对buffer_head的解锁将 <BR>唤醒所有等待此块操作完成的睡眠进程。如解析文件名称时,EXT2文件系 <BR>统必须从包含此文件系统的设备中读取包含下个EXT2目录入口的数据块。 <BR>在buffer_head上睡眠的进程在设备驱动被唤醒后将包含此目录入口。 <BR>request数据结构被标记成空闲以便被其它块请求使用。 <BR>8.5 硬盘 <BR>磁盘驱动器提供了一个永久性存储数据的方式,将数据保存在旋转的盘片 <BR>上。写入数据时磁头将磁化盘片上的一个小微粒。这些盘片被连接到一个 <BR>中轴上并以3000到10,000RPM(每分钟多少转)的恒定速度旋转。而软盘 <BR>的转速仅为360RPM。磁盘的读/写磁头负责读写数据,每个盘片的两侧各 <BR>有一个磁头。磁头读写时并不接触盘片表面而是浮在距表面非常近的空气 <BR>垫中(百万分之一英寸)。磁头由一个马达驱动在盘片表面移动。所有的 <BR>磁头被连在一起,它们同时穿过盘片的表面。 <BR>盘片的每个表面都被划分成为叫做磁道的狭窄同心圆。0磁道位于最外面 <BR>而最大磁道位于最靠近中央主轴。柱面指一组相同磁道号的磁道。所以每 <BR>个盘片上的第五磁道组成了磁盘的第五柱面。由于柱面号与磁道号相等所 <BR>以我们经常可以看到以柱面描叙的磁盘布局。每个磁道可进一步划分成扇 <BR>区。它是硬盘数据读写的最小单元同时也是磁盘的块大小。一般的扇区大 <BR>小为512字节并且这个大小可以磁盘制造出来后格式化时设置。 <BR>一个磁盘经常被描绘成有多少各柱面、磁头以及扇区。例如系统启动时 <BR>Linux将这样描叙一个IDE硬盘: <BR>hdb: Conner Peripherals 540MB - CFS540A, 516MB w/64kB Cache, <BR>CHS=1050/16/63 <BR>这表示此磁盘有1050各柱面(磁道),16个磁头(8个盘片)且每磁道包 <BR>含63个扇区。这样我们可以通过扇区数、块数以及512字节扇区大小计算 <BR>出磁盘的存储容量为529200字节。这个容量和磁盘自身声称的516M字节并 <BR>不相同,这是因为有些扇区被用来存放磁盘分区信息。有些磁盘还能自动 <BR>寻找坏扇区并重新索引磁盘以正常使用。 <BR>物理硬盘可进一步划分成分区。一个分区是一大组为特殊目的而分配的扇 <BR>区。对磁盘进行分区使得磁盘可以同时被几个操作系统或不同目的使用。 <BR>许多Linux系统具有三个分区:DOS文件系统分区,EXT2文件系统分区和交 <BR>换分区。硬盘分区用分区表来描叙;表中每个入口用磁头、扇区及柱面号 <BR>来表示分区的起始与结束。对于用DOS格式化的硬盘有4个主分区表。但不 <BR>一定所有的四个入口都被使用。fdisk支持3中分区类型:主分区、扩展分 <BR>区及逻辑分区。扩展分区并不是真正的分区,它只不过包含了几个逻辑分 <BR>区。扩展和逻辑分区用来打破四个主分区的限制。以下是一个包含两个主 <BR>分区的fdisk命令的输出: <BR>Disk /dev/sda: 64 heads, 32 sectors, 510 cylinders <BR>Units = cylinders of 2048 * 512 bytes <BR> Device Boot Begin Start End Blocks Id System <BR>/dev/sda1 1 1 478 489456 83 Linux native <BR>/dev/sda2 479 479 510 32768 82 Linux swap <BR>Expert command (m for help): p <BR>Disk /dev/sda: 64 heads, 32 sectors, 510 cylinders <BR>Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID <BR> 1 00 1 1 0 63 32 477 32 978912 83 <BR> 2 00 0 1 478 63 32 509 978944 65536 82 <BR> 3 00 0 0 0 0 0 0 0 0 00 <BR> 4 00 0 0 0 0 0 0 0 0 00 <BR>这些内容表明第一个分区从柱面(或者磁道)0,头1和扇区1开始一直 <BR>到柱面477,扇区22和头63结束。由于每磁道有32个扇区且有64个读写 <BR>磁头则此分区在大小上等于柱面数。fdisk使分区在柱面边界上对齐。 <BR>它从最外面的柱面0开始并向中间扩展478个柱面。第二个分区:交换分 <BR>区从478号柱面开始并扩展到磁盘的最内圈。 <BR>在初始化过程中Linux取得系统中硬盘的拓扑结构映射。它找出有多少 <BR>中硬盘以及是什么类型。另外Linux还要找到每个硬盘的分区方式。所 <BR>有这些都用由gendisk_head链指针指向的gendisk结构链表来表示。每 <BR>个磁盘子系统如IDE在初始化时产生表示磁盘结构的gendisk结构。同 <BR>时它将注册其文件操作例程并将此入口添加到blk_dev数据结构中。每 <BR>个gendisk结构包含唯一的主设备号,它与块相关设备的主设备号相同。 <BR>例如SCSI磁盘子系统创建了一个主设备号为8的gendisk入口("sd"), <BR>这也是所有SCSI硬盘设备的主设备号。图8.3给出了两个gendisk入口, <BR>一个表示SCSI磁盘子系统而另一个表示IDE磁盘控制器。ide0表示主IDE <BR>控制器。 <BR>尽管磁盘子系统在其初始化过程中就建立了gendisk入口,但是只有Linux <BR>作分区检查时才使用。每个磁盘子系统通过维护一组数据结构将物理 <BR>硬盘上的分区与某个特殊主从特殊设备互相映射。无论何时通过buffer <BR>cache或文件操作对块设备的读写都将被核心定向到对具有某个特定主 <BR>设备号的设备文件上(如/dev/sda2)。而从设备号的定位由各自设备 <BR>驱动或子系统来映射。 <BR>8.5.1 IDE 硬盘 <BR>Linux系统上使用得最广泛的硬盘是集成电子磁盘或者IDE硬盘。IDE是 <BR>一个硬盘接口而不是类似SCSI的I/O总线接口。每个IDE控制器支持两 <BR>个硬盘,一个为主另一个为从。主从硬盘可以通过盘上的跳线来设置。 <BR>系统中的第一个IDE控制器成为主IDE控制器而另一个为从属控制器。 <BR>IDE可以以每秒3.3M字节的传输率传输数据且最大容量为538M字节。EIDE <BR>或增强式IDE可以将磁盘容量扩展到8.6G字节而数据传输率为16.6M字节/秒。 <BR>由于IDE和EIDE都比SCSI硬盘便宜,所以大多现代PC机在包含一个或几个 <BR>板上IDE控制器。 <BR>Linux以其发现控制器的顺序来对IDE硬盘进行命名。在主控制器中的主 <BR>盘为/dev/hda而从盘为/dev/hdb。/dev/hdc用来表示从属IDE控制器中的 <BR>主盘。IDE子系统将向Linux核心注册IDE控制器而不是IDE硬盘。主IDE控 <BR>制器的主标志符为3而从属IDE控制器的主标志符为22。如果系统中包含两 <BR>个IDE控制器则IDE子系统的入口在blk_dev和blkdevs数组的第2和第22处。 <BR>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -