1
2
3
4 package hcsv2
5
6 import (
7 "context"
8 "fmt"
9 "path/filepath"
10 "strings"
11
12 "github.com/Microsoft/hcsshim/internal/guest/storage/pci"
13 "github.com/Microsoft/hcsshim/internal/log"
14 "github.com/opencontainers/runc/libcontainer/devices"
15 oci "github.com/opencontainers/runtime-spec/specs-go"
16 "github.com/pkg/errors"
17 )
18
19 const (
20 sysfsDevPathFormat = "/sys/dev/%s/%d:%d"
21
22 charType = "char"
23 blockType = "block"
24
25 vpciDeviceIDTypeLegacy = "vpci"
26 vpciDeviceIDType = "vpci-instance-id"
27 )
28
29
30
31
32 func addAssignedDevice(ctx context.Context, spec *oci.Spec) error {
33 for _, d := range spec.Windows.Devices {
34 switch d.IDType {
35 case vpciDeviceIDTypeLegacy, vpciDeviceIDType:
36
37 fullPCIPath, err := pci.FindDeviceFullPath(ctx, d.ID)
38 if err != nil {
39 return errors.Wrapf(err, "failed to find device pci path for device %v", d)
40 }
41
42 dev, err := devicePathFromPCIPath(fullPCIPath)
43 if err != nil {
44 return errors.Wrapf(err, "failed to find dev node for device %v", d)
45 }
46 addLinuxDeviceToSpec(ctx, dev, spec, true)
47 }
48 }
49
50 return nil
51 }
52
53
54
55 func devicePathFromPCIPath(pciPath string) (*devices.Device, error) {
56
57 pciFullPath, err := filepath.EvalSymlinks(pciPath)
58 if err != nil {
59 return nil, err
60 }
61
62
63 hostDevices, err := devices.HostDevices()
64 if err != nil {
65 return nil, err
66 }
67
68
69 for _, d := range hostDevices {
70 major := d.Rule.Major
71 minor := d.Rule.Minor
72
73 deviceTypeString := ""
74 switch d.Rule.Type {
75 case devices.BlockDevice:
76 deviceTypeString = blockType
77 case devices.CharDevice:
78 deviceTypeString = charType
79 default:
80 return nil, errors.New("unsupported device type")
81 }
82
83 syfsDevPath := fmt.Sprintf(sysfsDevPathFormat, deviceTypeString, major, minor)
84 sysfsFullPath, err := filepath.EvalSymlinks(syfsDevPath)
85 if err != nil {
86 return nil, err
87 }
88 if strings.HasPrefix(sysfsFullPath, pciFullPath) {
89
90 return d, nil
91 }
92 }
93
94 return nil, errors.New("failed to find the device node from sysfs pci path")
95 }
96
97 func addLinuxDeviceToSpec(ctx context.Context, hostDevice *devices.Device, spec *oci.Spec, addCgroupDevice bool) {
98 rd := oci.LinuxDevice{
99 Path: hostDevice.Path,
100 Type: string(hostDevice.Type),
101 Major: hostDevice.Major,
102 Minor: hostDevice.Minor,
103 UID: &hostDevice.Uid,
104 GID: &hostDevice.Gid,
105 }
106 if hostDevice.Major == 0 && hostDevice.Minor == 0 {
107
108 return
109 }
110 found := false
111 for i, dev := range spec.Linux.Devices {
112 if dev.Path == rd.Path {
113 found = true
114 spec.Linux.Devices[i] = rd
115 break
116 }
117 if dev.Type == rd.Type && dev.Major == rd.Major && dev.Minor == rd.Minor {
118 log.G(ctx).Warnf("The same type '%s', major '%d' and minor '%d', should not be used for multiple devices.", dev.Type, dev.Major, dev.Minor)
119 }
120 }
121 if !found {
122 spec.Linux.Devices = append(spec.Linux.Devices, rd)
123 if addCgroupDevice {
124 deviceCgroup := oci.LinuxDeviceCgroup{
125 Allow: true,
126 Type: string(hostDevice.Type),
127 Major: &hostDevice.Major,
128 Minor: &hostDevice.Minor,
129 Access: string(hostDevice.Permissions),
130 }
131 spec.Linux.Resources.Devices = append(spec.Linux.Resources.Devices, deviceCgroup)
132 }
133 }
134 }
135
View as plain text