えんでぃの技術ブログ

えんでぃの技術ブログ

ネットワークエンジニアの視点で、IT系のお役立ち情報を提供する技術ブログです。

Linuxのディスク拡張手順 (KVM, LVM, EXT4)

thumbnail

お伝えしたいこと

KVM仮想マシンのディスク拡張手順をご紹介します。

ディスク拡張方法は、利用しているストレージ、LVM2の利用有無、ファイルシステムによって変わります。
今回ご紹介する手順は、以下の環境を前提としています。

ディスク拡張を行う際は、必ずバックアップを取った上で作業してください。
本手順においても、#パーティション拡張の工程で「間違えるとデータが消える」部分があります。
fdiskの操作でyes/noを間違えてそのまま気づかずwriteしてしまい、更に対処を間違えると詰みます。

なお、記事の後半でパーティションテーブルやアラインメントなどの背景知識に触れていますので、興味のある方はぜひご覧ください。

作業の流れ

ディスク拡張ですが、基本的にファイルシステムを作成する時の流れに沿って作業します。

冒頭で述べたストレージ環境を構築する手順は、ざっくり以下の流れです。

  1. qcow2ファイルの作成 (ホストマシン上で実施)
  2. パーティション作成
  3. LVMの設定
    1. PV作成 (PVとパーティションを紐づけて登録)
    2. VG作成 (VGにPVを所属させる)
    3. LV作成 (VGの領域の一部を切り出してLV作成)
  4. LV上にファイルシステム作成

従って、ディスク拡張作業は以下の流れで進めることになります。

  1. qcow2ファイルの拡張 (ホストマシン上で実施)
  2. パーティション拡張
  3. LVMの設定
    1. PV拡張 & VG拡張 (PVを拡張すると、VGも拡張された扱いになります)
    2. LV拡張
  4. ファイルシステム拡張

LVMを使っていない場合、「LVMの設定」は丸ごとスキップします。
また、ファイルシステムを拡張するコマンドが若干変わります。
今回の環境ではLVM2を使っているので、この設定についても触れていきます。

図解

#作業の流れと重なりますが、ディスク拡張前後の状態を図解しました。

まずは、ディスク拡張前の状態です。
今回の作業では、(1)〜(6)を順に拡張していきます。

first_state

ディスク拡張後は、以下の状態になります。
qcow2のサイズを5GiB増やし、その分ルートファイルシステムを拡張しています。
拡張によって、ルートファイルシステムのアドレスがSWAP用の領域を挟んで不連続になっているように表現していますが、LVM2の仮想化機能によりこれでも問題なく動作します。

last_state

次のセクションから、具体的なコマンドを紹介します。

qcow2ファイルの拡張

ここの説明は、KVMで作成したVMのディスク拡張をしたい方にのみ関係があります。
また、KVMのセットアップが完了していることが前提です。
KVMの設定については、過去の記事を参照してください。

endy-tech.hatenablog.jp

さて、本題に入ります。

KVM仮想マシンのボリュームのリサイズにはvirshコマンドを使用します。
コマンドの書式は以下の通りです。
以下のコマンドをKVMのホストマシン上で実行します。

virsh vol-resize vol-name-or-path capacity [--pool pool-or-uuid] [--allocate] [--delta] [--shrink]

それぞれのキーワードの意味は、以下のとおりです。
詳細はman virshvol-resizeの項や、Red Hat Virtualization Deployment and Administration Guide を参照してください。

キーワード 意味
vol-name-or-path ボリューム名、またはファイルフルパス (*.qcow2)
capacity ボリュームのサイズ。
1GB (1000MB), 1GiB (1024MiB) など
--pool pool-or-uuid プール名、またはUUID。
vol-name-or-path にフルパスを指定した場合は省略可
--allocate rawファイルにのみ対応。
qcow2ファイルに対して指定するとエラーになる。
基本使わない
--delta --deltaを指定しない場合、capacity には変更後のサイズを記載する。
--deltaを指定すると、代わりにサイズ拡張/縮小の差分の値を記載する。
--shrink ボリュームを縮小する際に指定する。
拡張の際に指定するとエラーになる

さて、ここでvolume名とpool名が必要であることがわかります。
それらを先に調べておきます。

以下のコマンドより、volume名はvm_name.qcow2、pool名はdefaultと判明しました。

virsh pool-list
#  Name                     State    Autostart
# ----------------------------------------------
#  default                  active   yes

virsh vol-list --pool default
#  Name          Path
# -----------------------------------------------------
#  vm_name.qcow2 /home/shared/kvm_volumes/vm_name.qcow2

ついでに、現在のボリュームサイズも調べておきます。

virsh vol-info --pool default my_vm.qcow2
# Name:           my_vm.qcow2
# Type:           file
# Capacity:       20.00 GiB
# Allocation:     16.46 GiB

さて、情報が揃いました。
以下のコマンドにより、pool defaultに存在するsize 20GiB のvolume my_vm.qcow2を、25GiBに拡張します。

2種類のコマンドを提示していますが、どちらも同じ結果になります。
現在の容量を意識せずに済む分--deltaを使う方が検証用途ではお手軽ですが、間違えて2回同じコマンドを実行しても安全なのは--deltaを使わないコマンドですね。

# virsh vol-resize my_vm.qcow2 --pool default --delta 5GiB
virsh vol-resize my_vm.qcow2 --pool default 25GiB

今回のケースとは関係ないですが、ご参考までに5GiB縮小する際のコマンドも記載しておきます。
ディスクサイズの縮小はデータを破壊するリスクがあるので、試す際は事前にデータバックアップを取っておきましょう。

# virsh vol-resize my_vm.qcow2 --pool default --delta -5GiB --shrink
virsh vol-resize my_vm.qcow2 --pool default 15GiB --shrink

パーティション拡張

以降のコマンドはVMゲスト上で実行します。
今回はfdiskコマンドでパーティションを拡張します。

fdiskコマンドを実行するために、デバイスファイル名を確認します。

3行目の出力より、今回は/dev/vdaを見ればよいとわかります。
他にもdf -Thsudo blkidなどで確認できます。

なお、冒頭の2行に警告が出ていますが、こちらはあまり気にする必要はありません。
パーティションテーブルを書き換えないままディスクサイズ (qcow2のサイズ) が変わったことで、fdiskが不整合を検出したというメッセージです。
メッセージに書いてあるとおり、fdiskでwriteすることでPMBRを含むパーティションテーブルの情報が上書きされてエラーは解消されます (本当に何もせず、wでwriteするだけでエラーは解消されます)。
エラーメッセージの意味については、#(参考) GPTとPMBRの概要にて考察するので、気になる方はこちらも読んでみてください。

