達成したい目的。
LVM から ext4を取り出して、単独でブートするように作り直したい。
言い換えると
パーティションなんて、HDDの先頭にセクタ位置を書いてるだけだろ?とおもって調べたらやっぱりそうだった。
準備。
新規インストールで実験環境を整える。
サクッとインストールして、ext4 on LVM を用意する。
ext4 on LVM でインストールしたLinuxを仮想マシンで作成。
sudo virt-install \
--connect=qemu:///system \
--name lc01 \
--ram 8192 \
--disk path=/var/lib/libvirt/images/lc01.qcow2,size=5 \
--vcpus 8 \
--virt-type kvm \
--os-variant debian10 \
--graphics none \
--location http://ftp.kddilabs.jp/pub/Linux/distributions/Debian/debian/dists/buster/main/installer-amd64/ \
--extra-args="console=ttyS0" \
--check all=off
qcow2 から raw ファイルを取り出す。
sudo qemu-img convert -p -f qcow2 le01.qcow2 -O raw le01.img
ループバックにつなぐ
sudo losetup -P -f le01.img --show
LVMが接続されるのを確認する。
pvs
vgs
lvs
接続されたLVMから ext4 を抜き出す。
sudo ddrescue /dev/mapper/le01--vg-root vgroot.img
後片付けする。
vgchange -an le01-vg
sudo losetup -d /dev/loopX
取り出したファイルがEXT4なことを確認
$ file vgroot.img
vgroot.img: Linux rev 1.0 ext4 filesystem data, UUID=33cc43c6-b3f7-4001-9460-d6d28f11d91f (extents) (64bit) (large files) (huge files)
取り出したパーティションをディスクイメージに変換する。
ext4 の先頭に1Mを追加する。
ext4のイメージファイルの先頭に1MBを足せばいいのですが。
ファイルの先頭に1Mを追加するという処理は面倒です。
そこで、1Mのファイルを作って末尾にExt4を追記するという逆のアプローチでやります。
dd または truncate で1MiB のファイルを作る。
dd if=/dev/zero of=new-hdd.img count=1 bs=1MiB
パーティションとは、ファイルシステムの先頭に、1MBがあるだけです。 bs=1MiB
と書くのに注意。
先頭に16kがあり、どのセクタにファイルシステムがあるか書いてる。
GPTは16k-1M までの領域にEFIとかUUIDとか色々書いてるらしい。
1MB+ext4 => ディスクイメージ
pv とリダイレクトを用いて追記します。
pv vgroot.img >> new-hdd.img
ディスクイメージをコピーすると時間がかかるのでcp よりもpv の方が扱いやすい。
これで、パーティションがぶっ壊れたHDDイメージの出来上がり。
先頭が空っぽなので、パーティションとして認識されません。
パーティションが消えた状態になっています。
takuya@:images$ fdisk -l new-hdd.img
Disk new-hdd.img: 3.56 GiB, 3826253824 bytes, 7473152 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
fdisk を使ってパーティションを作り直します。
takuya@:images$ sudo fdisk new-hdd.img
Welcome to fdisk (util-linux 2.36.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xb2368926.
Command (m for help): p # ← print
Disk new-hdd.img: 3.56 GiB, 3826253824 bytes, 7473152 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: 0xb2368926
Command (m for help): n # ← new
Partition type
p primary (0 primary, 0 extended, 4 free)
e extended (container for logical partitions)
Select (default p): p # ← primary
Partition number (1-4, default 1):
First sector (2048-7473151, default 2048):
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-7473151, default 7473151):
Created a new partition 1 of type 'Linux' and of size 3.6 GiB.
Partition #1 contains a ext4 signature.
Do you want to remove the signature? [Y]es/[N]o: no # ←既存を使うのでno
The signature will be removed by a write command.
Command (m for help): p # ← print
Disk new-hdd.img: 3.56 GiB, 3826253824 bytes, 7473152 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: 0xb2368926
Device Boot Start End Sectors Size Id Type
new-hdd.img1 2048 7473151 7471104 3.6G 83 Linux
Filesystem/RAID signature on partition 1 will be wiped.
Command (m for help): a # ← Make MBR bootable flag on
Selected partition 1
The bootable flag on partition 1 is enabled now.
Command (m for help): w # ← Write and Quit
The partition table has been altered.
Syncing disks.
これでパーティションとして認識されるはずです。
takuya@:images$ fdisk -l new-hdd.img
Disk new-hdd.img: 3.56 GiB, 3826253824 bytes, 7473152 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: 0xb2368926
Device Boot Start End Sectors Size Id Type
new-hdd.img1 * 2048 7473151 7471104 3.6G 83 Linux
ファイルを確認
ext4 が壊れてないか確認しておきます。
イメージファイルををループバックで接続してみます。
losetup -P -f new-hdd.img --show
接続できたのでパーティションが認識されるはずです。確認しておきます。
takuya@:images$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
loop11 7:11 0 3.6G 0 loop
└─loop11p1 259:4 0 3.6G 0 part
マウントしてみます。あらら失敗です
sudo mount /dev/loop11p1 test
mount: /var/lib/libvirt/images/test: wrong fs type, bad option, bad superblock on /dev/loop11p1, missing codepage or helper program, or other error.
dmesg を確認してみます。どこか失敗した模様(ddのbsミス でした)
$ sudo dmesg
[694912.138454] EXT4-fs (loop11p1): bad geometry: block count 933888 exceeds size of device (933883 blocks)
[694917.971654] EXT4-fs (loop11p1): bad geometry: block count 933888 exceeds size of device (933883 blocks)
[695308.681524] EXT4-fs (loop11p1): bad geometry: block count 933888 exceeds size of device (933883 blocks)
[695314.313132] EXT4-fs (loop11p1): bad geometry: block count 933888 exceeds size of device (933883 blocks)
[695351.389589] EXT4-fs (loop11p1): mounted filesystem with ordered data mode. Opts: (null)
[695371.450113] EXT4-fs (loop11p1): mounted filesystem with ordered data mode. Opts: (null)
やり直しました。問題なさそうです。
$ sudo fsck /dev/loop11p1
fsck from util-linux 2.36.1
e2fsck 1.46.2 (28-Feb-2021)
/dev/loop11p1: clean, 28743/233856 files, 286271/933888 blocks
$ sudo e2fsck -f /dev/loop11p1
e2fsck 1.46.2 (28-Feb-2021)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/loop11p1: 28743/233856 files (0.2% non-contiguous), 286271/933888 blocks
$ sudo resize2fs /dev/loop11p1
resize2fs 1.46.2 (28-Feb-2021)
The filesystem is already 933888 (4k) blocks long. Nothing to do!
GPTに変更する
今どきのディスクはGPTなのでGPTでもできるが、、EFIパーティションとか、MBRハイブリッドとか考えることが多いので今回はパス。
ブートの修正
ブート修正は取り出したイメージをマウントして修正します。
マウント
losetup -f -P --show new.img
mount /dev/loop11p1 /mnt
chrootする
cd /mnt
sudo mount -t proc proc proc/
sudo mount -t sysfs sys sys/
sudo mount -o bind /dev dev/
#
sudo chroot . /bin/bash
ブート修正。
grub-install /dev/loop11
## 作業PCの boot を拾ってマルチブートになるのを避ける
chmod a-x /etc/grub.d/30_os-prober
update-grub
update-initramfs -u
作業が終わったら後片付けする
sudo umount -lf ./sys
sudo umount -lf ./proc
sudo umount -lf ./dev
cd
umount /mnt
losetup -d /dev/loopX
update-grub は次が出れば成功
Found linux image: /boot/vmlinuz-xxxx-generic
Found initrd image: /boot/initrd.img-xxx-generic
出てこない場合は、 /boot にファイルがないはずなので、/boot
が別パーティションにありddできてない可能性がある。/bootを取り損ねていないか確認。見つけ次第コピー
LVMを停止関連
LVM を停止してデータを取り出したので、以前のLVM関連の設定が残らないようにする。
lvm バックアップを削除
rm /etc/lvm/backup/le01-vg
スワップファイル
LVM のスワップがあるときは、スワップファイルを作り直してlvmスワップを除去
sudo vim /etc/initramfs-tools/conf.d/resume
スワップファイル再生成
sudo dd if=/dev/zero of=/swap.img bs=1M count=1000
sudo chmod 600 /swap.img
mkswap /swap.img
fstab のスワップ設定を変える
sudo vim /etc/fstab
LVM除去が終わったら
update-grub
update-initramfs -u
その他の問題 btrfs
btrfs の場合 update-initramfs -u
が次のエラーになるので。
/sbin/fsck.btrfs doesn't exist, can't install to initramfs
ダミーで対応する。
sudo cp /bin/true /sbin/fsck.btrfs
その他の問題 GRUB /boot
/boot
の中身をコピーし忘れたときは、単純に grub だけが起動する。
grub で、not found になるときはコピーし忘れ
grub > ls
grub > set root=(hd0,1)
grub > ls /vmlinuz
file not found
その他の問題 GRUB lvm 除去漏れ
lvm → ext4 に変えたとき、update-initramfs をせずに起動すると、LVMを探しに行ってgrub 付近でエラーになることが有る。
そのときは、手作業で起動してみる
ディスクの確認
grub > ls
root の設定
grub > set root=(hd0,1)
uuidを確認
grub > ls (hd0,1)
Partition hd1,3: Filesystem type ext4- Last modification time...
2022-05-23 07:49:05 Sunday, UUID FFEXXX-5X23456
カーネルを起動する
grub > linux /vmlinuz quiet s root=UUID-FFEXXX-5X23456
grub > initrd /boot/initrd.img
grub > boot
MBRパーティションは次のように表示される。dosが入ってるわけでなくDOS/V用のMBRパーティションの意味である。
(hd0,msdos1)
これは、msdosを省略でアクセスできる
set root=(hd0,1)
set root=(hd0,msdos1) # 同じ
gpt ( (hd0,gpt1)
) についても同じだと思う。
まとめ
ディスク内のパーティションの管理は、先頭1MiBで行っている。
単純なext4 イメージに先頭1MiBをつければディスクイメージに変えられるとわかった。
lvm の内部にあるパーティションも強引に取り出して先頭をつければ、単純なディスクイメージに変更できるとわかった。
先頭1MiB について
先頭の1MiBが使われているのは fdisk で確認できます。
sudo sgdisk -p /dev/nvme0n1
Sector size (logical/physical): 512/512 bytes
Number Start (sector) End (sector) Size Code Name
1 2048 1050623 512.0 MiB EF00
3 3147776 4000794623 1.9 TiB 8300
ssd/HDDの中身は、2048 セクタから書きます。
1セクタは、512 バイトです。
パーティション1は2048セクタから開始してます。先頭-2047にはext4 は存在しません
先頭-2047セクタ分、つまり2048セクタが管理用に予約され使われているわけです。
この2048セクタのバイトサイズを計算すると・・・1セクタ=512バイトだから
2048 セクタ
⇔ 512バイトx 2048
⇔ 512 x 2x 1024 バイト
⇔ 1024x 1024 バイト
⇔ 1048576 バイト
⇔ 1MiB
だから先頭に1MiBをつけておけば、ext4のシンプルボリュームをディスクイメージとして使えるってことなんだろうな。
大昔のFDDの頃は容量節約のために1セクタ=128/256/512バイトなど、サイズは自分で決められたらしい。むかし先輩にちらっと聞いたけど、当時はよくわからんけどなんか便利な単位なんですねって聞き流してた。が、まさか今更役に立つなんて。
参考資料