📄 +ަ
字号:
8.4.2 块设备
块设备也支持以文件方式访问。系统对块设备特殊文件提供了非常类似于字符特殊文件的文件操作机制。Linux在blkdevs数组中维护所有已注册的块设备。象chrdevs数组一样,blkdevs也使用设备的主设备号进行索引。其入口也是device_struct结构。和字符设备不同的是系统有几类块设备。SCSI设备是一类而IDE设备则是另外一类。它们将以各自类别登记到Linux核心中并为核心提供文件操作功能。某类块设备的设备驱动为此类型设备提供了类别相关的接口。如SCSI设备驱动必须为SCSI子系统提供接口以便SCSI子系统能用它来为核心提供对此设备的文件操作。
和普通文件操作接口一样, 每个块设备驱动必须为buffer cache提供接口。每个块设备驱动将填充其在blk_dev数组中的blk_dev_struct结构入口。数组的索引值还是此设备的主设备号。这个blk_dev_struct结构包含请求过程的地址以及指向请求数据结构链表的指针,每个代表一个从buffer cache中来让设备进行数据读写的请求。
图8.2 buffer cache块设备请求
每当buffer cache希望从一个已注册设备中读写数据块时,它会将request结构添加到其blk_dev_struct中。图8.2表示每个请求有指向一个或多个buffer_hear结构的指针,每个请求读写一块数据。如buffer cache对buffer_head结构上锁, 则进程会等待到对此缓冲的块操作完成。每个request结构都从静态链表all_requests中分配。如果此请求被加入到空请求链表中,则将调用驱动请求函数以启动此请求队列的处理,否则该设备驱动将简单地处理请求链表上的request 。
一旦设备驱动完成了请求则它必须将每个buffer_heard结构从request结构中清除,将它们标记成已更新状态并解锁之。对buffer_head的解锁将唤醒所有等待此块操作完成的睡眠进程。如解析文件名称时,EXT2文件系统必须从包含此文件系统的设备中读取包含下个EXT2目录入口的数据块。在buffer_head上睡眠的进程在设备驱动被唤醒后将包含此目录入口。request数据结构被标记成空闲以便被其它块请求使用。
8.5 硬盘
磁盘驱动器提供了一个永久性存储数据的方式,将数据保存在旋转的盘片上。写入数据时磁头将磁化盘片上的一个小微粒。这些盘片被连接到一个中轴上并以3000到10,000RPM(每分钟多少转)的恒定速度旋转。而软盘的转速仅为360RPM。磁盘的读/写磁头负责读写数据,每个盘片的两侧各有一个磁头。磁头读写时并不接触盘片表面而是浮在距表面非常近的空气垫中(百万分之一英寸)。磁头由一个马达驱动在盘片表面移动。所有的磁头被连在一起,它们同时穿过盘片的表面。
盘片的每个表面都被划分成为叫做磁道的狭窄同心圆。0磁道位于最外面而最大磁道位于最靠近中央主轴。柱面指一组相同磁道号的磁道。所以每个盘片上的第五磁道组成了磁盘的第五柱面。由于柱面号与磁道号相等所以我们经常可以看到以柱面描叙的磁盘布局。每个磁道可进一步划分成扇区。它是硬盘数据读写的最小单元同时也是磁盘的块大小。一般的扇区大小为512字节并且这个大小可以磁盘制造出来后格式化时设置。
一个磁盘经常被描绘成有多少各柱面、磁头以及扇区。例如系统启动时Linux将这样描叙一个IDE硬盘:
hdb: Conner Peripherals 540MB - CFS540A, 516MB w/64kB Cache, CHS=1050/16/63
这表示此磁盘有1050各柱面(磁道),16个磁头(8个盘片)且每磁道包含63个扇区。这样我们可以通过扇区数、块数以及512字节扇区大小计算出磁盘的存储容量为529200字节。这个容量和磁盘自身声称的516M字节并不相同,这是因为有些扇区被用来存放磁盘分区信息。有些磁盘还能自动寻找坏扇区并重新索引磁盘以正常使用。
物理硬盘可进一步划分成分区。一个分区是一大组为特殊目的而分配的扇区。对磁盘进行分区使得磁盘可以同时被几个操作系统或不同目的使用。许多Linux系统具有三个分区:DOS文件系统分区,EXT2文件系统分区和交换分区。硬盘分区用分区表来描叙;表中每个入口用磁头、扇区及柱面号来表示分区的起始与结束。对于用DOS格式化的硬盘有4个主分区表。但不一定所有的四个入口都被使用。fdisk 支持3中分区类型:主分区、扩展分区及逻辑分区。扩展分区并不是真正的分区,它只不过包含了几个逻辑分区。扩展和逻辑分区用来打破四个主分区的限制。以下是一个包含两个主分区的fdisk命令的输出:
Disk /dev/sda: 64 heads, 32 sectors, 510 cylinders
Units = cylinders of 2048 * 512 bytes
Device Boot Begin Start End Blocks Id System
/dev/sda1 1 1 478 489456 83 Linux native
/dev/sda2 479 479 510 32768 82 Linux swap
Expert command (m for help): p
Disk /dev/sda: 64 heads, 32 sectors, 510 cylinders
Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID
1 00 1 1 0 63 32 477 32 978912 83
2 00 0 1 478 63 32 509 978944 65536 82
3 00 0 0 0 0 0 0 0 0 00
4 00 0 0 0 0 0 0 0 0 00
这些内容表明第一个分区从柱面(或者磁道)0,头1和扇区1开始一直到柱面477,扇区22和头63结束。 由于每磁道有32个扇区且有64个读写磁头则此分区在大小上等于柱面数。fdisk使分区在柱面边界上对齐。 它从最外面的柱面0开始并向中间扩展478个柱面。第二个分区:交换分区从478号柱面开始并扩展到磁盘的最内圈。
图8.3 磁盘链表
在初始化过程中Linux取得系统中硬盘的拓扑结构映射。它找出有多少中硬盘以及是什么类型。另外Linux 还要找到每个硬盘的分区方式。所有这些都用由gendisk_head链指针指向的gendisk结构链表来表示。每个磁盘子系统如IDE在初始化时产生表示磁盘结构的gendisk结构。同时它将注册其文件操作例程并将此入口添加到blk_dev数据结构中。每个gendisk结构包含唯一的主设备号,它与块相关设备的主设备号相同。例如SCSI磁盘子系统创建了一个主设备号为8的gendisk入口("sd"),这也是所有SCSI硬盘设备的主设备号。图8.3给出了两个gendisk入口,一个表示SCSI磁盘子系统而另一个表示IDE磁盘控制器。ide0表示主IDE控制器。
尽管磁盘子系统在其初始化过程中就建立了gendisk入口, 但是只有Linux作分区检查时才使用。每个磁盘子系统通过维护一组数据结构将物理硬盘上的分区与某个特殊主从特殊设备互相映射。无论何时通过 buffer cache或文件操作对块设备的读写都将被核心定向到对具有某个特定主设备号的设备文件上(如 /dev/sda2)。而从设备号的定位由各自设备驱动或子系统来映射。
8.5.1 IDE 硬盘
Linux系统上使用得最广泛的硬盘是集成电子磁盘或者IDE硬盘。IDE是一个硬盘接口而不是类似SCSI的I/O总线接口。每个IDE控制器支持两个硬盘,一个为主另一个为从。主从硬盘可以通过盘上的跳线来设置。系统中的第一个IDE控制器成为主IDE控制器而另一个为从属控制器。IDE可以以每秒3.3M字节的传输率传输数据且最大容量为538M字节。EIDE或增强式IDE可以将磁盘容量扩展到8.6G字节而数据传输率为16.6M字节/秒。由于IDE和EIDE都比SCSI硬盘便宜, 所以大多现代PC机在包含一个或几个板上IDE控制器。
Linux以其发现控制器的顺序来对IDE硬盘进行命名。在主控制器中的主盘为/dev/hda而从盘为/dev/hdb。/dev/hdc用来表示从属IDE控制器中的主盘。IDE子系统将向Linux核心注册IDE控制器而不是IDE硬盘。主IDE控制器的主标志符为3而从属IDE控制器的主标志符为22。如果系统中包含两个IDE控制器则IDE子系统的入口在blk_dev和blkdevs数组的第2和第22处。IDE的块设备文件反应了这种编号方式,硬盘 /dev/hda和/dev/hdb都连接到主IDE控制器上,其主标志符为3。对IDE子系统上这些块相关文件的文件或者buffer cache的操作都通过核心使用主设备标志符作为索引定向到IDE子系统上。当发出请求时,此请求由哪个IDE硬盘来完成取决于IDE子系统。为了作到这一点IDE子系统使用从设备编号对应的设备特殊标志符,由它包含的信息来将请求发送到正确的硬盘上。位于主IDE控制器上的IDE从盘/dev/hdb的设备标志符为(3,64)。而此盘中第一个分区(/dev/hdb1)的设备标志符为(3,65)。
8.5.2 初始化IDE子系统
IDE磁盘与IBM PC关系非常密切。在这么多年中这些设备的接口发生了变化。这使得IDE子系统的初始化过程比看上去要复杂得多。
Linux可以支持的最多IDE控制器个数为4。每个控制器用ide_hwifs数组中的ide_hwif_t结构来表示。每个ide_hwif_t结构包含两个ide_drive_t结构以支持主从IDE驱动器。在IDE子系统的初始化过程中Linux通过访问系统CMOS来判断是否有关于硬盘的信息。这种CMOS由电池供电所以系统断电时也不会遗失其中的内容。它 位于永不停止的系统实时时钟设备中。此CMOS内存的位置由系统BIOS来设置,它将通知Linux系统中有多少个IDE控制器与驱动器。Linux使用这些从BIOS中发现的磁盘数据来建立对应此驱动器的ide_hwif_t结构。 许多现代PC系统使用PCI芯片组如Intel 82430 VX芯片组将PCI EIDE控制器封装在内。IDE子系统使用PCI BIOS回调函数来定位系统中PCI (E)IDE控制器。然后对这些芯片组调用PCI特定查询例程。
每次找到一个IDE接口或控制器就有建立一个ide_hwif_t结构来表示控制器和与之相连的硬盘。在操作过程中IDE驱动器对I/O内存空间中的IDE命令寄存器写入命令。主IDE控制器的缺省控制和状态寄存器是0x1F0 - 0x1F7。这个地址由早期的IBM PC规范设定。IDE驱动器为每个控制器向Linux注册块缓冲cache和VFS节点并将其加入到blk_dev和blkdevs数组中。IDE驱动器需要申请某个中断。一般主IDE控制器中断号为14而从属IDE控制器为15。然而这些都可以通过命令行选项由核心来重载。IDE驱动器同时还将gendisk入口加入到启动时发现的每个IDE控制器的gendisk链表中去。分区检查代码知道每个IDE控制器可能包含两个IDE硬盘。
8.5.3 SCSI 硬盘
SCSI(小型计算机系统接口)总线是一种高效的点对点数据总线,它最多可以支持8个设备,其中包括多个主设备。每个设备有唯一的标志符并可以通过盘上的跳线来设置。在总线上的两个设备间数据可以以同步或异步方式,在32位数据宽度下传输率为40M字节来交换数据。SCSI总线上可以在设备间同时传输数据与状态信息。initiator设备和target设备间的执行步骤最多可以包括8个不同的阶段。你可以从总线上5个信号来分辨SCSI总线的当前阶段。这8个阶段是:
BUS FREE
当前没有设备在控制总线且总线上无事务发生。
ARBITRATION
一个SCSI设备试图取得SCSI总线的控制权,这时它将其SCSI标志符放置到地址引脚上。具有最高SCSI标志符编号的设备将获得总线控制权。
SELECTION
当设备通过仲裁成功地取得了对SCSI总线的控制权后它必须向它准备发送命令的那个SCSI设备发出信号。具体做法是将目标设备的SCSI标志符放置在地址引脚上进行声明。
RESELECTION
在一个请求的处理过程中SCSI设备可能会断开连接。目标(target)设备将再次选择启动设备 (initiator)。不是所有的SCSI设备都支持此阶段。
COMMAND
此阶段中initiator设备将向target设备发送6、10或12字节命令。
DATA IN, DATA OUT
此阶段中数据将在initiator设备和target设备间传输。
STATUS
所有命令完毕后将进入此阶段,此时允许target设备向initiator设备发送状态信息以指示操作成功与否。
MESSAGE IN, MESSAGE OUT
此阶段附加信息将在initiator设备和target设备间传输。
Linux SCSI子系统由两个基本部分组成,每个由一个数据结构来表示。
host
一个SCSI host即一个硬件设备:SCSI控制权。NCR 810 PCI SCSI控制权即一种SCSI host。在Linux 系统中可以存在相同类型的多个SCSI控制权,每个由一个单独的SCSI host来表示。这意味着一个SCSI设备驱动可以控制多个控制权实例。SCSI host总是SCSI命令的initiator设备。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -