流程简述:
(镜像基本的文件系统配置)
1、下载ubuntu-base的镜像
2、挂载镜像,配置镜像的网络,并安装各类软件
(PM模块配置)
3、编译内核模块,并拷贝到镜像中
4、启动qemu
5、安装内核模块,并配置相关软件
1、使用qemu-img
创建image镜像(此处起名为ubuntu14.04.raw 20G
)
# [可选] sudo apt install qemu
qemu-img create -f raw ubuntu-rootfs-raw-20G.image 20G
注意:此处需要是
raw
类型,否则后续无法正常格式化(因为qcow2类型没有预先分配空间)。报错信息如下$ sudo mkfs.ext4 ubuntu-rootfs-qcow2-20G.image mke2fs 1.45.5 (07-Jan-2020) ubuntu-rootfs-qcow2-20G.image: Not enough space to build proposed filesystem while setting up superblock
2、格式化镜像文件为ext4的文件系统
# 格式化
sudo mkfs.ext4 ubuntu-rootfs-raw-20G.image
# 检查
file ubuntu-rootfs-raw-20G.image
3、创建一个空目录,镜像的挂载点;然后将镜像挂载上去
mkdir ubuntu-rootfs-dir
sudo mount ubuntu-rootfs-raw-20G.image ubuntu-rootfs-dir
4、下载ubuntu-base-20.04.1-base-amd64.tar.gz
镜像,并将其解压到ubuntu-rootfs-dir
文件夹中(实质就是向镜像中塞文件,因为当前镜像已经被挂载到文件夹了)
(1)下载地址,https://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.1-base-amd64.tar.gz。
也可以自行选择其他版本:https://cdimage.ubuntu.com/ubuntu-base/releases/,
wget https://cdimage.ubuntu.com/ubuntu-base/releases/20.04/release/ubuntu-base-20.04.1-base-amd64.tar.gz
(2)解压到ubuntu-rootfs-dir
sudo tar -xzvf ubuntu-base-20.04.1-base-amd64.tar.gz -C ubuntu-rootfs-dir
5、拷贝主机中的网络配置信息到镜像中,方便后续用apt安装软件
sudo cp /etc/resolv.conf ubuntu-rootfs-dir/etc/
6、自行修改source.list文件,设置apt镜像进行加速
假设主机与客服机都是基于ubuntu 20.04,则可以直接拷贝主机的source.list,
否则需要自行配置
sudo cp /etc/apt/source.list ubuntu-rootfs-dir/etc/apt/source.list
7、使用chroot
将ubuntu-rootfs-dir
暂时设置为根目录(与docker类似),并启动终端
sudo chroot ubuntu-rootfs-dir
8、安装软件
apt update\
&& apt upgrade\
&& apt install linux-image-kvm init vim -y
9、设置密码之类的
update-initramfs -u
echo root:root | chpasswd
echo ttyS0 > /etc/securetty
systemctl enable [email protected]
10、退出并卸载
sudo umount ubuntu-rootfs-dir
11、后续扩展
(1)如果需要重新安装软件,可以重复第7步骤,挂载镜像,然后chroot
进去。
(2)镜像扩容操作
qemu-img resize ubuntu-rootfs-raw-20G.image +10G
如果要运行PM
1、安装软件包(安装到镜像里面)
apt install -y systemd numactl ndctl daxctl
2、编译内核时,编译相关模块
make -j16 vmlinux bzImage
make M=drivers/dax -j16
make M=drivers/nvdimm/ -j16
make M=drivers/dax/pmem -j16
3、将编译好的模块复制到镜像中
# 1、挂载镜像
# 略
# 2、设置路径(路径根据需要进行修改)
image_dir_path=/home/my/my_images/ubuntu-base/ubuntu-rootfs-dir
module_path=$image_dir_path/root/my_modules
sudo mkdir $module_path
# 3、拷贝编译的内核模块到镜像中
cd linux-5.15.114
sudo cp -r ./drivers/dax $module_path/drivers/dax
sudo cp -r ./drivers/nvdimm $module_path/drivers/nvdimm
# 4、卸载镜像
# 略
3、运行qemu
qemu-system-x86_64 \
-machine pc,nvdimm=on \
-m 2G,slots=4,maxmem=32G \
-nographic -kernel bzImage \
-smp cores=4,threads=1,sockets=2 \
-hda ubuntu_rootfs.ext4 \
-object memory-backend-ram,id=mem0,size=1G \
-object memory-backend-ram,id=mem1,size=1G \
-numa node,memdev=mem0,cpus=0-3,nodeid=0 \
-numa node,memdev=mem1,cpus=4-7,nodeid=1 \
-numa node,nodeid=2 -numa node,nodeid=3 \
-object memory-backend-ram,id=nvdimm1,size=4G\
-device nvdimm,memdev=nvdimm1,id=nv1,unarmed=off,node=2 \
-object memory-backend-ram,id=nvdimm2,size=4G\
-device nvdimm,memdev=nvdimm2,id=nv2,unarmed=off,node=3 \
-append "console=ttyS0 crashkernel=256M root=/dev/sda rootfstype=ext4 rw loglevel=8"
4、安装模块(注意模块之间的依赖)
insmod /root/my_modules/drivers/dax/device_dax.ko
insmod /root/my_modules/drivers/dax/kmem.ko
insmod /root/my_modules/drivers/dax/pmem/dax_pmem_core.ko
insmod /root/my_modules/drivers/dax/pmem/dax_pmem.ko
insmod /root/my_modules/drivers/dax/pmem/dax_pmem_compat.ko
insmod /root/my_modules/drivers/nvdimm/nd_btt.ko
insmod /root/my_modules/drivers/nvdimm/nd_blk.ko
insmod /root/my_modules/drivers/nvdimm/nd_pmem.ko
insmod /root/my_modules/drivers/nvdimm/nd_virtio.ko
insmod /root/my_modules/drivers/nvdimm/virtio_pmem.ko
# check
lsmod
此处注意:模块之间可能存在依赖,需要按照一定的顺序。如果顺序不对,可能出现如下报错信息
insmod: ERROR: could not insert module device_dax.mod: Invalid module format
。此时,使用dmesg | tail
可以查看详细日志信息,使用modinfo ./dax_pmem.ko | grep depend
可以查看模块的依赖。$ modinfo ./dax_pmem.ko | grep depend depends: dax_pmem_core # 可以看到dax_pmem.ko依赖dax_pmem_core模块
5、配置nvdimm
# 首次配置
daxctl migrate-device-model
echo offline > /sys/devices/system/memory/auto_online_blocks
ndctl create-namespace -f --mode devdax --continue
daxctl reconfigure-device --mode=system-ram all
# 重启后重新配置
echo offline > /sys/devices/system/memory/auto_online_blocks
ndctl disable-namespace all
ndctl destroy-namespace all
ndctl create-namespace -f --mode devdax --continue
daxctl reconfigure-device --mode=system-ram all
6、合并四五步
后续可以创建一个init.sh文件放到镜像中,启动时自动运行
# init.sh
# 用于image镜像中挂载内核模块等
insmod /root/my_modules/drivers/dax/device_dax.ko
insmod /root/my_modules/drivers/dax/kmem.ko
insmod /root/my_modules/drivers/dax/pmem/dax_pmem_core.ko
insmod /root/my_modules/drivers/dax/pmem/dax_pmem.ko
insmod /root/my_modules/drivers/dax/pmem/dax_pmem_compat.ko
insmod /root/my_modules/drivers/nvdimm/nd_btt.ko
insmod /root/my_modules/drivers/nvdimm/nd_blk.ko
insmod /root/my_modules/drivers/nvdimm/nd_pmem.ko
insmod /root/my_modules/drivers/nvdimm/nd_virtio.ko
insmod /root/my_modules/drivers/nvdimm/virtio_pmem.ko
# 首次配置
# daxctl migrate-device-model
# echo offline > /sys/devices/system/memory/auto_online_blocks
# ndctl create-namespace -f --mode devdax --continue
# daxctl reconfigure-device --mode=system-ram all
# 重启后重新配置
echo offline > /sys/devices/system/memory/auto_online_blocks
ndctl disable-namespace all
ndctl destroy-namespace all
ndctl create-namespace -f --mode devdax --continue
daxctl reconfigure-device --mode=system-ram all
root@localhost:~/my_modules/drivers/nvdimm/nvdimm# echo offline > /sys/devices/system/memory/auto_online_blocks
root@localhost:~/my_modules/drivers/nvdimm/nvdimm# ndctl create-namespace -f --mode devdax --continue
{
"dev":"namespace1.0",
"mode":"devdax",
"map":"dev",
"size":"3.94 GiB (4.23 GB)",
"uuid":"12f978b1-c1f4-4be8-a67d-aa076e0a4152",
"daxregion":{
"id":1,
"size":"3.94 GiB (4.23 GB)",
"align":2097152,
"devices":[
{
"chardev":"dax1.0",
"size":"3.94 GiB (4.23 GB)",
"target_node":3,
"mode":"devdax"
}
]
},
"align":2097152
}
{
"dev":"namespace0.0",
"mode":"devdax",
"map":"dev",
"size":"3.94 GiB (4.23 GB)",
"uuid":"0529e940-38b1-45fd-a0b1-43fcf95192ce",
"daxregion":{
"id":0,
"size":"3.94 GiB (4.23 GB)",
"align":2097152,
"devices":[
{
"chardev":"dax0.0",
"size":"3.94 GiB (4.23 GB)",
"target_node":2,
"mode":"devdax"
}
]
},
"align":2097152
}
created 2 namespaces
root@localhost:~/my_modules/drivers/nvdimm/nvdimm# daxctl reconfigure-device --mode=system-ram all
[
{
"chardev":"dax0.0",
"size":4225761280,
"target_node":2,
"mode":"system-ram",
"movable":true
}
]
非首次运行:
root@localhost:~/my_modules/drivers/nvdimm# echo offline > /sys/devices/system/memory/auto_online_blocks
oy-namespace all
ndctl create-namespace -f --mode devdax --continue
daxctl reconfigure-device --moderoot@localhost:~/my_modules/drivers/nvdimm# ndctl disable-namespace all
=system-ram alldisabled 2 namespaces
root@localhost:~/my_modules/drivers/nvdimm# ndctl destroy-namespace all
destroyed 0 namespaces
root@localhost:~/my_modules/drivers/nvdimm# ndctl create-namespace -f --mode devdax --continue
{
"dev":"namespace1.0",
"mode":"devdax",
"map":"dev",
"size":"3.94 GiB (4.23 GB)",
"uuid":"8259f939-0c3d-43c4-89cb-6e89653c290f",
"daxregion":{
"id":1,
"size":"3.94 GiB (4.23 GB)",
"align":2097152,
"devices":[
{
"chardev":"dax1.0",
"size":"3.94 GiB (4.23 GB)",
"target_node":3,
"mode":"devdax"
}
]
},
"align":2097152
}
{
"dev":"namespace0.0",
"mode":"devdax",
"map":"dev",
"size":"3.94 GiB (4.23 GB)",
"uuid":"41d3381f-cd6a-4c02-b8d1-c97cd2633cb4",
"daxregion":{
"id":0,
"size":"3.94 GiB (4.23 GB)",
"align":2097152,
"devices":[
{
"chardev":"dax0.0",
"size":"3.94 GiB (4.23 GB)",
"target_node":2,
"mode":"devdax"
}
]
},
"align":2097152
}
created 2 namespaces
root@localhost:~/my_modules/drivers/nvdimm# daxctl reconfigure-device --mode=system-ram all
[
{
"chardev":"dax0.0",
"size":4225761280,
"target_node":2,
"mode":"system-ram",
"movable":true
}
]
reconfigured 2 devices
[ 3.630969] EXT4-fs error (device sda): htree_dirblock_to_tree:1080: inode #393220: comm systemd-tmpfile: Directory block failed checksum
这还会导致其它的问题,例如:
rm: cannot remove 'directory': Bad message
# 提示双重目录(因为daxctl.conf变成了目录)
conf_files_filter_out: Directories inside directories are not supported: /etc/modprobe.d/daxctl.conf
# 删除不了
"cannot remove 'daxctl.conf': Directory not empty"
使用e2fsck
工具扫描并修复一下文件系统,基本全程按y
确定,即可。(按我看到的信息,貌似是一些文件的ref没有更新,导致文件出错)
e2fsck -y ubuntu-rootfs-raw-20G.image
其中,
-f
选项用于强制检查文件系统,即使文件系统处于已挂载状态。
-y
选项用于自动回答所有修复问题为 “yes”,以便自动修复文件系统错误。
检查:
$ e2fsck ubuntu-rootfs-raw-20G.image
e2fsck 1.45.5 (07-Jan-2020)
ubuntu-rootfs-raw-20G.image: clean, 13654/1310720 files, 321042/5242880 blocks
出错信息
$ ndctl create-namespace -f --mode devdax --continue
libkmod: ERROR ../libkmod/libkmod-module.c:838 kmod_module_insert_module: could not find module by name='dax_pmem'
原因:lsmod检查一下,应该是dax_pmem模块没有成功加载。
root@localhost:~# depmod -a
depmod: ERROR: could not open directory /lib/modules/5.15.114+: No such file or directory
原因:我一开始忘记把内核模块放到镜像里了。
# qemu环境中,执行关机命令
$ shutdown now
....
systemd-journald[202]: Failed to send stream file descriptor to service manager: Connection refused
猜测:可能是这里有文件没有写完,qemu就被我关了。说不定前面文件系统出错就是因为这个原因。
不知道具体什么原因(猜测是因为我有时挂载了/dev目录,然后导致终端无法打开,vscode远程链接的终端也无法打开),报错信息如下:
There was an error creating the child proces for this terminalFailed to open PTY: No such device
解决办法:
1、想办法进入系统,通过安全模式或者启动盘,或者什么的,反正只要能运行boot-repair
2、下载boot-repair
3、运行boot-repair进行修复。
$ sudo apt install boot-repair
$ boot-repair