无忧启动论坛

 找回密码
 注册
搜索
系统gho:最纯净好用系统下载站广告联系 微信:wuyouceo QQ:184822951
查看: 26506|回复: 73

[原创] vdfuseloop:支持更多格式虚拟磁盘启动的Linux方式(vdi/vmdk/vhd等)

    [复制链接]
发表于 2020-2-2 04:29:59 | 显示全部楼层 |阅读模式
本帖最后由 Misty 于 2021-3-21 07:00 编辑

受到 @2011niumao 大佬的启发,近日研究了如何从vhd等虚拟磁盘启动Linux。可以注意到niumao大佬的kloop方案有诸多限制:
1. 仅限VHD
2. VHD必须固定大小
而固定大小的vhd实际上和wubi所使用的raw原始格式并没有任何区别,只不过加了一个header。实际上并不需要kloop,可以手动获取到分区起始位置并使用-o loop, offset=XXXX。所以其实和wubi方案并没有太大差别,都是物理设备 → loop partition → ext4

这明显丧失了虚拟磁盘的快照、 动态容量等各种特性,满足不了需求。经过一段时间的查找,找到国外网友使用vdfuse来支持多种虚拟磁盘读写的方案:
https://unix.stackexchange.com/questions/309900/deploy-linux-into-and-boot-from-vhd/465215#465215

思路(原理及调试方法见最下面):
vdfuse借助开源项目virtualbox的内核模块读写virtualbox支持的格式(至少有vmdk、vhd、vdi),从而挂载出loop,并可以支持动态大小的虚拟磁盘文件。
上面连接中的回答时间很新,所以操作基本都可以正常执行。经过实践,我总结出来了这些步骤

编译安装vdfuse

1. 安装依赖(注:还需要安装svn和git,请自行安装):sudo apt install libfuse-dev virtualbox pkg-config
2. 下载vdfuse: vdfuse年久失修,利用github的fork network追踪功能,发现有一个人将其fork并适配了新版的vbox 6.0.2,仅有少量编译错误需要修改。我已经把编译错误修复:https://github.com/NyaMisty/vdfuse
3. 编译并安装vdfuse:执行这些命令(注:可能需要挂代理)
  • ./autogen.sh
  • ./fetch_vbox_headers.sh
  • ./configure
  • make
  • sudo make install

dracut方案:
dracut可以在systemd关机后返回initramfs从而得以让我们正确卸载vhd。

(0. 安装dracut:sudo apt install dracut)
1. 同上编译安装vdfuse,然后执行sudo cp /usr/local/bin/vdfuse /usr/bin/vdfuse
2. 下载或克隆https://github.com/NyaMisty/dracut-vdfuseloop
3. 将90vdfuseloop复制到/usr/lib/dracut/modules.d
4. 修改/etc/dracut.conf.d/10-debian.conf,修改hostonly=no,在add_drivers一行前加#注释掉
5. 执行sudo dracut -f生成initramfs
6. 将生成好的/boot/initramfs-XXXXX.img和vmlinuz复制出来供引导
7. 编辑/usr/lib/dracut/dracut-initramfs-restore,找到其中的[[ -f $IMG ]] || IMG="/boot/XXXXXXXXXX",将其对应修改为dracut生成的img的文件名格式,如[[ -f $IMG ]] || IMG="/boot/initramfs-${KERNEL_VERSION}.img"
8. 配置grub参数
  1. iftitle [ find --set-root --ignore-floppies --ignore-cd  /VMs/LinuxWorkspace/LinuxWorkspace.vmdk ] 启动Ubuntu
  2. find --set-root --ignore-floppies --ignore-cd  /VMs/LinuxWorkspace/LinuxWorkspace.vmdk
  3. uuid ()
  4. kernel /ubuntuvm-vhd-helper/vmlinuz  rw rd.hostdev=UUID=%?% rd.vdisk=/VMs/LinuxWorkspace/LinuxWorkspace.vmdk rd.vdloop=/dev/vdhost/Partition1 rd.debug rd.shell verbose nomodeset
复制代码


initramfs-tool方案 (已废弃,仅作为记录保留):
initramfs-tool方案难以解决关机Buffer IO问题,如有高手解决可以考虑共享

