Merge pull request #3891 from fredericdalleau/qemu-virtiofs

Add virtiofs command line option for qemu run
This commit is contained in:
Rolf Neugebauer 2023-02-28 21:32:44 +00:00 committed by GitHub
commit 7d9f1f03a8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 157 additions and 83 deletions

View File

@ -45,6 +45,8 @@ type QemuConfig struct {
UUID uuid.UUID UUID uuid.UUID
USB bool USB bool
Devices []string Devices []string
VirtiofsdBinPath string
VirtiofsShares []string
} }
const ( const (
@ -136,6 +138,8 @@ func runQEMUCmd() *cobra.Command {
usbEnabled bool usbEnabled bool
deviceFlags multipleFlag deviceFlags multipleFlag
publishFlags multipleFlag publishFlags multipleFlag
virtiofsdCmd string
virtiofsShares []string
) )
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -300,13 +304,22 @@ func runQEMUCmd() *cobra.Command {
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

View File

@ -22,6 +22,7 @@ type virtualizationFramwworkConfig struct {
state string state string
networking string networking string
kernelBoot bool kernelBoot bool
virtiofsShares []string
} }
func runVirtualizationFrameworkCmd() *cobra.Command { func runVirtualizationFrameworkCmd() *cobra.Command {
@ -31,6 +32,7 @@ func runVirtualizationFrameworkCmd() *cobra.Command {
state string state string
networking string networking string
kernelBoot bool kernelBoot bool
virtiofsShares []string
) )
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -51,6 +53,7 @@ func runVirtualizationFrameworkCmd() *cobra.Command {
state: state, state: state,
networking: networking, networking: networking,
kernelBoot: kernelBoot, kernelBoot: kernelBoot,
virtiofsShares: virtiofsShares,
} }
return runVirtualizationFramework(cfg, args[0]) return runVirtualizationFramework(cfg, args[0])
}, },
@ -63,6 +66,7 @@ func runVirtualizationFrameworkCmd() *cobra.Command {
cmd.Flags().StringVar(&networking, "networking", virtualizationNetworkingDefault, "Networking mode. Valid options are 'default', 'vmnet' and 'none'. 'vmnet' uses the Apple vmnet framework. 'none' disables networking.`") cmd.Flags().StringVar(&networking, "networking", virtualizationNetworkingDefault, "Networking mode. Valid options are 'default', 'vmnet' and 'none'. 'vmnet' uses the Apple vmnet framework. 'none' disables networking.`")
cmd.Flags().BoolVar(&kernelBoot, "kernel", false, "Boot image is kernel+initrd+cmdline 'path'-kernel/-initrd/-cmdline") cmd.Flags().BoolVar(&kernelBoot, "kernel", false, "Boot image is kernel+initrd+cmdline 'path'-kernel/-initrd/-cmdline")
cmd.Flags().StringArrayVar(&virtiofsShares, "virtiofs", []string{}, "Directory shared on virtiofs")
return cmd return cmd
} }

View File

@ -239,6 +239,30 @@ func runVirtualizationFramework(cfg virtualizationFramwworkConfig, path string)
config.SetSocketDevicesVirtualMachineConfiguration([]vz.SocketDeviceConfiguration{ config.SetSocketDevicesVirtualMachineConfiguration([]vz.SocketDeviceConfiguration{
socketDeviceConfiguration, socketDeviceConfiguration,
}) })
if len(cfg.virtiofsShares) > 0 {
var cs []vz.DirectorySharingDeviceConfiguration
for idx, share := range cfg.virtiofsShares {
tag := fmt.Sprintf("virtiofs%d", idx)
device, err := vz.NewVirtioFileSystemDeviceConfiguration(tag)
if err != nil {
log.Fatal("virtiofs device configuration failed", err)
}
dir, err := vz.NewSharedDirectory(share, false)
if err != nil {
log.Fatal("virtiofs shared directory failed", err)
}
single, err := vz.NewSingleDirectoryShare(dir)
if err != nil {
log.Fatal("virtiofs single directory share failed", err)
}
device.SetDirectoryShare(single)
cs = append(cs, device)
}
config.SetDirectorySharingDevicesVirtualMachineConfiguration(cs)
}
validated, err := config.Validate() validated, err := config.Validate()
if !validated || err != nil { if !validated || err != nil {
log.Fatal("validation failed", err) log.Fatal("validation failed", err)