sudo fdisk -l
# GPT PMBR size mismatch (41943039 != 52428799) will be corrected by write.
# The backup GPT table is not on the end of the device. This problem will be corrected by write.
# Disk /dev/vda: 25 GiB, 26843545600 bytes, 52428800 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: gpt
# Disk identifier: 3AED67ED-0074-4379-987F-320ED57ED3CB

# Device       Start      End  Sectors  Size Type
# /dev/vda1     2048  1230847  1228800  600M EFI System
# /dev/vda2  1230848  3327999  2097152    1G Linux filesystem
# /dev/vda3  3328000 41940991 38612992 18.4G Linux LVM


# Disk /dev/mapper/my_vm-root: 16.26 GiB, 17448304640 bytes, 34078720 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


# Disk /dev/mapper/my_vm-swap: 2 GiB, 2147483648 bytes, 4194304 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

ついでに、LVM周りの情報とファイルシステムの情報を予め取得しておいてください。
fdisk -lのログも含めて、取得した情報はホストPC上のテキストファイルなどゲストOS以外の場所に保存してください。
いざというときの復旧に役に立ちます。

# LVM Information
pvdisplay
vgdisplay
lvdisplay
cat /etc/lvm/backup/*

# File System Information
df -Th

では、fdiskによってパーティションサイズを20GiBから25GiBに拡張します。
手順は以下の流れです。

  • d, 3: /dev/vda3の削除
  • n, 3, (Enter)x2, n: 新しいサイズで/dev/vda3の再作成
  • w: 変更の確定。パーティションテーブルに情報を書き込む

2番目の工程でパーティションを作成する際のパラメータ指定について補足です。
man fdiskに書いてあるように安全な方法でパラメータを指定します (Enter x2)。
First sectorはデフォルト値で指定することで、Alignmentの問題を踏まないようにしています。
Last sectorは単位 (MiB/GiB) を付けてサイズで指定するのが一般的ですが、今回は最終セクタを指定したいのでここもデフォルト値を使っています。

また、「Do you want to remove the signature? [Y]es/[N]o:」と聞かれる箇所がありますが、ここでは絶対にNoを選択してください。
間違えてYesを選択した場合は、writeをせず、落ち着いてqから抜けてください。
もしYesを選択した上でwriteしてしまうと、/dev/vda3パーティションタイプがLinux LVMであるという情報が消えてしまいます。
結果として、次のPV拡張の工程でpvdisplayなどを実行しても何も表示されず、pvresizeコマンドも失敗してしまいます。
※既存のデータを全て削除して問題ない場合はYesでも良いのですが...

LVMを間違えて削除してしまった時も復旧できますが、それでも対処を間違えると詰みます。
もしLVMを削除した場合は、ひとまずOSシャットダウンや再起動は絶対にしないでください。
その上で#(参考) LVMを削除した時の復旧方法を参考にしつつ、対処法をご検討ください。

ただ、上記の方法で復旧するぐらいなら作業前のバックアップからやり直したほうが楽でしょう。
fdiskの操作は、くれぐれもお気をつけください。

前置きが長くなりましたが、具体的なfdiskのコマンドを以下に記載します。

Command (m for help): p
# Disk /dev/vda: 25 GiB, 26843545600 bytes, 52428800 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: gpt
# Disk identifier: 3AED67ED-0074-4379-987F-320ED57ED3CB

# Device       Start      End  Sectors  Size Type
# /dev/vda1     2048  1230847  1228800  600M EFI System
# /dev/vda2  1230848  3327999  2097152    1G Linux filesystem
# /dev/vda3  3328000 41940991 38612992 18.4G Linux LVM

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

# Partition 3 has been deleted.

Command (m for help): p

# Disk /dev/vda: 25 GiB, 26843545600 bytes, 52428800 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: gpt
# Disk identifier: 3AED67ED-0074-4379-987F-320ED57ED3CB

# Device       Start     End Sectors  Size Type
# /dev/vda1     2048 1230847 1228800  600M EFI System
# /dev/vda2  1230848 3327999 2097152    1G Linux filesystem

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

# Created a new partition 3 of type 'Linux filesystem' and of size 23.4 GiB.
# Partition #3 contains a LVM2_member signature.

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

Command (m for help): p

# Disk /dev/vda: 25 GiB, 26843545600 bytes, 52428800 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: gpt
# Disk identifier: 3AED67ED-0074-4379-987F-320ED57ED3CB

# Device       Start      End  Sectors  Size Type
# /dev/vda1     2048  1230847  1228800  600M EFI System
# /dev/vda2  1230848  3327999  2097152    1G Linux filesystem
# /dev/vda3  3328000 52428766 49100767 23.4G Linux filesystem

Command (m for help): w
# The partition table has been altered.
# Syncing disks.

最後に、パーティションサイズが変更されたことを確認します。

sudo fdisk -l

# (中略)

# Device       Start      End  Sectors  Size Type
# /dev/vda1     2048  1230847  1228800  600M EFI System
# /dev/vda2  1230848  3327999  2097152    1G Linux filesystem
# /dev/vda3  3328000 52428766 49100767 23.4G Linux filesystem

# (中略)

最後の/dev/vda3のSectorsが奇数になっていますが、Alignmentの観点では気にする必要はありません。
Alignmentが問題となるのはあくまで開始セクタの位置のみです。

もちろん、例えば/dev/vda1の終了セクタは、次の/dev/vda2の開始セクタのデフォルト値に影響するので、配慮した方が良いとは思います。
ここで言っているのは、最後のパーティションの最終セクタ位置は気にしなくても良いということです1

(参考) LVMを削除した時の復旧方法

ここでは、上記のfdisk操作で誤ってLinux LVM Partition Type を誤って削除し、そのままwriteしてしまった時の対処法を紹介します。

最初に補足しておきます。
今回の障害の契機は、fdiskによるパーティションタイプの削除です。
fdiskには、tパーティションタイプを作成することができ、30 (Linux LVM) を指定することで同様のパーティションタイプを作成することができます。
しかし、今回のケースはパーティションタイプの再作成では復旧できません。
fdiskパーティションテーブルを削除する際、どうやらLVMのPV、LV、VGなどのメタデータも全て削除してしまっているようです。
その証拠に、実際にパーティションタイプを再作成しても、pvdisplayなどのコマンドでPV、VG、LVは表示されませんでした。

さて、本題に入ります。

基本的には、Red Hat社のマニュアルにあるPVの復旧方法2 を参考に進めます。
具体的には、以下のような流れで進めます。

  1. LVMメタデータのバックアップ
  2. レスキューモードの起動
  3. (任意) キーボードの日本語化
  4. (任意) SSHサーバの有効化、バックアップファイル送付
  5. (任意) 非LVM領域のマウント
  6. PVの復旧
  7. VG,LVの復旧

具体的な内容をstep by stepで紹介します。

LVMメタデータのバックアップ

まずは、以下のパスにあるLVMメタデータを外部ストレージに退避してください。

  • /etc/lvm/backup
    • lvcreateなどの変更コマンドを実行する度にバックアップを自動保存するフォルダ
    • 最新の情報のみ保存されている
  • /etc/lvm/archive
    • 過去のバックアップを世代管理しているフォルダ
    • archive内の最新のファイルは、/etc/lvm/backupと同じ中身

私の場合は、VMを動かしているホストPCにSCPでファイルコピーしておきました。
外部ストレージをどうしても用意できない場合は、/bootなどLVM外のパーティションにファイルコピーしておくのでも最悪OKです。

これらのバックアップファイルは、復旧時にレスキューモードで起動したVM上に送る必要があります。
ファイルの送り方はSCPと非LVM領域のマウントの2パターンがあります (他にもあるかもしれません)。

SCPの場合は、パスワード無しでrootログインされてしまうというセキュリティリスクがあります。
詳細は、#(任意) SSHサーバの有効化、バックアップファイル送付を参照してください。

非LVM領域のマウントは、レスキューモードでマウントできる構成か、事前に確認が必要です。
/bootであれば簡単にマウントできます。
詳細は、#(任意) 非LVM領域のマウントを参照してください。

レスキューモードでの起動

この手順が必要か否かは状況によって変わります。
後続の手順でpvcreateコマンドを実行する際、対象のパーティションはアンマウントされている必要があります。

そして、今回のケースではルートファイルシステムも復旧対象に含んでいます。
ルートファイルシステムをアンマウントするために、レスキューモードの起動が必要となります。

レスキューモードに入る前に、必ず上述の#LVMメタデータのバックアップが完了していることをご確認ください。
ここでOSシャットダウンすると、ルートファイルシステムが読み込めないため、次回以降通常のOS起動ができなくなってしまいます。

レスキューモードへの入り方は過去記事に書いてあるので、そちらを参照してください。
レスキューモードからの起動

ディスクのマウントができないので、最後の起動メニューは3) Skip to shellを選択し、ディスクをマウントせずにシェルを起動してください。

KVMを使っている方向けに補足です。
KVMを使っている場合は、OS起動順序をCD Drive優先にして、CDにLinuxインストール用のISOファイルをセットすることでISOファイルから起動することができます。
KVMの操作方法については、以下のリンクを参考にしてください。

以降の作業は、レスキューモードに入った後のウィンドウで実行します。

(任意) キーボードの日本語化

こちらの作業は任意で実行してください。

レスキューモードでは、以下のようにキーボードの言語が英字配列 (us) になっています。
日本語キーボードに慣れている方は、まずはキーボードの言語を変更しましょう。

蛇足ですが、普段私はコンソールとデスクトップ環境のキーボード設定を両方変更可能なlocalectl set-x11-keymapばかりを使っています。

localectl
  #  System Locale: LANG=C.UTF-8
  #      VC Keymap: us
  #     X11 Layout: n/a

localectl set-keymap jp

localectl
  #  System Locale: LANG=C.UTF-8
  #      VC Keymap: jp
  #     X11 Layout: n/a

(任意) SSHサーバの有効化、バックアップファイル送付

SSHサーバの有効化、SCPによるファイル送付は、任意で実行してください。

SSHサーバの有効化により、SCPによるファイル転送やSSHログインが可能となります。
パスワード無しでrootユーザにログインできてしまうので、商用環境では辞めておいた方が良いかもしれません...。
最低限、ファイアウォールやNATでガチガチに守られたサブネットで作業するなどの検討をした方が良いと思います。
私の環境は手元の検証用VMなので、気にせず有効化します。

単純にサービス起動しようとすると、sshd_configが無いとのエラーで起動失敗します。

systemctl start sshd
# Job for sshd.service failed because the control process exited with error code.
# See "systemctl status sshd.service" and "journalctl -xe" for details.

journalctl -e
# Nov 12 08:11:34 my-vm /etc/ssh/sshd_config: No such file or directory

これに対処するため、sshd_configを用意します。

cp /etc/ssh/sshd_config.anaconda /etc/ssh/sshd_config

cat /etc/ssh/sshd_config

sshdサービスを起動します。
今度はうまくいきます。

systemctl start sshd

ホストPCにLVMのバックアップを取得していた方は、SCPでファイルを送ってしまいましょう。
バックアップファイルの選択ですが、最新のバックアップファイルの場合はbackup/配下のファイルを使用します。
2世代以上前のファイルを使いたい場合は、archive/配下のファイルから適切なものを選択してください。

バックアップファイル名がmy_vmだったとしたときのコマンドは、以下のようになります。
レスキューモードの場合はパスワード無しでSCPできます。

scp my_vm root@x.x.x.x:/

更に、そのままSSHログインします。

ssh root@x.x.x.x
cd /

以降の操作は、SSHログインして行います。
SSHを長時間有効化することに抵抗がある場合は、systemctl stop sshdsshdを停止しても結構です。

(任意) 非LVM領域のマウント

非LVM領域のマウントは、任意で実施してください。

前の手順でSSHを有効化しなかった場合、別の方法でファイルを送付する必要があります。
例えば、LVMを利用していない/bootにファイルを配置していた場合は、以下のようなコマンドで/bootをマウントします。

環境によっては/bootではなく、NFSストレージや、LVMを使っていない別パーティションの領域かもしれません。
そのあたりは、環境によってアレンジしてください。

/mnt/sysroot/は、レスキューモードで1) Continueを選択した時などにマウント先として自動で選択される領域です。
深い意味はありませんが、何となく合わせました。

mkdir -p /mnt/sysroot/boot
mount /dev/vda2 /mnt/sysroot/boot

最後に、マウントしたディスク上に、予め配置しておいたバックアップファイルがあることを確認してください。

もし/bootを一時的なファイル置き場に指定する場合は、一連の復旧作業が終わった後にゴミファイルを削除するのを忘れずに...。

PVの復旧

次に、バックアップファイルを利用してPVを再作成します。

バックアップファイルを利用しなくてもPVの再作成は可能ですが、以下の観点でバックアップファイルを使ったほうが良いと思います。

  • UUIDの保持 (ただし、--uuid, --norestorefileオプションの組み合わせでも可能)
  • --restorefileを使った場合、安全に復旧するための追加ロジックが発動する (man pvcreate --restorefileの説明より)

コマンド実行の前に、まずはバックアップファイルを開いてPVのUUIDを確認します。
以下の例では、PVのUUIDはBPTO1p-dz0e-gM36-37ls-nGY0-cUeD-Zcmt4bであるとわかります。
また、PVの作成先が/dev/vda3であると再確認できます。
※PVの作成先は、事前ログのdf -Thからも確認できます

cat my_vm
# (中略)
  # physical_volumes {
  # pv0 {
  #   id = "BPTO1p-dz0e-gM36-37ls-nGY0-cUeD-Zcmt4b"
  #   device = "/dev/vda3"    # Hint only
  #   status = ["ALLOCATABLE"]
  #   flags = []
  #   dev_size = 38612992     # 18.4121 Gigabytes
  #   pe_start = 2048
  #   pe_count = 4713 # 18.4102 Gigabytes
  # }
  # }
# (中略)

では、pvcreateコマンドによってPVを復旧させます。
復旧の前に、ステータス確認とテストモード実行をしてみます。

pvdisplay
# (出力なし)

pvcreate --uuid "BPTO1p-dz0e-gM36-37ls-nGY0-cUeD-Zcmt4b" --restorefile my_vm /dev/vda3 -t
  # TEST MODE: Metadata will NOT be updated and volumes will not be (de)activated.
  # WARNING: Couldn't find device with uuid BPTO1p-dz0e-gM36-37ls-nGY0-cUeD-Zcmt4b.
  # Physical volume "/dev/vda3" successfully created.

問題なく通ったので、今度は-tオプションを外して実際に実行します。

pvcreate --uuid "BPTO1p-dz0e-gM36-37ls-nGY0-cUeD-Zcmt4b" --restorefile my_vm /dev/vda3
  # WARNING: Couldn't find device with uuid BPTO1p-dz0e-gM36-37ls-nGY0-cUeD-Zcmt4b.
  # Physical volume "/dev/vda3" successfully created.

成功しました。
PVの状態を確認します。
PE Sizeなどが0になっていますが、これはVG作成前であるためなので気にしないで大丈夫です。

  # "/dev/vda3" is a new physical volume of "18.41 GiB"
  # --- NEW Physical volume ---
  # PV Name               /dev/vda3
  # VG Name               
  # PV Size               18.41 GiB
  # Allocatable           NO
  # PE Size               0   
  # Total PE              0
  # Free PE               0
  # Allocated PE          0
  # PV UUID               BPTO1p-dz0e-gM36-37ls-nGY0-cUeD-Zcmt4b

最後に、pvcreateコマンドの構文を紹介します。

pvcreate pv-name [options...]

今回使ったものを中心に、構文の詳細を下表にまとめます。
バックアップファイルから復旧する際は、--uuid--restorefileを使います。

キーワード 説明
pv-name PVの名前。
/dev/vda3など。
pvdisplayで確認可能
-t,
--test
テストモード実行。
実際にはメタデータを書き込まずに終了する
-u uuid,
--uuid uuid
PVのUUIDを明示的に指定したい場合に記載する。
--uuidを指定した場合、--restorefile string, または--norestorefileのどちらかが必須になる
--restorefile string --uuid uuidとセットで指定する。
stringにはvgcfgbackupで取得したバックアップファイルパスを指定する。
--restorefileを指定することで、PEを書き込むディスクアドレスなどが復旧前と同一になるようにPVを作成し、新たに書き込んだメタデータが通常データを上書きしないよう制御する。
※バックアップファイルにpe_startなどのパラメータが記録されている
vgcfgbackupは、pvcreatevgcreateなどのLVM変更コマンドを実行する度に内部的に実行されている
--norestorefile --uuid uuidとセットで指定する。
UUIDを指定しつつも、バックアップファイルを使わずにPVを作成したい時に使う

VG,LVの復旧

VG、LVは、バックアップファイルを用いて1コマンドで復旧できます。

復旧コマンドを実行する前に状態確認とテストモード実行をしてみます。

vgdisplay
# (出力なし)

lvdisplay
# (出力なし)

vgcfgrestore -f my_vm my_vm -t
  # TEST MODE: Metadata will NOT be updated and volumes will not be (de)activated.
  # Restored volume group my_vm.

テストモード実行は問題なく通りました。
-tオプションを外して実行し、実際に復旧させます。

vgcfgrestore -f my_vm fedora_cinnamon
  # Restored volume group fedora_cinnamon.

確認コマンドを実行します。
PV, VG, LV共に無事作成されました。
これにて復旧完了です。

復旧を確認できたら、再度fdiskによるパーティション拡張に挑戦してみてください。
よろしければ、再挑戦の前にVMクローンによるバックアップもご検討ください。

pvdisplay
  # --- Physical volume ---
  # PV Name               /dev/vda3
  # VG Name               fedora_cinnamon
  # PV Size               18.41 GiB / not usable 2.00 MiB
  # Allocatable           yes 
  # PE Size               4.00 MiB
  # Total PE              4713
  # Free PE               41
  # Allocated PE          4672
  # PV UUID               BPTO1p-dz0e-gM36-37ls-nGY0-cUeD-Zcmt4b

vgdisplay
  # --- Volume group ---
  # VG Name               fedora_cinnamon
  # System ID             
  # Format                lvm2
  # Metadata Areas        1
  # Metadata Sequence No  4
  # VG Access             read/write
  # VG Status             resizable
  # MAX LV                0
  # Cur LV                2
  # Open LV               0
  # Max PV                0
  # Cur PV                1
  # Act PV                1
  # VG Size               18.41 GiB
  # PE Size               4.00 MiB
  # Total PE              4713
  # Alloc PE / Size       4672 / 18.25 GiB
  # Free  PE / Size       41 / 164.00 MiB
  # VG UUID               RTiZsE-pO7c-2rMe-O5So-h2FA-PcFk-gz3wSi

lvdisplay
  # --- Logical volume ---
  # LV Path                /dev/fedora_cinnamon/root
  # LV Name                root
  # VG Name                fedora_cinnamon
  # LV UUID                geKCRT-Q1TN-rJBV-zP4F-jdjI-Sucm-eichFQ
  # LV Write Access        read/write
  # LV Creation host, time fedora-cinnamon, 2020-09-11 02:31:26 +0000
  # LV Status              available
  # # open                 0
  # LV Size                16.25 GiB
  # Current LE             4160
  # Segments               1
  # Allocation             inherit
  # Read ahead sectors     auto
  # - currently set to     256
  # Block device           253:2
   
  # --- Logical volume ---
  # LV Path                /dev/fedora_cinnamon/swap
  # LV Name                swap
  # VG Name                fedora_cinnamon
  # LV UUID                ZyTqNg-8MTo-JuVE-JWTi-1kfy-ZxJU-7fe812
  # LV Write Access        read/write
  # LV Creation host, time fedora-cinnamon, 2020-09-11 02:31:26 +0000
  # LV Status              available
  # # open                 0
  # LV Size                2.00 GiB
  # Current LE             512
  # Segments               1
  # Allocation             inherit
  # Read ahead sectors     auto
  # - currently set to     256
  # Block device           253:3

PV拡張 & VG拡張

PVを拡張すると、対応するVGも拡張された扱いになります。
PVの拡張には、pvresizeコマンドを使用します3

pvresizeコマンドを実行するためにPV (Physical Volume) の名前を事前に調べておきます。
PVを表示するコマンドはpvdisplaypvscanpvsの3種類がありますが、一番見やすいpvdisplayで表示します4
PV名は/dev/vda3で、現時点のサイズは18.41 GiBと認識されていることがわかります。

sudo pvdisplay
#   --- Physical volume ---
#   PV Name               /dev/vda3
#   VG Name               fedora_my_vm
#   PV Size               18.41 GiB / not usable 2.00 MiB
#   Allocatable           yes 
#   PE Size               4.00 MiB
#   Total PE              4713
#   Free PE               41
#   Allocated PE          4672
#   PV UUID               BPTO1p-dz0e-gM36-37ls-nGY0-cUeD-Zcmt4b

では、pvresizeでPVサイズを拡張します。

pvresizeのSyntaxは以下の構造です。

pvresize <pv-name> [options...]

オプションは多数ありますが、代表的なものは以下の通りです。

オプション 意味
-t, --test 実際に変更を行わず、想定結果のみ返して終了する
--setphysicalvolumesize Size PVのサイズを指定する。
指定しない場合は自動認識する。
基本使わない

まずは、テストモードで実行してみます。
"1 physical volume(s) resized or updated" と出ているので、テスト実行としては成功しています。

sudo pvresize -t /dev/vda3
#   TEST MODE: Metadata will NOT be updated and volumes will not be (de)activated.
#   Physical volume "/dev/vda3" changed
#   1 physical volume(s) resized or updated / 0 physical volume(s) not resized

次は実際に変更します。

sudo pvresize /dev/vda3
#   TEST MODE: Metadata will NOT be updated and volumes will not be (de)activated.
#   Physical volume "/dev/vda3" changed
#   1 physical volume(s) resized or updated / 0 physical volume(s) not resized

pvdisplayで確認します。
変更前のサイズは18.41 GiBでしたが、正しく23.41 GiBに拡張されました。

sudo pvdisplay
#   --- Physical volume ---
#   PV Name               /dev/vda3
#   VG Name               my_vm
#   PV Size               23.41 GiB / not usable 1.98 MiB
#   Allocatable           yes 
#   PE Size               4.00 MiB
#   Total PE              5993
#   Free PE               1321
#   Allocated PE          4672
#   PV UUID               BPTO1p-dz0e-gM36-37ls-nGY0-cUeD-Zcmt4b

VGのサイズも確認します。
PV拡張後、VG Sizeも23.41 GiBになっていることがわかります。

sudo vgdisplay
#   --- Volume group ---
#   VG Name               my_vm
#   System ID             
#   Format                lvm2
#   Metadata Areas        1
#   Metadata Sequence No  4
#   VG Access             read/write
#   VG Status             resizable
#   MAX LV                0
#   Cur LV                2
#   Open LV               2
#   Max PV                0
#   Cur PV                1
#   Act PV                1
#   VG Size               23.41 GiB
#   PE Size               4.00 MiB
#   Total PE              5993
#   Alloc PE / Size       4672 / 18.25 GiB
#   Free  PE / Size       1321 / 5.16 GiB
#   VG UUID               RTiZsE-pO7c-2rMe-O5So-h2FA-PcFk-gz3wSi

LV拡張 & File System拡張

LV (Logical Volume) の拡張には、lvextendコマンドを使います5
lvextend--resizefsオプションを付与することで、ファイルシステムの拡張も同時に行えます。
ファイルシステムの同時拡張は、ext2, ext3, ext4, ReiserFS, XFSに対応しているようです (※)。

(※)
man lvextendによると、--resizefsは裏でfsadm resizeコマンドを実行することでファイルシステムのサイズ変更を行っています。
そしてman fsadmによると、fsadmは上述のファイルシステムに対応しているようでした。

なお、lvresizeというlvextend(拡張)とlvreduce(縮小) を両方行えるコマンドもあります。
今回は「サイズ指定を間違えて誤って縮小し、データが破損した...」といったミスを防ぐために、lvextendを使います。

さて、LVを拡張するために、まずはlvdisplayによってLVの名前を調べておきます。
他にもlvslvscanといった同様のコマンドがありますが、ほぼ見た目しか変わりません。

コマンド出力より、今回拡張したいLVの名前は、/dev/my_vm/rootであるとわかります。
また、拡張前のLV Sizeは16.25 GiBでした。

sudo lvdisplay
#   --- Logical volume ---
#   LV Path                /dev/my_vm/root
#   LV Name                root
#   VG Name                my_vm
#   LV UUID                geKCRT-Q1TN-rJBV-zP4F-jdjI-Sucm-eichFQ
#   LV Write Access        read/write
#   LV Creation host, time my-vm, 2020-09-11 11:31:26 +0900
#   LV Status              available
#   # open                 1
#   LV Size                16.25 GiB
#   Current LE             4160
#   Segments               1
#   Allocation             inherit
#   Read ahead sectors     auto
#   - currently set to     256
#   Block device           253:0
   
#   --- Logical volume ---
#   LV Path                /dev/my_vm/swap
#   LV Name                swap
#   VG Name                my_vm
#   LV UUID                ZyTqNg-8MTo-JuVE-JWTi-1kfy-ZxJU-7fe812
#   LV Write Access        read/write
#   LV Creation host, time my-vm, 2020-09-11 11:31:26 +0900
#   LV Status              available
#   # open                 2
#   LV Size                2.00 GiB
#   Current LE             512
#   Segments               1
#   Allocation             inherit
#   Read ahead sectors     auto
#   - currently set to     256
#   Block device           253:1

次に、LVを拡張します。

lvextendの構文は、以下のとおりです。

lvextend [options...] LV-name [PV-name]

主なオプションの意味は、下表のとおりです。
LVのサイズは--extents--sizeの2通りの指定方法がありますが、今回の場合は--extents +100%FREEを使うことで、LVの空き容量を全てroot LVに追加で割り当てます。
VGの空き領域などは、vgdisplayで確認できます。
もちろん、vgdisplayで確認したFREE PE / Sizeの値を参考に、--sizeで指定しても問題ありません。

PV-nameは、--extentsでPE (Physical Extent) を利用したサイズ指定を行う場合や、%PVSを使う際にPE Sizeを特定する際に必要となります。

オプション 意味
-l size,
--extents size
拡張後のLVのサイズ。
数値のみ記載した場合、LE (Logical Extent) 数での指定となる。
他に%を後置した動的な指定も可能。
%VG: VGの総容量
%FREE: VGの空き容量
%PVS: 指定したPVの空き容量
%ORIGIN: スナップショット元 (Original) のVGの合計サイズ
 (LVM Snapshot領域のLVに対して使う)
+-を先頭に付けると、今のLV Sizeに対する相対値になる。
-L, --sizeと併用すると、sizeが上限値となる
例1: -l 100%FREEでVGの空き領域を全て割り当て
例2: -l +100%FREEでVGの空き領域を現状のLV Sizeに上乗せして割り当て
-L size,
--size size
拡張後のLVのサイズ。
単位としてbBsSkKmMgGtTpPeEが使える。
bBはByte, sSはセクタ, kKは1024Bといった意味。
+か-をつけると、今のLV Sizeに対する相対値になる。
-L, --sizeの代わりに-l,--extentsを使ってもよい
-r,
--resizefs
ファイルシステムのサイズ変更も同時に行う。
ext2, ext3, ext4, ReiserFS, XFSに対応。
詳細はman fsadmを参照
-t,
--test
テストモード実行になる。
LVMのメタデータを書き込まずに成功扱いで終了する。
-rを指定すると、fsadm --dry-runも内部的に実行してくれる。
lvreduceの場合はfsadm --dry-runの実行は行わないので注意(参考)
-v,
--verbose
より詳細な情報を画面出力する。
-vを複数指定するとより詳細に出力する (最大4回)
-d,
--debug
syslogにも結果を出力する。
-dを複数指定するとより詳細に出力する (最大6回)

まずはテストモードで実行してみます。
無事に21.41 GiBまで拡張できそうです。

sudo lvextend -t -r -l +100%FREE /dev/my_vm/root
  TEST MODE: Metadata will NOT be updated and volumes will not be (de)activated.
  Size of logical volume my_vm/root changed from 16.25 GiB (4160 extents) to 21.41 GiB (5481 extents).
  Logical volume my_vm/root successfully resized.

-vオプション付きでテストモード実行してみます。
後半でfsadm --dry-runが実行され、さらにfsadmが内部的にresize2fsコマンドを呼んでいるところまで読み取れます。
理解が深まりますね。

sudo lvextend -t -r -l +100%FREE /dev/my_vm/root -v
  TEST MODE: Metadata will NOT be updated and volumes will not be (de)activated.
  Converted 100%FREE into at most 1321 physical extents.
  Executing: /usr/sbin/fsadm --dry-run --verbose check /dev/my_vm/root
fsadm: "ext4" filesystem found on "/dev/mapper/my_vm-root".
fsadm: Skipping filesystem check for device "/dev/mapper/my_vm-root" as the filesystem is mounted on /
  /usr/sbin/fsadm failed: 3
  Test mode: Skipping archiving of volume group.
  Extending logical volume my_vm/root to up to 21.41 GiB
  Size of logical volume my_vm/root changed from 16.25 GiB (4160 extents) to 21.41 GiB (5481 extents).
  Test mode: Skipping backup of volume group.
  Logical volume my_vm/root successfully resized.
  Executing: /usr/sbin/fsadm --dry-run --verbose resize /dev/my_vm/root 22450176K
fsadm: "ext4" filesystem found on "/dev/mapper/my_vm-root".
fsadm: Device "/dev/mapper/my_vm-root" size is 17448304640 bytes
fsadm: Parsing tune2fs -l "/dev/mapper/my_vm-root"
fsadm: Resizing filesystem on device "/dev/mapper/my_vm-root" to 22988980224 bytes (4259840 -> 5612544 blocks of 4096 bytes)
fsadm: Dry execution resize2fs /dev/mapper/my_vm-root 5612544

さて、テスト実行に成功したので、実際にLVを拡張します。
テストモード実行時のコマンドから-tオプションを外して実行します。
ログ出力を見るに、LV、ファイルシステム共に正しく拡張されたようです。

sudo lvextend -r -l +100%FREE /dev/my_vm/root
#   Size of logical volume my_vm/root changed from 16.25 GiB (4160 extents) to 21.41 GiB (5481 extents).
#   Logical volume my_vm/root successfully resized.
# resize2fs 1.45.5 (07-Jan-2020)
# Filesystem at /dev/mapper/my_vm-root is mounted on /; on-line resizing required
# old_desc_blocks = 3, new_desc_blocks = 3
# The filesystem on /dev/mapper/my_vm-root is now 5612544 (4k) blocks long.

拡張後のLVとファイルシステムの状態をそれぞれ確認します。
いずれも21GiBに拡張されていることが読み取れました。

sudo lvdisplay /dev/my_vm/root
#   --- Logical volume ---
#   LV Path                /dev/my_vm/root
#   LV Name                root
#   VG Name                my_vm
#   LV UUID                geKCRT-Q1TN-rJBV-zP4F-jdjI-Sucm-eichFQ
#   LV Write Access        read/write
#   LV Creation host, time my-vm, 2020-09-11 11:31:26 +0900
#   LV Status              available
#   # open                 1
#   LV Size                21.41 GiB
#   Current LE             5481
#   Segments               2
#   Allocation             inherit
#   Read ahead sectors     auto
#   - currently set to     256
#   Block device           253:0

df -Th
# Filesystem                       Type      Size  Used Avail Use% Mounted on
# (中略)
# /dev/mapper/my_vm-root ext4       21G   14G  6.7G  67% /
# (中略)

以上でディスク拡張は無事完了です。

最後に補足ですが、lvextend-r, --resizefsを指定しなかった場合、LV拡張後に手動でファイルシステムの拡張コマンドを実行する必要があります。

EXT4の場合、手動実行のコマンドは、以下のいずれかになります。

# sudo fsadm resize /dev/my_vm/root
# sudo resize2fs /dev/my_vm/root

基本的には、lvextend -rを使うのが簡単でおすすめです。
-rを付けるのを忘れてしまった場合は、fsadmファイルシステムの違いを抽象化してくれる上に-nでテスト実行もできるので良いと思います。
resize2fsは、Fedoraにおいて使うことはあまりないかなと思います。

参考情報

ディスク拡張手順の説明では省略した、背景知識について補足します。
記事を書き始めた時点では私も知らず、もやもやした部分が対象です。

参考情報については、本題とは関係ないので読み飛ばしても問題ありません。
もし興味のあるトピックがあれば、拾い読みいただければと思います。

(参考) fdisk vs parted

今回はパーティション拡張にfdiskを使いましたが、partedを使っても良いと思います。
他にもファイルをInputとして動作する自動化向きのsfdiskや、TUI (Table User Interface) のcfdisk、partedのGUI版であるGPartedなどのバリエーションもあり、基本的にどれを使っても問題ないとは思います。

RHEL 8 Managing storage devicesによると、2021年11月現在においてはpartedよりもfdiskの方がサポートするパーティションタイプの種類が多いようです
ただ、こういった情報は今後ソフトウェアがアップデートされるごとに変わっていきます。
その時々で気になった際にmanなどの情報を確認し、要件にあっているか確認すると良いでしょう。

機能面で特に差がなければ、自分が慣れている方を使えば良いと思います。
fdiskもpartedのどちらも対話式のインターフェースを持ちつつも、スクリプトで自動化することも可能です6
私はpartedとfdiskのどちらにも慣れていませんが、writeしない限り何も起こらないfdiskの方が気軽に色々試せて好みです。
使い捨てのVM上で作業しているとは言え、何度もクローンし直すのは手間ですから...。

(参考) GPTとPMBRの概要

Wikipedia - GUID Partition Tableの記事を参考に、GPTやPMBRといった用語について補足します。

GPT (GUID Partition Table) は、従来のMBR (Master Boot Record) を置き換えるものです。
GUID (Globally Unique Identifier) は、UUIDと同じ意味で、「絶対に被らない128bitの16進数」で、要するに"ID"です。
GPTは、BIOSの後継であるUEFIの仕様の一部として定義されています。

GPTとは、その名の通りPartition Tableであり、ディスク上でLVM2やファイルシステムなどを含むパーティションの前後に書き込まれたメタデータを表します。
GPTのフォーマットは、Wikipediaの図が参考になります。

GUID_Partition_Table_Scheme
引用元:Wikipedia - GUID Partition Table

図に出てくるLBA (Logical Block Address) とは、物理的なディスク上のアドレス (CHS: cylinder-head-sectorなど) を抽象化する論理アドレスです。
LBA0が先頭アドレス、LBA1が次のアドレス...といったように表記します。
(参考:Wikipedia - Logical Block Addressing)

ディスク先頭のLBA0 (ディスク製品によって512 Byteであったり、4096 Byteであったりします) にPMBR (Protective Master Boot Record) の領域が存在します。
PMBRは、従来のMBRを認識する古いプログラムが、GPTの先頭ディスク領域を上書きしてPartition Tableを破壊することを防ぐための仕組みです。
原理について補足すると、PMBRには、MBRと同様のフォーマットでデータが書き込まれています。
そして、PMBRのPartition IDには "EFI" を表すEEh というデータを書き込まれています。
するとMBRしか認識できない古いプログラムは、後続のGPTの領域 (LBA1以降) を「不明なフォーマットの単一のパーティションが存在する」と認識し、データを書き込む前に大抵何らかの警告を出すようになります。
こうして、PMBRは古いプログラムの誤動作によるパーティションの破壊を防いでいます。

さて、ここでディスクサイズ拡張直後にfdisk -lを実行した時のエラーメッセージについて振り返ります。

# GPT PMBR size mismatch (41943039 != 52428799) will be corrected by write.
# The backup GPT table is not on the end of the device. This problem will be corrected by write.

このエラーメッセージが出る前に、ゲストOS側では何の操作もすることなく仮想ディスクファイル (qcow2) を5 GiB拡張しています。
この時、qcow2の中身は以下のようになっています。

after_qcow2_extension

qcow2の拡張操作は、GPTを含むディスク上のデータを一切書き換えることなく、単純にディスク容量が増えています。
これによって、以下の点で整合性が取れなくなっています。

  • PMBRから読み取ったパーティションの最終セクタ番号 (=ディスクの最終セクタ) と実際のディスクの最終セクタ番号が異なっている7, 8
  • Secondary GPT Headerはディスクの最後のアドレス (LBA-1) に書き込まれるのが正しいが、実際にはSecondary GPT Headerの後に空き領域がある (上述のWikipediaの図も参照)

fdiskでwriteすると、GPT (= パーティションテーブル = PMBR + Partition Header + Partition Entries) が再書き込みされます。
#パーティション拡張では、この操作によりエラーが解消されたというわけです。

(参考) 論理セクタと物理セクタ

ディスクのデータ読み書きの単位であるセクタは、物理と論理の2種類があります。
それぞれの意味は、以下のとおりです9

  • 物理セクタ: ディスクが一度のI/Oでデータを読み書きする最小単位 (atomic write)
  • 論理セクタ: LBA 1ブロック分のサイズ。ディスクが受け付け可能なI/Oの最小単位

なお、LBA 1ブロックあたりのデータ容量は、論理セクタのサイズと同じです。

物理セクタと論理セクタのサイズは、ディスクが工場から出荷された段階で予めセットされています。
ディスク製品の多くは、出荷時の段階でセクタ境界にbit列を書き込み、物理セクタサイズを設定しています (LLF: Low-Level Format)。
論理セクタサイズがどのように決まるかは情報が見つかりませんでしたが、恐らく同様に製品出荷時に決まっています10

ちなみに、製品によってはre-initialization といってユーザー側で再度フォーマットすることでセクタサイズを変更できるものもあるそうです11

論理セクタサイズと物理セクタサイズは、fdiskコマンドによって確認できます。
ホストマシンで実行した以下のログによると、論理セクタサイズ, 物理セクタサイズ共に512 Byte であることがわかります。
ただkernelのバージョンにも依りますが、この情報が必ずしも正しいとは限らないという話もあるようです12
正確な情報が必要な場合は、製造メーカーのデータシートなどを参照することになりそうです。
ただセクタサイズを意識する場面はAlignmentを意識するときぐらいです (#後述)。
現時点で一番大きい4KiBやそれよりも大きい1MiB単位でAlignmentしていれば、実用上セクタサイズに対してそれほど神経質になる必要はないと思います。

sudo fdisk -l
# Disk /dev/nvme0n1: 931.51 GiB, 1000204886016 bytes, 1953525168 sectors
# Disk model: WDC WDS100T2B0C-00PXH0                  
# Units: sectors of 1 * 512 = 512 bytes
# Sector size (logical/physical): 512 bytes / 512 bytes
# I/O size (minimum/optimal): 512 bytes / 512 bytes

今どきのディスク製品のフォーマット (FMT) 形式は、論理セクタサイズと物理セクタサイズによって以下のように分類できます13, 14

フォーマット名 論理 物理
512n (512 Native) 512 Bytes 512 Bytes
512e (AF, 512-byte Emulation) 512 Bytes 4096 Bytes
4Kn (AF, 4KB Native) 4096 Bytes 4096 Bytes

AFとはAdvanced Format の略で、物理セクタサイズを従来型の512 Bytesから4096 Bytesに増やし、ディスクの容量効率を向上させる技術のことです15

AFに対応した製品は2010年から出荷され始めた関係で、4096 Bytesのセクタサイズに対応していないOSやプログラムが「昔は」あったようです。
2015年より前のWindows Server 2008、RHEL6、ESXi5.5などの時代の話です。
恐らく、今の段階で4K非対応を気にする必要はあまりないのではないかと思います16

(参考) 4K Disk Alignment

概要

結論から言えば、パーティション開始位置をfdiskのデフォルトに任せつつ、パーティションサイズを1MiBの倍数で指定していれば基本問題ありません。

1MiBの倍数で指定する場合、1M Alignmentと呼ばれることもあります17
ここでの説明だけを参照すると4KiBでも十分そうに見えるのですが、RAID5, RAID6を組んでいる場合は16KiB, 256KiBのデータストライプに合わせる必要があります。18

LVMにもAlignmentは関係します。
LVM2はデフォルトで1MiBでAlignmentを調整します。
詳しい内容は、man pvcreateに書かれています。
LVMを使う場合は、1MiB単位でAlignmentを揃えるのが良さそうです。

さらに別の話題としてSSDのErase Block Sizeに合わせると16KiB〜8MiB程度の粒度になってしまうのですが、本当にErase Block SizeとPartition開始点を合わせる必要があるのかははっきりとしていません。
業務用ストレージでSSDを使う場合は、恐らくメーカーのドキュメントなどを参照して推奨される設計を確認することになりそうですが、個人利用の範囲ではあまり気にしないようにします。
SSDについてはsuperuser - Is partition alignment to SSD erase block size pointless?にて興味深い議論がされていますので、興味のある方は読んでみてください。

上記を総合すると、「パソコン用途では基本1MiBでAlignmentを調整し、エンタープライズ用途のSSDストレージやRAID構成であればメーカーの仕様に沿って検討するのが良さそう」というのが私なりの結論です。

さて、本題の「Alignmentの理解」に入ります。

パーティションを作成する際、セクター開始位置には注意を払う必要があります。
セクター開始位置のアドレス (LBA: Logical Block Address) が4KiBの倍数でない場合、I/Oのパフォーマンスが低下する可能性があります。
2021年現在においては、ディスクのフォーマット形式が512e (物理セクタサイズ=4KiB、論理セクタサイズ=512B) の場合のみ、この問題が発生する可能性があると理解しています。
512eについては、#(参考) 論理セクタと物理セクタに記載があります。

Misalignmentによってなぜパフォーマンスが低下するのか、以下の図で説明します。
Alignmentが正しいケースと誤っているケースを比較してみましょう。

correct_alignment

incorrect_alignment

上記スライドは、File Systemのブロックサイズ (※) が4KiBの場合を想定しています。
つまり、File Systemが発行するI/O命令は必ず4KiBの倍数になります。
(※) ディスクのセクターサイズとはまた別物。多くのファイルシステムでは、デフォルト値は4096Bか512B。例えばEXT4の場合、詳細はman mke2fsを参照。

ここで4KiBのI/Oが発生したとします。
Alignmentが適切であれば、物理ディスク上で実際に発生するI/Oは物理セクタ1つ分 (4KiB) のI/Oになります。
一方でAlignmentが適切ではない場合、物理ディスク上で物理セクタ2つにまたがってI/Oが発生してしまうため、非効率的です

File Systemのブロックサイズ、パーティションの開始位置、物理セクタサイズに合わせてシステムを構成することで、上述のMisalignmentによるI/Oパフォーマンスの低下を防ぐことができます。

では、実際に構築する際、どうすればAlignmentを正しくできるのでしょうか?
それについては、次のセクションに記載します。

Misaligmnetを防ぐ方法

今どきのfdisk (util-linux 2.18以降。RHEL6以降に同梱) であれば、以下のやり方でパーティションを作成すればMisalignmentは起こらないようになっています19, 20

なぜなら、fdiskは以下のように動作するためです。
上記ルールと合わせれば、各パーティションの開始セクターは必ず2048セクター (1MiB) の倍数、つまり8セクターの倍数となります。
従って、Misalignmentは起こりえません。

なお、PartedやGPartedについても同様のAlignmentへの配慮がされています21

Misalignmentが発生しているか否かの確認方法

sudo fdisk -lにおいて論理セクタサイズが512 Bytes 表記の場合、各パーティションの開始セクタを8で割り切れない場合は、misalignmentが発生している可能性があります。
ディスクのフォーマット形式が512eかどうかを調べる作業は労力がかかりますので、そういったことを考えずに済むように、1MiBの倍数でセクタ開始点を定めるように意識していきたいところです。

以下にfdisk -lの出力の一部を貼ります。
Startの部分が2048, 1230848, 3328000と並んでいます。
これらはいずれも8で割り切れます。
つまり、パーティションの開始点は4KiB (512 Bytes * 8) の倍数なので、正しく4K Alignmentされています。
更に言うと2048でも割り切れるので、1M Alignmentされています (1MiB = 512 Bytes * 2048)。
1M Alignmentは、RAIDなどを考慮に入れても対応可能で、4K Alignmentよりも更に手堅いAlignment方法です22

sudo fdisk -l
# (中略)
# Units: sectors of 1 * 512 = 512 bytes
# Sector size (logical/physical): 512 bytes / 512 bytes

# (中略)

# Device       Start      End  Sectors  Size Type
# /dev/vda1     2048  1230847  1228800  600M EFI System
# /dev/vda2  1230848  3327999  2097152    1G Linux filesystem
# /dev/vda3  3328000 52428766 49100767 23.4G Linux LVM

まとめ

KVM仮想マシンのディスク拡張の手順を紹介しました。
LVMならではのトラブルの対処方法や、GPTやAlignmentの予備知識を参考情報として盛り込んだことで、内容が大変盛りだくさんとなりました。

目次を活用して、必要な情報を拾って読んでいただければと思います。


  1. Unix & Linux - How to calculate partition Start End Sector?

  2. Red Hat - RHEL8 - Configuring and managing logical volumes - 19.5. Restoring metadata on an LVM physical volume

  3. Red Hat - RHEL8 - Configuring and managing logical volumes - 7.3. Resizing an LVM physical volume

  4. Red Hat - RHEL8 - Configuring and managing logical volumes - 3.1. Creating LVM physical volume

  5. Red Hat - RHEL8 - Configuring and managing logical volumes - 5.1. Growing a logical volume and file system

  6. Red Hat Customer Portal - Tool Battle Royale - FDISK vs. PARTED ※fdiskをシェルスクリプトで自動化している方もいました

  7. Wikipedia - GUID Partition Table #Protective_MBR_(LBA_0))

  8. GitHub - util-linux/util-linux - gpt.c

  9. Dell Engineering - 512e and 4Kn Disk Formats p9

  10. Wikipedia - Disk formatting

  11. WD Community - SN550 - Why it uses 512B sector instead of 4096? ※WD製やIntelSSDの例

  12. IBM - Linux on 4 KB sector disks: Practical advice - #Determining physical sector size

  13. Dell Engineering - 512e and 4Kn Disk Formats - p4

  14. Wikipedia - Advanced Format

  15. Wikipedia - Advanced Format

  16. Dell Engineering - 512e and 4Kn Disk Formats - p9〜p10

  17. Wikipedia - Partition alignment

  18. IBM - Linux on 4 KB sector disks: Practical advice #Determining physical sector size

  19. libblkid, or why you don’t need to worry about 4K disk format

  20. IBM - Linux on 4 KB sector disks: Practical advice #The fdisk family

  21. IBM - Linux on 4 KB sector disks: Practical advice #The libparted library

  22. Wikipedia - Partition alignment