Files
kata-containers/virtcontainers/device/drivers/generic.go
Wei Zhang affd6e3216 devices: add reference count for devices.
Fixes #635

Remove `Hotplugged bool` field from device and add two new fields
instead:
* `RefCount`: how many references to this device. One device can be
referenced(`NewDevice()`) many times by same/different container(s),
two devices are regarded identical if they have same hostPath
* `AttachCount`: how many times this device has been attached. A device
can only be hotplugged once to the qemu, every new Attach command will
add the AttachCount, and real `Detach` will be done only when
`AttachCount == 0`

Signed-off-by: Wei Zhang <zhangwei555@huawei.com>
2018-08-31 09:53:01 +08:00

130 lines
3.1 KiB
Go

// Copyright (c) 2017-2018 Intel Corporation
// Copyright (c) 2018 Huawei Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
package drivers
import (
"fmt"
"github.com/kata-containers/runtime/virtcontainers/device/api"
"github.com/kata-containers/runtime/virtcontainers/device/config"
)
// GenericDevice refers to a device that is neither a VFIO device or block device.
type GenericDevice struct {
ID string
DeviceInfo *config.DeviceInfo
RefCount uint
AttachCount uint
}
// NewGenericDevice creates a new GenericDevice
func NewGenericDevice(devInfo *config.DeviceInfo) *GenericDevice {
return &GenericDevice{
ID: devInfo.ID,
DeviceInfo: devInfo,
}
}
// Attach is standard interface of api.Device
func (device *GenericDevice) Attach(devReceiver api.DeviceReceiver) error {
skip, err := device.bumpAttachCount(true)
if err != nil {
return err
}
if skip {
return nil
}
device.AttachCount = 1
return nil
}
// Detach is standard interface of api.Device
func (device *GenericDevice) Detach(devReceiver api.DeviceReceiver) error {
skip, err := device.bumpAttachCount(false)
if err != nil {
return err
}
if skip {
return nil
}
device.AttachCount = 0
return nil
}
// DeviceType is standard interface of api.Device, it returns device type
func (device *GenericDevice) DeviceType() config.DeviceType {
return config.DeviceGeneric
}
// GetDeviceInfo returns device information used for creating
func (device *GenericDevice) GetDeviceInfo() interface{} {
return device.DeviceInfo
}
// GetAttachCount returns how many times the device has been attached
func (device *GenericDevice) GetAttachCount() uint {
return device.AttachCount
}
// DeviceID returns device ID
func (device *GenericDevice) DeviceID() string {
return device.ID
}
// GetMajorMinor returns device major and minor numbers
func (device *GenericDevice) GetMajorMinor() (int64, int64) {
return device.DeviceInfo.Major, device.DeviceInfo.Minor
}
// Reference adds one reference to device
func (device *GenericDevice) Reference() uint {
if device.RefCount != intMax {
device.RefCount++
}
return device.RefCount
}
// Dereference remove one reference from device
func (device *GenericDevice) Dereference() uint {
if device.RefCount != 0 {
device.RefCount--
}
return device.RefCount
}
// bumpAttachCount is used to add/minus attach count for a device
// * attach bool: true means attach, false means detach
// return values:
// * skip bool: no need to do real attach/detach, skip following actions.
// * err error: error while do attach count bump
func (device *GenericDevice) bumpAttachCount(attach bool) (skip bool, err error) {
if attach { // attach use case
switch device.AttachCount {
case 0:
// do real attach
return false, nil
case intMax:
return true, fmt.Errorf("device was attached too many times")
default:
device.AttachCount++
return true, nil
}
} else { // detach use case
switch device.AttachCount {
case 0:
return true, fmt.Errorf("detaching a device that wasn't attached")
case 1:
// do real work
return false, nil
default:
device.AttachCount--
return true, nil
}
}
}