aeb@cwi.nl
要查看本文档的最新版本,请访问 www.win.tue.nl。
您获得了一个新磁盘。该怎么做?好吧,在软件方面:使用 fdisk
或 cfdisk
创建分区,然后使用 mke2fs
或 mkreiserfs
等创建文件系统,然后使用 mount
将新文件系统附加到大型文件层次结构。确保您拥有这些实用程序的相对较新版本 - 通常旧版本在处理大磁盘时会遇到问题。
您无需阅读本 HOWTO,因为现在的大硬盘没有任何问题。
很久以前,当磁盘容量大于 528 MB,或大于 8.4 GB,或大于 33.8 GB 时,磁盘才算大。如今,有趣的限制是 137 GB。在所有情况下,足够新的 Linux 内核都能很好地处理磁盘。
有时启动需要一些注意,因为 Linux 在尚未运行时无法为您提供帮助。但是,同样,使用足够新的 BIOS 和启动加载器,就不会有问题。以下大部分文本将处理以下情况:(i)旧硬件,(ii)损坏的硬件或 BIOS,(iii)同一磁盘上的多个操作系统,(iv)启动旧系统。
建议
对于大型 SCSI 磁盘:Linux 从很早以前就支持它们。无需采取任何措施。
对于大型 IDE 磁盘(超过 8.4 GB):请确保您的内核是 2.0.34 或更高版本。
对于大型 IDE 磁盘(超过 33.8 GB):请确保您的内核是 2.0.39/2.2.14/2.3.21 或更高版本。
对于大型 IDE 磁盘(超过 137 GB):请确保您的内核是 2.4.19/2.5.3 或更高版本。
如果内核启动正常,并且启动消息指示它正确识别了磁盘,但实用程序存在问题,请升级实用程序。
如果 LILO 在启动时挂起,请确保您拥有 21.4 或更高版本,并在配置文件 /etc/lilo.conf
中指定关键字 lba32
。对于旧版本的 LILO,请尝试使用和不使用 linear
关键字。
可能存在几何结构问题,可以通过向内核/LILO/fdisk 提供显式几何结构来解决。
如果您有一个旧的 fdisk
并且它警告 重叠 分区:忽略警告,或使用 cfdisk
检查是否一切正常。
对于 HPT366,请参阅 Linux HPT366 HOWTO。
如果在启动时内核无法读取分区表,请考虑是否选择了 UDMA66,而控制器或电缆或磁盘驱动器不支持 UDMA66。在这种情况下,每次读取尝试都会失败,而读取分区表是内核要做的第一件事。确保未使用 UDMA66。
如果 BIOS 由于大磁盘而在启动时挂起,并且刷新较新版本不是一种选择,请将磁盘从 BIOS 设置中取出。如果您必须从磁盘启动,请查看容量裁剪跳线是否有帮助。
如果您认为磁盘大小有问题,请确保您没有混淆二进制和十进制 单位,并意识到 df
在空磁盘上报告的可用空间比分区大小小几个百分点,因为存在管理开销。不理解 48 位寻址的软件会将 137+ GB 的磁盘视为容量为 137 GB。当存在容量裁剪 跳线 时,较大的磁盘可能已被裁剪为 33 GB 或 2 GB。
如果对于可移动驱动器,内核报告两个不同的大小,则一个是来自驱动器的,另一个是来自磁盘/软盘的。当驱动器没有介质时,第二个值将为零。
现在,如果您仍然认为存在问题,或者只是好奇,请继续阅读。
以下是所有相关细节的相当详细的描述。我使用了内核版本 2.0.8 源代码作为参考。其他版本可能略有不同。
千字节 (kB) 是 1000 字节。兆字节 (MB) 是 1000 kB。吉字节 (GB) 是 1000 MB。太字节 (TB) 是 1000 GB。这是 SI 标准。但是,有人使用 1 MB=1024000 字节并谈论 1.44 MB 软盘,也有人认为 1 MB=1048576 字节。在这里,我遵循 最新标准,并将 Ki、Mi、Gi、Ti 用于二进制单位,以便这些软盘为 1440 KiB(1.47 MB,1.41 MiB),1 MiB 为 1048576 字节(1.05 MB),1 GiB 为 1073741824 字节(1.07 GB),而 1 TiB 为 1099511627776 字节(1.1 TB)。
磁盘驱动器制造商非常正确地遵循 SI 标准并使用十进制单位。但是,Linux 内核启动消息(对于不太新的内核)和一些旧的 fdisk 类型程序使用符号 MB 和 GB 表示二进制或混合二进制-十进制单位。因此,在您认为您的磁盘比购买时承诺的要小时,请首先计算十进制单位(或仅字节)的实际大小。
关于二进制单位的术语和缩写,Knuth 有一个替代 建议,即使用 KKB、MMB、GGB、TTB、PPB、EEB、ZZB、YYB 并将它们称为大千字节、大兆字节、...大尧字节。他写道:“请注意,重复字母既表示二进制性,又表示大尺寸。”这是一个很好的建议——“大吉字节”听起来比“吉比字节”更好。然而,对于我们的目的而言,唯一重要的是强调兆字节正好有 1000000 字节,并且如果您指的是其他含义,则需要一些其他术语和缩写。
磁盘访问以称为扇区的单位完成。为了从磁盘读取或写入某些内容,我们必须指定磁盘上的位置,例如通过给出扇区号。如果磁盘是 SCSI 磁盘,则此扇区号直接进入 SCSI 命令并被磁盘理解。如果磁盘是使用 LBA 的 IDE 磁盘,则情况完全相同。但是,如果磁盘是旧的,RLL 或 MFM 或 LBA 时代之前的 IDE,则磁盘硬件期望三元组(柱面、磁头、扇区)来指定磁盘上的所需位置。
磁盘的扇区编号为 0、1、2、... 这称为 LBA 寻址。
在古代,在 IDE 磁盘出现之前,磁盘具有由三个常数 C、H、S 描述的几何结构:柱面数、磁头数、每磁道扇区数。扇区的地址由三个数字给出:c、h、s:柱面号(介于 0 和 C-1 之间)、磁头号(介于 0 和 H-1 之间)以及磁道内的扇区号(介于 1 和 S 之间),其中出于某种神秘的原因,c 和 h 从 0 开始计数,但 s 从 1 开始计数。这称为 CHS 寻址。
最近十年内制造的磁盘都没有几何结构,但是古老的 3D 扇区寻址仍然被 INT13 BIOS 接口使用(具有与任何物理现实无关的幻想数字 C、H、S)。
线性编号与此 3D 表示法之间的对应关系如下:对于具有 C 个柱面、H 个磁头和 S 个扇区/磁道的磁盘,3D 或 CHS 表示法中的位置 (c,h,s) 与线性或 LBA 表示法中的位置 c*
H*
S + h*
S + (s-1) 相同。
因此,为了访问非常旧的非 SCSI 磁盘,我们需要知道其几何结构,即 C、H 和 S 的值。(如果您不知道,www.thetechpage.com 上有很多有用的信息。)
在本文中,一个扇区有 512 字节。这几乎总是正确的,但例如某些 MO 磁盘使用 2048 字节的扇区大小,并且下面给出的所有容量都必须乘以四。(在这些磁盘上使用 fdisk
时,请确保您拥有 2.9i 或更高版本,并给出 `-b 2048' 选项。)
具有 C 个柱面、H 个磁头和 S 个扇区/磁道的磁盘总共有 C*
H*
S 个扇区,并且可以存储 C*
H*
S*
512 字节。例如,如果磁盘标签说 C/H/S=4092/16/63,则磁盘有 4092*
16*
63=4124736 个扇区,并且可以容纳 4124736*
512=2111864832 字节 (2.11 GB)。行业惯例是对于大于 8.4 GB 的磁盘给出 C/H/S=16383/16/63,并且磁盘大小不再能从磁盘报告的 C/H/S 值中读取出来。
旧的 INT13 BIOS 接口到磁盘 I/O 使用 24 位来寻址扇区:10 位用于柱面,8 位用于磁头,6 位用于磁道内的扇区号(从 1 开始计数)。这意味着此接口最多只能寻址 1024*256*63 个扇区,即 8.5 GB(使用 512 字节扇区)。并且如果为磁盘指定的(幻想)几何结构的柱面少于 1024 个,或磁头少于 256 个,或每磁道扇区少于 63 个,则此限制将更小。
(更准确地说:使用 INT 13,AH 选择要执行的功能,CH 是柱面号的低 8 位,CL 在位 7-6 中具有柱面号的高两位,在位 5-0 中具有扇区号,DH
是磁头号,DL 是驱动器号 (80h 或 81h)。这解释了分区表的部分布局。)
当引入所谓的扩展 INT13 功能时,这种情况得到了纠正。现代 BIOS 在访问大磁盘时没有问题。
(更准确地说:DS:SI 指向一个 16 字节的磁盘地址包,其中包含一个 8 字节的起始绝对块号。)
Linux 不使用 BIOS,因此没有(并且过去也没有)这个问题。
但是,这种几何结构的东西在分区表的解释中起作用,因此,如果 Linux 与例如 DOS 共享磁盘,那么它需要知道 DOS 会认为磁盘具有什么几何结构。它在启动时也起作用,BIOS 必须加载启动加载器,并且启动加载器必须加载操作系统。
旧的 ATA 标准描述了如何使用 28 位(8 位用于扇区,4 位用于磁头,16 位用于柱面)寻址 IDE 磁盘上的扇区。这意味着 IDE 磁盘最多可以有 2^28 个可寻址扇区。使用 512 字节扇区,这是 2^37 字节,即 137.4 GB。
ATA-6 标准包括如何寻址超过 2^28 扇区边界的规范。新标准允许寻址 2^48 个扇区。最新的 Linux 内核(例如 2.4.18-pre7-ac3 和 2.5.3)中支持已合并 Andre Hedrick 的 IDE 补丁。
Maxtor 自 2001 年秋季以来销售 160 GB IDE 磁盘。旧内核会将此类磁盘视为 137.4 GB 磁盘。
最多 65536 个柱面(编号 0-65535),16 个磁头(编号 0-15),255 个扇区/磁道(编号 1-255),最大总容量为 267386880 个扇区(每个扇区 512 字节),即 136902082560 字节 (137 GB)。2001 年 9 月,出现了第一个大于此值的驱动器(160 GB Maxtor Diamondmax)。
最多 1024 个柱面(编号 0-1023),256 个磁头(编号 0-255),63 个扇区/磁道(编号 1-63),最大总容量为 8455716864 字节 (8.5 GB)。这在今天是一个严重的限制。这意味着 DOS 无法使用当今的大型磁盘。
如果 BIOS Int 13 调用和 IDE 磁盘 I/O 使用相同的 c、h、s 值,则两个限制相结合,最多可以使用 1024 个柱面,16 个磁头,63 个扇区/磁道,最大总容量为 528482304 字节 (528MB),即 DOS 的臭名昭著的 504 MiB 限制(使用旧 BIOS)。这在 1993 年左右开始成为一个问题,人们求助于各种技巧,包括硬件 (LBA)、固件(转换 BIOS)和软件(磁盘管理器)。“转换”的概念被发明出来(1994 年):BIOS 可以在与驱动器通信时使用一种几何结构,而在与 DOS 通信时使用另一种伪造的几何结构,并在两者之间进行转换。
一些较旧的 BIOS 只为 CMOS RAM 中的字段分配 12 位,该字段给出柱面数。因此,此数字最多为 4095,并且只能访问 4095*
16*
63*
512=2113413120 字节。拥有更大磁盘的效果是在启动时挂起。这使得几何结构为 4092/16/63 的磁盘非常流行。直到今天,许多大型磁盘驱动器仍然配备跳线,使其看起来像 4092/16/63。另请参阅 over2gb.htm。 其他 BIOS 不会挂起,而只会检测到一个小得多的磁盘,例如 429 MB 而不是 2.5 GB。
Phoenix 4.03 和 4.04 BIOS 固件中存在一个错误,该错误会导致系统在 CMOS 设置中锁定容量超过 3277 MB 的驱动器。请参阅 over3gb.htm。
简单的 BIOS 转换(ECHS=扩展 CHS,有时称为“大磁盘支持”或简称为“大”)通过重复将磁头数加倍并将显示给 DOS 的柱面数减半来工作,直到柱面数最多为 1024。现在 DOS 和 Windows 95 无法处理 256 个磁头,并且在磁盘报告 16 个磁头的常见情况下,这意味着这种简单的机制仅适用于 8192*
16*
63*
512=4227858432 字节(具有 1024 个柱面、128 个磁头、63 个扇区/磁道的伪造几何结构)。请注意,ECHS 不会更改每磁道扇区数,因此如果不是 63,则限制会更低。请参阅 over4gb.htm。
稍微智能的 BIOS 通过首先将磁头数调整为 15(“修订的 ECHS”)来避免先前的问题,以便可以获得具有 240 个磁头的伪造几何结构,这对于 1024*
240*
63*
512=7927234560 字节来说是足够的。
最后,如果 BIOS 尽其所能使此转换成功,并使用 255 个磁头和 63 个扇区/磁道(“辅助 LBA”或简称为“LBA”),则它可以达到 1024*
255*
63*
512=8422686720 字节,略小于之前的 8.5 GB 限制,因为必须避免使用 256 个磁头的几何结构。(此转换将对磁头数使用序列 16、32、64、128、255 中的第一个值 H,总磁盘容量适合 1024*
H*
63*
512,然后计算柱面数 C 为总容量除以 (H*
63*
512)。)
下一个障碍出现在大小超过 33.8 GB 时。问题在于,对于默认的 16 个磁头和 63 个扇区/磁道,这对应于超过 65535 的柱面数,这不适合短整数。许多 BIOS 无法处理此类磁盘。(例如,请参阅 华硕升级 以获取可用的新闪存映像。)旧于 2.2.14 / 2.3.21 的 Linux 内核需要补丁程序。请参阅下面的 34+ GB 磁盘的 IDE 问题。
如上所述,旧的 ATA 协议使用 16+4+8 = 28 位来指定扇区号,因此无法寻址超过 2^28 个扇区。ATA-6 描述了一种扩展,该扩展允许寻址 2^48 个扇区,是以前的一百万倍。非常新的内核中提供了支持。
使用 32 位扇区号,可以寻址 2 TiB。一旦磁盘变得更大,许多软件将不得不重写。
超过 8.4 GB 的硬盘驱动器应该将其几何结构报告为 16383/16/63。这实际上意味着“几何结构”已经过时,并且总磁盘大小不再能从几何结构计算出来,而是在 IDENTIFY 命令 返回的 LBA 容量字段中找到。超过 137.4 GB 的硬盘驱动器应该报告 0xfffffff = 268435455 个扇区(137438952960 字节)的 LBA 容量。现在,实际磁盘大小在新的 48 容量字段中找到。
当系统启动时,BIOS 从第一个磁盘(或从软盘或 CDROM)读取扇区 0(称为 MBR - 主引导记录),并跳转到那里找到的代码 - 通常是一些引导程序加载器。在那里找到的这些小型引导程序通常没有自己的磁盘驱动程序,而是使用 BIOS 服务。这意味着,除非您同时拥有现代 BIOS(支持扩展 INT13 功能的 BIOS)和现代启动加载器(在可用时使用这些功能的启动加载器),否则只能启动完全位于前 1024 个柱面内的 Linux 内核。
这个问题(如果它是一个问题)很容易解决:确保内核(以及启动期间使用的其他文件,例如 LILO 映射文件)位于分区上,该分区完全包含在 BIOS 可以访问的磁盘的前 1024 个柱面内 - 这可能意味着第一个或第二个磁盘。
因此:创建一个小分区,例如 10 MB 大小,以便有空间容纳少量内核,确保它完全包含在第一个或第二个磁盘的前 1024 个柱面内。将其挂载到 /boot
,以便 LILO 将其内容放在那里。
1998 年或之后的大多数系统都将具有现代 BIOS。
总结:如果您使用 LILO 作为启动加载器,请确保您拥有 LILO 21.4 或更高版本。(可以在 ftp://metalab.unc.edu/pub/Linux/system/boot/lilo/ 找到。)始终使用 lba32
选项。
调用 /sbin/lilo
(启动映射安装程序)会在启动映射中存储地址列表,以便 LILO(启动加载器)知道从何处读取内核映像。默认情况下,这些地址以 (c,h,s) 形式存储,并且在启动时使用普通的 INT13 调用。
当配置文件指定 lba32
或 linear
时,将存储线性地址。使用 lba32
时,如果在 BIOS 支持扩展 INT13 的情况下,也会在启动时使用线性地址。使用 linear
或旧 BIOS 时,这些线性地址会转换回 (c,h,s) 形式,并使用普通的 INT13 调用。
因此,使用 lba32
,没有几何结构问题,也没有 1024 柱面限制。不使用它,则存在 1024 柱面限制。几何结构呢?
启动加载器和 BIOS 必须就磁盘几何结构达成一致。 /sbin/lilo
向内核询问几何结构,但不保证 Linux 内核几何结构与 BIOS 将使用的几何结构一致。因此,内核提供的几何结构通常毫无价值。在这种情况下,向 LILO 提供“linear
”选项会有所帮助。优点是 Linux 内核对几何结构的理解不再起作用。缺点是当内核的某些部分存储在 1024 柱面限制之上时,lilo
无法警告您,您最终可能会得到一个无法启动的系统。
在低于 v21 的 LILO 版本中,还有另一个缺点:启动时完成的地址转换存在错误:当 c*H 为 65536 或更大时,计算中会发生溢出。对于大于 64 的 H,这会导致对 c 的限制比众所周知的 c < 1024 更严格;例如,对于 H=255 和旧的 LILO,必须有 c < 258。(c=内核映像所在的柱面,H=磁盘的磁头数)
Tim Williams 写道:“我的 Linux 分区在前 1024 个柱面内,但仍然无法启动。当我将其移动到 1 GB 以下时,事情才开始工作。”这怎么可能呢?好吧,这是一个带有 AHA2940UW 控制器的 SCSI 磁盘,它使用 H=64,S=32(即 1 MiB = 1.05 MB 的柱面)或 H=255,S=63(即 8.2 MB 的柱面),具体取决于固件和 BIOS 中的设置选项。毫无疑问,BIOS 假定前者,因此在 1 GiB 处找到 1024 柱面限制,而 Linux 使用后者,LILO 认为此限制在 8.4 GB 处。
nuni
启动加载器不使用 BIOS 服务,而是直接访问 IDE 驱动器。因此,可以将其放在软盘或 MBR 中,并从任何 IDE 驱动器上的任何位置启动(不仅限于前两个)。在 //metalab.unc.edu/pub/Linux/system/boot/loaders/ 找到它。
LILO 有点脆弱,它需要每次安装新内核时都运行 /sbin/lilo
的纪律。一些其他启动加载器没有这个缺点。特别是 grub
现在很流行;一个主要的缺点是它不支持 lilo -R label
功能。
如果您的磁盘上有多个操作系统,则每个操作系统都使用一个或多个磁盘分区。关于这些分区在哪里的分歧可能会带来灾难性后果。
MBR 包含一个分区表,描述了(主)分区的位置。有 4 个表条目,用于 4 个主分区,每个条目看起来像
struct partition {
char active; /* 0x80: bootable, 0: not bootable */
char begin[3]; /* CHS for first sector */
char type;
char end[3]; /* CHS for last sector */
int start; /* 32 bit sector number (counting from 0) */
int length; /* 32 bit number of sectors */
};
(其中 CHS 代表柱面/磁头/扇区)。此信息是冗余的:分区的位置由 24 位 begin
和 end
字段以及 32 位 start
和 length
字段给出。
Linux 仅使用 start
和 length
字段,因此可以处理不超过 2^32 个扇区的分区,即最多 2 TiB 的分区。这比今天可用的磁盘大十二倍,所以也许在未来五年左右的时间里就足够了。(因此,分区可能非常大,但存在一个严重的限制,即具有 32 位整数的硬件上的 ext2 文件系统中的文件不能大于 2 GiB。)
DOS 使用 begin
和 end
字段,并使用 BIOS INT13 调用来访问磁盘,因此即使使用转换 BIOS,也只能处理不超过 8.4 GB 的磁盘。(由于 FAT16 文件系统的限制,分区不能大于 2.1 GB。)Windows 3.11 和 WfWG 以及 Windows NT 3.* 也一样。
Windows 95 支持扩展 INT13 接口,并使用特殊的分区类型(c、e、f 而不是 b、6、5)来指示应以这种方式访问分区。当使用这些分区类型时,begin
和 end
字段包含虚拟信息 (1023/255/63)。Windows 95 OSR2 引入了 FAT32 文件系统(分区类型 b 或 c),允许分区大小最大为 2 TiB。
当实际上没有任何问题时,您从 fdisk
获得的关于“重叠”分区的废话是什么?好吧 - 有些“错误”:如果您查看此类分区的 begin
和 end
字段(就像 DOS 所做的那样),它们会重叠。(这是无法纠正的,因为这些字段无法存储高于 1024 的柱面号 - 只要您有超过 1024 个柱面,就总会有“重叠”)。但是,如果您查看 start
和 length
字段(就像 Linux 所做的那样,以及 Windows 95 在分区类型为 c、e 或 f 的情况下所做的那样),那么一切都很好。因此,当 cfdisk
感到满意并且您拥有仅限 Linux 的磁盘时,请忽略这些警告。当磁盘与 DOS 共享时,请小心。使用命令 cfdisk -Ps /dev/hdx
和 cfdisk -Pt /dev/hdx
查看 /dev/hdx
的分区表。
许多旧的 IBM PS/2 系统使用磁盘,其缺陷映射写入磁盘末尾。(磁盘参数表 的控制字中的位 0x20 已设置。)因此,FDISK 将不会使用最后一个柱面。为了确保安全,BIOS 通常已经报告磁盘大小比实际小一个柱面,这可能意味着丢失了两个柱面。较新的 BIOS 具有多个磁盘大小报告功能,其中一个内部调用另一个。当两者都为此保留柱面减去 1,并且 FDISK 也这样做时,则可能会丢失三个柱面。如今,所有这些都不相关,但这可以解释为什么有人观察到不同的实用程序对磁盘大小的看法略有不同。
一个众所周知的说法是,分区应在柱面边界处开始和结束。
由于“磁盘几何结构”是没有客观存在的东西,因此不同的操作系统将为同一磁盘发明不同的几何结构。人们经常看到一个操作系统使用像 */255/63 这样的转换几何结构,而另一个操作系统使用像 */16/63 这样的未转换几何结构。(有人告诉我 Windows NT 使用 */64/32,而 Windows 2K 使用 */255/63。)因此,根据每个系统对柱面大小的各种想法,将分区与柱面边界对齐可能是不可能的。此外,不同的 Linux 内核可能会为同一磁盘分配不同的几何结构。此外,启用或禁用 SCSI 卡的 BIOS 可能会更改连接的 SCSI 磁盘的伪造几何结构。
幸运的是,对于 Linux 而言,根本没有对齐要求。(除了某些半损坏的安装软件喜欢非常确定一切正常;因此,在具有未对齐分区的磁盘上安装 RedHat 7.1 可能会失败,因为 DiskDruid 不满意。)
人们报告说,在 Windows NT 中创建未对齐的分区很容易,而没有任何明显的负面影响。
但是 MSDOS 6.22 有对齐要求。未位于柱面边界上的扩展分区扇区会被其 FDISK 忽略。系统本身对任何对齐方式都很满意,但是解释相对起始地址时,就好像相对于对齐的地址一样:逻辑分区的起始地址不是相对于描述它的扩展分区扇区的地址,而是相对于包含该扇区的柱面的起始地址。(因此,PartitionMagic 也需要对齐就不足为奇了。)
对齐的定义是什么?MSDOS 6.22 FDISK 将执行以下操作:1. 如果柱面的第一个扇区是分区表扇区,则磁道的其余部分未使用,并且分区从下一个磁道开始。这适用于扇区 0(MBR)和逻辑分区之前的分区表扇区。2. 否则,分区从柱面的第一个扇区开始。扩展分区也从柱面边界开始。 cfdisk
手册页说,旧版本的 DOS 不对齐分区。
对扩展分区使用分区类型 85 使其对 DOS 不可见,从而确保只有 Linux 会查看内部。
顺便提一句:在 Sparc 架构上,启动分区必须从柱面边界开始(但对结束位置没有要求)。
磁盘几何结构(包括磁头、柱面和磁道)是 MFM 和 RLL 时代的产物。在那个时代,它对应着物理现实。如今,使用 IDE 或 SCSI,没有人关心磁盘的“真实”几何结构是什么。实际上,每个磁道的扇区数是可变的——靠近磁盘外缘的磁道扇区更多——因此不存在“真实”的每磁道扇区数。恰恰相反:IDE 命令 INITIALIZE DRIVE PARAMETERS (91h) 用于告诉磁盘今天它应该有多少磁头和每磁道扇区数。看到一块大型现代磁盘报告 2 个磁头,但向 BIOS 报告 15 或 16 个磁头,而 BIOS 又可能向用户软件报告 255 个磁头,这非常正常。
对于用户来说,最好将磁盘视为一个简单的线性扇区数组,编号为 0、1、...,并将其留给固件来找出给定扇区在磁盘上的位置。这种线性编号称为 LBA。
所以现在的概念图景如下。DOS 或某些引导加载程序使用 (c,h,s) 符号与 BIOS 通信。BIOS 使用用户正在使用的假的几何结构将 (c,h,s) 转换为 LBA 符号。如果磁盘接受 LBA,则此值用于磁盘 I/O。否则,它会使用磁盘当前使用的几何结构转换回 (c',h',s'),并用于磁盘 I/O。
请注意,在“LBA”表达式的使用中存在一些混淆:作为描述磁盘功能的术语,它表示“线性块寻址”(与 CHS 寻址相反)。作为 BIOS 设置中的术语,它描述了一种有时称为“辅助 LBA”的转换方案——请参见上面“8.4 GB 限制”下的内容。
当固件不支持 LBA 但 BIOS 了解转换时,也会发生类似的情况。(在设置中,这通常表示为“Large”。)现在,BIOS 将向操作系统呈现几何结构 (C,H,S),并在与磁盘控制器通信时使用 (C',H',S')。通常 S = S',C = C'/N,H = H'*N,其中 N 是确保 C' <= 1024 的最小 2 的幂(以便通过 C' = C/N 中的向下舍入浪费最少的容量)。同样,这允许访问高达 8.4 GB (7.8 GiB) 的容量。
(第三个设置选项通常是“Normal”,不涉及任何转换。)
如果 BIOS 不了解“Large”或“LBA”,则存在软件解决方案。像 OnTrack 或 EZ-Drive 这样的磁盘管理器会用它们自己的程序替换 BIOS 磁盘处理例程。通常,这是通过让磁盘管理器代码驻留在 MBR 和后续扇区中来实现的(OnTrack 将此代码称为 DDO:动态驱动器覆盖),以便它在任何其他操作系统之前启动。这就是为什么当安装了磁盘管理器时,从软盘启动可能会遇到问题的原因。
效果与使用转换 BIOS 或多或少相同——但特别是当在同一磁盘上运行多个不同的操作系统时,磁盘管理器可能会引起很多麻烦。
自 1.3.14 版本以来,Linux 开始支持 OnTrack Disk Manager,自 1.3.29 版本以来,开始支持 EZ-Drive。更多详细信息将在下一节中给出。
在 2.5.70 版本中,自动磁盘管理器支持被移除。取而代之的是添加了两个启动选项:“hda=remap”用于执行 EZ-Drive 将扇区 0 重映射到扇区 1 的操作,以及“hda=remap63”用于执行 OnTrack Disk Manager 偏移 63 个扇区的操作。
如果 Linux 内核检测到 IDE 磁盘上存在某些磁盘管理器,它将尝试以与该磁盘管理器相同的方式重新映射磁盘,以便 Linux 看到的磁盘分区与例如使用 OnTrack 或 EZ-Drive 的 DOS 相同。但是,如果在命令行上指定了几何结构,则不会进行重新映射——因此 `hd=
cyls,
heads,
secs' 命令行选项很可能会破坏与磁盘管理器的兼容性。
如果您遇到了这种情况,并且认识可以为您编译新内核的人,请找到文件 linux/drivers/block/ide.c
并在例程 ide_xlate_1024()
中删除测试 if (drive->forced_geom) { ...; return 0; }
。
重新映射是通过尝试 4、8、16、32、64、128、255 个磁头(保持 H*
C 恒定)来完成的,直到 C <= 1024 或 H = 255。
详细信息如下——小节标题是在相应的启动消息中出现的字符串。本文以及其他任何地方的分区类型都以十六进制给出。
EZ-Drive 的检测方法是,第一个主分区类型为 55。几何结构如上所述重新映射,并且丢弃扇区 0 的分区表——而是从扇区 1 读取分区表。磁盘块号未更改,但写入扇区 0 的操作被重定向到扇区 1。可以通过使用 ide.c
中的 #define FAKE_FDISK_FOR_EZDRIVE 0
重新编译内核来更改此行为。
OnTrack DiskManager(在第一个磁盘上)的检测方法是,第一个主分区类型为 54。几何结构如上所述重新映射,并且整个磁盘偏移 63 个扇区(以便旧的扇区 63 变为扇区 0)。之后,从新的扇区 0 读取新的 MBR(带有分区表)。当然,这种偏移是为了给 DDO 腾出空间——这就是为什么其他磁盘上没有偏移的原因。
OnTrack DiskManager(在其他磁盘上)的检测方法是,第一个主分区类型为 51 或 53。几何结构如上所述重新映射。
较旧版本的 OnTrack DiskManager 不是通过分区类型检测到的,而是通过签名检测到的。(测试在 MBR 的字节 2 和 3 中找到的偏移量是否不超过 430,并且在此偏移量处找到的 short 值等于 0x55AA,并且后面跟一个奇数字节。)几何结构再次如上所述重新映射。
最后,有一个测试尝试从主分区的 start
和 end
值推断出转换:如果某个分区的起始和结束扇区号分别为 1 和 63,并且结束磁头为 31、63、127 或 254,那么,由于习惯上分区以柱面边界结束,并且由于 IDE 接口最多使用 16 个磁头,因此推测 BIOS 转换处于活动状态,并且几何结构被重新映射为分别使用 32、64、128 或 255 个磁头。但是,当当前几何结构概念已经有每磁道 63 个扇区且至少有相同数量的磁头时,则不进行重新映射(因为这可能意味着已经进行了重新映射)。
当 Linux 检测到 OnTrack Disk Manager 时,它会将所有磁盘访问偏移 63 个扇区。同样,当 Linux 检测到 EZ-Drive 时,它会将扇区 0 的所有访问偏移到扇区 1。这意味着可能难以摆脱这些磁盘管理器。大多数磁盘管理器都有卸载选项,但如果您需要删除某些磁盘管理器,通常有效的一种方法是在命令行上给出显式的磁盘几何结构。现在 Linux 跳过了 ide_xlate_1024()
例程,并且可以使用以下命令擦除带有磁盘管理器的分区表(并且可能丢失对所有磁盘数据的访问):
dd if=/dev/zero of=/dev/hdx bs=512 count=1
详细信息在内核版本上略有不同。最新的内核(自 2.3.21 起)可以识别像 “hda=remap” 和 “hdb=noremap” 这样的启动参数,因此无论分区表的内容如何,都可以获得或避免 EZD 偏移。“hdX=noremap” 启动参数还可以避免 OnTrack Disk Manager 偏移。
在 2.5.70 版本中,自动磁盘管理器支持被移除。取而代之的是添加了两个启动选项:“hda=remap”用于执行 EZ-Drive 将扇区 0 重映射到扇区 1 的操作,以及“hda=remap63”用于执行 OnTrack Disk Manager 偏移 63 个扇区的操作。
这也意味着摆脱磁盘管理器不再是一个问题。
这一切意味着什么?对于 Linux 用户来说,只有一件事:他们必须确保 LILO 和 fdisk
使用正确的几何结构,其中“正确”对于 fdisk
的定义是与同一磁盘上的其他操作系统使用的几何结构相同,对于 LILO 的定义是能够与启动时的 BIOS 成功交互的几何结构。(通常这两者是一致的。)
fdisk
如何知道几何结构?有三个信息来源。首先,如果用户以交互方式或在命令行上指定了几何结构,那么我们采用用户输入。其次,如果可以从分区表猜测使用的几何结构,那么我们使用它。第三,当没有其他可用信息时,fdisk
使用 HDIO_GETGEO
ioctl 询问内核。
LILO 如何知道几何结构?它使用 HDIO_GETGEO
ioctl 询问内核。但是用户可以使用 /etc/lilo.conf
中的 `disk=
' 选项覆盖几何结构(请参阅 lilo.conf(5))。也可以为 LILO 提供 linear
选项,它将在其映射文件中存储 LBA 地址而不是 CHS 地址,并在启动时找出要使用的几何结构(通过使用 INT 13 Function 8 来询问驱动器几何结构)。
内核如何知道要回答什么?首先,用户可能已使用 `hda=
cyls,
heads,
secs' 内核命令行选项指定了显式几何结构(请参阅 bootparam(7)),可能是手动指定的,或者通过要求引导加载程序向内核提供这样的选项。例如,可以通过在 /etc/lilo.conf
中添加 `append = "hda=
cyls,
heads,
secs"
' 行来告诉 LILO 提供这样的选项(请参阅 lilo.conf(5))。否则,内核将进行猜测,可能会使用从 BIOS 或硬件获得的值。
请注意,内核猜测的值非常不可靠。内核没有很好的方法来找出 BIOS 使用的值,或者磁盘是否为 BIOS 所知。
可以使用 /proc
文件系统更改内核对几何结构的理解(自 Linux 2.1.79 起)。例如
# sfdisk -g /dev/hdc
/dev/hdc: 4441 cylinders, 255 heads, 63 sectors/track
# cd /proc/ide/ide1/hdc
# echo bios_cyl:17418 bios_head:128 bios_sect:32 > settings
# sfdisk -g /dev/hdc
/dev/hdc: 17418 cylinders, 128 heads, 32 sectors/track
#
如果您需要太多的启动参数以至于超出 LILO(非常有限的)命令行长度,这尤其有用。(如果您想影响通过 HDIO_GETGEO ioctl 从内核获取其几何结构概念的实用程序,这也很有帮助。)自 Linux 2.6.5 起,内核(当使用 CONFIG_EDD 编译时)将使用 INT 13/AH=08h 向 BIOS 询问 legacy_cylinders、legacy_heads、legacy_sectors。获得的值在 /sys/firmware/edd/int13_dev{80,81,82,83}/legacy_*
中可用。在 2.6.5 中,文件是 legacy_{cylinders,heads,sectors}
(内容为十六进制,例如 0xfe 表示 254),但这些名称令人困惑,在 2.6.7 中,它们被更改为 legacy_max_cylinder
、legacy_max_head
、legacy_sectors_per_track
(内容为十进制)。像 C/H/S=1000/255/63 这样的几何结构在这里被找到为 999、254、63。
# insmod edd.ko
# cd /sys/firmware/edd/int13_dev83
# cat legacy_max_head
254
# cat sectors
120064896
#
因此,我们在这里看到一个磁盘,它总共有 255 个磁头和 120064896 个扇区。仔细比较表明这是 /dev/hdf
。BIOS 如何知道几何结构?用户可能已在 CMOS 设置中指定它。或者几何结构是从磁盘读取的,并可能按照设置中的指定进行转换。在 SCSI 磁盘的情况下,由于不存在几何结构,BIOS 必须发明的几何结构通常可以通过跳线或设置选项来指定。(例如,Adaptec 控制器可以选择通常的 H=64、S=32 和“扩展转换” H=255、S=63。)有时 BIOS 会读取分区表以查看上次分区磁盘时使用的几何结构是什么——当存在 55aa 签名时,它将假定存在有效的分区表。这很好,因为它允许将磁盘移动到不同的机器。但是让 BIOS 行为取决于磁盘内容也会引起奇怪的问题。(例如,据报道,一个 2.5 GB 的磁盘被视为具有 528 MB,因为 BIOS 读取了分区表并得出结论,它应该使用未转换的 CHS。在报告中发现了另一种效果,未分区的磁盘比分区的磁盘慢,因为 BIOS 通过读取 MBR 并查看是否正确获得了 55aa 签名来测试 32 位模式。)
磁盘如何知道几何结构?嗯,制造商发明了一种几何结构,其乘积大致等于正确的容量。许多磁盘都有跳线,可以更改报告的几何结构,以避免 BIOS 错误。例如,所有 IBM 磁盘都允许用户在 15 个磁头和 16 个磁头之间进行选择,并且许多制造商添加了跳线,使磁盘看起来小于 2.1 GB 或 33.8 GB。另请参阅下面的跳线。有时,有一些实用程序可以更改磁盘固件。
有时,通过在内核命令行上添加 `hda=
cyls,
heads,
secs' 来强制使用特定的几何结构很有用。几乎总是希望 secs=63,添加此参数的目的是指定 heads。(今天合理的取值是 heads=16 和 heads=255。)应该为 cyls 指定什么?精确地说是那个能够给出正确的 C*H*S 扇区总容量的数字。例如,对于一个具有 71346240 个扇区(36529274880 字节)的驱动器,可以将 C 计算为 71346240/(255*63)=4441(例如使用程序 bc
),并给出启动参数 hdc=4441,255,63
。如何知道正确的总容量?例如,
# hdparm -g /dev/hdc | grep sectors
geometry = 4441/255/63, sectors = 71346240, start = 0
# hdparm -i /dev/hdc | grep LBAsects
CurCHS=16383/16/63, CurSects=16514064, LBA=yes, LBAsects=71346240
给出了两种查找扇区总数 71346240 的方法。最新的内核还在启动消息中给出了精确的大小
# dmesg | grep hde
hde: Maxtor 93652U8, ATA DISK drive
hde: 71346240 sectors (36529 MB) w/2048KiB Cache, CHS=70780/16/63
hde: hde1 hde2 hde3 < hde5 > hde4
hde2: <bsd: hde6 hde7 hde8 hde9 >
旧版本的内核仅给出 MB 和 CHS。通常 CHS 值会被向下舍入,因此上面的输出告诉我们至少有 70780*16*63=71346240 个扇区。在本例中,恰好是精确值。MB 值可能会被舍入而不是截断,并且在旧版本的内核中可能是“二进制”(MiB)而不是十进制。请注意内核大小(MB)和 Maxtor 型号之间的协议。同样在 SCSI 磁盘的情况下,扇区的精确数量在内核启动消息中给出
SCSI device sda: 17755792 512-byte hdwr sectors (9091 MB)
IDE 驱动程序有五个关于几何结构的信息来源。第一个 (G_user) 是用户在命令行上指定的。第二个 (G_bios) 是 BIOS 固定磁盘参数表(仅适用于第一个和第二个磁盘),它在系统启动时、切换到 32 位模式之前读取。第三个 (G_phys) 和第四个 (G_log) 是 IDE 控制器响应 IDENTIFY 命令 返回的——它们是“物理”几何结构和“当前逻辑”几何结构。
另一方面,驱动程序需要两个几何结构值:一方面是 G_fdisk,由 HDIO_GETGEO
ioctl 返回,另一方面是 G_used,它实际上用于执行 I/O。如果给出 G_user,则 G_fdisk 和 G_used 都初始化为 G_user;如果 CMOS 中存在此信息,则初始化为 G_bios;否则初始化为 G_phys。如果 G_log 看起来合理,则将 G_used 设置为 G_log。否则,如果 G_used 不合理且 G_phys 看起来合理,则将 G_used 设置为 G_phys。这里“合理”意味着磁头数在 1-16 的范围内。
换句话说:命令行覆盖 BIOS,并将决定 fdisk
看到的内容,但如果它指定了转换后的几何结构(具有超过 16 个磁头),那么对于内核 I/O,它将被 IDENTIFY 命令的输出覆盖。
请注意,G_bios 相当不可靠:对于从 SCSI 启动的系统,第一个和第二个磁盘很可能都是 SCSI 磁盘,并且 BIOS 为 sda 报告的几何结构被内核用于 hda。此外,BIOS 设置中未提及的磁盘不会被 BIOS 看到。这意味着,例如,在仅 IDE 系统中,如果 hdb 未在设置中给出,则 BIOS 为第一个和第二个磁盘报告的几何结构将应用于 hda 和 hdc。
为了避免这种混淆,自 Linux 2.5.51 起,不再使用 G_bios。
当向 IDE 驱动器发送 IDENTIFY DRIVE (0xec) 命令时,它将返回 256 个字(512 字节)的信息。这包含大量技术内容。让我们在这里仅描述在几何结构问题中起作用的内容。这些字编号为 0-255。
我们在这里找到四个信息:DefaultCHS(字 1,3,6)、CurrentCHS(字 54-58)和 LBAcapacity(字 60-61)以及 48 位容量(字 100-103)。
| 描述 | 示例 |
0 | 位字段:位 6:固定磁盘,位 7:可移动介质 | 0x0040 |
1 | 默认柱面数 | 16383 |
3 | 默认磁头数 | 16 |
6 | 默认每磁道扇区数 | 63 |
10-19 | 序列号(ASCII 码) | G8067TME |
23-26 | 固件版本(ASCII 码) | GAK&1B0 |
27-46 | 型号名称(ASCII 码) | Maxtor 4G160J8 |
49 | 位字段:位 9:支持 LBA | 0x2f00 |
53 | 位字段:位 0:字 54-58 有效 | 0x0007 |
54 | 当前柱面数 | 16383 |
55 | 当前磁头数 | 16 |
56 | 当前每磁道扇区数 | 63 |
57-58 | 当前 LBA 容量 | 16514064 |
60-61 | 默认 LBA 容量 | 268435455 |
82-83 | 支持的命令集 | 7c69 4f09 |
85-86 | 启用的命令集 | 7c68 0e01 |
100-103 | 48 位寻址的最大用户 LBA | 320173056 |
255 | 校验和与签名 (0xa5) | 0x44a5 |
在 ASCII 字符串中,每个字包含两个字符,高位字节是第一个字符,低位字节是第二个字符。32 位值以低位字优先给出。字 54-58 由命令 INITIALIZE DRIVE PARAMETERS (0x91) 设置。它们仅在使用 CHS 寻址时才重要,但在磁盘将 DefaultCHS 设置为 4092/16/63 以避免 BIOS 问题的情况下,可能有助于找到实际的磁盘大小。
有时,当跳线导致大容量驱动器错误报告 LBAcapacity(通常为 66055248 个扇区,以保持在 33.8 GB 限制以下)时,需要第四个信息来查找实际的磁盘大小,即 READ NATIVE MAX ADDRESS (0xf8) 命令的结果。
SCSI 的情况略有不同,因为 SCSI 命令已经使用逻辑块号,因此“几何结构”对于实际的 I/O 完全无关紧要。但是,分区表的格式仍然相同,因此 fdisk
必须发明一些几何结构,并且在这里也使用 HDIO_GETGEO
——实际上,fdisk
不区分 IDE 和 SCSI 磁盘。正如从下面的详细描述中可以看到的,各种驱动程序各自发明了略有不同的几何结构。确实,一团糟。
如果您不使用 DOS 或类似系统,那么请避免所有扩展转换设置,并尽可能使用 64 个磁头、每磁道 32 个扇区(对于方便的每柱面 1 MiB),这样当您将磁盘从一个控制器移动到另一个控制器时,就不会出现问题。一些 SCSI 磁盘驱动程序(aha152x、pas16、ppa、qlogicfas、qlogicisp)对 DOS 兼容性过于敏感,以至于它们不允许仅 Linux 系统使用超过约 8 GiB 的容量。这是一个错误。
真实的几何结构是什么?最简单的答案是没有这样的东西。即使有,您也不想知道,当然永远不要告诉 fdisk
或 LILO 或内核。这严格来说是 SCSI 控制器和磁盘之间的事情。让我重复一遍:只有傻瓜才会告诉 fdisk
/LILO/内核真实的 SCSI 磁盘几何结构。
但是如果您好奇并坚持,您可以询问磁盘本身。有一个重要的命令 READ CAPACITY,它将给出磁盘的总大小,还有一个 MODE SENSE 命令,它在 Rigid Disk Drive Geometry Page(第 04 页)中给出柱面数和磁头数(这是无法更改的信息),在 Format Page(第 03 页)中给出每扇区字节数和每磁道扇区数。后一个数字通常取决于凹槽,并且每磁道扇区数是可变的——外磁道比内磁道有更多的扇区。Linux 程序 scsiinfo
将给出此信息。有很多细节和复杂性,很明显没有人(可能甚至操作系统)想要使用此信息。此外,只要我们只关心 fdisk
和 LILO,通常会得到像 C/H/S=4476/27/171 这样的答案——fdisk
无法使用的值,因为分区表仅为 C/H/S 保留了 10 位、8 位和 6 位。
那么内核 HDIO_GETGEO
从哪里获取其信息呢?嗯,要么来自 SCSI 控制器,要么通过进行有根据的猜测。一些驱动程序似乎认为我们想知道“现实”,但当然我们只想知道 DOS 或 OS/2 FDISK(或 Adaptec AFDISK 等)将使用什么。
请注意,Linux fdisk
需要磁头数 H 和每磁道扇区数 S,才能将 LBA 扇区号转换为 c/h/s 地址,但柱面数 C 在此转换中不起作用。一些驱动程序使用 (C,H,S) = (1023,255,63) 来表示驱动器容量至少为 1023*
255*
63 个扇区。这是不幸的,因为它没有揭示实际大小,并且会将大多数 fdisk
版本的用户限制为大约 8 GiB 的磁盘容量——在当今时代,这是一个真正的限制。
在下面的描述中,M 表示磁盘总容量,C、H、S 表示柱面数、磁头数和每磁道扇区数。如果我们认为 C 由 M / (H*
S) 定义,则只需给出 H、S 即可。
默认情况下,H=64,S=32。
H=64,S=32。
H=64,S=32,除非 C > 1024,在这种情况下 H=255,S=63,C = min(1023, M/(H*
S))。(因此 C 被截断,并且 H*
S*
C 不是磁盘容量 M 的近似值。这将使大多数版本的 fdisk
感到困惑。)ppa.c
代码使用 M+1 而不是 M,并表示由于 sd.c
中的错误,M 偏移了 1。
H=64,S=32,除非 C > 1024,并且 BIOS 中启用了“> 1 GB”选项,在这种情况下 H=255,S=63。
询问控制器正在使用哪两种可能的转换方案,并使用 H=255、S=63 或 H=64、S=32。在前一种情况下,会有一条启动消息“aha1542.c: Using extended bios translation”。
H=64,S=32,除非 C > 1024,并且给出了“extended”启动参数,或者在 SEEPROM 或 BIOS 中设置了“extended”位,在这种情况下 H=255,S=63。在 Linux 2.0.36 中,如果没有找到 SEEPROM,则始终会设置此扩展转换,但在 Linux 2.2.6 中,如果没有找到 SEEPROM,则仅当用户使用此启动参数请求时才设置扩展转换(而在找到 SEEPROM 时,启动参数将被忽略)。这意味着在 2.0.36 下工作的设置可能无法在 2.2.6 下启动(并且需要 LILO 的 linear
关键字或 aic7xxx=extended
内核启动参数)。
H=64,S=32,除非 C >= 1024,并且在控制器上启用了扩展转换,在这种情况下,如果 M < 2^22,则 H=128,S=32;否则 H=255,S=63。但是,在为 (C,H,S) 做出此选择后,将读取分区表,并且如果对于三种可能性 (H,S) = (64,32)、(128,32)、(255,63) 之一,在某处看到值 endH=H-1,则使用该对 (H,S),并打印启动消息“Adopting Geometry from Partition Table”。
在 BIOS 驱动器参数表中查找几何结构信息,或者读取分区表并使用 H=endH+1、S=endS 作为第一个分区,前提是它是非空的,或者对于 M < 2^21 (1 GiB) 使用 H=64、S=32,对于 M < 63*
2^17 (3.9 GiB) 使用 H=128、S=63,否则使用 H=255、S=63。
使用 (H,S) = (64,32)、(64,63)、(128,63)、(255,63) 中的第一个,这将使 C <= 1024。在最后一种情况下,将 C 截断为 1023。
从磁盘读取 C、H、S。(可怕!)如果 C 或 S 太大,则设置 S=17,H=2 并使 H 加倍,直到 C <= 1024。这意味着如果 M > 128*
1024*
17 (1.1 GiB),则 H 将设置为 0。这是一个错误。
根据控制器映射模式,使用三种映射 ((H,S) = (16,63)、(64,32)、(64,63)) 之一。
查看分区表。由于按照惯例分区以柱面边界结束,因此,给定任何分区的 end = (endC,endH,endS)
,我们可以简单地设置 H = endH+1
和 S = endS
。(回想一下,扇区从 1 开始计数。)更准确地说,执行以下操作。如果存在非空分区,则选择具有最大 beginC
的分区。对于该分区,查看 end+1
,通过添加 start
和 length
计算,并通过假设此分区以柱面边界结束来计算。如果两个值一致,或者如果 endC
= 1023 并且 start+length
是 (endH+1)
的整数倍,则假定此分区确实与柱面边界对齐,并设置 H = *
endSendH+1
和 S = endS
。如果这失败,要么是因为没有分区,要么是因为它们的大小很奇怪,那么只查看磁盘容量 M。算法:设置 H = M/(62*
1024)(向上舍入),S = M/(1024*
H)(向上舍入),C = M/(H*
S)(向下舍入)。这具有产生 (C,H,S) 的效果,其中 C 最大为 1024,S 最大为 62。
Linux IDE 驱动程序通过使用 ATA IDENTIFY 请求来获取磁盘的几何结构和容量(以及许多其他内容)。如果 Linux 内核返回的 lba_capacity 值比 C*
H*
S 计算的容量大 10% 以上,则 2.0.34/2.1.90 之前的 Linux 内核将不会相信该值。但是,根据行业协议,大型 IDE 磁盘(具有超过 16514064 个扇区)返回 C=16383、H=16、S=63,总共 16514064 个扇区 (7.8 GB),与其实际大小无关,但在 lba_capacity 中给出其真实大小。
自 2.0.34/2.1.90 版本以来,Linux 内核了解了这一点并做了正确的事情。如果您使用的是较旧的 Linux 内核,并且不想升级,并且此内核仅看到远大于此容量的磁盘的 8 GiB,请尝试将 /usr/src/linux/drivers/block/ide.c
中的例程 lba_capacity_is_ok
更改为类似以下内容:
static int lba_capacity_is_ok (struct hd_driveid *id) {
id->cyls = id->lba_capacity / (id->heads * id->sectors);
return 1;
}
有关更谨慎的补丁,请参见 2.1.90。
正如刚才提到的,大型磁盘返回几何结构 C=16383、H=16、S=63,与其实际大小无关,而实际大小在 LBAcapacity 的值中返回。一些 BIOS 无法识别这一点,并将此 16383/16/63 转换为具有更少柱面和更多磁头的内容,例如 1024/255/63 或 1027/255/63。因此,内核不仅必须识别单个几何结构 16383/16/63,而且还必须识别所有 BIOS 篡改的版本。自 2.2.2 起,这已正确完成(通过采用 BIOS 对 H 和 S 的理解,并计算 C = 容量/(H*S))。通常,此问题通过在 BIOS 设置中将磁盘设置为 Normal(或者,更好的是,设置为 None,根本不向 BIOS 提及它)来解决。如果由于您必须从中启动或也与 DOS/Windows 一起使用而无法做到这一点,并且升级到 2.2.2 或更高版本不是一个选项,请使用内核启动参数。
如果 BIOS 报告 16320/16/63,那么这通常是为了在转换后获得 1024/255/63 而完成的。
这里还有一个额外的问题。如果磁盘是使用几何结构转换进行分区的,那么内核在启动时可能会看到分区表中使用的此几何结构,并报告 hda: [PTBL] [1027/255/63]
。这很糟糕,因为现在磁盘只有 8.4 GB。这在 2.3.21 中得到了修复。同样,内核启动参数会有所帮助。
许多磁盘都有跳线,允许您在 15 头几何结构和 16 头几何结构之间进行选择。默认设置将为您提供 16 头磁盘。有时,两种几何结构都寻址相同数量的扇区,有时 15 头版本更小。这种设置可能有很好的理由:Petri Kaukasoina 写道:“一台 10.1 Gig IBM Deskstar 16 GP(型号 IBM-DTTA-351010)默认跳线为 16 个磁头,但这台旧 PC(带有 AMI BIOS)无法启动,我不得不将其跳线为 15 个磁头。hdparm -i 告诉我 RawCHS=16383/15/63 和 LBAsects=19807200。我使用 20960/15/63 来获得全部容量。” 有关跳线设置,请参阅 http://www.hitachigst.com/hdd/support/jumpers.htm。
许多磁盘都有跳线器,允许你将磁盘显示得比实际容量小。这似乎很愚蠢,可能没有 Linux 用户会想用这个功能,但有些 BIOS 在遇到大容量磁盘时会崩溃。通常的解决方案是将磁盘完全排除在 BIOS 设置之外。但这可能只在磁盘不是你的启动盘时才可行。
第一个 серьезный 限制是 4096 柱面限制(即,在 16 磁头和 63 扇区/磁道的情况下,为 2.11 GB)。 例如,富士通 MPB3032ATU 3.24 GB 硬盘的默认几何参数为 6704/15/63,但可以通过跳线设置为 4092/16/63,然后报告 LBA 容量为 4124736 扇区,这样操作系统就无法得知它的实际容量更大。 在这种情况下(如果 BIOS 因为得知硬盘的真实大小而崩溃,因此需要跳线),则需要启动参数来告知 Linux 硬盘的实际大小。
这很不幸。 大多数磁盘都可以通过跳线设置为显示为 2 GB 磁盘,然后报告一个裁剪后的几何参数,如 4092/16/63 或 4096/16/63,但仍然报告完整的 LBA 容量。 这样的磁盘可以很好地工作,并在 Linux 下使用完整容量,而无需考虑跳线设置。
更新的限制是 33.8 GB 限制。 早于 2.2.14 / 2.3.21 的 Linux 内核需要补丁才能处理大于此容量的 IDE 磁盘。
对于旧的 BIOS 和大于 33.8 GB 的磁盘,BIOS 可能会挂起,在这种情况下,即使将磁盘从 CMOS 设置中移除,也可能无法启动。
因此,IBM、迈拓和希捷的大容量磁盘都带有跳线器,可以将磁盘显示为 33.8 GB 磁盘。 例如,IBM Deskstar 37.5 GB (DPTA-353750) 拥有 73261440 个扇区(对应于 72680/16/63 或 4560/255/63),可以通过跳线设置为显示为 33.8 GB 磁盘,然后报告的几何参数为 16383/16/63,就像任何大容量磁盘一样,但 LBA 容量为 66055248(对应于 65531/16/63 或 4111/255/63)。 最近的迈拓大容量磁盘也存在类似情况。
以下是一些过去相关的更多细节,但现在可能可以忽略。
在存在跳线器的情况下,几何参数 (16383/16/63) 和容量 (66055248) 都是传统的,并且不提供关于实际容量的信息。 此外,尝试访问扇区 66055248 及以上扇区会产生 I/O 错误。 但是,在迈拓驱动器上,可以使用 READ NATIVE MAX ADDRESS 和 SET MAX ADDRESS 命令找到并访问实际容量。 据推测,这就是 MaxBlast/EZ-Drive 所做的事情。 有一个小的 Linux 实用程序 setmax.c 可以执行相同的操作。 只有极少数磁盘需要它 - 几乎总是 CONFIG_IDEDISK_STROKE 可以解决问题。
对于大于 137 GB 的驱动器,READ NATIVE MAX ADDRESS 也返回一个传统值,即 0xfffffff,对应于 137 GB。 这里需要使用 READ NATIVE MAX ADDRESS EXT 和 SET MAX ADDRESS EXT(使用 48 位寻址)。 setmax
实用程序尚不了解这一点。 一个非常小的补丁使 2.5.3 能够处理这种情况。
早期的迈拓大容量磁盘还有一个额外的细节:对于这些 34-40 GB 的磁盘,J46 跳线器将几何参数从 16383/16/63 更改为 4092/16/63,并且不更改报告的 LBA 容量。 这意味着即使存在跳线器,BIOS(旧的 Award 4.5*)也会在启动时挂起。 对于这种情况,迈拓提供了一个实用程序 JUMPON.EXE,用于升级固件以使 J46 的行为如上所述。
在最近的迈拓驱动器上,调用 setmax -d 0 /dev/hdX
将再次为您提供最大容量。 但是,在稍旧的驱动器上,固件错误不允许您使用 -d 0
,而 setmax -d 255 /dev/hdX
会使您恢复到几乎全部容量。 对于迈拓 D540X-4K,请参见下文。
对于 IBM 来说,情况更糟:跳线器确实会裁剪容量,并且没有软件方法可以恢复它。 解决方案是不使用跳线器,而是使用 setmax -m 66055248 /dev/hdX
来通过软件裁剪磁盘。 “怎么做?” 你会说 - “我无法启动!”。 IBM 给出了提示:如果使用 Award BIOS 的系统在驱动器检测期间挂起:重启系统并按住 F4 键以绕过驱动器的自动检测。 如果这没有帮助,请找到另一台计算机,将驱动器连接到它,并在那里运行 setmax
。 完成此操作后,您返回第一台机器,情况与使用跳线的迈拓磁盘相同:启动工作正常,并且在通过 BIOS 后,使用打过补丁的内核或 setmax -d 0
可以使您获得完整容量。
Thomas Charbonnel 报告了一种不同的方法:“我有一个 80 GB 的 IBM IC35L080AVVA07-0 驱动器,并安装了 IBM 的 Disk Manager。 将我的引导加载程序安装在驱动器的 MBR 上。 一切工作正常。 请注意,IDE 驱动器必须成为启动驱动器,以便使用此方法只能安装一个 34+ GB 的驱动器。”
希捷磁盘有一个跳线器,可以在小于 33.8 GB 的驱动器上将报告的柱面数限制为 4092,而在更大的磁盘上,它会将报告的 LBA 容量(Identify words 60/61)限制为 33.8 GB。
对于型号 ST-340810A、ST-360020A、ST-380020A:可以使用 ATA Read Native Max 和 Set Max 命令来重置为真正的完整容量。
对于型号 ST-340016A、ST-340823A、ST-340824A、ST-360021A、ST-380021A:ATA Set Features F1 子命令将导致 Identify Data words 60-61 报告真正的完整容量。
迈拓 Diamond Max 驱动器 4K080H4、4K060H3、4K040H2(又名 D540X-4K)与驱动器 4D080H4、4D060H3、4D040H2(又名 D540X-4D)相同,只是跳线器设置不同。 迈拓 FAQ 指定了它们的主盘/从盘/电缆选择设置,但 “4K” 驱动器的容量限制跳线器似乎未记录在案。 Nils Ohlmeier 报告说,他通过实验发现它是最靠近电源连接器的 J42 跳线器(“工厂使用保留”)。 (“4D” 驱动器使用 J46 跳线器,就像所有其他迈拓驱动器一样。)
但是,可能是这个未记录在案的跳线器的作用类似于 IBM 跳线器:机器可以正确启动,但磁盘已被裁剪为 33 GB,并且 setmax -d 0
无助于恢复完整容量。 而 IBM 的解决方案有效:不要使用任何磁盘裁剪跳线器,而是首先将磁盘放入具有非损坏 BIOS 的机器中,使用 setmax -m 66055248 /dev/hdX
进行软裁剪,然后将其放回第一台机器中,并在启动后运行 setmax -d 0 /dev/hdX
以再次获得完整容量。
与此同时,迈拓网站上出现了一些文档和图片,证实了上述部分内容。 请比较
有关容量裁剪跳线器的设置等信息,请参见 西部数据网站。 我不知道这些跳线器具体做什么。
如果 IDE/ATA 磁盘支持 Host Protected Area (HPA) 功能集,则可以将 LBA 容量设置为低于实际容量的任何值。 访问超出指定点的区域通常会导致 I/O 错误。 由于传统软件通过查看 Identify 信息的 LBA 容量字段来了解磁盘大小,因此此类软件不会怀疑磁盘实际上更大。
磁盘的实际总大小使用 READ NATIVE MAX ADDRESS 命令读取。 这个 “软磁盘大小” 使用 SET MAX ADDRESS 命令设置。 它有两种类型:如果设置了 “易失” 位,则该命令的效果将持续到下次重启或硬件复位; 否则,效果是永久性的。 可以使用密码保护设置。 (有关详细信息,请参见 ATA 标准。)
这种裁剪后的容量(至少)有两个应用:一方面,可以伪造一个较小的磁盘,以便 BIOS 不会出现问题,并让 Linux 或(对于 DOS/Windows)磁盘管理器恢复总容量; 另一方面,可以在末尾设置一个供应商区域,普通用户无法访问。
对于上面讨论的许多磁盘,设置跳线器恰好具有这种效果:LBA 容量减小,而本机最大容量保持不变,并且 SET MAX ADDRESS 将恢复完整容量。
Linux 2.4.19/2.5.3 及更高版本的 CONFIG_IDEDISK_STROKE 选项将告知 Linux 读取本机最大容量并执行 SET MAX ADDRESS 以访问完整容量。 此配置选项位于内核配置部分的 “IDE, ATA and ATAPI block devices” 标题下的 “Auto-Geometry Resizing support” 中。
该配置选项在 2.6.7 中消失,并被一个(每个磁盘)启动参数所取代,因此可以说 “hda=stroke”。
使用此 “stroke” 选项,跳线磁盘在许多情况下将得到正确处理,即,即使存在跳线器,也会看到完整容量。 当磁盘以其他方式(非跳线器)获得 Host Protected Area 时,情况也是如此。
这是处理因 BIOS 损坏而需要跳线器的磁盘的首选方法。
HDIO_GETGEO
ioctl 返回短整型柱面数。 这意味着,如果您的柱面数超过 65535,则该数字将被截断,并且(对于典型的 1 MiB 柱面的 SCSI 设置)80 GiB 磁盘可能会显示为 16 GiB 磁盘。 一旦认识到问题所在,就可以很容易地避免它。 使用 fdisk 2.10i 或更高版本。
(编程约定是使用 BLKGETSIZE
ioctl 获取总大小,使用 HDIO_GETGEO
获取磁头数和扇区/磁道数,并在需要时通过 C = size/(H*S) 获取 C。)
(以下是关于 Linux 内核问题的讨论。 BIOS 问题和裁剪容量的跳线器在 上面 讨论过。)
大于 33.8 GB 的驱动器无法与早于 2.0.39 / 2.2.14 / 2.3.21 的内核一起使用。 详细信息如下。 假设您购买了一个新的 IBM-DPTA-373420 磁盘,容量为 66835440 扇区 (34.2 GB)。 2.3.21 之前的内核会告诉您大小为 769*16*63 = 775152 扇区 (0.4 GB),这有点令人失望。 并且给出命令行参数 hdc=4160,255,63 根本没有帮助 - 这些参数只是被忽略了。 发生了什么? 例程 idedisk_setup() 检索磁盘报告的几何参数(即 16383/16/63)并覆盖用户在命令行上指定的参数,因此用户数据仅用于 BIOS 几何参数。 例程 current_capacity() 或 idedisk_capacity() 将柱面数重新计算为 66835440/(16*63)=66305,但由于它存储在一个短整型中,因此变为 769。 由于 lba_capacity_is_ok() 破坏了 id->cyls,因此后续对它的每次调用都将返回 false,因此磁盘容量变为 769*16*63。 对于多个内核,补丁是可用的。 可以在 ftp.kernel.org 找到 2.0.38 的补丁。 可以在 www.uwsg.indiana.edu 找到 2.2.12 的补丁(可能需要进行一些编辑以去除 html 标记)。 2.2.14 内核确实支持这些磁盘。 在 2.3.* 内核系列中,自 2.3.21 起支持这些磁盘。 也可以通过 使用跳线器 将容量裁剪为 33.8 GB 来 “解决” 硬件问题。 在许多情况下,如果想要从磁盘启动,则需要 BIOS 升级。
如上所述, 我们看到了 MBR(扇区 0)的结构:引导加载程序代码,后跟 4 个分区表项,每个 16 字节,后跟 AA55 签名。 类型为 5 或 F 或 85 (hex) 的分区表项具有特殊意义:它们描述 扩展 分区:进一步划分为 逻辑 分区的空间块。 (因此,扩展分区只是一个框,它本身不能使用,可以使用内部的逻辑分区。) 只有扩展分区的第一个扇区的位置很重要。 第一个扇区包含一个分区表,其中包含四个条目:一个逻辑分区,一个扩展分区和两个未使用的条目。 通过这种方式,可以获得一个分区表扇区链,分散在磁盘上,其中第一个扇区描述了三个主分区和一个扩展分区,而每个后续的分区表扇区描述了一个逻辑分区和下一个分区表扇区的位置。
理解这一点很重要:当人们在分区磁盘时做了一些愚蠢的事情时,他们想知道:我的数据还在吗? 答案通常是:是的。 但是,如果创建了逻辑分区,则描述它们的分区表扇区将写入这些逻辑分区的开头,并且之前存在的数据将丢失。
程序 sfdisk 将显示完整链。 例如,
# sfdisk -l -x /dev/hda
Disk /dev/hda: 16 heads, 63 sectors, 33483 cylinders
Units = cylinders of 516096 bytes, blocks of 1024 bytes, counting from 0
Device Boot Start End #cyls #blocks Id System
/dev/hda1 0+ 101 102- 51376+ 83 Linux
/dev/hda2 102 2133 2032 1024128 83 Linux
/dev/hda3 2134 33482 31349 15799896 5 Extended
/dev/hda4 0 - 0 0 0 Empty
/dev/hda5 2134+ 6197 4064- 2048224+ 83 Linux
- 6198 10261 4064 2048256 5 Extended
- 2134 2133 0 0 0 Empty
- 2134 2133 0 0 0 Empty
/dev/hda6 6198+ 10261 4064- 2048224+ 83 Linux
- 10262 16357 6096 3072384 5 Extended
- 6198 6197 0 0 0 Empty
- 6198 6197 0 0 0 Empty
...
/dev/hda10 30581+ 33482 2902- 1462576+ 83 Linux
- 30581 30580 0 0 0 Empty
- 30581 30580 0 0 0 Empty
- 30581 30580 0 0 0 Empty
#
可以构造错误的分区表。 如果某些扩展分区指回自身或链中较早的分区,则许多内核会进入循环。 可能在一个分区表扇区中有两个扩展分区,从而导致分区表链分支。 (例如,当 fdisk 无法识别 5、F、85 中的每一个作为扩展分区,并在 F 旁边创建 5 时,可能会发生这种情况。) 没有标准的 fdisk 类型程序可以处理这种情况,并且需要一些手工操作来修复它们。 Linux 内核将接受最外层的分支。 也就是说,您可以有两个逻辑分区链。 有时这很有用 - 例如,可以使用类型 5 并被 DOS 看到,而另一种类型 85,对 DOS 不可见,因此 DOS FDISK 不会因为超过 1024 柱面的逻辑分区而崩溃。 通常需要 sfdisk
来创建这样的设置。
许多人认为他们有问题,但实际上没有任何问题。 或者,他们认为他们遇到的问题是由于磁盘几何参数引起的,但实际上磁盘几何参数与此事无关。 以上所有内容可能听起来很复杂,但是磁盘几何参数处理非常容易:什么都不做,一切都很好; 或者,如果 LILO 在启动时无法通过 “LI”,则可能给 LILO 关键字 lba32
。 观看内核启动消息,并记住:您调整几何参数(向 LILO 和 fdisk 以及内核命令行指定磁头和柱面)的次数越多,事情就越不可能正常工作。 粗略地说,默认情况下一切都很好。
并记住:Linux 中的任何地方都没有使用磁盘几何参数,因此您在运行 Linux 时遇到的任何问题都不可能是由磁盘几何参数引起的。 实际上,磁盘几何参数仅由 LILO 和 fdisk 使用。 因此,如果 LILO 无法启动内核,则可能是几何参数问题。 如果不同的操作系统不理解分区表,则可能是几何参数问题。 没有其他问题。 特别是,如果 mount 似乎不起作用,则永远不要担心磁盘几何参数 - 问题出在其他地方。
磁盘很可能获得错误的几何参数。 Linux 内核向 BIOS 询问 hd0 和 hd1(BIOS 驱动器编号为 80H 和 81H),并假设此数据用于 hda 和 hdb。 但是在从 SCSI 启动的系统上,前两个磁盘很可能是 SCSI 磁盘,因此可能会发生第五个磁盘(即第一个 IDE 磁盘 hda)被分配了属于 sda 的几何参数。 通过在启动时或在 /etc/lilo.conf 中为适当的数字 C、H 和 S 提供启动参数 hda=C,H,S
,可以轻松解决此类问题。
自 Linux 2.5.51 以来,不再使用此 BIOS 信息,并且所有磁盘都出现相同的问题。 请参见下文。
“我有两个相同的 10 GB IBM 磁盘。 但是,fdisk 给出的它们的大小不同。 看
# fdisk -l /dev/hdb
Disk /dev/hdb: 255 heads, 63 sectors, 1232 cylinders
Units = cylinders of 16065 * 512 bytes
Device Boot Start End Blocks Id System
/dev/hdb1 1 1232 9896008+ 83 Linux native
# fdisk -l /dev/hdd
Disk /dev/hdd: 16 heads, 63 sectors, 19650 cylinders
Units = cylinders of 1008 * 512 bytes
Device Boot Start End Blocks Id System
/dev/hdd1 1 19650 9903568+ 83 Linux native
怎么回事?”这里发生了什么? 好吧,首先,这些驱动器确实是 10 GB:hdb 的大小为 255*
63*
1232*
512 = 10133544960,hdd 的大小为 16*
63*
19650*
512 = 10141286400,因此,一切正常,内核将两者都视为 10.1 GB。 为什么大小不同? 这是因为内核从 BIOS 获取前两个 IDE 磁盘的数据,并且 BIOS 已将 hdb 重新映射为具有 255 个磁头(和 16*
19650/255=1232 个柱面)。 此处的向下舍入损失了将近 8 MB。
如果您想以相同的方式重新映射 hdd,请提供内核启动参数 hdd=1232,255,63
。
另一方面,如果磁盘不与 DOS 等共享,则最好在 BIOS 设置中将 hdb 设置为 Normal,而不是请求像 LBA 这样的转换。
自 Linux 2.5.51 以来,IDE 驱动程序不再使用前两个磁盘的 BIOS 信息,并且前两个磁盘的不同处理方式已经消失。
由于几何参数不存在,因此 2.0/2.2/2.4/2.6 中的每一个都报告略有不同的磁盘几何参数也就不足为奇了。
有些人会坚持认为几何参数 *确实* 存在,在这种情况下,不是指磁盘的属性,而是指 BIOS 报告的值。 那是其他几个操作系统将要使用的内容。 自 Linux 2.5.51 以来,内核不再使用 BIOS 报告的值 - 很难将 BIOS 设备编号与 Linux 磁盘名称匹配,可能只有两个磁盘的数据可用,可能某些磁盘在 BIOS 设置中不存在,等等。 但是,如果需要这些值,自 Linux 2.6.5 以来,可以设置 CONFIG_EDD 并挂载 sysfs,然后在 /sys/firmware/edd/int13_dev*
下找到各种磁盘的 BIOS 数据。 现在,用户空间软件可以完成 BIOS 编号(以目录名称(如 int13_dev82
)表示)与 Linux 名称(如 sda
)的匹配,可能需要用户的帮助。
当许多在同一磁盘上同时使用 Linux 和 Windows 的用户从 2.4 升级到 2.6,并使用尚未更新的分区工具程序 parted
时,2.5.51 的更改导致了问题。 我尚未检查当前的 parted 是否正常。
fdisk 将告诉您磁盘上有多少块。 如果您在磁盘上创建文件系统,例如使用 mke2fs,则此文件系统需要一些空间用于簿记 - 通常约为文件系统大小的 4%,如果您在 mke2fs 期间要求大量 inode,则会更多。 例如
# sfdisk -s /dev/hda9
4095976
# mke2fs -i 1024 /dev/hda9
mke2fs 1.12, 9-Jul-98 for EXT2 FS 0.5b, 95/08/09
...
204798 blocks (5.00%) reserved for the super user
...
# mount /dev/hda9 /somewhere
# df /somewhere
Filesystem 1024-blocks Used Available Capacity Mounted on
/dev/hda9 3574475 13 3369664 0% /mnt
# df -i /somewhere
Filesystem Inodes IUsed IFree %IUsed Mounted on
/dev/hda9 4096000 11 4095989 0% /mnt
#
我们有一个包含 4095976 个块的分区,在其上创建一个 ext2 文件系统,将其挂载到某个位置,并发现它只有 3574475 个块 - 521501 个块 (12%) 丢失给了 inode 和其他簿记。 请注意,总共 3574475 个块与用户可用的 3369664 个块之间的差异是正在使用的 13 个块加上为 root 保留的 204798 个块。 后一个数字可以通过 tune2fs 更改。 此 `-i 1024` 仅对新闻 spool 之类的东西合理,其中包含大量小文件。 默认值将是
# mke2fs /dev/hda9
# mount /dev/hda9 /somewhere
# df /somewhere
Filesystem 1024-blocks Used Available Capacity Mounted on
/dev/hda9 3958475 13 3753664 0% /mnt
# df -i /somewhere
Filesystem Inodes IUsed IFree %IUsed Mounted on
/dev/hda9 1024000 11 1023989 0% /mnt
#
现在只有 137501 个块 (3.3%) 用于 inode,因此我们比以前多了 384 MB。 (显然,每个 inode 占用 128 字节。) 另一方面,此文件系统最多可以有 1024000 个文件(绰绰有余),而之前为 4096000 个(太多)。