Skip to content

Commit

Permalink
Add lcow-partitioned-layer mount type
Browse files Browse the repository at this point in the history
Adds support for a new type of LCOW mount that can use individual disk
partitions for each read-only layer. This change adds the work to parse
the new layer type and pass it through the shim, as well as the support
to the shim-side SCSI package to send the partition index in the guest
request.

This change does not add the GCS-side work to actually mount the
specified partition. That will come in a future change.

This change also does not handle formatting the scratch disk. It it
desired to be able to format it on the fly when creating the container,
but that will also come in a future change.

Signed-off-by: Kevin Parsons <kevpar@microsoft.com>
  • Loading branch information
kevpar committed May 3, 2023
1 parent dbe9fb1 commit f0563c1
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 11 deletions.
23 changes: 23 additions & 0 deletions cmd/containerd-shim-runhcs-v1/rootfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,29 @@ func getLCOWLayers(rootfs []*types.Mount, layerFolders []string) (*layers.LCOWLa
return nil, err
}
return legacyLayer(scratchLayer, parentLayers), nil
case "lcow-partitioned-layer":
var (
scratchPath string
layerData []struct {
Path string
Partition uint64
}
)
for _, opt := range m.Options {
if optPrefix := "scratch="; strings.HasPrefix(opt, optPrefix) {
scratchPath = strings.TrimPrefix(opt, optPrefix)
} else if optPrefix := "parent-partitioned-layers="; strings.HasPrefix(opt, optPrefix) {
layerJSON := strings.TrimPrefix(opt, optPrefix)
if err := json.Unmarshal([]byte(layerJSON), &layerData); err != nil {
return nil, err
}
}
}
roLayers := make([]*layers.LCOWLayer, 0, len(layerData))
for _, layer := range layerData {
roLayers = append(roLayers, &layers.LCOWLayer{VHDPath: layer.Path, Partition: layer.Partition})
}
return &layers.LCOWLayers{Layers: roLayers, ScratchVHDPath: scratchPath}, nil
default:
return nil, fmt.Errorf("unrecognized rootfs mount type: %s", m.Type)
}
Expand Down
26 changes: 15 additions & 11 deletions internal/layers/layers.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ import (
)

type LCOWLayer struct {
VHDPath string
VHDPath string
Partition uint64
}

// Defines a set of LCOW layers.
Expand Down Expand Up @@ -104,7 +105,7 @@ func MountLCOWLayers(ctx context.Context, containerID string, layers *LCOWLayers

for _, layer := range layers.Layers {
log.G(ctx).WithField("layerPath", layer.VHDPath).Debug("mounting layer")
uvmPath, closer, err := addLCOWLayer(ctx, vm, layer.VHDPath)
uvmPath, closer, err := addLCOWLayer(ctx, vm, layer)
if err != nil {
return "", "", nil, fmt.Errorf("failed to add LCOW layer: %s", err)
}
Expand Down Expand Up @@ -392,15 +393,17 @@ func mountWCOWIsolatedLayers(ctx context.Context, containerID string, layerFolde
return containerScratchPathInUVM, closer, nil
}

func addLCOWLayer(ctx context.Context, vm *uvm.UtilityVM, layerPath string) (uvmPath string, _ resources.ResourceCloser, err error) {
// don't try to add as vpmem when we want additional devices on the uvm to be fully physically backed
if !vm.DevicesPhysicallyBacked() {
func addLCOWLayer(ctx context.Context, vm *uvm.UtilityVM, layer *LCOWLayer) (uvmPath string, _ resources.ResourceCloser, err error) {
// Don't add as VPMEM when we want additional devices on the UVM to be fully physically backed.
// Also don't use VPMEM when we need to mount a specific partition of the disk, as this is only
// supported for SCSI.
if !vm.DevicesPhysicallyBacked() && layer.Partition == 0 {
// We first try vPMEM and if it is full or the file is too large we
// fall back to SCSI.
mount, err := vm.AddVPMem(ctx, layerPath)
mount, err := vm.AddVPMem(ctx, layer.VHDPath)
if err == nil {
log.G(ctx).WithFields(logrus.Fields{
"layerPath": layerPath,
"layerPath": layer.VHDPath,
"layerType": "vpmem",
}).Debug("Added LCOW layer")
return mount.GuestPath, mount, nil
Expand All @@ -411,15 +414,16 @@ func addLCOWLayer(ctx context.Context, vm *uvm.UtilityVM, layerPath string) (uvm

sm, err := vm.SCSIManager.Add(
ctx,
&scsi.AttachConfig{Path: layerPath, ReadOnly: true, Type: scsi.AttachmentTypeVirtualDisk},
&scsi.MountConfig{ReadOnly: true, Verity: scsi.ReadVerityInfo(ctx, layerPath), Options: []string{"ro"}},
&scsi.AttachConfig{Path: layer.VHDPath, ReadOnly: true, Type: scsi.AttachmentTypeVirtualDisk},
&scsi.MountConfig{Partition: layer.Partition, ReadOnly: true, Verity: scsi.ReadVerityInfo(ctx, layer.VHDPath), Options: []string{"ro"}},
)
if err != nil {
return "", nil, fmt.Errorf("failed to add SCSI layer: %s", err)
}
log.G(ctx).WithFields(logrus.Fields{
"layerPath": layerPath,
"layerType": "scsi",
"layerPath": layer.VHDPath,
"layerPartition": layer.Partition,
"layerType": "scsi",
}).Debug("Added LCOW layer")
return sm.GuestPath(), sm, nil
}
Expand Down
1 change: 1 addition & 0 deletions internal/protocol/guestresource/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ type LCOWMappedVirtualDisk struct {
MountPath string `json:"MountPath,omitempty"`
Lun uint8 `json:"Lun,omitempty"`
Controller uint8 `json:"Controller,omitempty"`
Partition uint64 `json:"Partition,omitempty"`
ReadOnly bool `json:"ReadOnly,omitempty"`
Encrypted bool `json:"Encrypted,omitempty"`
Options []string `json:"Options,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions internal/uvm/scsi/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ func mountRequest(controller, lun uint, path string, config *MountConfig, osType
MountPath: path,
Controller: uint8(controller),
Lun: uint8(lun),
Partition: uint64(config.Partition),
ReadOnly: config.ReadOnly,
Encrypted: config.Encrypted,
Options: config.Options,
Expand Down
1 change: 1 addition & 0 deletions internal/uvm/scsi/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ type mount struct {
// MountConfig specifies the options to apply for mounting a SCSI device in
// the guest OS.
type MountConfig struct {
Partition uint64
ReadOnly bool
Encrypted bool
Verity *guestresource.DeviceVerityInfo
Expand Down

0 comments on commit f0563c1

Please sign in to comment.