scsi

package
v0.12.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 2, 2023 License: MIT Imports: 14 Imported by: 0

README

Package scsi

This README intends to act as internal developer guidance for the package. Guidance to consumers of the package should be included as Go doc comments in the package code itself.

Terminology

We will generally use the term "attachment" to refer to a SCSI device being made available to a VM, so that it is visible to the guest OS. We will generally use the term "mount" to refer to a SCSI device being mounted to a specific path, and with specific settings (e.g. encryption) inside a guest OS. Note that in Manager, "Mount" refers to the overall action of attaching and mounting in the guest OS. If we come up with a better name for this aggregate action, we should rename this.

Principles

The general principle of this package is that attachments and mounts of SCSI devices are completely separate operations, so they should be tracked and handled separately. Out of a desire for convenience to the client of the package, we provide a Manager type which handles them together, but under the hood attach/mount are managed by separate components.

Architecture

The package is composed of several layers of components:

Top level, the Manager type

Manager is an exported type which acts as the primary entrypoint from external consumers. It provides several methods which can be used to attach+mount a SCSI device to a VM.

Add* methods on Manager return a Mount, which serves two purposes:

  • Provides information to the caller on the attachment/mount, such as controller, LUN, and guest OS mount path.
  • Tracks the resources associated with the SCSI attachment/mount, and provides a Release method to clean them up.

Manager itself is a fairly thin layer on top of two unexported types: attachManager and mountManager.

Mid level, the attachManager and mountManager types

These types are responsible for actually managing the state of attachments and mounts on the VM.

attachManager:

  • Tracks what SCSI devices are currently attached, along with what controllers/LUNs are used.
  • When it is asked to attach a new SCSI device, it will first check if the attachment already exists, and increase its refcount if so. If not, it will allocate a new controller/LUN slot for the attachment, and then call the attacher to actually carry out the attach operation.
  • When it is asked to detach a SCSI device, it first uses the unplugger to carry out any guest-side remove actions, and then uses the attacher to remove the attachment from the VM.
  • Tracks refcount on any attached SCSI devices, so that they are not detached until there has been a detach request for each matching attach request.

mountManager:

  • Tracks current SCSI devices mounted in the guest OS, and what mount options were applied.
  • When it is asked to mount a new SCSI device, it will first check if the mount (with same options) already exists, and increase its refcount if so. If not, it will track the new mount, and call the mounter to actually carry out the guest mount operation.
  • Tracks refcount on any mounted SCSI devices, so that they are not unmounted until there has been an unmount request for each matching mount request.
Low level, the backend types

There are three interfaces that provide the low-level implementation to attachManager and mountManager. They are attacher, mounter and unplugger.

  • attacher provides the host-side operations of attach/detach of SCSI devices to a VM.
  • mounter provides the guest-side operations of mount/unmount of SCSI devices inside the guest OS.
  • unplugger provides the guest-side operation of safely removing a SCSI device, before it is detached from the VM.

To improve clarity, these three interfaces are grouped into the external interfaces HostBackend, consisting of attacher, and GuestBackend, consisting of mounter and unplugger. There are also corresponding implementations of the external interfaces for HCS and direct bridge connections.

The client passes in implementations of HostBackend and GuestBackend when instantiating the Manager.

Future work

Some thoughts on how this package could evolve in the future. This is intended to inform the direction of future changes as we work in the package.

  • The mountManager actually has very little to do with SCSI (at least for Linux containers, Windows may be more complicated/limited). In fact, the only SCSI-specific part of mounting in the guest is pretty much just identifying a block device based on the SCSI controller/LUN. It would be interesting to separate out the SCSI controller/LUN -> block device mapping part from the rest of the guest mount operation. This could enable us to e.g. use the same "mount" operation for SCSI and VPMEM, since they both present a block device.
  • We should not be silently and automatically scanning a SCSI device for verity info. Determining what (if any) verity info to use for a device should probably be determined by the client of the package.
  • Likewise, ACLing disks so a VM can access them should likely fall outside the purview of the package as well.
  • The implemnentations of HostBackend and GuestBackend should probably live outisde the package. There is no real reason for them to be defined in here, other than not having a clear place to put them instead right now. They would make more sense to live close to the concrete implementation they depend upon. For instance, bridgeGuestBackend might make sense to be near the GCS bridge connection implementation.
  • For unmounting, it is awkward to have to re-pass the mount configuration to the guest again. There is not a clear course of action if this differs from the original mount configuration, nor is this checked anywhere. It would be good for the guest to instead track what cleanup is needed for each mount point, and then we don't need to pass anything except the mount point in the unmount request.

Documentation

Overview

Package scsi handles SCSI device attachment and mounting for VMs. The primary entrypoint to the package is Manager.

The backend implementation of working with disks for a given VM is provided by the interfaces [Attacher], [Mounter], and [Unplugger].

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoAvailableLocation indicates that a new SCSI attachment failed because
	// no new slots were available.
	ErrNoAvailableLocation = errors.New("no available location")
	// ErrNotInitialized is returned when a method is invoked on a nil [Manager].
	ErrNotInitialized = errors.New("SCSI manager not initialized")
	// ErrAlreadyReleased is returned when [Mount.Release] is called on a Mount
	// that had already been released.
	ErrAlreadyReleased = errors.New("mount was already released")
)

Functions

This section is empty.

Types

type GuestBackend

type GuestBackend interface {
	// contains filtered or unexported methods
}

GuestBackend provides the guest-side operations needed to manage SCSI, such as mount/unmount and unplug.

