...

Source file src/github.com/Microsoft/hcsshim/internal/guest/storage/devicemapper/targets.go

Documentation: github.com/Microsoft/hcsshim/internal/guest/storage/devicemapper

     1  //go:build linux
     2  // +build linux
     3  
     4  package devicemapper
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"time"
    10  
    11  	"github.com/pkg/errors"
    12  	"go.opencensus.io/trace"
    13  
    14  	"github.com/Microsoft/hcsshim/ext4/dmverity"
    15  	"github.com/Microsoft/hcsshim/internal/oc"
    16  	"github.com/Microsoft/hcsshim/internal/protocol/guestresource"
    17  )
    18  
    19  // CreateZeroSectorLinearTarget creates dm-linear target for a device at `devPath` and `mappingInfo`, returns
    20  // virtual block device path.
    21  func CreateZeroSectorLinearTarget(ctx context.Context, devPath, devName string, mappingInfo *guestresource.LCOWVPMemMappingInfo) (_ string, err error) {
    22  	_, span := oc.StartSpan(ctx, "devicemapper::CreateZeroSectorLinearTarget")
    23  	defer span.End()
    24  	defer func() { oc.SetSpanStatus(span, err) }()
    25  
    26  	size := int64(mappingInfo.DeviceSizeInBytes)
    27  	offset := int64(mappingInfo.DeviceOffsetInBytes)
    28  	linearTarget := zeroSectorLinearTarget(size, devPath, offset)
    29  
    30  	span.AddAttributes(
    31  		trace.StringAttribute("devicePath", devPath),
    32  		trace.Int64Attribute("deviceStart", offset),
    33  		trace.Int64Attribute("sectorSize", size),
    34  		trace.StringAttribute("linearTable", fmt.Sprintf("%s: '%d %d %s'", devName, linearTarget.SectorStart, linearTarget.LengthInBlocks, linearTarget.Params)))
    35  
    36  	devMapperPath, err := CreateDevice(devName, CreateReadOnly, []Target{linearTarget})
    37  	if err != nil {
    38  		// todo (maksiman): add better retry logic, similar to how SCSI device mounts are
    39  		// retried on unix.ENOENT and unix.ENXIO.
    40  		time.Sleep(500 * time.Millisecond)
    41  		if devMapperPath, err = CreateDevice(devName, CreateReadOnly, []Target{linearTarget}); err != nil {
    42  			return "", errors.Wrapf(err, "failed to create dm-linear target, device=%s, offset=%d", devPath, mappingInfo.DeviceOffsetInBytes)
    43  		}
    44  	}
    45  
    46  	return devMapperPath, nil
    47  }
    48  
    49  // CreateVerityTarget creates a dm-verity target for a given device and returns created virtual block device path.
    50  //
    51  // Example verity target table:
    52  //
    53  //	  0 417792 verity 1 /dev/sdb /dev/sdc 4096 4096 52224 1 sha256 2aa4f7b7b6...f4952060e8 762307f4bc8...d2a6b7595d8..
    54  //	  |   |      |    |     |        |    |     |     |   |    |              |                        |
    55  //	start |      |    | data_dev     |    |     | #blocks | hash_alg      root_digest                salt
    56  //	     size    |  version      hash_dev | hash_block_sz |
    57  //	           target              data_block_sz      hash_offset
    58  //
    59  // See [dm-verity] for more information
    60  //
    61  // [dm-verity]: https://www.kernel.org/doc/html/latest/admin-guide/device-mapper/verity.html#construction-parameters
    62  func CreateVerityTarget(ctx context.Context, devPath, devName string, verityInfo *guestresource.DeviceVerityInfo) (_ string, err error) {
    63  	_, span := oc.StartSpan(ctx, "devicemapper::CreateVerityTarget")
    64  	defer span.End()
    65  	defer func() { oc.SetSpanStatus(span, err) }()
    66  
    67  	dmBlocks := verityInfo.Ext4SizeInBytes / blockSize
    68  	dataBlocks := verityInfo.Ext4SizeInBytes / int64(verityInfo.BlockSize)
    69  	hashOffsetBlocks := dataBlocks
    70  	if verityInfo.SuperBlock {
    71  		hashOffsetBlocks++
    72  	}
    73  	hashes := fmt.Sprintf("%s %s %s", verityInfo.Algorithm, verityInfo.RootDigest, verityInfo.Salt)
    74  	blkInfo := fmt.Sprintf("%d %d %d %d", verityInfo.BlockSize, verityInfo.BlockSize, dataBlocks, hashOffsetBlocks)
    75  	devices := fmt.Sprintf("%s %s", devPath, devPath)
    76  
    77  	verityTarget := Target{
    78  		SectorStart:    0,
    79  		LengthInBlocks: dmBlocks,
    80  		Type:           dmverity.VeritySignature,
    81  		Params:         fmt.Sprintf("%d %s %s %s", verityInfo.Version, devices, blkInfo, hashes),
    82  	}
    83  
    84  	span.AddAttributes(
    85  		trace.StringAttribute("devicePath", devPath),
    86  		trace.Int64Attribute("sectorSize", dmBlocks),
    87  		trace.StringAttribute("verityTable", verityTarget.Params))
    88  
    89  	mapperPath, err := CreateDevice(devName, CreateReadOnly, []Target{verityTarget})
    90  	if err != nil {
    91  		// todo (maksiman): add better retry logic, similar to how SCSI device mounts are
    92  		// retried on unix.ENOENT and unix.ENXIO
    93  		time.Sleep(500 * time.Millisecond)
    94  		if mapperPath, err = CreateDevice(devName, CreateReadOnly, []Target{verityTarget}); err != nil {
    95  			return "", errors.Wrapf(err, "failed to create dm-verity target. device=%s", devPath)
    96  		}
    97  	}
    98  
    99  	return mapperPath, nil
   100  }
   101  

View as plain text