mirror of
				https://github.com/containers/podman.git
				synced 2025-10-31 01:50:50 +08:00 
			
		
		
		
	 bf541c6740
			
		
	
	bf541c6740
	
	
	
		
			
			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>
		
			
				
	
	
		
			100 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			100 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| //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
 | |
| }
 |