UML高级话题

在虚拟机之间共享文件系统

不要试图仅仅通过从同一个文件启动两个uml来共享文件系统。这与从共享磁盘引导两台物理机器是一样的。它将导致文件系统损坏。

使用分层块设备

在两个虚拟机之间共享文件系统的方法是使用ubd块驱动程序的写时复制(COW)分层功能。任何更改的块都存储在私有COW文件中,而读取来自任何设备—如果请求的块在其中有效,则为私有设备,如果无效则为共享设备。使用这种方案,大部分未更改的数据在任意数量的虚拟机之间共享,每个虚拟机都有一个小得多的文件,其中包含它所做的更改。由于大量uml从大型根文件系统引导,这将节省大量磁盘空间。

共享文件系统数据也将有助于提高性能,因为主机将能够使用更少的内存缓存共享数据,因此UML磁盘请求将从主机的内存而不是磁盘提供服务。在多套接字NUMA机器上执行此操作有一个主要警告。在这样的硬件上,使用共享的主映像和COW更改运行许多UML实例可能会导致诸如nmi之类的问题,因为套接字间流量过多。

如果您在像这样的高端硬件上运行UML,请确保使用taskset命令将UML绑定到驻留在相同套接字上的一组逻辑cpu,或者查看一下“调优”部分。

要将写时复制层添加到现有的块设备文件中,只需将COW文件的名称添加到相应的ubd开关中:

ubd0=root_fs_cow,root_fs_debian_22

其中root_fs_cow为私有COW文件,root_fs_debian_22为已存在的共享文件系统。COW文件不需要存在。如果没有,驱动程序将创建并初始化它。

使用磁盘

UML具有TRIM支持,它将把磁盘映像文件中任何未使用的空间释放到底层操作系统。使用ls -ls或du来验证实际文件大小是很重要的。

cow有效性

对主映像的任何更改都将使所有COW文件无效。如果发生这种情况,UML将不会自动删除任何COW文件,并将拒绝启动。在这种情况下,唯一的解决方案是恢复旧映像(包括其最后修改的时间戳)或删除所有COW文件,这将导致重新创建它们。COW文件中的任何更改都将丢失。

合并COW文件和它的备份文件

根据您使用UML和COW设备的方式,建议您每隔一段时间将COW文件中的更改合并到备份文件中。

执行此操作的实用程序是uml_mooo。用法是:

uml_moo COW_file new_backing_file

不需要指定后备文件,因为该信息已经在COW文件头中。如果你很偏执,启动新的合并文件,如果你对它满意,把它移到旧的备份文件上。

默认情况下,uml_mooo创建一个新的备份文件作为安全措施。它还有一个破坏性的合并选项,可以将COW文件直接合并到当前的备份文件中。只有当后备文件只有一个与之关联的COW文件时,这才真正有用。如果有多个奶牛与备份文件相关联,其中一个奶牛的-d合并将使所有其他奶牛无效。但是,如果磁盘空间不足,它会很方便,而且它也应该比非破坏性合并要快得多。

uml_mooo与UML发布包一起安装,并且可以作为UML实用程序的一部分使用。

主机文件访问

如果您希望从UML内部访问主机上的文件,您可以将其视为一台单独的机器,并且可以从主机上nfs挂载目录,或者使用scp将文件复制到虚拟机中。然而,由于UML在主机上运行,它可以像任何其他进程一样访问这些文件,并使它们在虚拟机中可用,而不需要使用网络。使用hostfs虚拟文件系统可以实现这一点。有了它,您可以将一个主机目录装入UML文件系统,并像在主机上一样访问其中包含的文件。

没有任何UML映像参数的Hostfs将允许映像挂载主机文件系统的任何部分并对其进行写入。如果运行UML,总是将主机限制在特定的“无害”目录(例如/var/tmp)。如果UML作为根运行,这一点尤其重要。

使用hostfs

首先,确保hostfs在虚拟机中可用:

cat /proc/filesystems

主机应该被列出。如果不是,要么重新构建内核,并将hostfs配置到内核中,要么确保将hostfs构建为一个模块并在虚拟机中可用,然后insmod它。

现在你需要做的就是运行mount:

mount none /mnt/host -t hostfs

将主机的/挂载到虚拟机的/mnt/host上。如果你不想挂载主机的根目录,那么你可以使用-o开关来指定要挂载的子目录:

mount none /mnt/home -t hostfs -o /home

将主机的/home挂载到虚拟机的/mnt/home上。

hostfs as the root filesystem

可以使用hostfs而不是使用文件中的标准文件系统从主机上的目录层次结构引导。首先,你需要层次结构。最简单的方法是挂载一个现有的root_fs文件:

mount root_fs uml_root_dir -o loop

你需要将etc/fstab中的/文件系统类型更改为’ hostfs ‘,因此该行看起来像这样:

/dev/ubd/0       /        hostfs      defaults          1   1

然后,您需要拥有该目录中所有由根用户拥有的文件。这对我很有效:

find . -uid 0 -exec chown jdike {} \;

接下来,确保您的UML内核中编译了hostfs,而不是作为一个模块。然后运行UML,引导设备指向该目录:

ubd0=/path/to/uml/root/directory

然后UML应该像往常一样启动。

Hostfs Caveats

Hostfs不支持跟踪主机(在UML之外)上的主机文件系统更改。因此,如果一个文件在UML不知情的情况下被更改,UML将不知道它,并且它自己的文件内存缓存可能会损坏。虽然有可能解决这个问题,但目前还没有解决这个问题。

UML调优

UML目前是严格的单处理器。但是,它将启动许多线程来处理各种函数。

UBD驱动程序、SIGIO和MMU仿真可以做到这一点。如果系统空闲,这些线程将被迁移到SMP主机上的其他处理器上。不幸的是,这通常会导致较低的性能,因为所有内核之间的缓存/内存同步流量。因此,将UML固定在单个CPU上通常会受益,特别是在大型系统上。在某些基准测试中,这可能导致5倍或更高的性能差异。

类似地,在大型多节点NUMA系统上,如果UML的所有内存都是从它将运行的同一个NUMA节点分配的,那么UML将受益。默认情况下,操作系统不会这样做。为了做到这一点,系统管理员需要创建一个绑定到特定节点的合适的tmpfs ramdisk,并通过在TMP或TEMP环境变量中指定它,将其用作UML RAM分配的源。UML将查看TMPDIR、TMP或TEMP的值。如果失败,它将查找挂载在/dev/shm下的shmfs如果这些都失败了,使用/tmp/,不管它使用的文件系统类型:

mount -t tmpfs -ompol=bind:X none /mnt/tmpfs-nodeX
TEMP=/mnt/tmpfs-nodeX taskset -cX linux options options options..