(1-3接编译vdfuse)
4. 修改hooks使得vdfuse工具被包含到initramfs中
sudo gedit /usr/share/initramfs-tools/hooks/vdfuse

  1. #!/bin/sh -e
  2. PREREQ=""
  3. prereqs()
  4. {
  5.     echo "$PREREQ"
  6. }

  7. case "$1" in
  8.     prereqs)
  9.     prereqs
  10.     exit 0
  11.     ;;
  12. esac

  13. . /usr/share/initramfs-tools/hook-functions

  14. copy_exec /bin/ntfs-3g /sbin
  15. copy_exec /usr/local/bin/vdfuse /sbin
复制代码
5. 修改init-top实现自定义文件系统挂载逻辑
sudo gedit /usr/share/initramfs-tools/scripts/init-top/vdfuse

  1. #!/bin/bash -e
  2. PREREQ="udev"
  3. prereqs()
  4. {
  5.     echo "$PREREQ"
  6. }

  7. case "$1" in
  8.     prereqs)
  9.     prereqs
  10.     exit 0
  11.     ;;
  12. esac

  13. if [ ! -z $vdisk ]; then
  14.     mkdir /vdhost
  15.     mkdir /dev/vdhost
  16.     exec -a @ntfs-3g ntfs-3g $host /vdhost/
  17.     exec -a @vdfuse vdfuse -t VMDK -f /vdhost$vdisk /dev/vdhost
  18.     mount -t ext4 $ROOT /root
  19. fi
复制代码
注1:vdfuse的-t参数为虚拟磁盘的格式,请根据自己的虚拟磁盘来配置,支持VMDK/VHD/VDI三个值
注2:此处niumao前辈利用patch ntfs3g实现了防止buffer io的错误,但是实际上可以通过简单的exec传参来让argv[0][0] == "@"。方法来源于https://github.com/systemd/systemd/issues/13981
注3:虽然配置了ntfs3g和vdfuse不被kill,但仍然会出现buffer I/O error,原因不明


6. 修改init-bottom
sudo gedit /usr/share/initramfs-tools/scripts/init-bottom/vdhost
  1. #!/bin/sh -e
  2. PREREQ=""
  3. prereqs()
  4. {
  5.     echo "$PREREQ"
  6. }
  7. case "$1" in
  8.     prereqs)
  9.     prereqs
  10.     exit 0
  11.     ;;
  12. esac
  13. if [ -d ${rootmnt}/vdhost ]; then
  14.     mount -n -o move /vdhost ${rootmnt}/vdhost
  15. fi
复制代码


6. 设置权限
  1. sudo chmod +x /usr/share/initramfs-tools/hooks/vdfuse
  2. sudo chmod +x /usr/share/initramfs-tools/scripts/init-top/vdfuse
  3. sudo chmod +x /usr/share/initramfs-tools/scripts/init-bottom/vdhost
复制代码

7. 生成initramfs,并拷贝initrd.img和vmlinuz
具体方法参见niumao前辈的文章

8.  设置grub参数
这里仅列出grub4dos的参数设置(抄自niumao大佬)
  1. iftitle [ find --set-root --ignore-floppies --ignore-cd  /VMs/LinuxWorkspace/LinuxWorkspace.vmdk ] 启动Ubuntu
  2. find --set-root --ignore-floppies --ignore-cd  /VMs/LinuxWorkspace/LinuxWorkspace.vmdk
  3. uuid ()
  4. kernel /ubuntuvm-vhd-helper/vmlinuz  root=/dev/vdhost/Partition1 host=/dev/XXXX vdisk=/VMs/LinuxWorkspace/LinuxWorkspace.vmdk verbose nomodeset
  5. initrd /ubuntuvm-vhd-helper/initrd.img
复制代码

其中host参数代指vhd所在物理磁盘的分区设备文件路径;
root代指vhd挂载后linux rootfs所在分区(vdfuse挂载后会在/dev/vdhost下形成EntireDisk以及各个分区,如Partition1。一般均为Partition1,即第一个主分区)
vdisk代指vhd所在分区中的路径
kernel和initrd的路径设置为复制出来的路径

此处参数设置错误时或不知道具体值时,可以随便填写,initramfs会自动出错,并弹出shell供诊断。相应的查看各个参数对应信息即可

