Skip to content

Commit

Permalink
Don't create container scratch per base layer
Browse files Browse the repository at this point in the history
For WCIFS based layers, a container scratch base VHD (and a differencing VHD) both are created per unique base
layer. This is because we add reparse points for the base layer files inside the VHD. However, with UnionFS we
don't add any reparse points and the VHD is empty, so we don't need to create a VHD per unique base layer. Now
the CimFS snapshotter will handle container scratch VHD creation and the LayerWriter will only created a VHD
for the UtilityVM. (The UtilityVM VHD still needs to be created per unique base layer since the BCD of that
layer is configured to boot from the UtilityVM VHD and the BCD is unique per image)

Signed-off-by: Amit Barve <ambarve@microsoft.com>
  • Loading branch information
ambarve committed Jan 18, 2024
1 parent 0285b8b commit ed3de0e
Showing 1 changed file with 8 additions and 89 deletions.
97 changes: 8 additions & 89 deletions internal/wclayer/cim/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,77 +22,14 @@ import (

const defaultVHDXBlockSizeInMB = 1

func createContainerBaseLayerVHDs(ctx context.Context, layerPath string) (err error) {
baseVhdPath := filepath.Join(layerPath, wclayer.ContainerBaseVhd)
diffVhdPath := filepath.Join(layerPath, wclayer.ContainerScratchVhd)
defaultVhdSize := uint64(20)

if _, err := os.Stat(baseVhdPath); err == nil {
if err := os.RemoveAll(baseVhdPath); err != nil {
return fmt.Errorf("failed to remove base vhdx path: %w", err)
}
}
if _, err := os.Stat(diffVhdPath); err == nil {
if err := os.RemoveAll(diffVhdPath); err != nil {
return fmt.Errorf("failed to remove differencing vhdx: %w", err)
}
}

createParams := &vhd.CreateVirtualDiskParameters{
Version: 2,
Version2: vhd.CreateVersion2{
MaximumSize: defaultVhdSize * memory.GiB,
BlockSizeInBytes: defaultVHDXBlockSizeInMB * memory.MiB,
},
}
handle, err := vhd.CreateVirtualDisk(baseVhdPath, vhd.VirtualDiskAccessNone, vhd.CreateVirtualDiskFlagNone, createParams)
if err != nil {
return fmt.Errorf("failed to create vhdx: %w", err)
}

defer func() {
if err != nil {
os.RemoveAll(baseVhdPath)
os.RemoveAll(diffVhdPath)
}
}()

err = computestorage.FormatWritableLayerVhd(ctx, windows.Handle(handle))
// we always wanna close the handle whether format succeeds for not.
closeErr := syscall.CloseHandle(handle)
if err != nil {
return err
} else if closeErr != nil {
return fmt.Errorf("failed to close vhdx handle: %w", closeErr)
}

// Create the differencing disk that will be what's copied for the final rw layer
// for a container.
if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
return fmt.Errorf("failed to create differencing disk: %w", err)
}

if err = security.GrantVmGroupAccess(baseVhdPath); err != nil {
return fmt.Errorf("failed to grant vm group access to %s: %w", baseVhdPath, err)
}
if err = security.GrantVmGroupAccess(diffVhdPath); err != nil {
return fmt.Errorf("failed to grant vm group access to %s: %w", diffVhdPath, err)
}
return nil
}

// processUtilityVMLayer is similar to createContainerBaseLayerVHDs but along with the scratch creation it
// also does some BCD modifications to allow the UVM to boot from the CIM. It expects that the UVM BCD file is
// present at layerPath/`wclayer.BcdFilePath` and a UVM SYSTEM hive is present at
// layerPath/UtilityVM/`wclayer.RegFilesPath`/SYSTEM. The scratch VHDs are created under the `layerPath`
// directory.
// processUtilityVMLayer creates a base VHD for the UtilityVM's scratch. Configures the BCD file at path
// "layerPath/`wclayer.BcdFilePath`" to make the UVM boot from this base VHD. Also, configures the UVM's
// SYSTEM hive at path "layerPath/UtilityVM/`wclayer.RegFilesPath`/SYSTEM" to specify that the UVM is booting
// from a CIM.
func processUtilityVMLayer(ctx context.Context, layerPath string) error {
// func createUtilityVMLayerVHDs(ctx context.Context, layerPath string) error {
baseVhdPath := filepath.Join(layerPath, wclayer.UtilityVMPath, wclayer.UtilityVMBaseVhd)
diffVhdPath := filepath.Join(layerPath, wclayer.UtilityVMPath, wclayer.UtilityVMScratchVhd)
defaultVhdSize := uint64(10)

// Just create the vhdx for utilityVM layer, no need to format it.
createParams := &vhd.CreateVirtualDiskParameters{
Version: 2,
Version2: vhd.CreateVersion2{
Expand All @@ -109,7 +46,6 @@ func processUtilityVMLayer(ctx context.Context, layerPath string) error {
defer func() {
if err != nil {
os.RemoveAll(baseVhdPath)
os.RemoveAll(diffVhdPath)
}
}()

Expand All @@ -121,6 +57,10 @@ func processUtilityVMLayer(ctx context.Context, layerPath string) error {
return fmt.Errorf("failed to close vhdx handle: %w", closeErr)
}

if err := security.GrantVmGroupAccess(baseVhdPath); err != nil {
return fmt.Errorf("failed to grant vm group access to %s: %w", baseVhdPath, err)
}

partitionInfo, err := vhdx.GetScratchVhdPartitionInfo(ctx, baseVhdPath)
if err != nil {
return fmt.Errorf("failed to get base vhd layout info: %w", err)
Expand All @@ -138,23 +78,6 @@ func processUtilityVMLayer(ctx context.Context, layerPath string) error {
return fmt.Errorf("failed to setup cim image for uvm boot: %w", err)
}

// Note: diff vhd creation and granting of vm group access must be done AFTER
// getting the partition info of the base VHD. Otherwise it causes the vhd parent
// chain to get corrupted.
// TODO(ambarve): figure out why this happens so that bcd update can be moved to a separate function

// Create the differencing disk that will be what's copied for the final rw layer
// for a container.
if err = vhd.CreateDiffVhd(diffVhdPath, baseVhdPath, defaultVHDXBlockSizeInMB); err != nil {
return fmt.Errorf("failed to create differencing disk: %w", err)
}

if err := security.GrantVmGroupAccess(baseVhdPath); err != nil {
return fmt.Errorf("failed to grant vm group access to %s: %w", baseVhdPath, err)
}
if err := security.GrantVmGroupAccess(diffVhdPath); err != nil {
return fmt.Errorf("failed to grant vm group access to %s: %w", diffVhdPath, err)
}
return nil
}

Expand Down Expand Up @@ -228,10 +151,6 @@ func processLayoutFile(layerPath string) ([]pendingCimOp, error) {
// inside the cim, some registry file links must be updated. This function takes care of all those
// steps. This function opens the cim file for writing and updates it.
func (cw *CimLayerWriter) processBaseLayer(ctx context.Context, processUtilityVM bool) (err error) {
if err = createContainerBaseLayerVHDs(ctx, cw.path); err != nil {
return fmt.Errorf("failed to create container base VHDs: %w", err)
}

if processUtilityVM {
if err = processUtilityVMLayer(ctx, cw.path); err != nil {
return fmt.Errorf("process utilityVM layer: %w", err)
Expand Down

0 comments on commit ed3de0e

Please sign in to comment.