1
2
3
4 package pmem
5
6 import (
7 "context"
8 "fmt"
9 "os"
10
11 "github.com/pkg/errors"
12 "go.opencensus.io/trace"
13 "golang.org/x/sys/unix"
14
15 "github.com/Microsoft/hcsshim/internal/guest/storage"
16 dm "github.com/Microsoft/hcsshim/internal/guest/storage/devicemapper"
17 "github.com/Microsoft/hcsshim/internal/log"
18 "github.com/Microsoft/hcsshim/internal/oc"
19 "github.com/Microsoft/hcsshim/internal/protocol/guestresource"
20 )
21
22
23 var (
24 osMkdirAll = os.MkdirAll
25 osRemoveAll = os.RemoveAll
26 unixMount = unix.Mount
27 mountInternal = mount
28 createZeroSectorLinearTarget = dm.CreateZeroSectorLinearTarget
29 createVerityTarget = dm.CreateVerityTarget
30 removeDevice = dm.RemoveDevice
31 )
32
33 const (
34 pMemFmt = "/dev/pmem%d"
35 linearDeviceFmt = "dm-linear-pmem%d-%d-%d"
36 verityDeviceFmt = "dm-verity-pmem%d-%s"
37 )
38
39
40 func mount(ctx context.Context, source, target string) (err error) {
41 if err := osMkdirAll(target, 0700); err != nil {
42 return err
43 }
44 defer func() {
45 if err != nil {
46 if err := osRemoveAll(target); err != nil {
47 log.G(ctx).WithError(err).Debugf("error cleaning up target: %s", target)
48 }
49 }
50 }()
51
52 flags := uintptr(unix.MS_RDONLY)
53 if err := unixMount(source, target, "ext4", flags, "noload"); err != nil {
54 return errors.Wrapf(err, "failed to mount %s onto %s", source, target)
55 }
56 return nil
57 }
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 func Mount(
73 ctx context.Context,
74 device uint32,
75 target string,
76 mappingInfo *guestresource.LCOWVPMemMappingInfo,
77 verityInfo *guestresource.DeviceVerityInfo,
78 ) (err error) {
79 mCtx, span := oc.StartSpan(ctx, "pmem::Mount")
80 defer span.End()
81 defer func() { oc.SetSpanStatus(span, err) }()
82
83 span.AddAttributes(
84 trace.Int64Attribute("deviceNumber", int64(device)),
85 trace.StringAttribute("target", target))
86
87 devicePath := fmt.Sprintf(pMemFmt, device)
88
89
90
91 if mappingInfo != nil {
92 dmLinearName := fmt.Sprintf(linearDeviceFmt, device, mappingInfo.DeviceOffsetInBytes, mappingInfo.DeviceSizeInBytes)
93 if devicePath, err = createZeroSectorLinearTarget(mCtx, devicePath, dmLinearName, mappingInfo); err != nil {
94 return err
95 }
96 defer func() {
97 if err != nil {
98 if err := removeDevice(dmLinearName); err != nil {
99 log.G(mCtx).WithError(err).Debugf("failed to cleanup linear target: %s", dmLinearName)
100 }
101 }
102 }()
103 }
104
105 if verityInfo != nil {
106 dmVerityName := fmt.Sprintf(verityDeviceFmt, device, verityInfo.RootDigest)
107 if devicePath, err = createVerityTarget(mCtx, devicePath, dmVerityName, verityInfo); err != nil {
108 return err
109 }
110 defer func() {
111 if err != nil {
112 if err := removeDevice(dmVerityName); err != nil {
113 log.G(mCtx).WithError(err).Debugf("failed to cleanup verity target: %s", dmVerityName)
114 }
115 }
116 }()
117 }
118
119 return mountInternal(mCtx, devicePath, target)
120 }
121
122
123 func Unmount(
124 ctx context.Context,
125 devNumber uint32,
126 target string,
127 mappingInfo *guestresource.LCOWVPMemMappingInfo,
128 verityInfo *guestresource.DeviceVerityInfo,
129 ) (err error) {
130 _, span := oc.StartSpan(ctx, "pmem::Unmount")
131 defer span.End()
132 defer func() { oc.SetSpanStatus(span, err) }()
133
134 span.AddAttributes(
135 trace.Int64Attribute("device", int64(devNumber)),
136 trace.StringAttribute("target", target))
137
138 if err := storage.UnmountPath(ctx, target, true); err != nil {
139 return errors.Wrapf(err, "failed to unmount target: %s", target)
140 }
141
142 if verityInfo != nil {
143 dmVerityName := fmt.Sprintf(verityDeviceFmt, devNumber, verityInfo.RootDigest)
144 if err := dm.RemoveDevice(dmVerityName); err != nil {
145
146 log.G(ctx).WithError(err).Debugf("failed to remove dm verity target: %s", dmVerityName)
147 }
148 }
149
150 if mappingInfo != nil {
151 dmLinearName := fmt.Sprintf(linearDeviceFmt, devNumber, mappingInfo.DeviceOffsetInBytes, mappingInfo.DeviceSizeInBytes)
152 if err := dm.RemoveDevice(dmLinearName); err != nil {
153
154 log.G(ctx).WithError(err).Debugf("failed to remove dm linear target: %s", dmLinearName)
155 }
156 }
157
158 return nil
159 }
160
View as plain text