mirror of
https://github.com/kata-containers/kata-containers.git
synced 2025-04-30 12:44:39 +00:00
runtime: Sandbox: Add addSwap and removeSwap
addSwap will create a swap file, hotplug it to hypervisor as a special block device and let agent to setup it in the guest kernel. removeSwap will remove the swap file. Just QEMU support addSwap. Fixes: #2201 Signed-off-by: Hui Zhu <teawater@antfin.com>
This commit is contained in:
parent
e1b91986d7
commit
243d4b8689
@ -517,6 +517,10 @@ func (a *Acrn) stopSandbox(ctx context.Context, waitOnly bool) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *Acrn) updateBlockDevice(drive *config.BlockDrive) error {
|
func (a *Acrn) updateBlockDevice(drive *config.BlockDrive) error {
|
||||||
|
if drive.Swap {
|
||||||
|
return fmt.Errorf("Acrn doesn't support swap")
|
||||||
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if drive.File == "" || drive.Index >= AcrnBlkDevPoolSz {
|
if drive.File == "" || drive.Index >= AcrnBlkDevPoolSz {
|
||||||
return fmt.Errorf("Empty filepath or invalid drive index, Dive ID:%s, Drive Index:%d",
|
return fmt.Errorf("Empty filepath or invalid drive index, Dive ID:%s, Drive Index:%d",
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
|
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
|
||||||
pbTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols"
|
pbTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols"
|
||||||
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols/grpc"
|
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols/grpc"
|
||||||
|
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
|
||||||
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
|
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
@ -189,6 +190,9 @@ type agent interface {
|
|||||||
// copyFile copies file from host to container's rootfs
|
// copyFile copies file from host to container's rootfs
|
||||||
copyFile(ctx context.Context, src, dst string) error
|
copyFile(ctx context.Context, src, dst string) error
|
||||||
|
|
||||||
|
// Tell the agent to setup the swapfile in the guest
|
||||||
|
addSwap(ctx context.Context, PCIPath vcTypes.PciPath) error
|
||||||
|
|
||||||
// markDead tell agent that the guest is dead
|
// markDead tell agent that the guest is dead
|
||||||
markDead(ctx context.Context)
|
markDead(ctx context.Context)
|
||||||
|
|
||||||
|
@ -416,6 +416,10 @@ func clhPciInfoToPath(pciInfo chclient.PciDeviceInfo) (vcTypes.PciPath, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (clh *cloudHypervisor) hotplugAddBlockDevice(drive *config.BlockDrive) error {
|
func (clh *cloudHypervisor) hotplugAddBlockDevice(drive *config.BlockDrive) error {
|
||||||
|
if drive.Swap {
|
||||||
|
return fmt.Errorf("cloudHypervisor doesn't support swap")
|
||||||
|
}
|
||||||
|
|
||||||
if clh.config.BlockDeviceDriver != config.VirtioBlock {
|
if clh.config.BlockDeviceDriver != config.VirtioBlock {
|
||||||
return fmt.Errorf("incorrect hypervisor configuration on 'block_device_driver':"+
|
return fmt.Errorf("incorrect hypervisor configuration on 'block_device_driver':"+
|
||||||
" using '%v' but only support '%v'", clh.config.BlockDeviceDriver, config.VirtioBlock)
|
" using '%v' but only support '%v'", clh.config.BlockDeviceDriver, config.VirtioBlock)
|
||||||
|
@ -182,6 +182,9 @@ type BlockDrive struct {
|
|||||||
// Pmem enables persistent memory. Use File as backing file
|
// Pmem enables persistent memory. Use File as backing file
|
||||||
// for a nvdimm device in the guest
|
// for a nvdimm device in the guest
|
||||||
Pmem bool
|
Pmem bool
|
||||||
|
|
||||||
|
// This block device is for swap
|
||||||
|
Swap bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// VFIODeviceType indicates VFIO device type
|
// VFIODeviceType indicates VFIO device type
|
||||||
|
@ -1036,6 +1036,10 @@ func (fc *firecracker) addDevice(ctx context.Context, devInfo interface{}, devTy
|
|||||||
// hotplugBlockDevice supported in Firecracker VMM
|
// hotplugBlockDevice supported in Firecracker VMM
|
||||||
// hot add or remove a block device.
|
// hot add or remove a block device.
|
||||||
func (fc *firecracker) hotplugBlockDevice(ctx context.Context, drive config.BlockDrive, op operation) (interface{}, error) {
|
func (fc *firecracker) hotplugBlockDevice(ctx context.Context, drive config.BlockDrive, op operation) (interface{}, error) {
|
||||||
|
if drive.Swap {
|
||||||
|
return nil, fmt.Errorf("firecracker doesn't support swap")
|
||||||
|
}
|
||||||
|
|
||||||
var path string
|
var path string
|
||||||
var err error
|
var err error
|
||||||
driveID := fcDriveIndexToID(drive.Index)
|
driveID := fcDriveIndexToID(drive.Index)
|
||||||
|
@ -143,6 +143,7 @@ const (
|
|||||||
grpcStopTracingRequest = "grpc.StopTracingRequest"
|
grpcStopTracingRequest = "grpc.StopTracingRequest"
|
||||||
grpcGetOOMEventRequest = "grpc.GetOOMEventRequest"
|
grpcGetOOMEventRequest = "grpc.GetOOMEventRequest"
|
||||||
grpcGetMetricsRequest = "grpc.GetMetricsRequest"
|
grpcGetMetricsRequest = "grpc.GetMetricsRequest"
|
||||||
|
grpcAddSwapRequest = "grpc.AddSwapRequest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// newKataAgent returns an agent from an agent type.
|
// newKataAgent returns an agent from an agent type.
|
||||||
@ -2024,6 +2025,9 @@ func (k *kataAgent) installReqFunc(c *kataclient.AgentClient) {
|
|||||||
k.reqHandlers[grpcGetMetricsRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
|
k.reqHandlers[grpcGetMetricsRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
return k.client.AgentServiceClient.GetMetrics(ctx, req.(*grpc.GetMetricsRequest))
|
return k.client.AgentServiceClient.GetMetrics(ctx, req.(*grpc.GetMetricsRequest))
|
||||||
}
|
}
|
||||||
|
k.reqHandlers[grpcAddSwapRequest] = func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return k.client.AgentServiceClient.AddSwap(ctx, req.(*grpc.AddSwapRequest))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *kataAgent) getReqContext(ctx context.Context, reqName string) (newCtx context.Context, cancel context.CancelFunc) {
|
func (k *kataAgent) getReqContext(ctx context.Context, reqName string) (newCtx context.Context, cancel context.CancelFunc) {
|
||||||
@ -2184,6 +2188,14 @@ func (k *kataAgent) copyFile(ctx context.Context, src, dst string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k *kataAgent) addSwap(ctx context.Context, PCIPath vcTypes.PciPath) error {
|
||||||
|
span, ctx := katatrace.Trace(ctx, k.Logger(), "addSwap", kataAgentTracingTags)
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
_, err := k.sendReq(ctx, &grpc.AddSwapRequest{PCIPath: PCIPath.ToArray()})
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (k *kataAgent) markDead(ctx context.Context) {
|
func (k *kataAgent) markDead(ctx context.Context) {
|
||||||
k.Logger().Infof("mark agent dead")
|
k.Logger().Infof("mark agent dead")
|
||||||
k.dead = true
|
k.dead = true
|
||||||
|
@ -12,6 +12,7 @@ import (
|
|||||||
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
|
persistapi "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/persist/api"
|
||||||
pbTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols"
|
pbTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols"
|
||||||
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols/grpc"
|
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/agent/protocols/grpc"
|
||||||
|
vcTypes "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/pkg/types"
|
||||||
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
|
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/types"
|
||||||
specs "github.com/opencontainers/runtime-spec/specs-go"
|
specs "github.com/opencontainers/runtime-spec/specs-go"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
@ -215,6 +216,11 @@ func (n *mockAgent) copyFile(ctx context.Context, src, dst string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// addSwap is the Noop agent setup swap. It does nothing.
|
||||||
|
func (n *mockAgent) addSwap(ctx context.Context, PCIPath vcTypes.PciPath) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (n *mockAgent) markDead(ctx context.Context) {
|
func (n *mockAgent) markDead(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,6 +75,14 @@ func (p PciPath) IsNil() bool {
|
|||||||
return p.slots == nil
|
return p.slots == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p PciPath) ToArray() []uint32 {
|
||||||
|
var slots []uint32
|
||||||
|
for _, slot := range p.slots {
|
||||||
|
slots = append(slots, uint32(slot.slot))
|
||||||
|
}
|
||||||
|
return slots
|
||||||
|
}
|
||||||
|
|
||||||
func PciPathFromString(s string) (PciPath, error) {
|
func PciPathFromString(s string) (PciPath, error) {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return PciPath{}, nil
|
return PciPath{}, nil
|
||||||
|
@ -1232,7 +1232,9 @@ func (q *qemu) hotplugAddBlockDevice(ctx context.Context, drive *config.BlockDri
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if q.config.BlockDeviceCacheSet {
|
if drive.Swap {
|
||||||
|
err = q.qmpMonitorCh.qmp.ExecuteBlockdevAddWithCache(q.qmpMonitorCh.ctx, drive.File, drive.ID, false, false, false)
|
||||||
|
} else if q.config.BlockDeviceCacheSet {
|
||||||
err = q.qmpMonitorCh.qmp.ExecuteBlockdevAddWithCache(q.qmpMonitorCh.ctx, drive.File, drive.ID, q.config.BlockDeviceCacheDirect, q.config.BlockDeviceCacheNoflush, drive.ReadOnly)
|
err = q.qmpMonitorCh.qmp.ExecuteBlockdevAddWithCache(q.qmpMonitorCh.ctx, drive.File, drive.ID, q.config.BlockDeviceCacheDirect, q.config.BlockDeviceCacheNoflush, drive.ReadOnly)
|
||||||
} else {
|
} else {
|
||||||
err = q.qmpMonitorCh.qmp.ExecuteBlockdevAdd(q.qmpMonitorCh.ctx, drive.File, drive.ID, drive.ReadOnly)
|
err = q.qmpMonitorCh.qmp.ExecuteBlockdevAdd(q.qmpMonitorCh.ctx, drive.File, drive.ID, drive.ReadOnly)
|
||||||
@ -1248,25 +1250,8 @@ func (q *qemu) hotplugAddBlockDevice(ctx context.Context, drive *config.BlockDri
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case q.config.BlockDeviceDriver == config.VirtioBlockCCW:
|
case drive.Swap:
|
||||||
driver := "virtio-blk-ccw"
|
fallthrough
|
||||||
|
|
||||||
addr, bridge, err := q.arch.addDeviceToBridge(ctx, drive.ID, types.CCW)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
var devNoHotplug string
|
|
||||||
devNoHotplug, err = bridge.AddressFormatCCW(addr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
drive.DevNo, err = bridge.AddressFormatCCWForVirtServer(addr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err = q.qmpMonitorCh.qmp.ExecuteDeviceAdd(q.qmpMonitorCh.ctx, drive.ID, devID, driver, devNoHotplug, "", true, false); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case q.config.BlockDeviceDriver == config.VirtioBlock:
|
case q.config.BlockDeviceDriver == config.VirtioBlock:
|
||||||
driver := "virtio-blk-pci"
|
driver := "virtio-blk-pci"
|
||||||
addr, bridge, err := q.arch.addDeviceToBridge(ctx, drive.ID, types.PCI)
|
addr, bridge, err := q.arch.addDeviceToBridge(ctx, drive.ID, types.PCI)
|
||||||
@ -1296,6 +1281,25 @@ func (q *qemu) hotplugAddBlockDevice(ctx context.Context, drive *config.BlockDri
|
|||||||
if err = q.qmpMonitorCh.qmp.ExecutePCIDeviceAdd(q.qmpMonitorCh.ctx, drive.ID, devID, driver, addr, bridge.ID, romFile, 0, true, defaultDisableModern); err != nil {
|
if err = q.qmpMonitorCh.qmp.ExecutePCIDeviceAdd(q.qmpMonitorCh.ctx, drive.ID, devID, driver, addr, bridge.ID, romFile, 0, true, defaultDisableModern); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
case q.config.BlockDeviceDriver == config.VirtioBlockCCW:
|
||||||
|
driver := "virtio-blk-ccw"
|
||||||
|
|
||||||
|
addr, bridge, err := q.arch.addDeviceToBridge(ctx, drive.ID, types.CCW)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
var devNoHotplug string
|
||||||
|
devNoHotplug, err = bridge.AddressFormatCCW(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
drive.DevNo, err = bridge.AddressFormatCCWForVirtServer(addr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err = q.qmpMonitorCh.qmp.ExecuteDeviceAdd(q.qmpMonitorCh.ctx, drive.ID, devID, driver, devNoHotplug, "", true, false); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
case q.config.BlockDeviceDriver == config.VirtioSCSI:
|
case q.config.BlockDeviceDriver == config.VirtioSCSI:
|
||||||
driver := "scsi-hd"
|
driver := "scsi-hd"
|
||||||
|
|
||||||
@ -1369,7 +1373,7 @@ func (q *qemu) hotplugBlockDevice(ctx context.Context, drive *config.BlockDrive,
|
|||||||
if op == addDevice {
|
if op == addDevice {
|
||||||
return q.hotplugAddBlockDevice(ctx, drive, op, devID)
|
return q.hotplugAddBlockDevice(ctx, drive, op, devID)
|
||||||
}
|
}
|
||||||
if q.config.BlockDeviceDriver == config.VirtioBlock {
|
if !drive.Swap && q.config.BlockDeviceDriver == config.VirtioBlock {
|
||||||
if err := q.arch.removeDeviceFromBridge(drive.ID); err != nil {
|
if err := q.arch.removeDeviceFromBridge(drive.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"syscall"
|
"syscall"
|
||||||
@ -996,6 +998,87 @@ func (cw *consoleWatcher) stop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Sandbox) addSwap(ctx context.Context, swapID string, size int64) (*config.BlockDrive, error) {
|
||||||
|
swapFile := filepath.Join(getSandboxPath(s.id), swapID)
|
||||||
|
|
||||||
|
swapFD, err := os.OpenFile(swapFile, os.O_CREATE, 0600)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("creat swapfile %s fail %s", swapFile, err.Error())
|
||||||
|
s.Logger().WithError(err).Error("addSwap")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
swapFD.Close()
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
os.Remove(swapFile)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Check the size
|
||||||
|
pagesize := os.Getpagesize()
|
||||||
|
// mkswap refuses areas smaller than 10 pages.
|
||||||
|
size = int64(math.Max(float64(size), float64(pagesize*10)))
|
||||||
|
// Swapfile need a page to store the metadata
|
||||||
|
size += int64(pagesize)
|
||||||
|
|
||||||
|
err = os.Truncate(swapFile, size)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("truncate swapfile %s fail %s", swapFile, err.Error())
|
||||||
|
s.Logger().WithError(err).Error("addSwap")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = exec.CommandContext(ctx, "/sbin/mkswap", swapFile).Run()
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("mkswap swapfile %s fail %s", swapFile, err.Error())
|
||||||
|
s.Logger().WithError(err).Error("addSwap")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
blockDevice := &config.BlockDrive{
|
||||||
|
File: swapFile,
|
||||||
|
Format: "raw",
|
||||||
|
ID: swapID,
|
||||||
|
Swap: true,
|
||||||
|
}
|
||||||
|
_, err = s.hypervisor.hotplugAddDevice(ctx, blockDevice, blockDev)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("add swapfile %s device to VM fail %s", swapFile, err.Error())
|
||||||
|
s.Logger().WithError(err).Error("addSwap")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
_, e := s.hypervisor.hotplugRemoveDevice(ctx, blockDevice, blockDev)
|
||||||
|
if e != nil {
|
||||||
|
s.Logger().Errorf("remove swapfile %s to VM fail %s", swapFile, e.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
err = s.agent.addSwap(ctx, blockDevice.PCIPath)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("agent add swapfile %s PCIPath %+v to VM fail %s", swapFile, blockDevice.PCIPath, err.Error())
|
||||||
|
s.Logger().WithError(err).Error("addSwap")
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Logger().Infof("add swapfile %s size %d PCIPath %+v to VM success", swapFile, size, blockDevice.PCIPath)
|
||||||
|
|
||||||
|
return blockDevice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Sandbox) removeSwap(ctx context.Context, blockDevice *config.BlockDrive) error {
|
||||||
|
err := os.Remove(blockDevice.File)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("remove swapfile %s fail %s", blockDevice.File, err.Error())
|
||||||
|
s.Logger().WithError(err).Error("removeSwap")
|
||||||
|
} else {
|
||||||
|
s.Logger().Infof("remove swapfile %s success", blockDevice.File)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// startVM starts the VM.
|
// startVM starts the VM.
|
||||||
func (s *Sandbox) startVM(ctx context.Context) (err error) {
|
func (s *Sandbox) startVM(ctx context.Context) (err error) {
|
||||||
span, ctx := katatrace.Trace(ctx, s.Logger(), "startVM", s.tracingTags())
|
span, ctx := katatrace.Trace(ctx, s.Logger(), "startVM", s.tracingTags())
|
||||||
@ -1074,6 +1157,14 @@ func (s *Sandbox) startVM(ctx context.Context) (err error) {
|
|||||||
|
|
||||||
s.Logger().Info("Agent started in the sandbox")
|
s.Logger().Info("Agent started in the sandbox")
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err != nil {
|
||||||
|
if e := s.agent.stopSandbox(ctx, s); e != nil {
|
||||||
|
s.Logger().WithError(e).WithField("sandboxid", s.id).Warning("Agent did not stop sandbox")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1846,6 +1937,7 @@ func (s *Sandbox) updateResources(ctx context.Context) error {
|
|||||||
if err := s.agent.onlineCPUMem(ctx, 0, false); err != nil {
|
if err := s.agent.onlineCPUMem(ctx, 0, false); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user