1
2
3
4 package hcsoci
5
6
7
8 import (
9 "context"
10 "fmt"
11 "os"
12 "path"
13 "path/filepath"
14 "strings"
15
16 specs "github.com/opencontainers/runtime-spec/specs-go"
17 "github.com/pkg/errors"
18
19 "github.com/Microsoft/hcsshim/internal/guestpath"
20 "github.com/Microsoft/hcsshim/internal/layers"
21 "github.com/Microsoft/hcsshim/internal/log"
22 "github.com/Microsoft/hcsshim/internal/resources"
23 "github.com/Microsoft/hcsshim/internal/uvm"
24 )
25
26 func allocateLinuxResources(ctx context.Context, coi *createOptionsInternal, r *resources.Resources, isSandbox bool) error {
27 if coi.Spec.Root == nil {
28 coi.Spec.Root = &specs.Root{}
29 }
30 containerRootInUVM := r.ContainerRootInUVM()
31 if coi.Spec.Windows != nil && len(coi.Spec.Windows.LayerFolders) > 0 {
32 log.G(ctx).Debug("hcsshim::allocateLinuxResources mounting storage")
33 rootPath, scratchPath, closer, err := layers.MountLCOWLayers(ctx, coi.actualID, coi.Spec.Windows.LayerFolders, containerRootInUVM, coi.HostingSystem)
34 if err != nil {
35 return errors.Wrap(err, "failed to mount container storage")
36 }
37 coi.Spec.Root.Path = rootPath
38
39
40 if !isSandbox || coi.HostingSystem == nil {
41 r.SetLayers(closer)
42 }
43 r.SetLcowScratchPath(scratchPath)
44 } else if coi.Spec.Root.Path != "" {
45
46
47 hostPath := coi.Spec.Root.Path
48 uvmPathForContainersFileSystem := path.Join(r.ContainerRootInUVM(), guestpath.RootfsPath)
49 share, err := coi.HostingSystem.AddPlan9(ctx, hostPath, uvmPathForContainersFileSystem, coi.Spec.Root.Readonly, false, nil)
50 if err != nil {
51 return errors.Wrap(err, "adding plan9 root")
52 }
53 coi.Spec.Root.Path = uvmPathForContainersFileSystem
54 r.Add(share)
55 } else {
56 return errors.New("must provide either Windows.LayerFolders or Root.Path")
57 }
58
59 for i, mount := range coi.Spec.Mounts {
60 switch mount.Type {
61 case MountTypeBind:
62 case MountTypePhysicalDisk:
63 case MountTypeVirtualDisk:
64 default:
65
66 continue
67 }
68 if mount.Destination == "" || mount.Source == "" {
69 return fmt.Errorf("invalid OCI spec - a mount must have both source and a destination: %+v", mount)
70 }
71
72 if coi.HostingSystem != nil {
73 hostPath := mount.Source
74 uvmPathForShare := path.Join(containerRootInUVM, fmt.Sprintf(guestpath.LCOWMountPathPrefixFmt, i))
75 uvmPathForFile := uvmPathForShare
76
77 readOnly := false
78 for _, o := range mount.Options {
79 if strings.ToLower(o) == "ro" {
80 readOnly = true
81 break
82 }
83 }
84
85 l := log.G(ctx).WithField("mount", fmt.Sprintf("%+v", mount))
86 if mount.Type == MountTypePhysicalDisk {
87 l.Debug("hcsshim::allocateLinuxResources Hot-adding SCSI physical disk for OCI mount")
88 uvmPathForShare = fmt.Sprintf(guestpath.LCOWGlobalMountPrefixFmt, coi.HostingSystem.UVMMountCounter())
89 scsiMount, err := coi.HostingSystem.AddSCSIPhysicalDisk(ctx, hostPath, uvmPathForShare, readOnly, mount.Options)
90 if err != nil {
91 return errors.Wrapf(err, "adding SCSI physical disk mount %+v", mount)
92 }
93
94 uvmPathForFile = scsiMount.UVMPath
95 r.Add(scsiMount)
96 coi.Spec.Mounts[i].Type = "none"
97 } else if mount.Type == MountTypeVirtualDisk {
98 l.Debug("hcsshim::allocateLinuxResources Hot-adding SCSI virtual disk for OCI mount")
99 uvmPathForShare = fmt.Sprintf(guestpath.LCOWGlobalMountPrefixFmt, coi.HostingSystem.UVMMountCounter())
100
101
102
103 scsiMount, err := coi.HostingSystem.AddSCSI(
104 ctx,
105 hostPath,
106 uvmPathForShare,
107 readOnly,
108 false,
109 mount.Options,
110 uvm.VMAccessTypeIndividual,
111 )
112 if err != nil {
113 return errors.Wrapf(err, "adding SCSI virtual disk mount %+v", mount)
114 }
115
116 uvmPathForFile = scsiMount.UVMPath
117 r.Add(scsiMount)
118 coi.Spec.Mounts[i].Type = "none"
119 } else if strings.HasPrefix(mount.Source, guestpath.SandboxMountPrefix) {
120
121
122 uvmPathForFile = mount.Source
123 } else if strings.HasPrefix(mount.Source, guestpath.HugePagesMountPrefix) {
124
125 hugePageSubDirs := strings.Split(strings.TrimPrefix(mount.Source, guestpath.HugePagesMountPrefix), "/")
126 if len(hugePageSubDirs) < 2 {
127 return errors.Errorf(
128 `%s mount path is invalid, expected format: %s<hugepage-size>/<hugepage-src-location>`,
129 mount.Source,
130 guestpath.HugePagesMountPrefix,
131 )
132 }
133
134
135 if hugePageSubDirs[0] != "2M" {
136 return errors.Errorf(`only 2M (megabytes) pagesize is supported, got %s`, hugePageSubDirs[0])
137 }
138
139 uvmPathForFile = mount.Source
140 } else {
141 st, err := os.Stat(hostPath)
142 if err != nil {
143 return errors.Wrap(err, "could not open bind mount target")
144 }
145 restrictAccess := false
146 var allowedNames []string
147 if !st.IsDir() {
148
149
150 var fileName string
151 hostPath, fileName = filepath.Split(hostPath)
152 allowedNames = append(allowedNames, fileName)
153 restrictAccess = true
154 uvmPathForFile = path.Join(uvmPathForShare, fileName)
155 }
156 l.Debug("hcsshim::allocateLinuxResources Hot-adding Plan9 for OCI mount")
157
158 share, err := coi.HostingSystem.AddPlan9(ctx, hostPath, uvmPathForShare, readOnly, restrictAccess, allowedNames)
159 if err != nil {
160 return errors.Wrapf(err, "adding plan9 mount %+v", mount)
161 }
162 r.Add(share)
163 }
164 coi.Spec.Mounts[i].Source = uvmPathForFile
165 }
166 }
167
168 if coi.HostingSystem == nil {
169 return nil
170 }
171
172 if coi.hasWindowsAssignedDevices() {
173 windowsDevices, closers, err := handleAssignedDevicesLCOW(ctx, coi.HostingSystem, coi.Spec.Annotations, coi.Spec.Windows.Devices)
174 if err != nil {
175 return err
176 }
177 r.Add(closers...)
178 coi.Spec.Windows.Devices = windowsDevices
179 }
180 return nil
181 }
182
View as plain text