Large Disk mini-HOWTO 中譯版 作者: Andries Brouwer, [1]jaeb@cwi.nl 譯者: Asd L. Chen, [2]asdchen@ms1.hinet.net v1.0, 26 June 1996 翻譯日期: 10-13 November 1997 _________________________________________________________________ 所有有關 disk geometry 及 1024 cylinder 的限制. _________________________________________________________________ 1. 問題所在 2. 啟動 3. 磁碟 geometry 以及分割區 4. 轉換與磁碟管理程式 5. 核心的 IDE 磁碟轉換 * 5.1 EZD * 5.2 DM6:DDO * 5.3 DM6:AUX * 5.4 DM6:MBR * 5.5 PTBL 6. 結論 * 6.1 IDE 細節 * 6.2 SCSI 細節 _________________________________________________________________ 1. 問題所在 假如你的磁碟超過 1024 個磁簇(cylinders). 還有, 假如你的作業系統使用基 本輸出入系統(BIOS).那麼你會遇到一個問題, 因為一般磁碟輸出入/輸入所使 用的 INT13 BIOS 介面以一個 10 位元(bit) 的欄位來操作磁簇, 所以無法存取 第 1024 及之後的磁簇. 幸運的是, Linux 不使用 BIOS, 所以沒有問題. 話是這麼說, 但有兩件事例外: (1) 當你在啟動系統時, Linux 還沒開始執行所以無法讓你避免這個問題.這對 LILO 以及類似的啟動載入程式(boot loaders)有些影響. (2) 使用磁碟的所有作業系統必須同意分割區的位置.換句話說, 如果你在一顆 磁碟上使用 Linux 以及, 例如 DOS, 那麼兩者必須以相同的方式解讀分割表的資 料.這對 Linux 核心以及 fdisk 有些影響. 底下是對所有相關細節更詳細的描述.注意, 我使用 2.0.8 版核心原始程式做為 參考.其它的版本可能有一點點出入. 2. 啟動 當系統啟動時, BIOS 從第一個磁碟(或從軟碟)讀取磁區 0 (一般通稱的 MBR - Master Boot Record, 主啟動磁區)並跳至在該處的程式碼 - 通常是一些啟動載 入程式(bootstrap loader). 這些小小的啟動程式一般不會有自己的磁碟驅動程 式而會使用 BIOS 所提供的服務.這意謂著只有整個 Linux 核心都位於開頭的 1024 個磁簇內時才能夠被啟動. 這個問題很容易解決: 確定核心(也許還包括其它啟動時用到的檔案, 像是 LILO map 檔) 是放在一個 BIOS 可以存取的到, 全都在開頭的 1024 個磁簇內的分割 區裡 - 這可以(可能)是第一個或第二個磁碟. 另一點是啟動載入程式與 BIOS 必須同意彼此對磁碟邏輯(geometry)上的看法. 給 LILO `linear' 這個選項參數可能會有些幫助.細節後述. 3. 磁碟 geometry 以及分割區 如果你的磁碟上有好幾種作業系統, 每一種使用一個或多個分割區.那麼對於分 割區位於何處不同的看法可能導致災難性的後果. MBR 中包含一個分割表描述分割區(主分割區: primary) 在那裡.有四個表格給 四個主要分割區使用, 它們看起來像 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 是磁簇/磁頭/磁區: Cylinder/Head/Sector 的縮寫) 因此, 有項資訊是重覆的: 分割區的位置可以由 24 位元的 begin 以及 end 欄 位, 和 32 位元的 start 以及 length 欄位給定. Linux 只使用 start 以及 length 欄位, 故最多可以處理包含 2^32 個磁區的分 割區, 也就是, 最大 2 TB 的分割區.這是現今磁碟機的兩百倍, 所以也許足夠 往後十年的需求. 不幸的是, BIOS INT13 呼叫使用三個位元組的 CHS 編碼, 10 個位元作為磁簇號 碼, 8 個位元作為磁頭號碼, 及 6 個位元作為磁軌上的磁區號碼. 可能的磁簇 號碼是 0-1023, 可能的磁頭號碼是 0-255, 而磁軌上可能的磁區號碼為 1-63(是 的, 磁軌上的磁區是由 1 起算, 不是 0). 以這 24 位元最多可以定址 8455716864 個位元組(7.875 GB), 這是 1983 年磁碟機的兩百倍. 更不幸的是, 標準的 IDE 介面容許 256 個磁區/磁軌, 65536 個磁簇以及 16 個磁頭.它自己本身可以存取 2^37 = 137438953472 個位元組(128 GB), 但是加 上 BIOS 方面 63 個磁區與 1024 個磁簇的限制後只剩 528482304 個位元 組(504 MB)可以定址的到. 這不足以應付現今的磁碟, 人們使用各種硬體或軟體上的方法來克服. 4. 轉換與磁碟管理程式 沒有人對磁碟的'真實' geometry 有興趣.磁軌的磁區數通常是變動的 - 接近磁 碟外圍的磁軌有比較多的磁區 - 所以沒有'真實'的每磁軌磁區數. 對於使用者 而言最好是把磁碟當作編號 0,1,..., 的磁區組合成的線性陣列, 讓控制器去找 出磁區究竟位於磁碟的那裡. 此線性編號一般通稱為 LBA.對於 geometry 為 (C,H,S) 的磁碟而言屬(c,h,s) 的線性位址為 c*H*S+h*S+(s-1).所有 SCSI 控制器都使用 LBA, 某些 IDE 控制 器也是. 如果 BIOS 把這 24 個位元(c,h,s) 轉換成 LBA 並餵給懂得 LBA 的控制器, 那 麼又可以定址到 7.875 GB .並不足以應付所有的磁碟, 但仍然是個改進.注意 此處 BIOS 使用的 CHS, 它不再與'實體'有任何關係. 當控制器不懂何為 LBA 但是 BIOS 知道如何轉換時有些類似的方法可行.(在 BIOS 設定中通常稱為 'Large'.)現在 BIOS 將呈現 geometry 為(C',H',S')給 作業系統, 而在與磁碟控制器溝通時則使用(C,H,S). 通常 S=S', C'=C/N 而 H'=H*N, 其中 N 是確保 C'<=1024 之 2 的最小次方(所以 C'=C/N 時捨去的數浪 費少許容量).再一次, 這允許存取最多達 7.875 GB. 如果 BIOS 不知道 'Large' 或是 'LBA', 那麼還是有軟體的解決方案.像是 OnTracker 或 EZ-Drive 這些個磁碟管理程式會以它們自己的函式(routines)替 換掉 BIOS 的. 通常這是藉由將磁碟管理程式放在 MBR 及其後幾個磁 區(OnTrack 稱這些程式碼為 DDO: Dynamic Drive Overlay )來達成的, 所以它 會在任何其它作業系統之前被啟動. 這也就是為什麼在安裝磁碟管理程式後從軟 碟啟動可能會出問題. 這影響可能多於或少於 BIOS 轉換 - 但特別是在相同的磁碟上跑數種不同的作業 系統時, 磁碟管理程式可能引起許多問題. Linux 從 1.3.14 版開始支援 OnTrack 磁碟管理程式, 從 1.3.29 開始 支援 EZ-Drive .下面有些更進一步的資訊. 5. 核心的 IDE 磁碟轉換 如果 Linux 偵測到 IDE 磁碟上有某些磁碟管理程式存在, 它將會試著使用與該 磁碟管理程式相同的方式來重新對應磁碟, 所以 Linux 看到與, 例如 DOS 配合 OnTrack 或是 EZ-Drive 相同的磁碟分割. 然而, 當你在指令列上指定 geometry 時, 就不會做任何的重新對應 - 所以一行 `hd=cyls,heads,secs' 指 令列選項可能取消掉與磁碟管理程式的相容. 此重新對應的方式是嘗試 4,8,16,32,64,128,255 磁頭數(H*C 保持不變)直到 C <= 1024 或是 H = 255. 細節如下 - 小節的抬頭是出現在相對應之啟動訊息裡的字串.在此以及在這份文 件任何其它地方中分割的型態都以十六進位數字表示. 5.1 EZD 偵測到 EZ-Drive , 因為第一個主要分割區型態為 55 .如上述重新對應 geometry, 且忽略從第 0 磁區讀入的分割表 - 以第 1 磁區的分割表取代.磁碟 的區塊號碼(block numbers) 沒有改變, 但對磁區 0 的寫入會轉向磁區 1.此動 作可以藉由修改在 ide.c 中的 #define FAKE_FDISK_FOR_EZDRIVE 0 並重新編譯核心來改變. 5.2 DM6:DDO 偵測到 OnTrack DiskManager(在第一個磁碟上), 因為第一個主要分割區型態為 54 .如上述重新對應 geometry 而且整個磁碟平移 63 個磁區. (所以舊的磁區 63 變成磁區 0)然後從新的第 0 磁區讀入新的 MBR (與分割表).此平移當然是 為 DDO 留空間 - 這也就是為什麼其它磁碟不必平移. 5.3 DM6:AUX 偵測到 OnTrack DiskManager(在其它磁碟上), 因為第一個主要分割區型態為 51 或 53.如上述重新對應 geometry . 5.4 DM6:MBR 偵測到某舊版的 OnTrack DiskManager, 並非藉由分割區型態, 而是簽 名(signature).(測試在 MBR 裡第 2,3 位元組的偏移值是否不大於 430, 而且 在此偏移位址找到的 short 等於 0x55AA, 後面並跟著一個奇數的位元組) 再一 次如上述重新對應 geometry . 5.5 PTBL 最後, 核心會嘗試從主分割區的 start 以及 end 值推斷轉換方式: 若某些分割 區的 start 以及 end 磁簇小於 256, 而且 start 以及 end 磁區號碼分別為 1 和 63 , 而且 end 磁頭為 31, 63, 或 127, 那麼, 因為依慣例分割區會在磁簇 邊界結束, 而且更因為 IDE 介面最多使用 16 個磁頭, 故推測有開啟 BIOS 轉 換, 分別使用 32, 64 或 128 磁頭數重新對應 geometry. (也許這裡有點瑕 疵, genhd.c 不應該測試磁簇號碼前兩個位元嗎?)無論如何, 當目前的 geometry 已經為每磁軌 63 個磁區且至少這麼多磁頭時, 不會做重新對應 (因為 這可能意謂著重對應已完成). 6. 結論 這到底意謂著什麼? 對 Linux 的使用者而言只有一件事: 就是他們必須得確保 LILO 以及 fdisk 使用正確的 geometry , 其中'正確'的定義對 fdisk 而言是與 其它在同一個磁碟上的作業系統所使用的 geometry 相同, 而對 LILO 而言是能 夠在啟動時期成功地與 BIOS 交談的 geometry.(這兩者通常相符.) fdisk 如何得知該 geometry ? 它詢問核心, 使用 HDIO_GETGEO ioctl.但使用 者可以交談式地或在指令列上重定 geometry. LILO 如何得知該 geometry ? 它詢問核心, 使用 HDIO_GETGEO ioctl. 但使用 者可以用 `disk=' 選項重定.也可以給 LILO 一個 linear 選項, 如此它將在其 map 檔中儲存 LBA 位址以取代 CHS 位址, 並且在啟動時期找出該 geometry 來 使用(藉由 INT 13 功能呼叫 8 來詢問磁碟的 geometry). 核心如何知道該怎麼回答? 首先, 使用者可能以 `hd=cyls,heads,secs' 指令列 選項明確地指定 geometry, 否則核心將詢問硬體. 6.1 IDE 細節 讓我詳細說明.IDE 驅動程式有四個關於 geometry 的資訊來源.第一 個(G_user)是使用者在指令列上所指定的. 第二個(G_bios)是 BIOS 的固定磁碟 參數表(只用於第一及第二個磁碟), 在系統啟動時, 切換至 32 位元模式之前讀 入. 第三個(G_phys)及第四個(G_log) 是由 IDE 控制器傳回, 作為對 IDENTIFY 指令的回應 - 它們是 '實體的' 以及 '目前邏輯上的' geometries. 另一方面, 對於 geometry 驅動程式需要兩個值: 其中之一是 G_fdisk, 由 HDIO_GETGEO ioctl 傳回, 另一個是 G_used , 這是執行輸出/入時實際使用的 . 如果給定 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 看到的樣子, 但如果它指 定轉換的 geometry(磁頭數大於 16), 則核心會藉由 IDENTIFY 指令的輸出重定 它. 6.2 SCSI 細節 在 SCSI 方面情況有一點點不同, 因為 SCSI 指令已經使用邏輯區塊號碼, 所以 'geometry' 對實際的輸出/入完全沒關係. 然而, 分割區的格式仍然是相同 的, 所以 fdisk 必須得捏造些 geometry , 並且也在此使用 HDIO_GETGEO - 真 的, fdisk 不會分辨 IDE 以及 SCSI 磁碟. 你可以從下面的詳細描述見到各種 驅動程式捏造一些個不同的 geometry .真是, 一團混亂. 如果你沒有使用 DOS 或這類系統, 那麼避免使用所有額外的轉換設定, 可能的 話, 儘管使用 64 磁頭, 每磁軌 32 磁區 (良好的, 方便每磁簇 1 MB), 如此當 你把磁碟從一個控制器換到另一個去時不會遇到任何問題. 某些 SCSI 磁碟驅動 程式 (aha152x,pas16,ppa,qlogicfas,qlogicisp)非常在意與 DOS 的相容性而不 允許只有 Linux 的系統使用超過 8 GB 的容量, 這是隻臭蟲. 真實的 geometry 是什麼? 最簡單的答案是沒有這種東西.如果真有的話, 你不 會想知道, 而且的的確確從不, 永不需告訴 fdisk 或是 LILO 或核心有關它的事 .這絕對是 SCSI 控制器與磁碟之間的事. 讓我重覆這句話: 只有蠢蛋會告訴 fdisk/LILO/Kernel SCSI 磁碟真實的 geometry . 但如果你好學且堅持, 可以問磁碟機自己.有個重要指令 READ CAPACITY 將會傳 回磁碟的總容量, 而且有個 MODE SENSE 指令 Rigid Disk Drive Page(page 04) 會傳回磁簇以及磁頭的數目(這是不能改變的資訊), 而在 Format Page(page 03)有每磁區的位元組, 以及每磁軌的磁區數. 這數字一般與 notch 有關, 而且每磁軌的磁區數是變動的 - 外圍的磁軌擁有比內圈磁軌多的磁區 .Linux 程式 scsiinfo 會給予這項資訊. 其中有許多繁瑣的細節, 而且很明白 的, 沒有人(也許甚至是作業系統)需要使用這項資訊. 還有, 因為我們只關心 fdisk 以及 LILO , 一般得到的回答像 C/H/S=4476/27/171 - 這樣的值 fdisk 根本不能使用, 因為分割表只保留 10resp. 8resp. 6 bits 給 C/H/S. 那核心之 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 GB - 現今實際的限制. 在下面的描述中, M 表示磁碟的全部容量, 而 C,H,S 是磁簇, 磁頭以及每磁軌磁 區數.如果我們把 C 當作 M/(H*S) 那給 H,S 就可以滿足. 依預設, H=64, S=32. aha1740, dtc, g_NCR5380, t128, wd7000: H=64, S=32. aha152x, pas16, ppa, qlogicfas, qlogicisp: H=64, S=32 除非 C > 1024, 此情況下 H=255, S=63, C = min(1023, M/(H*S)). (故 C 被截斷, 且 H*S*C 不是磁碟容量的近似值. 這將會混 搖淆大部份版本的 fdisk.) ppa.c 程式碼使用 M+1 取代 M 並認為這是 因為在 sd.c 裡的一隻臭蟲使 M 的值少一. advansys: H=64, S=32 除非 C > 1024 而且還開啟 BIOS 中的 `> 1 GB' 選項, 此 情況下 H=255, S=63. aha1542: 詢問控制器使用兩種可能的 schemes 中的那一種, 並且使用 H=255, S=63 或 H=64, S=32. 前者有個啟動訊息 "aha1542.c: Using extended bios translation". aic7xxx: H=64, S=32 除非 C > 1024, 而且還給了 "extended" 啟動參數, 或在 SEEPROM 或 BIOS 設了 `extended' 位元, 此情況下 H=255, S=63. buslogic: 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". fdomain: 從 BIOS Drive Parameter Table 找出 geometry 資訊, 或從分割表讀取 並使用 H=endH+1, S=endS 給第一個分割區, 若非空, 或使用 H=64, S=32 for M < 2^21 (1 GB), H=128, S=63 for M < 63*2^17 (3.9 GB) and H=255, S=63 otherwise. in2000: 使用 (H,S) = (64,32), (64,63), (128,63), (255,63) 中第一個讓 C <= 1024 的. 此情況下, 在 1023 截掉 C . seagate: 從磁碟讀取 C,H,S. (真誠實!) 如果 C 或 S 太大, 放入 S=17, H=2 並 倍增 H 直到 C <= 1024. 這表示 H 將為 0 如果 M > 128*1024*17 (1.1 GB). 這是隻臭蟲. ultrastor and u14_34f: 三種對應之一 ((H,S) = (16,63), (64,32), (64,63)) 根據控制器的對 應模式而定. 如果驅動程式沒有指定 geometry , 我們就回到使用分割表或磁碟總容量來推斷 猜測. 仔細看看分割表.因為依慣例分割區在磁簇邊界結束, 我們可以為任何分割區定 end=(endC,endH,ednS) , 只要放入 H = endH+1 及 S = endS. (記得磁區由 1 起算.)更明確地的說.如果有個不是空的分割區, 則以最大的 beginC 計. 對 於此分割區, 看看 end+1, 計算加上 start 以及 length 並且假設此分割區在某 磁簇邊界結束. 如果兩個值都相符, 或 endC = 1023 且 start+length 是 (endH+1)*endS 的倍數, 那麼假定此分割區真的是在磁簇邊界, 並放入 H = endH+1 以及 S = endS. 如果不對, 不是因為沒有分割區, 就是因為它們的大小 很奇怪, 那麼只看磁碟容量 M. 演算法: 放入 H = M/(62*1024)(無條件進 位),S = M/(1024*H)(無條件進位), C = M/(H*S)(無條件捨去).這能產生一 (C,H,S) 其中 C 最大 1024 而 S 最大 62. References 1. mailto:aeb@cwi.nl 2. mailto:asdchen@ms1.hinet.net