「論理パーティション」の管理方法・データ構造を説明できますか？

ちょっと早い夏休みだ自由研究をしよう(4日目)

# TL;DR
- MBR から　基本パーティション or 拡張パーティションが合計4つ管理できる。
- 拡張パーティションの第１エントリーは論理パーティション、第２エントリーはリンク(PBR)。
- リンク(PBR)の、第１エントリーは論理パーティション、第２エントリーはリンク(PBR)。
- リンク(PBR)のオフセット計算は、どうやら拡張パーティション起点のよう。前のリンク(PBR)ではなさそう。

※用語がよく分からない。

# はじめに

「ディスクの先頭には、Master Boot Record、MBRがあって、基本パーティションや拡張パーティションが管理されている。拡張パーティションの中にいくつか論理パーティションを確保できる」というのはよく見知った話である。

しかし、ここでふと気が付いてしまった。

「じゃあ、論理パーティションって、どうやって管理しているのか、説明できる？

そこで、今回はこのあたりの知識を再度確認してみる。

# その前に…

実は、このMaster Boot Record管理には、色々な亜流がある。

今回はMS-DOS base、という前提で説明する。

# micro SDカードをこんな感じにpartition分割してみた。

ベースはRaspberry piのディスクイメージ。これに最終パーティションを分割し、拡張パーティションを作ってみた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89434/c6900f47-b351-445f-f201-4944d3fa9ce9.png)

# fdiskの結果

```plaintext

Command (m for help): p
Disk /dev/mmcblk0: 59.5 GiB, 63864569856 bytes, 124735488 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xDEADBEEF

Device         Boot     Start       End  Sectors  Size Id Type
/dev/mmcblk0p1           8192    532479   524288  256M  c W95 FAT32 (LBA)
/dev/mmcblk0p2         532480  93487103 92954624 44.3G 83 Linux
/dev/mmcblk0p3       93487104 124735487 31248384 14.9G  5 Extended
/dev/mmcblk0p5       93491200 101302271  7811072  3.7G 83 Linux
/dev/mmcblk0p6      101304320 109113343  7809024  3.7G 83 Linux
/dev/mmcblk0p7      109115392 124735487 15620096  7.5G 82 Linux swap / Solaris
```

# MBR:Master boot recordと、基本パーティション

https://en.wikipedia.org/wiki/Master_boot_record

ディスク先頭は… (先頭446byteは読み飛ばして、16*4 + 2 )

```bash
root@raspberrypi:/home/pi# hexdump /dev/mmcblk0 -C -s 446 -n 66
000001be  00 00 01 40 0c 03 e0 ff  00 20 00 00 00 00 08 00  |...@..... ......|
000001ce  00 03 e0 ff 83 3f e0 ff  00 20 08 00 00 60 8a 05  |.....?... ...`..|
000001de  00 3f e0 ff 05 3f e0 ff  00 80 92 05 00 d0 dc 01  |.?...?..........|
000001ee  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001fe  55 aa                                             |U.|
00000200
```

mmcblk0p1の情報は以下となる。

```plaintext
000001be  00 00 01 40 0c 03 e0 ff  00 20 00 00 00 00 08 00  |...@..... ......|
```

| ID | parameter |
|:-:|:-:|
| state_of_physical_drive  | 0x00  |
| chs_first_absolute_address | { 00,01,40 } |
| partition_type   | 0c  |
| chs_last_absolute_address | { 03 e0 ff } |
| first_address  | { 00 20 00 00 } = 0x0000_2000  |
| number_of_sectors | { 00 00 08 00 } = 0x0008_0000 = 524,288   |


先ほどの、fdiskの結果と並べてみる。

```plaintext
/dev/mmcblk0p1           8192    532479   524288  256M  c W95 FAT32 (LBA)

