mirror of
https://github.com/containers/podman.git
synced 2025-11-03 07:47:19 +08:00
machine/linux: Support virtiofs mounts (retain 9p default)
I'm hitting a bug with 9p when trying to transfer large files. In RHEL at least 9p isn't supported because it's known to have a lot of design flaws; virtiofsd is the supported and recommended way to share files between a host and guest. Add a new hidden `PODMAN_MACHINE_VIRTFS` environment variable that can be set to `virtiofs` to switch to virtiofsd. Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
99
pkg/machine/qemu/virtiofsd.go
Normal file
99
pkg/machine/qemu/virtiofsd.go
Normal file
@ -0,0 +1,99 @@
|
||||
//go:build linux || freebsd
|
||||
|
||||
package qemu
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"time"
|
||||
|
||||
"github.com/containers/common/pkg/config"
|
||||
"github.com/containers/podman/v5/pkg/machine/define"
|
||||
"github.com/containers/podman/v5/pkg/machine/vmconfigs"
|
||||
"github.com/containers/storage/pkg/fileutils"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// VirtiofsdSpawner spawns an instance of virtiofsd
|
||||
type virtiofsdSpawner struct {
|
||||
runtimeDir *define.VMFile
|
||||
binaryPath string
|
||||
mountCount uint
|
||||
}
|
||||
|
||||
func newVirtiofsdSpawner(runtimeDir *define.VMFile) (*virtiofsdSpawner, error) {
|
||||
var binaryPath string
|
||||
cfg, err := config.Default()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
binaryPath, err = cfg.FindHelperBinary("virtiofsd", true)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to find virtiofsd: %w", err)
|
||||
}
|
||||
return &virtiofsdSpawner{binaryPath: binaryPath, runtimeDir: runtimeDir}, nil
|
||||
}
|
||||
|
||||
// createVirtiofsCmd returns a new command instance configured to launch virtiofsd.
|
||||
func (v *virtiofsdSpawner) createVirtiofsCmd(directory, socketPath string) *exec.Cmd {
|
||||
args := []string{"--sandbox", "none", "--socket-path", socketPath, "--shared-dir", "."}
|
||||
// We don't need seccomp filtering; we trust our workloads. This incidentally
|
||||
// works around issues like https://gitlab.com/virtio-fs/virtiofsd/-/merge_requests/200.
|
||||
args = append(args, "--seccomp=none")
|
||||
cmd := exec.Command(v.binaryPath, args...)
|
||||
// This sets things up so that the `.` we passed in the arguments is the target directory
|
||||
cmd.Dir = directory
|
||||
// Quiet the daemon by default
|
||||
cmd.Env = append(cmd.Environ(), "RUST_LOG=ERROR")
|
||||
cmd.Stdin = nil
|
||||
cmd.Stdout = nil
|
||||
if logrus.IsLevelEnabled(logrus.DebugLevel) {
|
||||
cmd.Stderr = os.Stderr
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
type virtiofsdHelperCmd struct {
|
||||
command exec.Cmd
|
||||
socket *define.VMFile
|
||||
}
|
||||
|
||||
// spawnForMount returns on success a combination of qemu commandline and child process for virtiofsd
|
||||
func (v *virtiofsdSpawner) spawnForMount(hostmnt *vmconfigs.Mount) ([]string, *virtiofsdHelperCmd, error) {
|
||||
logrus.Debugf("Initializing virtiofsd mount for %s", hostmnt.Source)
|
||||
// By far the most common failure to spawn virtiofsd will be a typo'd source directory,
|
||||
// so let's synchronously check that ourselves here.
|
||||
if err := fileutils.Exists(hostmnt.Source); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to access virtiofs source directory %s", hostmnt.Source)
|
||||
}
|
||||
virtiofsChar := fmt.Sprintf("virtiofschar%d", v.mountCount)
|
||||
virtiofsCharPath, err := v.runtimeDir.AppendToNewVMFile(virtiofsChar, nil)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
qemuCommand := []string{}
|
||||
|
||||
qemuCommand = append(qemuCommand, "-chardev", fmt.Sprintf("socket,id=%s,path=%s", virtiofsChar, virtiofsCharPath.Path))
|
||||
qemuCommand = append(qemuCommand, "-device", fmt.Sprintf("vhost-user-fs-pci,queue-size=1024,chardev=%s,tag=%s", virtiofsChar, hostmnt.Tag))
|
||||
// TODO: Honor hostmnt.readonly somehow here (add an option to virtiofsd)
|
||||
virtiofsdCmd := v.createVirtiofsCmd(hostmnt.Source, virtiofsCharPath.Path)
|
||||
if err := virtiofsdCmd.Start(); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to start virtiofsd")
|
||||
}
|
||||
// Wait for the socket
|
||||
for {
|
||||
if err := fileutils.Exists(virtiofsCharPath.Path); err == nil {
|
||||
break
|
||||
}
|
||||
logrus.Debugf("waiting for virtiofsd socket %q", virtiofsCharPath.Path)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
// Increment our count of mounts which are used to create unique names for the devices
|
||||
v.mountCount += 1
|
||||
return qemuCommand, &virtiofsdHelperCmd{
|
||||
command: *virtiofsdCmd,
|
||||
socket: virtiofsCharPath,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user