+

Ubuntu的安装程序不能识别btrfs子卷,但是我偏偏又需要把它装到一个现有的btrfs子卷里面,因此才需要像下文那样折腾。

+

TL;DR 省流版

+

在虚拟机里装好一个ubuntu,然后把整个系统复制到目标子卷里面。改改/etc/fstab和引导。

+

前情提要

+

事情是这样的,原先我装了个debian,用掉了所有的空闲空间,文件系统选了btrfs(很有先见之明)。但是因为intel +oneapi理论上只适配的ubuntu,在arch和debian上跑会有各种问题。一直以来我都不得不用docker,直到最近才决定和自己和解,装个ubuntu。

+

但是debian所在的btrfs分区里面有一些很重要的数据,而我现在手边偏偏没有足够空间来备份。综上所述,我只能想办法把ubuntu直接装到一个新的子卷里面。

+

方法

+

在虚拟机里装个ubuntu

+

先建个qcow2映像,之后往里面装ubuntu,不一定要32G,够装系统就行了:

+
$ qemu-img create -f qcow2 ubuntu.qcow2 32G
+
+ +

然后写个脚本启动qemu,在同一个目录下新建start.sh

+
#!/bin/bash
+
+qemu-system-x86_64 \
+    -m 16G # 根据实际情况调整虚拟机内存大小 \
+    -enable-kvm # 开kvm性能显著更好 \
+    -boot uefi \
+    -display gtk,gl=on \
+    -vga qxl \
+    -smp 6 \
+    -cpu host \
+    -boot order=dc \
+    -hda ubuntu.qcow2 \
+    -cdrom ubuntu.iso # ubuntu的iso路径 \
+
+ +
$ chmox +x start.sh
+$ ./start.sh
+
+ +

然后在里面装好系统。

+

挂载qcow2映像

+
# qemu-nbd --connect /dev/nbd0 ubuntu.qcow2
+# mount /dev/nbd0p1 /mnt
+
+ +

mount前最好用fdisk检查一下是不是/dev/nbd0p1

+

用rsync复制整个系统到子卷里面

+

假设目标已经子卷已经挂载到/ubuntu,虚拟机的盘片挂载到了/mnt

+
# rsync -aX --progress --stats /mnt/ /ubuntu/
+
+ +

注意/mnt/不要写成/mnt

+

改/etc/fstab和引导

+

假设ubuntu已经复制到了/ubuntu里面。根据个人实际情况自己改/ubuntu/etc/fstab,参见archwiki

+

更新grub配置文件,如果os-prober找不到ubuntu,就自己写一条。如果需要自己写,修改或新建/boot/grub/custom.cfg,参见archwiki

+
menuentry 'Ubuntu GNU/Linux' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-eea47a38-15db-4ba8-a2ec-a35ee9503ed1' {
+    load_video
+    insmod gzio
+    if [ x$grub_platform = xxen ]; then insmod xzio; insmod lzopio; fi
+    insmod part_gpt
+    insmod btrfs
+    search --no-floppy --fs-uuid --set=root eea47a38-15db-4ba8-a2ec-a35ee9503ed1
+    echo    'Loading Ubuntu ...'
+    linux   /@ubuntu/boot/vmlinuz root=UUID=eea47a38-15db-4ba8-a2ec-a35ee9503ed1 ro rootflags=subvol=@ubuntu
+    echo    'Loading initial ramdisk ...'
+    initrd  /@ubuntu/boot/initrd.img
+}
+
+ +

不要照抄。有几个地方需要根据实际情况修改。

+
    +
  1. 第7行,root=后面的部分改成ubuntu所在的btrfs分区的uuid,可以用lsblk -o +UUID来查看
  2. +
  3. linux是指明内核的命令,vmlinuz改成具体的内核文件名。root=后面修改同上,subvol=后面改成实际的子卷名
  4. +
  5. initrd是指明initramfs的命令,后面改成实际initramfs的路径
  6. +
+ +