github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/device/drivers/generic.go (about)

     1  // Copyright (c) 2017-2018 Intel Corporation
     2  // Copyright (c) 2018-2019 Huawei Corporation
     3  //
     4  // SPDX-License-Identifier: Apache-2.0
     5  //
     6  
     7  package drivers
     8  
     9  import (
    10  	"fmt"
    11  
    12  	"github.com/kata-containers/runtime/virtcontainers/device/api"
    13  	"github.com/kata-containers/runtime/virtcontainers/device/config"
    14  	persistapi "github.com/kata-containers/runtime/virtcontainers/persist/api"
    15  )
    16  
    17  // GenericDevice refers to a device that is neither a VFIO device, block device or VhostUserDevice.
    18  type GenericDevice struct {
    19  	ID         string
    20  	DeviceInfo *config.DeviceInfo
    21  
    22  	RefCount    uint
    23  	AttachCount uint
    24  }
    25  
    26  // NewGenericDevice creates a new GenericDevice
    27  func NewGenericDevice(devInfo *config.DeviceInfo) *GenericDevice {
    28  	return &GenericDevice{
    29  		ID:         devInfo.ID,
    30  		DeviceInfo: devInfo,
    31  	}
    32  }
    33  
    34  // Attach is standard interface of api.Device
    35  func (device *GenericDevice) Attach(devReceiver api.DeviceReceiver) error {
    36  	_, err := device.bumpAttachCount(true)
    37  	return err
    38  }
    39  
    40  // Detach is standard interface of api.Device
    41  func (device *GenericDevice) Detach(devReceiver api.DeviceReceiver) error {
    42  	_, err := device.bumpAttachCount(false)
    43  	return err
    44  }
    45  
    46  // DeviceType is standard interface of api.Device, it returns device type
    47  func (device *GenericDevice) DeviceType() config.DeviceType {
    48  	return config.DeviceGeneric
    49  }
    50  
    51  // GetDeviceInfo returns device information used for creating
    52  func (device *GenericDevice) GetDeviceInfo() interface{} {
    53  	return device.DeviceInfo
    54  }
    55  
    56  // GetAttachCount returns how many times the device has been attached
    57  func (device *GenericDevice) GetAttachCount() uint {
    58  	return device.AttachCount
    59  }
    60  
    61  // DeviceID returns device ID
    62  func (device *GenericDevice) DeviceID() string {
    63  	return device.ID
    64  }
    65  
    66  // GetMajorMinor returns device major and minor numbers
    67  func (device *GenericDevice) GetMajorMinor() (int64, int64) {
    68  	return device.DeviceInfo.Major, device.DeviceInfo.Minor
    69  }
    70  
    71  // GetHostPath return the device path in the host
    72  func (device *GenericDevice) GetHostPath() string {
    73  	if device.DeviceInfo != nil {
    74  		return device.DeviceInfo.HostPath
    75  	}
    76  	return ""
    77  }
    78  
    79  // Reference adds one reference to device
    80  func (device *GenericDevice) Reference() uint {
    81  	if device.RefCount != intMax {
    82  		device.RefCount++
    83  	}
    84  	return device.RefCount
    85  }
    86  
    87  // Dereference remove one reference from device
    88  func (device *GenericDevice) Dereference() uint {
    89  	if device.RefCount != 0 {
    90  		device.RefCount--
    91  	}
    92  	return device.RefCount
    93  }
    94  
    95  // bumpAttachCount is used to add/minus attach count for a device
    96  // * attach bool: true means attach, false means detach
    97  // return values:
    98  // * skip bool: no need to do real attach/detach, skip following actions.
    99  // * err error: error while do attach count bump
   100  func (device *GenericDevice) bumpAttachCount(attach bool) (skip bool, err error) {
   101  	if attach { // attach use case
   102  		switch device.AttachCount {
   103  		case 0:
   104  			// do real attach
   105  			device.AttachCount++
   106  			return false, nil
   107  		case intMax:
   108  			return true, fmt.Errorf("device was attached too many times")
   109  		default:
   110  			device.AttachCount++
   111  			return true, nil
   112  		}
   113  	} else { // detach use case
   114  		switch device.AttachCount {
   115  		case 0:
   116  			return true, fmt.Errorf("detaching a device that wasn't attached")
   117  		case 1:
   118  			// do real work
   119  			device.AttachCount--
   120  			return false, nil
   121  		default:
   122  			device.AttachCount--
   123  			return true, nil
   124  		}
   125  	}
   126  }
   127  
   128  // Save converts Device to DeviceState
   129  func (device *GenericDevice) Save() persistapi.DeviceState {
   130  	dss := persistapi.DeviceState{
   131  		ID:          device.ID,
   132  		Type:        string(device.DeviceType()),
   133  		RefCount:    device.RefCount,
   134  		AttachCount: device.AttachCount,
   135  	}
   136  
   137  	info := device.DeviceInfo
   138  	if info != nil {
   139  		dss.DevType = info.DevType
   140  		dss.Major = info.Major
   141  		dss.Minor = info.Minor
   142  		dss.DriverOptions = info.DriverOptions
   143  		dss.ColdPlug = info.ColdPlug
   144  	}
   145  	return dss
   146  }
   147  
   148  // Load loads DeviceState and converts it to specific device
   149  func (device *GenericDevice) Load(ds persistapi.DeviceState) {
   150  	device.ID = ds.ID
   151  	device.RefCount = ds.RefCount
   152  	device.AttachCount = ds.AttachCount
   153  
   154  	device.DeviceInfo = &config.DeviceInfo{
   155  		DevType:       ds.DevType,
   156  		Major:         ds.Major,
   157  		Minor:         ds.Minor,
   158  		DriverOptions: ds.DriverOptions,
   159  		ColdPlug:      ds.ColdPlug,
   160  	}
   161  }