Merge pull request #1016 from stefanha/virtio-fs-core

Add virtio-fs support (alternative to virtio-9p)
This commit is contained in:
Eric Ernst 2019-05-07 11:19:58 -07:00 committed by GitHub
commit 9a27ac29bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 351 additions and 31 deletions

4
Gopkg.lock generated
View File

@ -378,11 +378,11 @@
revision = "2f1d1f20f75d5404f53b9edf6b53ed5505508675" revision = "2f1d1f20f75d5404f53b9edf6b53ed5505508675"
[[projects]] [[projects]]
digest = "1:f49a8b8840fe74235515e5bdb18b641b9d1887f3af7a38bec8f6998994e5ffca" digest = "1:2690f7d938dd074d30aa60849f26bcb9f5dd3ad88220a1f24c895c0df63fd1ae"
name = "github.com/intel/govmm" name = "github.com/intel/govmm"
packages = ["qemu"] packages = ["qemu"]
pruneopts = "NUT" pruneopts = "NUT"
revision = "35a8fd3ca9a36461b7dcf24e3b292f6e1ea4e71a" revision = "b3e7a9e78463a10f2a19e1a966c76a3afb215781"
[[projects]] [[projects]]
digest = "1:36dfd4701e98a9d8371dd3053e32d4f29e82b07bcc9e655db82138f9273bcb0f" digest = "1:36dfd4701e98a9d8371dd3053e32d4f29e82b07bcc9e655db82138f9273bcb0f"

View File

@ -48,7 +48,7 @@
[[constraint]] [[constraint]]
name = "github.com/intel/govmm" name = "github.com/intel/govmm"
revision = "35a8fd3ca9a36461b7dcf24e3b292f6e1ea4e71a" revision = "b3e7a9e78463a10f2a19e1a966c76a3afb215781"
[[constraint]] [[constraint]]
name = "github.com/kata-containers/agent" name = "github.com/kata-containers/agent"

View File

@ -156,6 +156,11 @@ DEFAULTEXPFEATURES := []
DEFENTROPYSOURCE := /dev/urandom DEFENTROPYSOURCE := /dev/urandom
DEFDISABLEBLOCK := false DEFDISABLEBLOCK := false
DEFSHAREDFS := virtio-9p
DEFVIRTIOFSDAEMON :=
# Default DAX mapping cache size in MiB
DEFVIRTIOFSCACHESIZE := 8192
DEFVIRTIOFSCACHE := always
DEFENABLEIOTHREADS := false DEFENABLEIOTHREADS := false
DEFENABLEMEMPREALLOC := false DEFENABLEMEMPREALLOC := false
DEFENABLEHUGEPAGES := false DEFENABLEHUGEPAGES := false
@ -320,6 +325,10 @@ USER_VARS += DEFAULTEXPFEATURES
USER_VARS += DEFDISABLEBLOCK USER_VARS += DEFDISABLEBLOCK
USER_VARS += DEFBLOCKSTORAGEDRIVER_FC USER_VARS += DEFBLOCKSTORAGEDRIVER_FC
USER_VARS += DEFBLOCKSTORAGEDRIVER_QEMU USER_VARS += DEFBLOCKSTORAGEDRIVER_QEMU
USER_VARS += DEFSHAREDFS
USER_VARS += DEFVIRTIOFSDAEMON
USER_VARS += DEFVIRTIOFSCACHESIZE
USER_VARS += DEFVIRTIOFSCACHE
USER_VARS += DEFENABLEIOTHREADS USER_VARS += DEFENABLEIOTHREADS
USER_VARS += DEFENABLEMEMPREALLOC USER_VARS += DEFENABLEMEMPREALLOC
USER_VARS += DEFENABLEHUGEPAGES USER_VARS += DEFENABLEHUGEPAGES
@ -456,6 +465,10 @@ $(GENERATED_FILES): %: %.in $(MAKEFILE_LIST) VERSION .git-commit
-e "s|@DEFDISABLEBLOCK@|$(DEFDISABLEBLOCK)|g" \ -e "s|@DEFDISABLEBLOCK@|$(DEFDISABLEBLOCK)|g" \
-e "s|@DEFBLOCKSTORAGEDRIVER_FC@|$(DEFBLOCKSTORAGEDRIVER_FC)|g" \ -e "s|@DEFBLOCKSTORAGEDRIVER_FC@|$(DEFBLOCKSTORAGEDRIVER_FC)|g" \
-e "s|@DEFBLOCKSTORAGEDRIVER_QEMU@|$(DEFBLOCKSTORAGEDRIVER_QEMU)|g" \ -e "s|@DEFBLOCKSTORAGEDRIVER_QEMU@|$(DEFBLOCKSTORAGEDRIVER_QEMU)|g" \
-e "s|@DEFSHAREDFS@|$(DEFSHAREDFS)|g" \
-e "s|@DEFVIRTIOFSDAEMON@|$(DEFVIRTIOFSDAEMON)|g" \
-e "s|@DEFVIRTIOFSCACHESIZE@|$(DEFVIRTIOFSCACHESIZE)|g" \
-e "s|@DEFVIRTIOFSCACHE@|$(DEFVIRTIOFSCACHE)|g" \
-e "s|@DEFENABLEIOTHREADS@|$(DEFENABLEIOTHREADS)|g" \ -e "s|@DEFENABLEIOTHREADS@|$(DEFENABLEIOTHREADS)|g" \
-e "s|@DEFENABLEMEMPREALLOC@|$(DEFENABLEMEMPREALLOC)|g" \ -e "s|@DEFENABLEMEMPREALLOC@|$(DEFENABLEMEMPREALLOC)|g" \
-e "s|@DEFENABLEHUGEPAGES@|$(DEFENABLEHUGEPAGES)|g" \ -e "s|@DEFENABLEHUGEPAGES@|$(DEFENABLEHUGEPAGES)|g" \