grub2配置可以根据niumao前辈的配置照葫芦画瓢



原理:
vdfuse与kpartx不同,会有进程驻留。vdfuse方案是物理设备 → vdfuse → loop partition → ext4,可以注意到比kpartx多了一级,这导致了systemd默认的卸载方式无法正常卸载掉vhd。
initramfs-tool提供的结构并不能很好的控制systemd,所以我没能实现解决buffer io的问题
dracut相比initramfs-tool与systemd结合更紧密,因而更容易控制systemd对我们挂载点的操作。所以我们得以借助dracut的强大功能解决buffer io error。

1. 用exec -a @ntfs-3g ntfs-3g方法挂载hostdev到/dev/host,避免被systemd关机时杀掉。挂载到/dev下在关机流程会被systemd忽略,从而避免被remount为ro(见systemd/src/core/umount.c/umount.c)
2. 用exec -a方法挂载vdfuse到/dev/vdhost。原理同上
3. 不提供root参数,使用mount hook,从而避免dracut使用systemd的挂载和设备探测功能(systemd对于loop设备支持较差)
4. 进行pre-shutdown hook,关机前按顺序卸载ext4、vdfuse、ntfs,从而避免buffer i/o error


调试方法:
1. initramfs-tool方案调试方法:添加参数: debug systemd.log_level=debug systemd.log_target=kmsg log_buf_len=1M printk.devkmsg=on enforcing=0
2. dracut方案调试方法: 添加参数debug rd.break=pre-shutdown rd.break=shutdown debug systemd.log_level=debug systemd.log_target=kmsg printk.devkmsg=on enforcing=0 log_buf_len=10M verbose nomodeset rd.udev.debug rd.timeout=300 rd.break=initqueue rd.break=pre-mount rd.break=mount






评分

参与人数 4无忧币 +15 收起 理由
vrboxing + 5 很给力!
koyong + 2 很给力!
2011niumao + 5 很给力!exec命令好!
studyggm + 3 赞一个!

查看全部评分

 楼主| 发表于 2020-2-2 06:42:38 | 显示全部楼层
本帖最后由 Misty 于 2021-3-21 07:35 编辑

更新:支持VMware快照功能! (仅bios)
1. 下载https://github.com/NyaMisty/grub-vmsnap,用build.sh编译后,复制grub/grub-core/vmsnap.mod到grub2的i386-pc目录下
2. 重新从github上下载dracut-vdfuseloop
3. 使用grub2引导:
  1. <blockquote><blockquote>menuentry 'Start Ubnutu'  --class ubuntu  {
复制代码

vmsnap模块的作用是解析vmx文件中的snapshot树,然后按顺序传入传入到内核参数中
PMBA`YV@%`[N6@8GJ7L5ZZH.png

需要注意的是如果snapshot传入的参数错误,则可能父盘被意外写入,导致整个磁盘无法使用,所以grub中预留了prompt供用户检查当前磁盘文件名是否正确,请务必仔细检查,如有错误请直接关机



点评

uefi能用了吗  详情 回复 发表于 2022-12-19 21:50
吊炸天了!怎么不更新了!正需要这个功能  详情 回复 发表于 2022-12-14 15:26
回复

使用道具 举报

发表于 2020-2-2 11:39:15 来自手机 | 显示全部楼层
很详细!
回复

使用道具 举报

发表于 2020-2-4 22:38:10 | 显示全部楼层
喜欢听大佬们技术分析
回复

使用道具 举报

发表于 2020-2-4 23:25:01 | 显示全部楼层
技术贴,标记了
回复

使用道具 举报

发表于 2020-2-19 23:00:28 | 显示全部楼层
非常棒的技术贴,收藏
回复

使用道具 举报

发表于 2020-2-21 17:48:46 | 显示全部楼层
qemu-img 创建的vhd WINDOWS为什么不能用,有知道的吗?
回复

使用道具 举报

发表于 2020-8-27 19:25:45 | 显示全部楼层
请问我以前安装了vbox,已经有vdfuse命令,还要编译安装vdfuse吗?
回复

使用道具 举报

发表于 2020-9-1 22:30:00 | 显示全部楼层
很给力! 完全同意
回复

使用道具 举报

发表于 2020-10-10 19:24:21 | 显示全部楼层
有个问题就是我每次运行起来报错
回复

使用道具 举报

发表于 2020-11-2 20:08:03 | 显示全部楼层
太复杂了,都是程序员之间的讨论,有没有更简单直接可操作性的方案啊。把linux装进VHDX启动。
回复

使用道具 举报

发表于 2020-11-3 10:20:11 | 显示全部楼层
没看懂,纯粹支持一下
回复

使用道具 举报

发表于 2020-11-26 21:53:49 | 显示全部楼层
66666666666666666666
回复

使用道具 举报

发表于 2020-11-27 11:03:47 | 显示全部楼层

非常棒的技术贴,收藏
回复

使用道具 举报

发表于 2020-11-29 20:56:07 | 显示全部楼层
一说代理 就放弃了,麻烦啊,
回复

使用道具 举报

发表于 2020-12-6 17:01:16 | 显示全部楼层
技术贴,学习学习。。。
回复

使用道具 举报

发表于 2020-12-22 10:32:05 | 显示全部楼层
按照这个思路,理论上qcow2也可以通过qemu-nbd来支持吧,但是实际上不行,不知道问题出在哪里,vmdk我已经尝试成功了。

点评

qemu-nbd 挂载 动态 ubuntu vhd ,在 dracut 的 pre-mount 挂脚本处理,救援模式shell 下看日志是可以成功挂到 sysroot上的,也手动验证了,但是在 switch root 的时候,qemu-nbd 就立马断开连接了(shutting down s  详情 回复 发表于 2022-11-23 17:44
那就得看看qemu-nbd为啥没挂载上了hhh 可以自己调试看看  详情 回复 发表于 2021-3-21 06:55
回复

使用道具 举报

 楼主| 发表于 2021-3-21 06:55:11 | 显示全部楼层
lijingjack 发表于 2020-12-22 10:32
按照这个思路,理论上qcow2也可以通过qemu-nbd来支持吧,但是实际上不行,不知道问题出在哪里,vmdk我已经 ...

那就得看看qemu-nbd为啥没挂载上了hhh
可以自己调试看看
回复

使用道具 举报

发表于 2021-3-21 07:11:44 来自手机 | 显示全部楼层
我使用kloop那个模式,在initrd.img挂载
回复

使用道具 举报

发表于 2021-3-21 07:13:59 来自手机 | 显示全部楼层
在内存盘系统initrd.img 里加入nbd模块和qemu-nbd 命令后挂载启动动态vhd成功了。
回复

使用道具 举报

发表于 2021-3-21 07:17:04 来自手机 | 显示全部楼层
另外,最近发现另一种可写挂载ntfs分区的方法,其挂载格式是ufsd ,可以安装到ubuntu上,用它代替ntfs-3g, 不需要改写源文件,就可以避免buffer io 错误。

点评

哦是paragon的那个驱动啊,感觉确实会好用一些,但是感觉这种闭源驱动配置起来都不简单,我个人感觉正确使用ntfs3g就够了(用dracut已经解决buffer io错误了) 这个帖子主要是想把vmware虚拟机起起来(这样既可以  详情 回复 发表于 2021-3-21 08:27
回复

使用道具 举报

发表于 2021-3-21 07:21:45 来自手机 | 显示全部楼层
论坛里就有帖子,“关于paragon ntfs驱动(ufsd)性能的问题请教”
回复

使用道具 举报

 楼主| 发表于 2021-3-21 08:27:34 | 显示全部楼层
2011niumao 发表于 2021-3-21 07:17
另外,最近发现另一种可写挂载ntfs分区的方法,其挂载格式是ufsd ,可以安装到ubuntu上,用它代替ntfs-3g,  ...

哦是paragon的那个驱动啊,感觉确实会好用一些,但是感觉这种闭源驱动配置起来都不简单,我个人感觉正确使用ntfs3g就够了(用dracut已经解决buffer io错误了)

这个帖子主要是想把vmware虚拟机起起来(这样既可以在vmware里跑,又可以在需要的时候拿出来跑)
回复

使用道具 举报

发表于 2021-4-1 19:53:45 | 显示全部楼层

求助vdfuse编译安装,和grub2启动项编写

本帖最后由 faoao 于 2021-4-13 17:25 编辑

我的系统是 ubuntu20.04 用VMware安装在vmdk里,自动分了 /boot/efi 和 /根目录两个分区

1、vdfuse编译安装问题
./fetch_vbox_headers.sh 执行有问题(是不是仓库地址改了?),我直接从 https://download、virtualbox、org/virtualbox/6.1.18/VirtualBox-6.1.18.tar.bz2 下载的源码提取了include文件夹放入vdfuse中(能不能行?)。
后面的 make 和 sudo make install 执行感觉有问题
  1. w@X:~/下载/vdfuse$ make
  2. gcc -DHAVE_CONFIG_H -I. -I./src    -Iinclude -I/usr/include/fuse -D_FILE_OFFSET_BITS=64 -MT vdfuse.o -MD -MP -MF .deps/vdfuse.Tpo -c -o vdfuse.o `test -f 'src/vdfuse.c' || echo './'`src/vdfuse.c
  3. src/vdfuse.c: In function ‘main’:
  4. src/vdfuse.c:272:7: warning: passing argument 5 of ‘VDInterfaceAdd’ makes integer from pointer without a cast [-Wint-conversion]
  5.   272 |   if (RT_FAILURE(VDInterfaceAdd(&vdError, "VD Error", VDINTERFACETYPE_ERROR,
  6.       |       ^~~~~~~~~~
  7.       |       |
  8.       |       void *
  9. In file included from include/VBox/vd.h:42,
  10.                  from src/vdfuse.c:114:
  11. include/VBox/vd-ifs.h:155:39: note: expected ‘size_t’ {aka ‘long unsigned int’} but argument is of type ‘void *’
  12.   155 |                                size_t cbInterface, PVDINTERFACE *ppVDIfs)
  13.       |                                ~~~~~~~^~~~~~~~~~~
  14. mv -f .deps/vdfuse.Tpo .deps/vdfuse.Po
  15. gcc -Iinclude -I/usr/include/fuse -D_FILE_OFFSET_BITS=64 -Wl,-rpath,/usr/lib/virtualbox  -o vdfuse vdfuse.o /usr/lib/virtualbox/VBoxDDU.so -lfuse -pthread
复制代码

2、grub2启动项编写问题

我的grub启动项参照 niumao大佬的改的
  1. menuentry 'VBUNTUFIX linux' --class ubuntu --class gnu-linux --class gnu --class os {
  2.         insmod gzio
  3.         insmod part_msdos
  4.         insmod part_gpt
  5.         insmod ext2
  6.         insmod ntfs
  7.         insmod probe
  8.         insmod search
  9.         search --no-floppy -f --set=aabbcc /Ubuntu/Ubuntucl.vmdk
  10.         set root=${aabbcc}
  11.         probe -u --set=ddeeff ${aabbcc}
  12.         linux /Ubuntu/vmlinuz root=UUID=${ddeeff} vloop=/Ubuntu/Ubuntucl.vmdk vlooppart=p1
  13.         initrd /Ubuntu/initramfs-5.8.0-48-generic.img
  14. }
复制代码
但是还是进不了系统,进入了 dracut: 的命令行
我现在不知道是vmdk系统中软件还没安装配置好,还是grub2启动项没编辑好。麻烦大佬帮忙修改下
回复

使用道具 举报

发表于 2021-4-1 20:59:15 | 显示全部楼层
本帖最后由 faoao 于 2021-4-13 17:27 编辑

已在上一楼修改,请删除本楼
回复

使用道具 举报

发表于 2021-9-22 21:35:12 | 显示全部楼层
本帖最后由 minmax 于 2021-9-23 20:54 编辑

vdfuse 讚
回复

使用道具 举报

发表于 2021-9-25 22:14:59 | 显示全部楼层
有哪位完成此帖 可以分享 完成的档案 感谢
回复

使用道具 举报

发表于 2021-10-20 18:44:20 | 显示全部楼层
I would like to study it
回复

使用道具 举报

发表于 2021-11-3 11:09:46 | 显示全部楼层
回复

使用道具 举报

发表于 2021-11-10 10:32:45 | 显示全部楼层
大佬,想用动态vhd装linux,能否出个详细的教程
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2024-3-28 16:56

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表