それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

パーティションをディスクに仕立てる(壊れたパーティションの先頭を作り直す)

達成したい目的。

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

ext4 を取り出す。

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

取り出したファイルが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 パーティションをディスクイメージに変換する。

取り出したパーティションをディスクイメージに変換する。

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
grub メモ

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バイトなど、サイズは自分で決められたらしい。むかし先輩にちらっと聞いたけど、当時はよくわからんけどなんか便利な単位なんですねって聞き流してた。が、まさか今更役に立つなんて。

参考資料