mirror of
https://github.com/aljazceru/kata-containers.git
synced 2026-01-11 10:24:22 +01:00
Rather than have device package depend on persist, let's define the (almost duplicate) structures within device itself, and have the Kata Container's persist pkg import these. This'll help avoid unecessary dependencies within our core packages. Signed-off-by: Eric Ernst <eric_ernst@apple.com>
210 lines
5.5 KiB
Go
210 lines
5.5 KiB
Go
// Copyright (c) 2017-2018 Intel Corporation
|
|
// Copyright (c) 2018-2019 Huawei Corporation
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
|
|
package drivers
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
|
|
"github.com/kata-containers/kata-containers/src/runtime/pkg/device/api"
|
|
"github.com/kata-containers/kata-containers/src/runtime/pkg/device/config"
|
|
"github.com/kata-containers/kata-containers/src/runtime/virtcontainers/utils"
|
|
)
|
|
|
|
const maxDevIDSize = 31
|
|
|
|
// BlockDevice refers to a block storage device implementation.
|
|
type BlockDevice struct {
|
|
*GenericDevice
|
|
BlockDrive *config.BlockDrive
|
|
}
|
|
|
|
// NewBlockDevice creates a new block device based on DeviceInfo
|
|
func NewBlockDevice(devInfo *config.DeviceInfo) *BlockDevice {
|
|
return &BlockDevice{
|
|
GenericDevice: &GenericDevice{
|
|
ID: devInfo.ID,
|
|
DeviceInfo: devInfo,
|
|
},
|
|
}
|
|
}
|
|
|
|
// Attach is standard interface of api.Device, it's used to add device to some
|
|
// DeviceReceiver
|
|
func (device *BlockDevice) Attach(ctx context.Context, devReceiver api.DeviceReceiver) (err error) {
|
|
skip, err := device.bumpAttachCount(true)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if skip {
|
|
return nil
|
|
}
|
|
|
|
// Increment the block index for the sandbox. This is used to determine the name
|
|
// for the block device in the case where the block device is used as container
|
|
// rootfs and the predicted block device name needs to be provided to the agent.
|
|
index, err := devReceiver.GetAndSetSandboxBlockIndex()
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
devReceiver.UnsetSandboxBlockIndex(index)
|
|
device.bumpAttachCount(false)
|
|
}
|
|
}()
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
drive := &config.BlockDrive{
|
|
File: device.DeviceInfo.HostPath,
|
|
Format: "raw",
|
|
ID: utils.MakeNameID("drive", device.DeviceInfo.ID, maxDevIDSize),
|
|
Index: index,
|
|
Pmem: device.DeviceInfo.Pmem,
|
|
ReadOnly: device.DeviceInfo.ReadOnly,
|
|
}
|
|
|
|
if fs, ok := device.DeviceInfo.DriverOptions[config.FsTypeOpt]; ok {
|
|
drive.Format = fs
|
|
}
|
|
|
|
customOptions := device.DeviceInfo.DriverOptions
|
|
if customOptions == nil ||
|
|
customOptions[config.BlockDriverOpt] == config.VirtioSCSI {
|
|
// User has not chosen a specific block device type
|
|
// Default to SCSI
|
|
scsiAddr, err := utils.GetSCSIAddress(index)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
drive.SCSIAddr = scsiAddr
|
|
} else if customOptions[config.BlockDriverOpt] != config.Nvdimm {
|
|
var globalIdx int
|
|
|
|
switch customOptions[config.BlockDriverOpt] {
|
|
case config.VirtioBlock:
|
|
globalIdx = index
|
|
case config.VirtioBlockCCW:
|
|
globalIdx = index
|
|
case config.VirtioMmio:
|
|
//With firecracker the rootfs for the VM itself
|
|
//sits at /dev/vda and consumes the first index.
|
|
//Longer term block based VM rootfs should be added
|
|
//as a regular block device which eliminates the
|
|
//offset.
|
|
//https://github.com/kata-containers/runtime/issues/1061
|
|
globalIdx = index + 1
|
|
}
|
|
|
|
driveName, err := utils.GetVirtDriveName(globalIdx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
drive.VirtPath = filepath.Join("/dev", driveName)
|
|
}
|
|
|
|
deviceLogger().WithField("device", device.DeviceInfo.HostPath).WithField("VirtPath", drive.VirtPath).Infof("Attaching %s device", customOptions[config.BlockDriverOpt])
|
|
device.BlockDrive = drive
|
|
if err = devReceiver.HotplugAddDevice(ctx, device, config.DeviceBlock); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// Detach is standard interface of api.Device, it's used to remove device from some
|
|
// DeviceReceiver
|
|
func (device *BlockDevice) Detach(ctx context.Context, devReceiver api.DeviceReceiver) error {
|
|
skip, err := device.bumpAttachCount(false)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if skip {
|
|
return nil
|
|
}
|
|
|
|
defer func() {
|
|
if err != nil {
|
|
device.bumpAttachCount(true)
|
|
} else {
|
|
devReceiver.UnsetSandboxBlockIndex(device.BlockDrive.Index)
|
|
}
|
|
}()
|
|
|
|
deviceLogger().WithField("device", device.DeviceInfo.HostPath).Info("Unplugging block device")
|
|
|
|
if err = devReceiver.HotplugRemoveDevice(ctx, device, config.DeviceBlock); err != nil {
|
|
deviceLogger().WithError(err).Error("Failed to unplug block device")
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeviceType is standard interface of api.Device, it returns device type
|
|
func (device *BlockDevice) DeviceType() config.DeviceType {
|
|
return config.DeviceBlock
|
|
}
|
|
|
|
// GetDeviceInfo returns device information used for creating
|
|
func (device *BlockDevice) GetDeviceInfo() interface{} {
|
|
return device.BlockDrive
|
|
}
|
|
|
|
// Save converts Device to DeviceState
|
|
func (device *BlockDevice) Save() config.DeviceState {
|
|
ds := device.GenericDevice.Save()
|
|
ds.Type = string(device.DeviceType())
|
|
|
|
drive := device.BlockDrive
|
|
if drive != nil {
|
|
ds.BlockDrive = &config.BlockDriveState{
|
|
File: drive.File,
|
|
Format: drive.Format,
|
|
ID: drive.ID,
|
|
Index: drive.Index,
|
|
MmioAddr: drive.MmioAddr,
|
|
PCIPath: drive.PCIPath,
|
|
SCSIAddr: drive.SCSIAddr,
|
|
NvdimmID: drive.NvdimmID,
|
|
VirtPath: drive.VirtPath,
|
|
DevNo: drive.DevNo,
|
|
Pmem: drive.Pmem,
|
|
}
|
|
}
|
|
return ds
|
|
}
|
|
|
|
// Load loads DeviceState and converts it to specific device
|
|
func (device *BlockDevice) Load(ds config.DeviceState) {
|
|
device.GenericDevice = &GenericDevice{}
|
|
device.GenericDevice.Load(ds)
|
|
|
|
bd := ds.BlockDrive
|
|
if bd == nil {
|
|
return
|
|
}
|
|
device.BlockDrive = &config.BlockDrive{
|
|
File: bd.File,
|
|
Format: bd.Format,
|
|
ID: bd.ID,
|
|
Index: bd.Index,
|
|
MmioAddr: bd.MmioAddr,
|
|
PCIPath: bd.PCIPath,
|
|
SCSIAddr: bd.SCSIAddr,
|
|
NvdimmID: bd.NvdimmID,
|
|
VirtPath: bd.VirtPath,
|
|
DevNo: bd.DevNo,
|
|
Pmem: bd.Pmem,
|
|
}
|
|
}
|
|
|
|
// It should implement GetAttachCount() and DeviceID() as api.Device implementation
|
|
// here it shares function from *GenericDevice so we don't need duplicate codes
|