開始アドレス = 8192 = 0x2000 
サイズ数 = 524288 sector = 0x8_0000
W95FAT32 -> partition type = 0x0c
```

ここで、「あれ？chs_first_absolute_address とか、chs_last_absolute_address  とかは？」と気になった人もいるかもしれない。linux kernelの、[msdos_partition()](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/block/partitions/msdos.c?h=v5.13.7#n580)ではCHS属性は一切使ってない。よって、気にすることはない（ものすごい雑な対応ですが）。


# 拡張パーティションと論理パーティション

拡張パーティションの中身を見てみる。

`/dev/mmcblk0p3       93487104 124735487 31248384 14.9G  5 Extended` ということなので、94387104セクタ目から1sector。


```bash
root@raspberrypi:/home/pi/work# dd if=/dev/mmcblk0 of=tmp.dat skip=93487104 bs=512 count=1
1+0 records in
1+0 records out
512 bytes copied, 0.00840728 s, 60.9 kB/s
root@raspberrypi:/home/pi/work# hexdump -C tmp.dat
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 3f  |...............?|
000001c0  e0 ff 83 3f e0 ff 00 10  00 00 00 30 77 00 00 3f  |...?.......0w..?|
000001d0  e0 ff 05 3f e0 ff 00 40  77 00 00 30 77 00 00 00  |...?...@w..0w...|
000001e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 55 aa  |..............U.|
00000200
root@raspberrypi:/home/pi/work# hexdump -s 446 -C tmp.dat
000001be  00 3f e0 ff 83 3f e0 ff  00 10 00 00 00 30 77 00  |.?...?.......0w.|
000001ce  00 3f e0 ff 05 3f e0 ff  00 40 77 00 00 30 77 00  |.?...?...@w..0w.|
000001de  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001fe  55 aa                                             |U.|
00000200
```

予想通り、第１エントリーと第２エントリーがある。第３、第４は全ゼロなので無効。

## 第1エントリー（実体部）

start offset = `0x0000_1000`。これに拡張パーティションの`93487104`を加算すると、`93491200`となる。これが論理パーティション`mmcblk0p5`を管理するセクタ情報となる。

`/dev/mmcblk0p5       93491200 101302271  7811072  3.7G 83 Linux `

`93491200`セクタ目の中身を確認すると…　空。まあ、初期化していませんからね…。

```
root@raspberrypi:/home/pi/work# dd if=/dev/mmcblk0 of=tmp.dat skip=93491200 bs=512 count=1
1+0 records in
1+0 records out
512 bytes copied, 0.00754861 s, 67.8 kB/s
root@raspberrypi:/home/pi/work# hexdump -s 446 -C tmp.dat
000001be  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200
root@raspberrypi:/home/pi/work# hexdump  -C tmp.dat
00000000  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200
```

## 第2エントリー（リンク部）

start_offset = "00 40 77 00` = `0x00774000` = 7,815,168。

これに拡張パーティションの`93487104`を加算すると、`101302272 = 0x609_C000`になる。これは、さっきのp5のちょうど真後ろ。

ここで、次のリンク(PBR)が管理されている。

```plaintext
root@raspberrypi:/home/pi/work# dd if=/dev/mmcblk0 of=tmp.dat skip=101302272 bs=512 count=1
1+0 records in
1+0 records out
512 bytes copied, 0.00807268 s, 63.4 kB/s
root@raspberrypi:/home/pi/work# hexdump -s446 -C tmp.dat
000001be  00 3f e0 ff 83 3f e0 ff  00 08 00 00 00 28 77 00  |.?...?.......(w.|
000001ce  00 3f e0 ff 05 3f e0 ff  00 70 ee 00 00 60 ee 00  |.?...?...p...`..|
000001de  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
000001fe  55 aa                                             |U.|
00000200
```

# まとめ

同様に計算をしていくと以下のような構造であることがわかる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89434/0377e83d-ae13-6d37-61aa-742c54bc19b8.png)

まとめると、こういうことが分かる。

- MBR から　基本パーティション or 拡張パーティションが合計4つ管理できる。
- 拡張パーティションの第１エントリーは論理パーティション、第２エントリーはリンク(PBR)。
- リンク(PBR)の、第１エントリーは論理パーティション、第２エントリーはリンク(PBR)。
- リンク(PBR)のオフセット計算は、どうやら拡張パーティション起点のよう。前のリンク(PBR)ではなさそう。


以上になります。