View File

@ -97,6 +97,32 @@ default_memory = @DEFMEMSZ@
# 9pfs is used instead to pass the rootfs. # 9pfs is used instead to pass the rootfs.
disable_block_device_use = @DEFDISABLEBLOCK@ disable_block_device_use = @DEFDISABLEBLOCK@
# Shared file system type:
# - virtio-9p (default)
# - virtio-fs
shared_fs = "@DEFSHAREDFS@"
# Path to vhost-user-fs daemon.
virtio_fs_daemon = "@DEFVIRTIOFSDAEMON@"
# Default size of DAX cache in MiB
virtio_fs_cache_size = @DEFVIRTIOFSCACHESIZE@
# Cache mode:
#
# - none
# Metadata, data, and pathname lookup are not cached in guest. They are
# always fetched from host and any changes are immediately pushed to host.
#
# - auto
# Metadata and pathname lookup cache expires after a configured amount of
# time (default is 1 second). Data is cached while the file is open (close
# to open consistency).
#
# - always
# Metadata, data, and pathname lookup are cached in guest and never expire.
virtio_fs_cache = "@DEFVIRTIOFSCACHE@"
# Block storage driver to be used for the hypervisor in case the container # Block storage driver to be used for the hypervisor in case the container
# rootfs is backed by a block device. This is virtio-scsi, virtio-blk # rootfs is backed by a block device. This is virtio-scsi, virtio-blk
# or nvdimm. # or nvdimm.

View File

@ -92,6 +92,7 @@ type HypervisorInfo struct {
MemorySlots uint32 MemorySlots uint32
Debug bool Debug bool
UseVSock bool UseVSock bool
SharedFS string
} }
// ProxyInfo stores proxy details // ProxyInfo stores proxy details
@ -352,6 +353,7 @@ func getHypervisorInfo(config oci.RuntimeConfig) HypervisorInfo {
UseVSock: config.HypervisorConfig.UseVSock, UseVSock: config.HypervisorConfig.UseVSock,
MemorySlots: config.HypervisorConfig.MemSlots, MemorySlots: config.HypervisorConfig.MemSlots,
EntropySource: config.HypervisorConfig.EntropySource, EntropySource: config.HypervisorConfig.EntropySource,
SharedFS: config.HypervisorConfig.SharedFS,
} }
} }

View File

@ -37,6 +37,7 @@ const testHypervisorVersion = "QEMU emulator version 2.7.0+git.741f430a96-6.1, C
var ( var (
hypervisorDebug = false hypervisorDebug = false
enableVirtioFS = false
proxyDebug = false proxyDebug = false
runtimeDebug = false runtimeDebug = false
runtimeTrace = false runtimeTrace = false
@ -91,6 +92,7 @@ func makeRuntimeConfig(prefixDir string) (configFile string, config oci.RuntimeC
enableIOThreads := true enableIOThreads := true
hotplugVFIOOnRootBus := true hotplugVFIOOnRootBus := true
disableNewNetNs := false disableNewNetNs := false
sharedFS := "virtio-9p"
filesToCreate := []string{ filesToCreate := []string{
hypervisorPath, hypervisorPath,
@ -126,6 +128,10 @@ func makeRuntimeConfig(prefixDir string) (configFile string, config oci.RuntimeC
return "", oci.RuntimeConfig{}, err return "", oci.RuntimeConfig{}, err
} }
if enableVirtioFS {
sharedFS = "virtio-fs"
}
hypConfig := katautils.GetDefaultHypervisorConfig() hypConfig := katautils.GetDefaultHypervisorConfig()
configFileOptions := katatestutils.RuntimeConfigOptions{ configFileOptions := katatestutils.RuntimeConfigOptions{
@ -157,6 +163,7 @@ func makeRuntimeConfig(prefixDir string) (configFile string, config oci.RuntimeC
NetmonDebug: netmonDebug, NetmonDebug: netmonDebug,
AgentDebug: agentDebug, AgentDebug: agentDebug,
AgentTrace: agentTrace, AgentTrace: agentTrace,
SharedFS: sharedFS,
} }
runtimeConfig := katatestutils.MakeRuntimeConfigFileData(configFileOptions) runtimeConfig := katatestutils.MakeRuntimeConfigFileData(configFileOptions)
@ -321,6 +328,7 @@ func getExpectedHypervisor(config oci.RuntimeConfig) HypervisorInfo {
MemorySlots: config.HypervisorConfig.MemSlots, MemorySlots: config.HypervisorConfig.MemSlots,
Debug: config.HypervisorConfig.Debug, Debug: config.HypervisorConfig.Debug,
EntropySource: config.HypervisorConfig.EntropySource, EntropySource: config.HypervisorConfig.EntropySource,
SharedFS: config.HypervisorConfig.SharedFS,
} }
} }
@ -498,6 +506,7 @@ func TestEnvGetEnvInfo(t *testing.T) {
// options are tested. // options are tested.
for _, toggle := range []bool{false, true} { for _, toggle := range []bool{false, true} {
hypervisorDebug = toggle hypervisorDebug = toggle
enableVirtioFS = toggle
proxyDebug = toggle proxyDebug = toggle
runtimeDebug = toggle runtimeDebug = toggle
runtimeTrace = toggle runtimeTrace = toggle

View File

@ -27,6 +27,7 @@ type RuntimeConfigOptions struct {
BlockDeviceDriver string BlockDeviceDriver string
AgentTraceMode string AgentTraceMode string
AgentTraceType string AgentTraceType string
SharedFS string
DisableBlock bool DisableBlock bool
EnableIOThreads bool EnableIOThreads bool
HotplugVFIOOnRootBus bool HotplugVFIOOnRootBus bool
@ -61,6 +62,8 @@ func MakeRuntimeConfigFileData(config RuntimeConfigOptions) string {
msize_9p = ` + strconv.FormatUint(uint64(config.DefaultMsize9p), 10) + ` msize_9p = ` + strconv.FormatUint(uint64(config.DefaultMsize9p), 10) + `
enable_debug = ` + strconv.FormatBool(config.HypervisorDebug) + ` enable_debug = ` + strconv.FormatBool(config.HypervisorDebug) + `
guest_hook_path = "` + config.DefaultGuestHookPath + `" guest_hook_path = "` + config.DefaultGuestHookPath + `"
shared_fs = "` + config.SharedFS + `"
virtio_fs_daemon = "/path/to/virtiofsd"
[proxy.kata] [proxy.kata]
enable_debug = ` + strconv.FormatBool(config.ProxyDebug) + ` enable_debug = ` + strconv.FormatBool(config.ProxyDebug) + `

View File

@ -92,6 +92,10 @@ type hypervisor struct {
MachineType string `toml:"machine_type"` MachineType string `toml:"machine_type"`
BlockDeviceDriver string `toml:"block_device_driver"` BlockDeviceDriver string `toml:"block_device_driver"`
EntropySource string `toml:"entropy_source"` EntropySource string `toml:"entropy_source"`
SharedFS string `toml:"shared_fs"`
VirtioFSDaemon string `toml:"virtio_fs_daemon"`
VirtioFSCache string `toml:"virtio_fs_cache"`
VirtioFSCacheSize uint32 `toml:"virtio_fs_cache_size"`
BlockDeviceCacheSet bool `toml:"block_device_cache_set"` BlockDeviceCacheSet bool `toml:"block_device_cache_set"`
BlockDeviceCacheDirect bool `toml:"block_device_cache_direct"` BlockDeviceCacheDirect bool `toml:"block_device_cache_direct"`
BlockDeviceCacheNoflush bool `toml:"block_device_cache_noflush"` BlockDeviceCacheNoflush bool `toml:"block_device_cache_noflush"`
@ -326,6 +330,22 @@ func (h hypervisor) blockDeviceDriver() (string, error) {
return "", fmt.Errorf("Invalid hypervisor block storage driver %v specified (supported drivers: %v)", h.BlockDeviceDriver, supportedBlockDrivers) return "", fmt.Errorf("Invalid hypervisor block storage driver %v specified (supported drivers: %v)", h.BlockDeviceDriver, supportedBlockDrivers)
} }
func (h hypervisor) sharedFS() (string, error) {
supportedSharedFS := []string{config.Virtio9P, config.VirtioFS}
if h.SharedFS == "" {
return config.Virtio9P, nil
}
for _, fs := range supportedSharedFS {
if fs == h.SharedFS {
return h.SharedFS, nil
}
}
return "", fmt.Errorf("Invalid hypervisor shared file system %v specified (supported file systems: %v)", h.SharedFS, supportedSharedFS)
}
func (h hypervisor) msize9p() uint32 { func (h hypervisor) msize9p() uint32 {
if h.Msize9p == 0 { if h.Msize9p == 0 {
return defaultMsize9p return defaultMsize9p
@ -521,6 +541,16 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
return vc.HypervisorConfig{}, err return vc.HypervisorConfig{}, err
} }
sharedFS, err := h.sharedFS()
if err != nil {
return vc.HypervisorConfig{}, err
}
if sharedFS == config.VirtioFS && h.VirtioFSDaemon == "" {
return vc.HypervisorConfig{},
errors.New("cannot enable virtio-fs without daemon path in configuration file")
}
useVSock := false useVSock := false
if h.useVSock() { if h.useVSock() {
if utils.SupportsVsocks() { if utils.SupportsVsocks() {
@ -548,6 +578,10 @@ func newQemuHypervisorConfig(h hypervisor) (vc.HypervisorConfig, error) {
EntropySource: h.GetEntropySource(), EntropySource: h.GetEntropySource(),
DefaultBridges: h.defaultBridges(), DefaultBridges: h.defaultBridges(),
DisableBlockDeviceUse: h.DisableBlockDeviceUse, DisableBlockDeviceUse: h.DisableBlockDeviceUse,
SharedFS: sharedFS,
VirtioFSDaemon: h.VirtioFSDaemon,
VirtioFSCacheSize: h.VirtioFSCacheSize,
VirtioFSCache: h.VirtioFSCache,
MemPrealloc: h.MemPrealloc, MemPrealloc: h.MemPrealloc,
HugePages: h.HugePages, HugePages: h.HugePages,
Mlock: !h.Swap, Mlock: !h.Swap,

View File

@ -83,6 +83,7 @@ func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConf
enableIOThreads := true enableIOThreads := true
hotplugVFIOOnRootBus := true hotplugVFIOOnRootBus := true
disableNewNetNs := false disableNewNetNs := false
sharedFS := "virtio-9p"
configFileOptions := ktu.RuntimeConfigOptions{ configFileOptions := ktu.RuntimeConfigOptions{
Hypervisor: "qemu", Hypervisor: "qemu",
@ -113,6 +114,7 @@ func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConf
NetmonDebug: netmonDebug, NetmonDebug: netmonDebug,
AgentDebug: agentDebug, AgentDebug: agentDebug,
AgentTrace: agentTrace, AgentTrace: agentTrace,
SharedFS: sharedFS,
} }
runtimeConfigFileData := ktu.MakeRuntimeConfigFileData(configFileOptions) runtimeConfigFileData := ktu.MakeRuntimeConfigFileData(configFileOptions)
@ -160,6 +162,8 @@ func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConf
MemSlots: defaultMemSlots, MemSlots: defaultMemSlots,
EntropySource: defaultEntropySource, EntropySource: defaultEntropySource,
GuestHookPath: defaultGuestHookPath, GuestHookPath: defaultGuestHookPath,
SharedFS: sharedFS,
VirtioFSDaemon: "/path/to/virtiofsd",
} }
agentConfig := vc.KataAgentConfig{} agentConfig := vc.KataAgentConfig{}

View File

@ -748,7 +748,7 @@ type VhostUserDevice struct {
TypeDevID string //variable QEMU parameter based on value of VhostUserType TypeDevID string //variable QEMU parameter based on value of VhostUserType
Address string //used for MAC address in net case Address string //used for MAC address in net case
Tag string //virtio-fs volume id for mounting inside guest Tag string //virtio-fs volume id for mounting inside guest
CacheSize uint32 //virtio-fs DAX cache size in GiB CacheSize uint32 //virtio-fs DAX cache size in MiB
SharedVersions bool //enable virtio-fs shared version metadata SharedVersions bool //enable virtio-fs shared version metadata
VhostUserType DeviceDriver VhostUserType DeviceDriver
@ -824,7 +824,7 @@ func (vhostuserDev VhostUserDevice) QemuParams(config *Config) []string {
devParams = append(devParams, string(driver)) devParams = append(devParams, string(driver))
devParams = append(devParams, fmt.Sprintf("chardev=%s", vhostuserDev.CharDevID)) devParams = append(devParams, fmt.Sprintf("chardev=%s", vhostuserDev.CharDevID))
devParams = append(devParams, fmt.Sprintf("tag=%s", vhostuserDev.Tag)) devParams = append(devParams, fmt.Sprintf("tag=%s", vhostuserDev.Tag))
devParams = append(devParams, fmt.Sprintf("cache-size=%dG", vhostuserDev.CacheSize)) devParams = append(devParams, fmt.Sprintf("cache-size=%dM", vhostuserDev.CacheSize))
if vhostuserDev.SharedVersions { if vhostuserDev.SharedVersions {
devParams = append(devParams, "versiontable=/dev/shm/fuse_shared_versions") devParams = append(devParams, "versiontable=/dev/shm/fuse_shared_versions")
} }

View File

@ -36,6 +36,9 @@ const (
//VhostUserBlk represents a block vhostuser device type //VhostUserBlk represents a block vhostuser device type
VhostUserBlk = "vhost-user-blk-pci" VhostUserBlk = "vhost-user-blk-pci"
//VhostUserFS represents a virtio-fs vhostuser device type
VhostUserFS = "vhost-user-fs-pci"
) )
const ( const (
@ -52,6 +55,14 @@ const (
Nvdimm = "nvdimm" Nvdimm = "nvdimm"
) )
const (
// Virtio9P means use virtio-9p for the shared file system
Virtio9P = "virtio-9p"
// VirtioFS means use virtio-fs for the shared file system
VirtioFS = "virtio-fs"
)
// Defining these as a variable instead of a const, to allow // Defining these as a variable instead of a const, to allow
// overriding this in the tests. // overriding this in the tests.
@ -174,6 +185,11 @@ type VhostUserDeviceAttrs struct {
// MacAddress is only meaningful for vhost user net device // MacAddress is only meaningful for vhost user net device
MacAddress string MacAddress string
// These are only meaningful for vhost user fs devices
Tag string
CacheSize uint32
Cache string
} }
// GetHostPathFunc is function pointer used to mock GetHostPath in tests. // GetHostPathFunc is function pointer used to mock GetHostPath in tests.

View File

@ -0,0 +1,65 @@
// Copyright (C) 2019 Red Hat, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
package drivers
import (
"encoding/hex"
"github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/config"
"github.com/kata-containers/runtime/virtcontainers/utils"
)
// VhostUserFSDevice is a virtio-fs vhost-user device
type VhostUserFSDevice struct {
*GenericDevice
config.VhostUserDeviceAttrs
}
// Device interface
func (device *VhostUserFSDevice) Attach(devReceiver api.DeviceReceiver) (err error) {
skip, err := device.bumpAttachCount(true)
if err != nil {
return err
}
if skip {
return nil
}
defer func() {
if err != nil {
device.bumpAttachCount(false)
}
}()
// generate a unique ID to be used for hypervisor commandline fields
randBytes, err := utils.GenerateRandomBytes(8)
if err != nil {
return err
}
id := hex.EncodeToString(randBytes)
device.DevID = id
device.Type = device.DeviceType()
return devReceiver.AppendDevice(device)
}
func (device *VhostUserFSDevice) Detach(devReceiver api.DeviceReceiver) error {
_, err := device.bumpAttachCount(false)
return err
}
func (device *VhostUserFSDevice) DeviceType() config.DeviceType {
return config.VhostUserFS
}
// GetDeviceInfo returns device information that the device is created based on
func (device *VhostUserFSDevice) GetDeviceInfo() interface{} {
device.Type = device.DeviceType()
return &device.VhostUserDeviceAttrs
}

View File

@ -138,6 +138,20 @@ type HypervisorConfig struct {
// DisableBlockDeviceUse disallows a block device from being used. // DisableBlockDeviceUse disallows a block device from being used.
DisableBlockDeviceUse bool DisableBlockDeviceUse bool
// Shared file system type:
// - virtio-9p (default)
// - virtio-fs
SharedFS string
// VirtioFSDaemon is the virtio-fs vhost-user daemon path
VirtioFSDaemon string
// VirtioFSCacheSize is the virtio-fs DAX cache size in MiB
VirtioFSCacheSize uint32
// VirtioFSCache cache mode for fs version cache or "none"
VirtioFSCache string
// KernelParams are additional guest kernel parameters. // KernelParams are additional guest kernel parameters.
KernelParams []Param KernelParams []Param

View File

@ -170,6 +170,9 @@ type HypervisorConfig struct {
// MemOffset specifies memory space for nvdimm device // MemOffset specifies memory space for nvdimm device
MemOffset uint32 MemOffset uint32
// VirtioFSCacheSize is the DAX cache size in MiB
VirtioFSCacheSize uint32
// KernelParams are additional guest kernel parameters. // KernelParams are additional guest kernel parameters.
KernelParams []Param KernelParams []Param
@ -215,6 +218,17 @@ type HypervisorConfig struct {
// entropy (/dev/random, /dev/urandom or real hardware RNG device) // entropy (/dev/random, /dev/urandom or real hardware RNG device)
EntropySource string EntropySource string
// Shared file system type:
// - virtio-9p (default)
// - virtio-fs
SharedFS string
// VirtioFSDaemon is the virtio-fs vhost-user daemon path
VirtioFSDaemon string
// VirtioFSCache cache mode for fs version cache or "none"
VirtioFSCache string
// customAssets is a map of assets. // customAssets is a map of assets.
// Each value in that map takes precedence over the configured assets. // Each value in that map takes precedence over the configured assets.
// For example, if there is a value for the "kernel" key in this map, // For example, if there is a value for the "kernel" key in this map,

View File

@ -65,6 +65,7 @@ var (
mountGuest9pTag = "kataShared" mountGuest9pTag = "kataShared"
kataGuestSandboxDir = "/run/kata-containers/sandbox/" kataGuestSandboxDir = "/run/kata-containers/sandbox/"
type9pFs = "9p" type9pFs = "9p"
typeVirtioFS = "virtio_fs"
vsockSocketScheme = "vsock" vsockSocketScheme = "vsock"
// port numbers below 1024 are called privileged ports. Only a process with // port numbers below 1024 are called privileged ports. Only a process with
// CAP_NET_BIND_SERVICE capability may bind to these port numbers. // CAP_NET_BIND_SERVICE capability may bind to these port numbers.
@ -74,7 +75,9 @@ var (
kataBlkDevType = "blk" kataBlkDevType = "blk"
kataSCSIDevType = "scsi" kataSCSIDevType = "scsi"
kataNvdimmDevType = "nvdimm" kataNvdimmDevType = "nvdimm"
kataVirtioFSDevType = "virtio-fs"
sharedDir9pOptions = []string{"trans=virtio,version=9p2000.L,cache=mmap", "nodev"} sharedDir9pOptions = []string{"trans=virtio,version=9p2000.L,cache=mmap", "nodev"}
sharedDirVirtioFSOptions = []string{"default_permissions,allow_other,rootmode=040000,user_id=0,group_id=0,dax,tag=" + mountGuest9pTag, "nodev"}
shmDir = "shm" shmDir = "shm"
kataEphemeralDevType = "ephemeral" kataEphemeralDevType = "ephemeral"
ephemeralPath = filepath.Join(kataGuestSandboxDir, kataEphemeralDevType) ephemeralPath = filepath.Join(kataGuestSandboxDir, kataEphemeralDevType)
@ -738,13 +741,24 @@ func (k *kataAgent) startSandbox(sandbox *Sandbox) error {
// append 9p shared volume to storages only if filesystem sharing is supported // append 9p shared volume to storages only if filesystem sharing is supported
if caps.IsFsSharingSupported() { if caps.IsFsSharingSupported() {
sharedDir9pOptions = append(sharedDir9pOptions, fmt.Sprintf("msize=%d", sandbox.config.HypervisorConfig.Msize9p))
// We mount the shared directory in a predefined location // We mount the shared directory in a predefined location
// in the guest. // in the guest.
// This is where at least some of the host config files // This is where at least some of the host config files
// (resolv.conf, etc...) and potentially all container // (resolv.conf, etc...) and potentially all container
// rootfs will reside. // rootfs will reside.
if sandbox.config.HypervisorConfig.SharedFS == config.VirtioFS {
sharedVolume := &grpc.Storage{
Driver: kataVirtioFSDevType,
Source: "none",
MountPoint: kataGuestSharedDir,
Fstype: typeVirtioFS,
Options: sharedDirVirtioFSOptions,
}
storages = append(storages, sharedVolume)
} else {
sharedDir9pOptions = append(sharedDir9pOptions, fmt.Sprintf("msize=%d", sandbox.config.HypervisorConfig.Msize9p))
sharedVolume := &grpc.Storage{ sharedVolume := &grpc.Storage{
Driver: kata9pDevType, Driver: kata9pDevType,
Source: mountGuest9pTag, Source: mountGuest9pTag,
@ -755,6 +769,7 @@ func (k *kataAgent) startSandbox(sandbox *Sandbox) error {
storages = append(storages, sharedVolume) storages = append(storages, sharedVolume)
} }
}
if sandbox.shmSize > 0 { if sandbox.shmSize > 0 {
path := filepath.Join(kataGuestSandboxDir, shmDir) path := filepath.Join(kataGuestSandboxDir, shmDir)

View File

@ -6,13 +6,16 @@
package virtcontainers package virtcontainers
import ( import (
"bufio"
"context" "context"
"encoding/hex"
"encoding/json" "encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"math" "math"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
@ -88,6 +91,7 @@ type qemu struct {
const ( const (
consoleSocket = "console.sock" consoleSocket = "console.sock"
qmpSocket = "qmp.sock" qmpSocket = "qmp.sock"
vhostFSSocket = "vhost-fs.sock"
qmpCapErrMsg = "Failed to negoatiate QMP capabilities" qmpCapErrMsg = "Failed to negoatiate QMP capabilities"
qmpExecCatCmd = "exec:cat" qmpExecCatCmd = "exec:cat"
@ -541,6 +545,10 @@ func (q *qemu) createSandbox(ctx context.Context, id string, hypervisorConfig *H
return nil return nil
} }
func (q *qemu) vhostFSSocketPath(id string) (string, error) {
return utils.BuildSocketPath(store.RunVMStoragePath, id, vhostFSSocket)
}
// startSandbox will start the Sandbox's VM. // startSandbox will start the Sandbox's VM.
func (q *qemu) startSandbox(timeout int) error { func (q *qemu) startSandbox(timeout int) error {
span, _ := q.trace("startSandbox") span, _ := q.trace("startSandbox")
@ -580,13 +588,77 @@ func (q *qemu) startSandbox(timeout int) error {
} }
}() }()
if q.config.SharedFS == config.VirtioFS {
sockPath, err := q.vhostFSSocketPath(q.id)
if err != nil {
return err
}
// The daemon will terminate when the vhost-user socket
// connection with QEMU closes. Therefore we do not keep track
// of this child process after returning from this function.
sourcePath := filepath.Join(kataHostSharedDir, q.id)
cmd := exec.Command(q.config.VirtioFSDaemon,
"-o", "vhost_user_socket="+sockPath,
"-o", "source="+sourcePath,
"-o", "cache="+q.config.VirtioFSCache)
stderr, err := cmd.StderrPipe()
if err != nil {
return err
}
if err = cmd.Start(); err != nil {
return err
}
defer func() {
if err != nil {
cmd.Process.Kill()
}
}()
// Wait for socket to become available
sockReady := make(chan error, 1)
timeStart := time.Now()
go func() {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
if strings.Contains(scanner.Text(), "Waiting for vhost-user socket connection...") {
sockReady <- nil
return
}
}
if err := scanner.Err(); err != nil {
sockReady <- err
}
sockReady <- fmt.Errorf("virtiofsd did not announce socket connection")
}()
timeoutDuration := time.Duration(timeout) * time.Second
select {
case err = <-sockReady:
case <-time.After(timeoutDuration):
err = fmt.Errorf("timed out waiting for virtiofsd (pid=%d) socket %s", cmd.Process.Pid, sockPath)
}
if err != nil {
return err
}
// Now reduce timeout by the elapsed time
elapsed := time.Since(timeStart)
if elapsed < timeoutDuration {
timeout = timeout - int(elapsed.Seconds())
} else {
timeout = 0
}
}
var strErr string var strErr string
strErr, err = govmmQemu.LaunchQemu(q.qemuConfig, newQMPLogger()) strErr, err = govmmQemu.LaunchQemu(q.qemuConfig, newQMPLogger())
if err != nil { if err != nil {
return fmt.Errorf("%s", strErr) return fmt.Errorf("%s", strErr)
} }
return q.waitSandbox(timeout) err = q.waitSandbox(timeout) // the virtiofsd deferred checks err's value
return err
} }
// waitSandbox will wait for the Sandbox's VM to be up and running. // waitSandbox will wait for the Sandbox's VM to be up and running.
@ -1288,7 +1360,36 @@ func (q *qemu) addDevice(devInfo interface{}, devType deviceType) error {
switch v := devInfo.(type) { switch v := devInfo.(type) {
case types.Volume: case types.Volume:
if q.config.SharedFS == config.VirtioFS {
q.Logger().WithField("volume-type", "virtio-fs").Info("adding volume")
var randBytes []byte
randBytes, err = utils.GenerateRandomBytes(8)
if err != nil {
return err
}
id := hex.EncodeToString(randBytes)
var sockPath string
sockPath, err = q.vhostFSSocketPath(q.id)
if err != nil {
return err
}
vhostDev := config.VhostUserDeviceAttrs{
Tag: v.MountTag,
Type: config.VhostUserFS,
CacheSize: q.config.VirtioFSCacheSize,
Cache: q.config.VirtioFSCache,
}
vhostDev.SocketPath = sockPath
vhostDev.DevID = id
q.qemuConfig.Devices, err = q.arch.appendVhostUserDevice(q.qemuConfig.Devices, vhostDev)
} else {
q.Logger().WithField("volume-type", "virtio-9p").Info("adding volume")
q.qemuConfig.Devices = q.arch.append9PVolume(q.qemuConfig.Devices, v) q.qemuConfig.Devices = q.arch.append9PVolume(q.qemuConfig.Devices, v)
}
case types.Socket: case types.Socket:
q.qemuConfig.Devices = q.arch.appendSocket(q.qemuConfig.Devices, v) q.qemuConfig.Devices = q.arch.appendSocket(q.qemuConfig.Devices, v)
case kataVSOCK: case kataVSOCK:

View File

@ -527,6 +527,10 @@ func (q *qemuArchBase) appendVhostUserDevice(devices []govmmQemu.Device, attr co
case config.VhostUserSCSI: case config.VhostUserSCSI:
qemuVhostUserDevice.TypeDevID = utils.MakeNameID("scsi", attr.DevID, maxDevIDSize) qemuVhostUserDevice.TypeDevID = utils.MakeNameID("scsi", attr.DevID, maxDevIDSize)
case config.VhostUserBlk: case config.VhostUserBlk:
case config.VhostUserFS:
qemuVhostUserDevice.TypeDevID = utils.MakeNameID("fs", attr.DevID, maxDevIDSize)
qemuVhostUserDevice.Tag = attr.Tag
qemuVhostUserDevice.CacheSize = attr.CacheSize
} }
qemuVhostUserDevice.VhostUserType = govmmQemu.DeviceDriver(attr.Type) qemuVhostUserDevice.VhostUserType = govmmQemu.DeviceDriver(attr.Type)

View File

@ -1737,7 +1737,7 @@ func (s *Sandbox) DecrementSandboxBlockIndex() error {
// Sandbox implement DeviceReceiver interface from device/api/interface.go // Sandbox implement DeviceReceiver interface from device/api/interface.go
func (s *Sandbox) AppendDevice(device api.Device) error { func (s *Sandbox) AppendDevice(device api.Device) error {
switch device.DeviceType() { switch device.DeviceType() {
case config.VhostUserSCSI, config.VhostUserNet, config.VhostUserBlk: case config.VhostUserSCSI, config.VhostUserNet, config.VhostUserBlk, config.VhostUserFS:
return s.hypervisor.addDevice(device.GetDeviceInfo().(*config.VhostUserDeviceAttrs), vhostuserDev) return s.hypervisor.addDevice(device.GetDeviceInfo().(*config.VhostUserDeviceAttrs), vhostuserDev)
} }
return fmt.Errorf("unsupported device type") return fmt.Errorf("unsupported device type")