Add qemu virtiofs command line option

Enables support for C version of virtiofs
A qemu option allows to specify virtiofsd path.
config.StatePath is used for storing the virtiofs sockets
Note that virtiofsd requires to start as root

Signed-off-by: Frédéric Dalleau <frederic.dalleau@docker.com>
This commit is contained in:
Frédéric Dalleau 2023-01-02 16:31:32 +01:00
parent f0f21bec52
commit 13426fe805

View File

@ -23,28 +23,30 @@ const (
// QemuConfig contains the config for Qemu // QemuConfig contains the config for Qemu
type QemuConfig struct { type QemuConfig struct {
Path string Path string
ISOBoot bool ISOBoot bool
UEFI bool UEFI bool
SquashFS bool SquashFS bool
Kernel bool Kernel bool
GUI bool GUI bool
Disks Disks Disks Disks
ISOImages []string ISOImages []string
StatePath string StatePath string
FWPath string FWPath string
Arch string Arch string
CPUs string CPUs string
Memory string Memory string
Accel string Accel string
Detached bool Detached bool
QemuBinPath string QemuBinPath string
QemuImgPath string QemuImgPath string
PublishedPorts []string PublishedPorts []string
NetdevConfig string NetdevConfig string
UUID uuid.UUID UUID uuid.UUID
USB bool USB bool
Devices []string Devices []string
VirtiofsdBinPath string
VirtiofsShares []string
} }
const ( const (
@ -119,23 +121,25 @@ func generateMAC() net.HardwareAddr {
func runQEMUCmd() *cobra.Command { func runQEMUCmd() *cobra.Command {
var ( var (
enableGUI bool enableGUI bool
uefiBoot bool uefiBoot bool
isoBoot bool isoBoot bool
squashFSBoot bool squashFSBoot bool
kernelBoot bool kernelBoot bool
state string state string
data string data string
dataPath string dataPath string
fw string fw string
accel string accel string
arch string arch string
qemuCmd string qemuCmd string
qemuDetached bool qemuDetached bool
networking string networking string
usbEnabled bool usbEnabled bool
deviceFlags multipleFlag deviceFlags multipleFlag
publishFlags multipleFlag publishFlags multipleFlag
virtiofsdCmd string
virtiofsShares []string
) )
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -279,34 +283,43 @@ func runQEMUCmd() *cobra.Command {
} }
config := QemuConfig{ config := QemuConfig{
Path: path, Path: path,
ISOBoot: isoBoot, ISOBoot: isoBoot,
UEFI: uefiBoot, UEFI: uefiBoot,
SquashFS: squashFSBoot, SquashFS: squashFSBoot,
Kernel: kernelBoot, Kernel: kernelBoot,
GUI: enableGUI, GUI: enableGUI,
Disks: disks, Disks: disks,
ISOImages: isoPaths, ISOImages: isoPaths,
StatePath: state, StatePath: state,
FWPath: fw, FWPath: fw,
Arch: arch, Arch: arch,
CPUs: fmt.Sprintf("%d", cpus), CPUs: fmt.Sprintf("%d", cpus),
Memory: fmt.Sprintf("%d", mem), Memory: fmt.Sprintf("%d", mem),
Accel: accel, Accel: accel,
Detached: qemuDetached, Detached: qemuDetached,
QemuBinPath: qemuCmd, QemuBinPath: qemuCmd,
PublishedPorts: publishFlags, PublishedPorts: publishFlags,
NetdevConfig: netdevConfig, NetdevConfig: netdevConfig,
UUID: vmUUID, UUID: vmUUID,
USB: usbEnabled, USB: usbEnabled,
Devices: deviceFlags, Devices: deviceFlags,
VirtiofsdBinPath: virtiofsdCmd,
VirtiofsShares: virtiofsShares,
} }
config, err = discoverBinaries(config) config, err = discoverQemu(config)
if err != nil { if err != nil {
return err return err
} }
if len(config.VirtiofsShares) > 0 {
config, err = discoverVirtiofsd(config)
if err != nil {
return err
}
}
if err = runQemuLocal(config); err != nil { if err = runQemuLocal(config); err != nil {
return err return err
} }
@ -351,6 +364,10 @@ func runQEMUCmd() *cobra.Command {
cmd.Flags().BoolVar(&usbEnabled, "usb", false, "Enable USB controller") cmd.Flags().BoolVar(&usbEnabled, "usb", false, "Enable USB controller")
cmd.Flags().Var(&deviceFlags, "device", "Add USB host device(s). Format driver[,prop=value][,...] -- add device, like -device on the qemu command line.") cmd.Flags().Var(&deviceFlags, "device", "Add USB host device(s). Format driver[,prop=value][,...] -- add device, like -device on the qemu command line.")
// Filesystems
cmd.Flags().StringVar(&virtiofsdCmd, "virtiofsd", "", "Path to virtiofsd binary (otherwise look in /usr/lib/qemu and /usr/local/lib/qemu)")
cmd.Flags().StringArrayVar(&virtiofsShares, "virtiofs", []string{}, "Directory shared on virtiofs")
return cmd return cmd
} }
@ -398,6 +415,25 @@ func runQemuLocal(config QemuConfig) error {
return fmt.Errorf("Detached mode is only supported when running in a container, not locally") return fmt.Errorf("Detached mode is only supported when running in a container, not locally")
} }
if len(config.VirtiofsShares) > 0 {
args = append(args, "-object", "memory-backend-memfd,id=mem,size="+config.Memory+"M,share=on", "-numa", "node,memdev=mem")
}
for index, source := range config.VirtiofsShares {
socket := filepath.Join(config.StatePath, fmt.Sprintf("%s%d", "virtiofs", index))
cmd := exec.Command(config.VirtiofsdBinPath,
"--socket-path="+socket,
"-o", fmt.Sprintf("source=%s", source))
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Start(); err != nil {
return fmt.Errorf("virtiofs server cannot start: %v", err)
}
args = append(args, "-chardev", fmt.Sprintf("socket,id=char%d,path=%s", index, socket))
args = append(args, "-device",
fmt.Sprintf("vhost-user-fs-pci,chardev=char%d,tag=virtiofs%d", index, index))
}
qemuCmd := exec.Command(config.QemuBinPath, args...) qemuCmd := exec.Command(config.QemuBinPath, args...)
// If verbosity is enabled print out the full path/arguments // If verbosity is enabled print out the full path/arguments
log.Debugf("%v\n", qemuCmd.Args) log.Debugf("%v\n", qemuCmd.Args)
@ -589,7 +625,7 @@ func buildQemuCmdline(config QemuConfig) (QemuConfig, []string) {
return config, qemuArgs return config, qemuArgs
} }
func discoverBinaries(config QemuConfig) (QemuConfig, error) { func discoverQemu(config QemuConfig) (QemuConfig, error) {
if config.QemuImgPath != "" { if config.QemuImgPath != "" {
return config, nil return config, nil
} }
@ -611,6 +647,16 @@ func discoverBinaries(config QemuConfig) (QemuConfig, error) {
return config, nil return config, nil
} }
func discoverVirtiofsd(config QemuConfig) (QemuConfig, error) {
if config.VirtiofsdBinPath != "" {
return config, nil
}
virtiofsdPath := filepath.Dir(config.QemuBinPath)
config.VirtiofsdBinPath = filepath.Join(virtiofsdPath, "..", "lib", "qemu", "virtiofsd")
return config, nil
}
func buildQemuForwardings(publishFlags multipleFlag) (string, error) { func buildQemuForwardings(publishFlags multipleFlag) (string, error) {
if len(publishFlags) == 0 { if len(publishFlags) == 0 {
return "", nil return "", nil