[Linuxパーティション] homeを縮小してセクターを移動してからrootのサイズを拡張する方法

# やりたいこと

この記事では、Linuxのrootパーティションが手狭になってしまったので、容量が余っているhomeパーティションを小さくして、rootパーティションを拡張していきます。

具体的には、最初こんな感じだった構成を

```
Device             Start       End   Sectors  Size Type
/dev/nvme0n1p1      2048    206847    204800  100M EFI System
/dev/nvme0n1p2    206848    239615     32768   16M Microsoft reserved
/dev/nvme0n1p3    239616 168011775 167772160   80G Microsoft basic data
/dev/nvme0n1p4 168011776 170108927   2097152    1G Windows recovery environment
/dev/nvme0n1p5 170108928 274966527 104857600   50G Microsoft basic data
/dev/nvme0n1p6 274966528 370976767  96010240 45.8G Linux root
/dev/nvme0n1p7 370976768 907847679 536870912  256G Linux home
```

`/dev/nvme0n1p7`を56GB縮小し、`/dev/nvme0n1p6`を50GB拡張して、次のような構成にしていきます

```
Device             Start       End   Sectors  Size Type
/dev/nvme0n1p1      2048    206847    204800  100M EFI System
/dev/nvme0n1p2    206848    239615     32768   16M Microsoft reserved
/dev/nvme0n1p3    239616 168011775 167772160   80G Microsoft basic data
/dev/nvme0n1p4 168011776 170108927   2097152    1G Windows recovery environment
/dev/nvme0n1p5 170108928 274966527 104857600   50G Microsoft basic data
/dev/nvme0n1p6 274966528 475834367 200867840 95.8G Linux root
/dev/nvme0n1p7 475834368 895264767 419430400  200G Linux home
```

# やったこと

操作は主に次の3つに分けられます

1. homeパーティション`/dev/nvme0n1p7`を縮小する
2. homeパーティション`/dev/nvme0n1p7`の開始セクタを移動して、rootパーティション`/dev/nvme0n1p6`の後ろに未割り当てのセクタを作る
3. rootパーティション`/dev/nvme0n1p6`を拡張する

2の操作の理由ですが、今回のパーティション構成の場合、rootパーティションの下のセクタにhomeパーティションがあります。セクタをまたいで1つのパーティションを作ることは出来ないので、homeパーティションを縮小した後、rootパーティションを拡張したい分だけ、homeパーティションの開始セクタを後ろにずらす必要があるためです。