func NewBridgeGuestBackend

func NewBridgeGuestBackend(gc *gcs.GuestConnection, osType string) GuestBackend

NewBridgeGuestBackend provides a GuestBackend using a gcs.GuestConnection.

osType should be either "windows" or "linux".

func NewHCSGuestBackend

func NewHCSGuestBackend(system *hcs.System, osType string) GuestBackend

NewHCSGuestBackend provides a GuestBackend using a hcs.System.

osType should be either "windows" or "linux".

type HostBackend

type HostBackend interface {
	// contains filtered or unexported methods
}

HostBackend provides the host-side operations needed to manage SCSI, such as attach/detach.

func NewHCSHostBackend

func NewHCSHostBackend(system *hcs.System) HostBackend

NewHCSHostBackend provides a HostBackend using a hcs.System.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager is the primary entrypoint for managing SCSI devices on a VM. It tracks the state of what devices have been attached to the VM, and mounted inside the guest OS.

func NewManager

func NewManager(
	hb HostBackend,
	gb GuestBackend,
	numControllers int,
	numLUNsPerController int,
	guestMountFmt string,
	reservedSlots []Slot,
) (*Manager, error)

NewManager creates a new Manager using the provided host and guest backends, as well as other configuration parameters.

guestMountFmt is the format string to use for mounts of SCSI devices in the guest OS. It should have a single %d format parameter.

reservedSlots indicates which SCSI slots to treat as already used. They will not be handed out again by the Manager.

func (*Manager) AddExtensibleVirtualDisk

func (m *Manager) AddExtensibleVirtualDisk(
	ctx context.Context,
	hostPath string,
	readOnly bool,
	mc *MountConfig,
) (*Mount, error)

AddExtensibleVirtualDisk attaches and mounts an extensible virtual disk (EVD) to the VM. EVDs are made available by special drivers on the host which interact with the Hyper-V synthetic SCSI stack. If the same physical disk has already been attached to the VM, the existing attachment will be reused. If the same physical disk has already been mounted in the guest OS with the same MountConfig, the same mount will be reused.

hostPath must adhere to the format "evd://<evdType>/<evdMountPath>".

mc determines the settings to apply on the guest OS mount. If it is nil, no guest OS mount is performed.

func (*Manager) AddPhysicalDisk

func (m *Manager) AddPhysicalDisk(
	ctx context.Context,
	hostPath string,
	readOnly bool,
	vmID string,
	mc *MountConfig,
) (*Mount, error)

AddPhysicalDisk attaches and mounts a physical disk on the host to the VM. If the same physical disk has already been attached to the VM, the existing attachment will be reused. If the same physical disk has already been mounted in the guest OS with the same MountConfig, the same mount will be reused.

If vmID is non-empty an ACL will be added to the disk so that the specified VHD can access it.

mc determines the settings to apply on the guest OS mount. If it is nil, no guest OS mount is performed.

func (*Manager) AddVirtualDisk

func (m *Manager) AddVirtualDisk(
	ctx context.Context,
	hostPath string,
	readOnly bool,
	vmID string,
	mc *MountConfig,
) (*Mount, error)

AddVirtualDisk attaches and mounts a VHD on the host to the VM. If the same VHD has already been attached to the VM, the existing attachment will be reused. If the same VHD has already been mounted in the guest OS with the same MountConfig, the same mount will be reused.

If vmID is non-empty an ACL will be added to the VHD so that the specified VHD can access it.

mc determines the settings to apply on the guest OS mount. If it is nil, no guest OS mount is performed.

type Mount

type Mount struct {
	// contains filtered or unexported fields
}

Mount represents a SCSI device that has been attached to a VM, and potentially also mounted into the guest OS.

func (*Mount) Controller

func (m *Mount) Controller() uint

Controller returns the controller number that the SCSI device is attached to.

func (*Mount) GuestPath

func (m *Mount) GuestPath() string

GuestPath returns the path inside the guest OS where the SCSI device was mounted. Will return an empty string if no guest mount was performed.

func (*Mount) LUN

func (m *Mount) LUN() uint

LUN returns the LUN number that the SCSI device is attached to.

func (*Mount) Release

func (m *Mount) Release(ctx context.Context) (err error)

Release releases the SCSI mount. Refcount tracking is used in case multiple instances of the same attachment or mount are used. If the refcount for the guest OS mount reaches 0, the guest OS mount is removed. If the refcount for the SCSI attachment reaches 0, the SCSI attachment is removed.

type MountConfig

type MountConfig struct {
	// Partition is the target partition index on a partitioned device to
	// mount. Partitions are 1-based indexed.
	// This is only supported for LCOW.
	Partition uint64
	// Encrypted indicates if we should encrypt the device with dm-crypt.
	// This is only supported for LCOW.
	Encrypted bool
	// Options are options such as propagation options, flags, or data to
	// pass to the mount call.
	// This is only supported for LCOW.
	Options []string
	// EnsureFilesystem indicates to format the mount as `Filesystem`
	// if it is not already formatted with that fs type.
	// This is only supported for LCOW.
	EnsureFilesystem bool
	// Filesystem is the target filesystem that a device will be
	// mounted as.
	// This is only supported for LCOW.
	Filesystem string
}

MountConfig specifies the options to apply for mounting a SCSI device in the guest OS.

type Slot

type Slot struct {
	Controller uint
	LUN        uint
}

Slot represents a single SCSI slot, consisting of a controller and LUN.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL