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

@ -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

View File

@ -14,23 +14,25 @@ const (
) )
type virtualizationFramwworkConfig struct { type virtualizationFramwworkConfig struct {
cpus uint cpus uint
mem uint64 mem uint64
disks Disks disks Disks
data string data string
dataPath string dataPath string
state string state string
networking string networking string
kernelBoot bool kernelBoot bool
virtiofsShares []string
} }
func runVirtualizationFrameworkCmd() *cobra.Command { func runVirtualizationFrameworkCmd() *cobra.Command {
var ( var (
data string data string
dataPath string dataPath string
state string state string
networking string networking string
kernelBoot bool kernelBoot bool
virtiofsShares []string
) )
cmd := &cobra.Command{ cmd := &cobra.Command{
@ -43,14 +45,15 @@ func runVirtualizationFrameworkCmd() *cobra.Command {
Example: "linuxkit run virtualization [options] prefix", Example: "linuxkit run virtualization [options] prefix",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
cfg := virtualizationFramwworkConfig{ cfg := virtualizationFramwworkConfig{
cpus: uint(cpus), cpus: uint(cpus),
mem: uint64(mem) * 1024 * 1024, mem: uint64(mem) * 1024 * 1024,
disks: disks, disks: disks,
data: data, data: data,
dataPath: dataPath, dataPath: dataPath,
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)