これから、ステップごとに説明していきます。
まずはどのディストリビューションでもいいので、LinuxをUSBからブートして、コンソールを表示してください。今回の環境はarchlinuxなので、archのインストールメディア([archlinux-2019.12.01-x86_64.iso](http://ftp.jaist.ac.jp/pub/Linux/ArchLinux/iso/2019.12.01/archlinux-2019.12.01-x86_64.iso))で進めていきます。

もし作業の途中でOSを起動する必要がある場合は、ファイルシステムを破壊する可能性があるので、必ず各ステップの終わりまでは進めてから起動してください。実際に各ステップの終わりごとにOSが問題なく起動することを確認しています。

# STEP1: homeパーティション`/dev/nvme0n1p7`を縮小する

まずは、e2fsckコマンドでファイルシステムをチェックします(次に使うresize2fsコマンドは、この結果で空き容量確認をしているため、この操作をしないと実行できません)

途中でextent treeをOptimizeするか聞かれますが、この処理はextent treeが上限を越えない限り行なわなくても大丈夫なようです。全てnoで進めました。
参考: https://unix.stackexchange.com/questions/392537/inode-extent-tree-at-level-1-could-be-shorter-ignored

```
e2fsck -f <チェックしたいファイルシステムのパス>
```

```
root@archiso ~ # e2fsck -f /dev/nvme0n1p7
e2fsck 1.45.4 (23-Sep-2019)
Pass 1: Checking inodes, blocks, and sizes
Inode 8404395 extent tree (at level 1) could be shorter. Optimize<y>? no
Inode 8404481 extent tree (at level 2) could be narrower. Optimize<y>? no
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/nvme0n1p7:2498456/16777216 files (0.9% non-contiguous), 32640354/67108864 blocks
e2fsck -f /dev/nvme0n1p7 7.08s user 0.82s system 6% cpu 2:07.42 total
```

続いて、resize2fsで縮小処理を実行します

```
resize2fs <縮小したいファイルシステムのパス> <縮小後のパーティションサイズ(K,M,Gなどで指定可)> 
```

```
root@archiso ~ # resize2fs /dev/nvme0n1p7　200G
resize2fs 1.45.4 (23-Sep-2019)
Resizing the filesystem on /dev/nvme0n1p7 to 52428800 (4k) blocks.
The filesystem on /dev/nvme0n1p7 is now 52428800 (4k) blocks long.

resize2fs /dev/nvme0n1p7　200G 6.41s user 14.03s system 36% cpu 55.878 total
```

ここまで実際のファイルシステムの縮小は完了しましたが、この情報はLVM(各パーティションの区切サイズなどが記録されているレイヤー)には反映されていません。そのため、fdiskを利用してLVMを更新します。

```
root@archiso ~ # fdisk <縮小したパーティションが含まれるボリューム>

dコマンドで縮小したパーティションの情報を一旦削除し、
nコマンドで縮小後のサイズに変更したパーティション情報を入力し情報を作り直す
wコマンドでLVMに保存
```

```
root@archiso ~ # fdisk /dev/nvme0n1
Welcome to fdisk (util-linux 2.34).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): d
Partition number (1-7, default 7): 7

Partition 7 has been deleted.

Command (m for help): n
Partition number (7-128, default 7): 
First sector (370976768-1000215182, default 370976768): 
Last sector, +/-sectors or +/-size{K,M,G,T,P} (370976768-1000215182, default 1000215182): +200G

Created a new partition 7 of type 'Linux filesystem' and of size 200 GiB.
Partition #7 contains a ext4 signature.

Do you want to remove the signature? [Y]es/[N]o: n

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
```

ここまでで、`/dev/nvme0n1p7`の縮小は完了です。

# STEP2: homeパーティション`/dev/nvme0n1p7`の開始セクタを移動して、rootパーティション`/dev/nvme0n1p6`の後ろに未割り当てのセクタを作る

sfdiskを使用してパーティションを移動していきます。このコマンドはLVMの更新もしてくれるので、このステップはこのコマンドだけで完了します。

この処理には時間がかかるので注意してください。今回の場合、SSDだし数十分で終わるかなーとか思ってましたが、実際には6時間くらいかかってしまいました。

```
echo '+<移動させたいサイズ(=rootパーティションの拡張分のサイズ)>' | sfdisk --move-data <移動させたいパーティションが含まれるボリューム> -N <移動するバーティションの番号>
```

```
root@archiso ~ # echo '+50G' | sfdisk --move-data /dev/nvme0n1 -N 7
Checking that no-one is using this disk right now ... OK

Disk /dev/nvme0n1: 476.96 GiB, 512110190592 bytes, 1000215216 sectors
Disk model: KXG50ZNV512G TOSHIBA                    
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: gpt
Disk identifier: 80F7A56F-2E69-49B5-8A44-09E9998615AE

Old situation:

Device             Start       End   Sectors  Size Type
/dev/nvme0n1p1      2048    206847    204800  100M EFI System
/dev/nvme0n1p2    206848    239615     32768   16M Microsoft reserved
/dev/nvme0n1p3    239616 168011775 167772160   80G Microsoft basic data
/dev/nvme0n1p4 168011776 170108927   2097152    1G Windows recovery environment
/dev/nvme0n1p5 170108928 274966527 104857600   50G Microsoft basic data
/dev/nvme0n1p6 274966528 370976767  96010240 45.8G Linux filesystem
/dev/nvme0n1p7 370976768 790407167 419430400  200G Linux home

/dev/nvme0n1p7:
New situation:
Disklabel type: gpt
Disk identifier: 80F7A56F-2E69-49B5-8A44-09E9998615AE

Device             Start       End   Sectors  Size Type
/dev/nvme0n1p1      2048    206847    204800  100M EFI System
/dev/nvme0n1p2    206848    239615     32768   16M Microsoft reserved
/dev/nvme0n1p3    239616 168011775 167772160   80G Microsoft basic data
/dev/nvme0n1p4 168011776 170108927   2097152    1G Windows recovery environment
/dev/nvme0n1p5 170108928 274966527 104857600   50G Microsoft basic data
/dev/nvme0n1p6 274966528 370976767  96010240 45.8G Linux filesystem
/dev/nvme0n1p7 475834368 895264767 419430400  200G Linux home

Data move:
 typescript file : /root/sfdisk-nvme0n1p7.move
 old start: 370976768, new start: 475834368 (move 419430400 sectors)
```

# STEP3: rootパーティション`/dev/nvme0n1p6`を拡張する

resize2fsにはfdiskの情報に合わせてパーティションサイズを変更してくれる機能が有ります。そのため、まずはfdiskでLVM上の情報を更新し、実際の拡張をresize2fsで行なっていきます。

fdiskはSTEP1と同様に以下のコマンドで行います。

```
root@archiso ~ # fdisk <拡大したいパーティションが含まれるボリューム>

dコマンドで拡大したいパーティションの情報を一旦削除し、
nコマンドで拡大後のサイズに変更したパーティション情報を入力し情報を作り直す
wコマンドでLVMに保存
```

```
root@archiso ~ # fdisk /dev/nvme0n1
Welcome to fdisk (util-linux 2.34).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): d
Partition number (1-7, default 7): 6

Partition 6 has been deleted.

Command (m for help): n
Partition number (6,8-128, default 6): 6
First sector (274966528-1000215182, default 274966528): 
Last sector, +/-sectors or +/-size{K,M,G,T,P} (274966528-475834367, default 475834367): 

Created a new partition 6 of type 'Linux filesystem' and of size 95.8 GiB.
Partition #6 contains a ext4 signature.

Do you want to remove the signature? [Y]es/[N]o: n

Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
```

次に、STEP1と同じe2fsckを実行した後、パーティションサイズの指定なしにresize2fsを実行します。縮小の時と違い、拡張は一瞬で終わりました。

```
root@archiso ~ # e2fsck -f /dev/nvme0n1p6
(中略: 実行結果はSTEP1のものと同じ様な感じで出ます)

root@archiso ~ # resize2fs /dev/nvme0n1p6
resize2fs 1.45.4 (23-Sep-2019)
Resizing the filesystem on /dev/nvme0n1p6 to 25108480 (4k) blocks.
The filesystem on /dev/nvme0n1p6 is now 25108480 (4k) blocks long.
```

これで、処理は完了です。

# まとめ

パーティションの拡大縮小には`resize2fs`、セクターの移動には`sfdisk`の`--move-data`が便利！

セクター移動する時、dd使ってゴリゴリしないといけないかなと思ってましたが、sfdiskを使ったら一発で解決できました！！