2023/11/16
本来ならば Web のページには解ったことを書くべきなのであるが、パーティションについて書いていると、基本的なことで解らなくなった。ネット上にも解決に必要な情報が見つからない。
問題意識をはっきりさせるために簡単なところから始めよう。ドライブのパーティションの設定状態を見る、あるいは新たにパーティションを設定するコマンドは Plan9 においても fdisk である。同名の fdisk は昔から MS-DOS に存在した、また Linux にも存在する。次の出力は Plan9 の例である。ドライブは 128 MB の usb stick である。(これを選んだ理由は、僕の持っているものの中で、一番小さなドライブだから)
hebe# ls -l /shr/usb/* --rw-r----- M 1227964 arisawa arisawa 104857600 Jan 1 1970 /shr/usb/sdU66a68/9fat --rw-rw-r-- M 1227964 arisawa arisawa 0 Jan 1 1970 /shr/usb/sdU66a68/ctl --rw-r----- M 1227964 arisawa arisawa 127401984 Jan 1 1970 /shr/usb/sdU66a68/data --rw-r----- M 1227964 arisawa arisawa 512 Jan 1 1970 /shr/usb/sdU66a68/nvram --rw-r----- M 1227964 arisawa arisawa 127385600 Jan 1 1970 /shr/usb/sdU66a68/plan9 --rw-r----- M 1227964 arisawa arisawa 0 Jan 1 1970 /shr/usb/sdU66a68/raw --r--r--r-- M 16 arisawa arisawa 0 Oct 17 07:24 /shr/usb/usbevent hebe# disk/fdisk /shr/usb/sdU66a68/data cylinder = 262144 bytes * p1 0 486 (486 cylinders, 121.50 MB) PLAN9 >>> q hebe#
cylinder 数 (= 486)、 及び cylinder 容量 (=262144 B) から disk 容量 121.5 MB は次のように得る:
> 486*262144/1024^2 121.5
Lua による容量計算
区分けの単位が cylinder であることに注目したい。これが今回の主なテーマである。
cylinder と言うのはヘッドの移動を伴わないで読み書きできる記録媒体の集合である。コンピュータにとってヘッドの移動は負荷が大きい。従ってできるだけヘッドの移動はやりたくないのである。可能ならばパーティションは cylinder を跨がないようにしたい。しかし大きなパーティションでは無理な相談である。せめて、パーティションの開始位置を cylinder 内のデータの開始位置に設定しましょうと言うのが、区分けの単位を cylinder にしていることの気持ちであろう。そのためには cylinder size に関する情報が必要なことは明らかである。OS は、この情報をどのようにして手に入れているのか?
記憶媒体がハードディスクからフラッシュメモリーに置き換えられつつあり、head なるものは存在しなくなっているが、それでも記憶領域をブロックに分け、ブロック単位に読み書きが行われておりハードディスクのシリンダーと類似の問題が存在する。
ドライブの先頭セクター(512B)には MBR が存在し特殊な役割を担っている、MBR の終わりの方(アドレス 0x1be
から始まる 64B)でパーティションの入り口の案内をしている。"partition entry" と呼んでいるが、これは言わば目次のような存在である。MBR が考えられた当初はパーティションは4つもあれば充分だと考えられたのであろう、この中に4つ分の entry が準備されている。次はその例である。(数字は16進数)
00001b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 01 | ................ 00001c0: 01 00 39 0F 60 E5 20 00 00 00 E0 CB 03 00 00 00 | ..9.`. ......... 00001d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ 00001e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ 00001f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA | ..............U.この例では4つの entry のうち、最初の entry 16B 以外は "
00
" で満たされている。最初の entry は:80 01 01 00 39 0F 60 E5 20 00 00 00 E0 CB 03 00
offset
size
meaning
this case
0
1
active or not (80 or 00)
80
1
3
starting CHS address
01 01 00
4
1
partition type
39
5
3
ending CHS address
0F 60 E5
8
4
starting LBA
20 00 00 00
12
4
partition size
E0 CB 03 00
つまり address はセクター位置を表す表現である。ここでは2種類のアドレス表現(CHS 方式と LBA 方式)が混在している。CHS 方式は (cylinder,header,sector) の3っの数字の組でドライブの中での sector の位置を表す表現法で、ドライブ容量が大きくなった現在では機能しなくなっている。そこで LBA (logical block address) 方式が考え出された。これはドライブ内のデータを 512B を単位としたまとまり (logical block あるいは単に sector と呼ばれることも多い) に一列に並べて、順に 0,1,2,... と番号を振る方式である。LBA 0 に MBR が存在することになる。現在は LBA が標準的に使われるようになっている。
セクター位置を表すのに歴史的に 1,2,3,... と 1 から開始して数えられてきた。この習慣は現在においても残っている。(C,H,S)
の3つ組でアドレスを表す場合には、次のようになる。
C: 0,1,2,...,Cmax H: 0,1,2,...,Hmax S: 1,2,...,Smax
(C,H,S)
で表したアドレスを小さい方から並べていけば LBA アドレスと対応する。Smax=3
,Hmax=1
とすると
LBA
CHS
0
(0,0,1)
1
(0,0,2)
2
(0,0,3)
3
(0,1,1)
4
(0,1,2)
5
(0,1,3)
6
(1,0,1)
7
(1,0,2)
8
(1,0,3)
...
...
となる。CHS から LBA はHnum = Hmax + 1; Snum = Smax
LBA = (C*Hnum + H)*Snum + S - 1
S = LBA % Snum + 1 H = (LBA // Snum) % Hnum C = (LBA // Snum) // Hnum
%
と //
の使い方は同じである)
ややこしいのは partition entry に含まれている CHS と関係する 3B のデータの扱いである。
"starting CHS address" とは素直に受け取れば、アドレスの開始を表している。しかし "ending CHS address" とは何か? 素直に受け取ればアドレスの終わりを表していると思いたい。しかし fdisk のプログラムを読んでいるとそのようには受け取れないのである。この3つ組は (Cmax,Hmax,Smax)
を知るために使われているようだ。論理的には別物でも、実際的にはそうなのでしょう。だって利用可能なセクターが存在するのに、そこにアクセスするアドレスを持たないなどというのはバカげたことだから。
かくして Cnum.Hnum,Snum
で cylinder, header, sector の個数を表せば
Cnum = Cmax +1, Hnum = Hmax +1, Snum = Smax
Cend,Hend,Send
で cylinder, header, sector の ending address を表せばCend = Cmax, Hend = Hmax, Send = Smax
partition entry 16B のうち、後半 8B が 00
であるか否かによって、このパーティションが LBA address 方式が使われていないか使われているかを判断すべきであろう。(他の解釈の余地はないだろうから)
この例ではアドレスは LBR 方式だと考えてよい。最初のパーティションの開始位置は "80 1F 00 00
" から判る。これは little endian の 16 進数ゆえ、0x1f80
(=8064
) (LBA) を意味する。これに512を掛けて Byte アドレス 4128768 (=0x3f0000) を得る。
サイズは "80 C0 B9 03
" より
0x03b9c080*512 --> 32002605056
fdisk に表示された 29.80 GB は GiB 単位で表された近似値である。正確なサイズは
hebe# ls -l sdU36d24 --rw-rw-r-- M 1082425 arisawa arisawa 0 Jan 1 1970 sdU36d24/ctl --rw-r----- M 1082425 arisawa arisawa 32006733824 Jan 1 1970 sdU36d24/data --rw-r----- M 1082425 arisawa arisawa 32002605056 Jan 1 1970 sdU36d24/dos --rw-r----- M 1082425 arisawa arisawa 0 Jan 1 1970 sdU36d24/raw hebe#で得られ、先の計算と一致している。
パーティションタイプの欄はこのケースでは 0C
となっている。文献によると 0C
は LBA 対応の FAT32 パーティションであると説明されている([1])。つまり、ここは DOS 用のパーティションですよと言っている。この欄は言わばパーティションに添えられた看板である。フォーマッタはパーティションタイプを見てフォーマットしているはずである(よほどへそ曲がりでは無い限り)。タイプ 00
の意味がはっきりしない。パーティションなのだが、まだ看板が掛かっていないと言っているのか? それともパーティションではないと言っているのか? パーティションではないなら、entry の 16B をすべて 00
にするのが無難なのであろう。
現在ではドライブの容量が大きくなって、もっと多くのパーティションやもっと大きなパーティションを使いたいとのニーズがあるらしい。パーティションを4つから増やすには、拡張パーティションを導入すれば足りる。また 512✕ 232(= 2TB) を超える大きなパーティションを持ちたい場合には GPT 方式が使える。GPT 方式については別の機会に回す。僕の個人的なニーズからすれば1、旧来通りの MBR 方式があれば足りている。
[1] マスターブートレコード
https://ja.wikipedia.org/wiki/マスターブートレコード
各パーティションの先頭 512B には PBS が存在する。ここにはパーティションに関する基本的な情報が書かれている。このディスクでは次のようになっていた。
03f0000: EB 58 90 4D 53 57 49 4E 34 2E 31 00 02 40 A0 04 | .X.MSWIN4.1..@.. 03f0010: 02 00 00 00 00 F8 00 00 20 00 10 00 80 1F 00 00 | ........ ....... 03f0020: 80 C0 B9 03 D0 1D 00 00 00 00 00 00 02 00 00 00 | ................ 03f0030: 01 00 08 00 00 00 00 00 00 00 00 00 00 00 00 00 | ................ 03f0040: 00 00 29 A3 12 1E 3A 54 4F 53 48 49 42 41 20 20 | ..)...:TOSHIBA 03f0050: 20 20 46 41 54 33 32 20 20 20 FA 33 C9 8E D1 BC | FAT32 .3.... 03f0060: F8 7B 8E C1 BD 78 00 C5 76 00 1E 56 16 55 BF 22 | .{...x..v..V.U." 03f0070: 05 89 7E 00 89 4E 02 B1 0B FC F3 A4 8E D9 BD 00 | ..~..N.......... 03f0080: 7C C6 45 FE 0F 8B 46 18 88 45 F9 38 4E 40 7D 25 | |.E...F..E.8N@}% 03f0090: 8B C1 99 BB 00 07 E8 97 00 72 1A 83 EB 3A 66 A1 | .........r...:f. 03f00a0: 1C 7C 66 3B 07 8A 57 FC 75 06 80 CA 02 88 56 02 | .|f;..W.u.....V. 03f00b0: 80 C3 10 73 ED BF 02 00 83 7E 16 00 75 45 8B 46 | ...s.....~..uE.F 03f00c0: 1C 8B 56 1E B9 03 00 49 40 75 01 42 BB 00 7E E8 | ..V....I@u.B..~. 03f00d0: 5F 00 73 26 B0 F8 4F 74 1D 8B 46 32 33 D2 B9 03 | _.s&..Ot..F23... 03f00e0: 00 3B C8 77 1E 8B 76 0E 3B CE 73 17 2B F1 03 46 | .;.w..v.;.s.+..F 03f00f0: 1C 13 56 1E EB D1 73 0B EB 27 83 7E 2A 00 77 03 | ..V...s..'.~*.w. 03f0100: E9 FD 02 BE 7E 7D AC 98 03 F0 AC 84 C0 74 17 3C | ....~}.......t.< 03f0110: FF 74 09 B4 0E BB 07 00 CD 10 EB EE BE 81 7D EB | .t............}. 03f0120: E5 BE 7F 7D EB E0 98 CD 16 5E 1F 66 8F 04 CD 19 | ...}.....^.f.... 03f0130: 41 56 66 6A 00 52 50 06 53 6A 01 6A 10 8B F4 60 | AVfj.RP.Sj.j...` 03f0140: 80 7E 02 0E 75 04 B4 42 EB 1D 91 92 33 D2 F7 76 | .~..u..B....3..v 03f0150: 18 91 F7 76 18 42 87 CA F7 76 1A 8A F2 8A E8 C0 | ...v.B...v...... 03f0160: CC 02 0A CC B8 01 02 8A 56 40 CD 13 61 8D 64 10 | ........V@..a.d. 03f0170: 5E 72 0A 40 75 01 42 03 5E 0B 49 75 B4 C3 03 18 | ^r.@u.B.^.Iu.... 03f0180: 01 27 0D 0A 49 6E 76 61 6C 69 64 20 73 79 73 74 | .'..Invalid syst 03f0190: 65 6D 20 64 69 73 6B FF 0D 0A 44 69 73 6B 20 49 | em disk...Disk I 03f01a0: 2F 4F 20 65 72 72 6F 72 FF 0D 0A 52 65 70 6C 61 | /O error...Repla 03f01b0: 63 65 20 74 68 65 20 64 69 73 6B 2C 20 61 6E 64 | ce the disk, and 03f01c0: 20 74 68 65 6E 20 70 72 65 73 73 20 61 6E 79 20 | then press any 03f01d0: 6B 65 79 0D 0A 00 00 00 49 4F 20 20 20 20 20 20 | key.....IO 03f01e0: 53 59 53 4D 53 44 4F 53 20 20 20 53 59 53 7E 01 | SYSMSDOS SYS~. 03f01f0: 00 57 49 4E 42 4F 4F 54 20 53 59 53 00 00 55 AA | .WINBOOT SYS..U.
この先頭部には次のような情報が含まれている:
EB 58 90 JmpBoot 4D 53 57 49 4E 34 2E 31 OEM name 00 02 BytesPersec 40 SecPerClus A0 04 RsvdSecCnt 02 NumFATs 00 00 RootEntCn 00 00 TotSec16 F8 Media 00 00 FATSz16 20 00 SecPerTrk 10 00 NumHeads 80 1F 00 00 HiddSec 80 C0 B9 03 TotSec32 D0 1D 00 00 FATSz32 00 00 ExtFlags 00 00 FSVer 02 00 00 00 RootClus 01 00 FSInfo 08 00 BkBootSec 00 00 00 00 00 00 00 00 00 00 00 00 Reserved 00 DrvNum 00 Reserved 29 BootSig A3 12 1E 3A VolID 54 4F 53 48 49 42 41 20 20 20 20 VolLab 46 41 54 33 32 20 20 20 FilSysType
文献[2]に沿って整理されている。この文献は素晴らしい。
ここに書いた分析はあくまで FAT ファイルシステムに対してのものである。Partition の中の情報の整理の仕方は OS やファイルシステムによって異なる。そのために "partition type" が存在するのである。ブート時に Partition を読みに行く前に、MBR の段階で Partition type が判る構造になっている。
ハードディスクに関して解説されてきた概念が過去のものとなり、もはや意味を持たなくなっている。それでもかろうじて意味を保持しているのはシリンダーの持つ情報量(Byte 数)である。フラッシュドライでは物理的なシリンダーもトラックもヘッドもセクターも存在しないものの効率の良い seek 動作が可能な領域は存在する。この領域の容量をシリンダー容量と同一視するのである。
ハードディスクの場合には、
scyl
ssec
nsec
nhead
scyl = nsec * ssec * nhead
ssec
は論理セクターとして形式的に 512B として考える。この場合 OS がデータを読み取る時に 512B の倍数を単位として読み取ることを意味している。nsec
と nhead
は確定しない。これらの決定にはドライバーが関与している可能性が高いのであるが2、僕はまだ具体的なことは知らない。
[2] FATファイルシステムのしくみと操作法
http://elm-chan.org/docs/fat.html