mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Add nested PCI device support and option to read directly from host dev files.
PiperOrigin-RevId: 670751194
This commit is contained in:
committed by
gVisor bot
parent
ae76d34ef5
commit
932d9dc64b
@@ -32,8 +32,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
pciPathGlobTPUv4 = "/sys/devices/pci0000:*/*/accel/accel*"
|
||||
pciPathGlobTPUv5 = "/sys/devices/pci0000:*/*/vfio-dev/vfio*"
|
||||
pciPathGlobTPUv4 = "/sys/devices/pci0000:*/**/accel/accel*"
|
||||
pciPathGlobTPUv5 = "/sys/devices/pci0000:*/**/vfio-dev/vfio*"
|
||||
iommuGroupPathGlob = "/sys/kernel/iommu_groups/*/devices/*"
|
||||
)
|
||||
|
||||
@@ -42,8 +42,8 @@ var (
|
||||
// TPU v4 devices are accessible via /sys/devices/pci0000:00/<pci_address>/accel/accel# on the host.
|
||||
// TPU v5 devices are accessible via at /sys/devices/pci0000:00/<pci_address>/vfio-dev/vfio# on the host.
|
||||
pathGlobToPathRegex = map[string]string{
|
||||
pciPathGlobTPUv4: `^/sys/devices/pci0000:[[:xdigit:]]{2}/\d+:\d+:\d+\.\d+/accel/accel(\d+)$`,
|
||||
pciPathGlobTPUv5: `^/sys/devices/pci0000:[[:xdigit:]]{2}/\d+:\d+:\d+\.\d+/vfio-dev/vfio(\d+)$`,
|
||||
pciPathGlobTPUv4: `^/sys/devices/pci0000:[[:xdigit:]]{2}/(0000:([[:xdigit:]]{2}|[[:xdigit:]]{4}):[[:xdigit:]]{2}\.[[:xdigit:]]{1,2}/)+accel/accel(\d+)$`,
|
||||
pciPathGlobTPUv5: `^/sys/devices/pci0000:[[:xdigit:]]{2}/(0000:([[:xdigit:]]{2}|[[:xdigit:]]{4}):[[:xdigit:]]{2}\.[[:xdigit:]]{1,2}/)+vfio-dev/vfio(\d+)$`,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -61,7 +61,7 @@ func RegisterHostTPUDevices(vfsObj *vfs.VirtualFilesystem, allowedDeviceIDs map[
|
||||
if ms == nil {
|
||||
continue
|
||||
}
|
||||
minorNum, err := strconv.ParseUint(ms[1], 10, 32)
|
||||
minorNum, err := strconv.ParseUint(ms[len(ms)-1], 10, 32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parsing PCI device number: %w", err)
|
||||
}
|
||||
@@ -117,7 +117,7 @@ func registerTPUDevice(vfsObj *vfs.VirtualFilesystem, minor, deviceNum uint32, d
|
||||
case tpu.TPUV4DeviceID, tpu.TPUV4liteDeviceID:
|
||||
return accel.RegisterTPUDevice(vfsObj, minor, deviceID == tpu.TPUV4liteDeviceID)
|
||||
case tpu.TPUV5eDeviceID, tpu.TPUV5pDeviceID:
|
||||
return vfio.RegisterTPUDevice(vfsObj, minor, deviceNum)
|
||||
return vfio.RegisterTPUDevice(vfsObj, minor, deviceNum, false /* useDevGofer */)
|
||||
default:
|
||||
return fmt.Errorf("unsupported TPU device with ID: 0x%x", deviceID)
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ func TestTPUPath(t *testing.T) {
|
||||
name: "TPUv4PCIPathMatch",
|
||||
pathGlob: pciPathGlobTPUv4,
|
||||
path: "/sys/devices/pci0000:00/0000:00:01.0/accel/accel16",
|
||||
submatch: []string{"/sys/devices/pci0000:00/0000:00:01.0/accel/accel16", "16"},
|
||||
submatch: []string{"/sys/devices/pci0000:00/0000:00:01.0/accel/accel16", "0000:00:01.0/", "00", "16"},
|
||||
},
|
||||
{
|
||||
name: "TPUv4PCIPathNoMatch",
|
||||
@@ -44,7 +44,7 @@ func TestTPUPath(t *testing.T) {
|
||||
name: "TPUv5PCIPathMatch",
|
||||
pathGlob: pciPathGlobTPUv5,
|
||||
path: "/sys/devices/pci0000:00/0000:00:05.0/vfio-dev/vfio20",
|
||||
submatch: []string{"/sys/devices/pci0000:00/0000:00:05.0/vfio-dev/vfio20", "20"},
|
||||
submatch: []string{"/sys/devices/pci0000:00/0000:00:05.0/vfio-dev/vfio20", "0000:00:05.0/", "00", "20"},
|
||||
},
|
||||
{
|
||||
name: "TPUv5PCIPathNoMatch",
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
package vfio
|
||||
|
||||
import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
"gvisor.dev/gvisor/pkg/abi/linux"
|
||||
@@ -51,23 +51,40 @@ type tpuDevice struct {
|
||||
minor uint32
|
||||
// num is the number of the device in the dev filesystem (e.g /dev/vfio/0).
|
||||
num uint32
|
||||
// useDevGofer indicates whether to use device gofer to open the TPU device.
|
||||
useDevGofer bool
|
||||
}
|
||||
|
||||
// Open implements vfs.Device.Open.
|
||||
func (dev *tpuDevice) Open(ctx context.Context, mnt *vfs.Mount, d *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
devClient := devutil.GoferClientFromContext(ctx)
|
||||
if devClient == nil {
|
||||
log.Warningf("devutil.CtxDevGoferClient is not set")
|
||||
return nil, linuxerr.ENOENT
|
||||
}
|
||||
dev.mu.Lock()
|
||||
defer dev.mu.Unlock()
|
||||
devName := filepath.Join("vfio", strconv.Itoa(int(dev.num)))
|
||||
hostFD, err := devClient.OpenAt(ctx, devName, opts.Flags)
|
||||
if err != nil {
|
||||
ctx.Warningf("tpuDevice: failed to open host %s: %v", devName, err)
|
||||
return nil, err
|
||||
|
||||
var hostFD int
|
||||
if dev.useDevGofer {
|
||||
devClient := devutil.GoferClientFromContext(ctx)
|
||||
if devClient == nil {
|
||||
log.Warningf("devutil.CtxDevGoferClient is not set")
|
||||
return nil, linuxerr.ENOENT
|
||||
}
|
||||
devName := filepath.Join("vfio", strconv.Itoa(int(dev.num)))
|
||||
var err error
|
||||
hostFD, err = devClient.OpenAt(ctx, devName, opts.Flags)
|
||||
if err != nil {
|
||||
ctx.Warningf("tpuDevice: failed to open host %s: %v", devName, err)
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
devPath := filepath.Join("/", "dev", "vfio", strconv.Itoa(int(dev.num)))
|
||||
var err error
|
||||
flags := int(opts.Flags&unix.O_ACCMODE | unix.O_NOFOLLOW)
|
||||
hostFD, err = unix.Openat(-1, devPath, flags, 0)
|
||||
if err != nil {
|
||||
ctx.Warningf("tpuDevice: failed to open host %s: %v", devPath, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
fd := &tpuFD{
|
||||
hostFD: int32(hostFD),
|
||||
device: dev,
|
||||
@@ -87,22 +104,40 @@ func (dev *tpuDevice) Open(ctx context.Context, mnt *vfs.Mount, d *vfs.Dentry, o
|
||||
}
|
||||
|
||||
// device implements vfs.Device for /dev/vfio/vfio.
|
||||
type vfioDevice struct{}
|
||||
type vfioDevice struct {
|
||||
// useDevGofer indicates whether to use device gofer to open the VFIO device.
|
||||
useDevGofer bool
|
||||
}
|
||||
|
||||
// Open implements vfs.Device.Open.
|
||||
func (dev *vfioDevice) Open(ctx context.Context, mnt *vfs.Mount, d *vfs.Dentry, opts vfs.OpenOptions) (*vfs.FileDescription, error) {
|
||||
client := devutil.GoferClientFromContext(ctx)
|
||||
if client == nil {
|
||||
log.Warningf("devutil.CtxDevGoferClient is not set")
|
||||
return nil, linuxerr.ENOENT
|
||||
var hostFD int
|
||||
if dev.useDevGofer {
|
||||
client := devutil.GoferClientFromContext(ctx)
|
||||
if client == nil {
|
||||
log.Warningf("devutil.CtxDevGoferClient is not set")
|
||||
return nil, linuxerr.ENOENT
|
||||
}
|
||||
|
||||
name := filepath.Join("vfio", "vfio")
|
||||
var err error
|
||||
hostFD, err = client.OpenAt(ctx, name, opts.Flags)
|
||||
if err != nil {
|
||||
ctx.Warningf("failed to open host file %s: %v", name, err)
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
devPath := filepath.Join("/", "dev", "vfio", "vfio")
|
||||
flags := int(opts.Flags&unix.O_ACCMODE | unix.O_NOFOLLOW)
|
||||
var err error
|
||||
hostFD, err = unix.Openat(-1, devPath, flags, 0)
|
||||
if err != nil {
|
||||
ctx.Warningf("vfioDevice: failed to open host %s: %v", devPath, err)
|
||||
log.Infof("here failed to open %v flags", devPath, opts.Flags)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
name := strings.ReplaceAll(VFIOPath, "/dev/", "")
|
||||
hostFD, err := client.OpenAt(ctx, name, opts.Flags)
|
||||
if err != nil {
|
||||
ctx.Warningf("failed to open host file %s: %v", name, err)
|
||||
return nil, err
|
||||
}
|
||||
fd := &vfioFD{
|
||||
hostFD: int32(hostFD),
|
||||
device: dev,
|
||||
@@ -122,18 +157,25 @@ func (dev *vfioDevice) Open(ctx context.Context, mnt *vfs.Mount, d *vfs.Dentry,
|
||||
}
|
||||
|
||||
// RegisterTPUDevice registers devices implemented by this package in vfsObj.
|
||||
func RegisterTPUDevice(vfsObj *vfs.VirtualFilesystem, minor, deviceNum uint32) error {
|
||||
func RegisterTPUDevice(vfsObj *vfs.VirtualFilesystem, minor, deviceNum uint32, useDevGofer bool) error {
|
||||
return vfsObj.RegisterDevice(vfs.CharDevice, linux.VFIO_MAJOR, minor, &tpuDevice{
|
||||
minor: minor,
|
||||
num: deviceNum,
|
||||
minor: minor,
|
||||
num: deviceNum,
|
||||
useDevGofer: useDevGofer,
|
||||
}, &vfs.RegisterDeviceOptions{
|
||||
GroupName: tpuDeviceGroupName,
|
||||
Pathname: path.Join("vfio", strconv.Itoa(int(deviceNum))),
|
||||
FilePerms: 0666,
|
||||
})
|
||||
}
|
||||
|
||||
// RegisterVFIODevice registers VFIO devices that are implemented by this package in vfsObj.
|
||||
func RegisterVFIODevice(vfsObj *vfs.VirtualFilesystem) error {
|
||||
return vfsObj.RegisterDevice(vfs.CharDevice, linux.MISC_MAJOR, VFIO_MINOR, &vfioDevice{}, &vfs.RegisterDeviceOptions{
|
||||
func RegisterVFIODevice(vfsObj *vfs.VirtualFilesystem, useDevGofer bool) error {
|
||||
return vfsObj.RegisterDevice(vfs.CharDevice, linux.MISC_MAJOR, VFIO_MINOR, &vfioDevice{
|
||||
useDevGofer: useDevGofer,
|
||||
}, &vfs.RegisterDeviceOptions{
|
||||
GroupName: vfioDeviceGroupName,
|
||||
Pathname: path.Join("vfio", "vfio"),
|
||||
FilePerms: 0666,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -52,39 +52,48 @@ var (
|
||||
"is_device_owned": nil, "device_owner": nil, "framework_version": nil,
|
||||
"user_mem_ranges": nil, "interrupt_counts": nil, "chip_model": nil,
|
||||
"bar_offsets": nil, "bar_sizes": nil, "resource0": nil, "resource1": nil,
|
||||
"resource2": nil, "resource3": nil, "resource4": nil, "resource5": nil, "enable": nil,
|
||||
"resource2": nil, "resource3": nil, "resource4": nil, "resource5": nil,
|
||||
"enable": nil,
|
||||
}
|
||||
|
||||
pciAddressLength = 13
|
||||
)
|
||||
|
||||
// sysDevicesPCIPaths returns the paths of all PCI devices on the host in a
|
||||
// pciDevicePaths returns the paths of all PCI devices on the host in a
|
||||
// /sys/devices directory.
|
||||
func sysDevicesPCIPaths(sysDevicesPath string) ([]string, error) {
|
||||
func pciDevicePaths(sysDevicesPath string) (map[string]string, error) {
|
||||
sysDevicesDents, err := hostDirEntries(sysDevicesPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var pciPaths []string
|
||||
for _, dent := range sysDevicesDents {
|
||||
if pciBusRegex.MatchString(dent) {
|
||||
pciDents, err := hostDirEntries(path.Join(sysDevicesPath, dent))
|
||||
if err != nil {
|
||||
pciPaths := map[string]string{}
|
||||
for _, busDent := range sysDevicesDents {
|
||||
if pciBusRegex.MatchString(busDent) {
|
||||
if err := walkPCIDeviceTopology(busDent, sysDevicesPath, pciPaths); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, pciDent := range pciDents {
|
||||
if pciDeviceRegex.MatchString(pciDent) {
|
||||
pciPaths = append(pciPaths, path.Join(sysDevicesPath, dent, pciDent))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return pciPaths, nil
|
||||
}
|
||||
|
||||
// pciBusFromAddress returns the PCI bus address from a PCI address.
|
||||
//
|
||||
// Preconditions: pciAddr is a valid PCI address.
|
||||
func pciBusFromAddress(pciAddr string) string {
|
||||
return strings.Join(strings.Split(pciAddr, ":")[:2], ":")
|
||||
// walkPCIDeviceTopology recursively walks the PCI device topology and returns
|
||||
// a map from PCI device name to its path starting from the PCI bus directory.
|
||||
func walkPCIDeviceTopology(pciPath, sysDevicesPath string, devices map[string]string) error {
|
||||
dents, err := hostDirEntries(path.Join(sysDevicesPath, pciPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, dent := range dents {
|
||||
if pciDeviceRegex.MatchString(dent) && len(dent) <= pciAddressLength {
|
||||
dentPath := path.Join(pciPath, dent)
|
||||
devices[dent] = dentPath
|
||||
if err := walkPCIDeviceTopology(dentPath, sysDevicesPath, devices); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates TPU devices' symlinks under /sys/class/. TPU device types that are
|
||||
@@ -92,18 +101,14 @@ func pciBusFromAddress(pciAddr string) string {
|
||||
//
|
||||
// TPU v4 symlinks are created at /sys/class/accel/accel#.
|
||||
// TPU v5 symlinks go to /sys/class/vfio-dev/vfio#.
|
||||
func (fs *filesystem) newDeviceClassDir(ctx context.Context, creds *auth.Credentials, tpuDeviceTypes []string, sysDevicesPath string) (map[string]map[string]kernfs.Inode, error) {
|
||||
func (fs *filesystem) newDeviceClassDir(ctx context.Context, creds *auth.Credentials, tpuDeviceTypes []string, sysDevicesPath string, pciPaths map[string]string) (map[string]map[string]kernfs.Inode, error) {
|
||||
dirs := map[string]map[string]kernfs.Inode{}
|
||||
for _, tpuDeviceType := range tpuDeviceTypes {
|
||||
dirs[tpuDeviceType] = map[string]kernfs.Inode{}
|
||||
}
|
||||
pciPaths, err := sysDevicesPCIPaths(sysDevicesPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, pciPath := range pciPaths {
|
||||
for _, tpuDeviceType := range tpuDeviceTypes {
|
||||
subPath := path.Join(pciPath, tpuDeviceType)
|
||||
subPath := path.Join(sysDevicesPath, pciPath, tpuDeviceType)
|
||||
deviceDents, err := hostDirEntries(subPath)
|
||||
if err != nil {
|
||||
// Skips the path that doesn't exist.
|
||||
@@ -115,9 +120,8 @@ func (fs *filesystem) newDeviceClassDir(ctx context.Context, creds *auth.Credent
|
||||
if numOfDeviceDents := len(deviceDents); numOfDeviceDents != 1 {
|
||||
return nil, fmt.Errorf("exactly one entry is expected at %v while there are %d", subPath, numOfDeviceDents)
|
||||
}
|
||||
pciAddr := path.Base(pciPath)
|
||||
pciBus := pciBusFromAddress(pciAddr)
|
||||
dirs[tpuDeviceType][deviceDents[0]] = kernfs.NewStaticSymlink(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), fmt.Sprintf("../../devices/pci%s/%s/%s/%s", pciBus, pciAddr, tpuDeviceType, deviceDents[0]))
|
||||
|
||||
dirs[tpuDeviceType][deviceDents[0]] = kernfs.NewStaticSymlink(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), fmt.Sprintf("../../devices/%s/%s/%s", pciPath, tpuDeviceType, deviceDents[0]))
|
||||
}
|
||||
}
|
||||
if len(dirs) == 0 {
|
||||
@@ -127,24 +131,17 @@ func (fs *filesystem) newDeviceClassDir(ctx context.Context, creds *auth.Credent
|
||||
}
|
||||
|
||||
// Create /sys/bus/pci/devices symlinks.
|
||||
func (fs *filesystem) newBusPCIDevicesDir(ctx context.Context, creds *auth.Credentials, sysDevicesPath string) (map[string]kernfs.Inode, error) {
|
||||
func (fs *filesystem) newBusPCIDevicesDir(ctx context.Context, creds *auth.Credentials, pciPaths map[string]string) (map[string]kernfs.Inode, error) {
|
||||
pciDevicesDir := map[string]kernfs.Inode{}
|
||||
pciPaths, err := sysDevicesPCIPaths(sysDevicesPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
for pciDevice, pciPath := range pciPaths {
|
||||
pciDevicesDir[pciDevice] = kernfs.NewStaticSymlink(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), fmt.Sprintf("../../../devices/%s", pciPath))
|
||||
}
|
||||
for _, pciPath := range pciPaths {
|
||||
pciAddr := path.Base(pciPath)
|
||||
pciBus := pciBusFromAddress(pciAddr)
|
||||
pciDevicesDir[pciAddr] = kernfs.NewStaticSymlink(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), fmt.Sprintf("../../../devices/pci%s/%s", pciBus, pciAddr))
|
||||
}
|
||||
|
||||
return pciDevicesDir, nil
|
||||
}
|
||||
|
||||
// Recursively build out sysfs directories according to the allowlisted files,
|
||||
// directories, and symlinks defined in this package.
|
||||
func (fs *filesystem) mirrorSysDevicesDir(ctx context.Context, creds *auth.Credentials, dir string, iommuGroups map[string]string) (map[string]kernfs.Inode, error) {
|
||||
func (fs *filesystem) mirrorSysDevicesDir(ctx context.Context, creds *auth.Credentials, dir string, iommuGroups, pciPaths map[string]string) (map[string]kernfs.Inode, error) {
|
||||
subs := map[string]kernfs.Inode{}
|
||||
dents, err := hostDirEntries(dir)
|
||||
if err != nil {
|
||||
@@ -161,7 +158,7 @@ func (fs *filesystem) mirrorSysDevicesDir(ctx context.Context, creds *auth.Crede
|
||||
if match := sysDevicesDirRegex.MatchString(dent); !match {
|
||||
continue
|
||||
}
|
||||
contents, err := fs.mirrorSysDevicesDir(ctx, creds, dentPath, iommuGroups)
|
||||
contents, err := fs.mirrorSysDevicesDir(ctx, creds, dentPath, iommuGroups, pciPaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -180,7 +177,7 @@ func (fs *filesystem) mirrorSysDevicesDir(ctx context.Context, creds *auth.Crede
|
||||
}
|
||||
// Both the device and PCI address entries are links to the original PCI
|
||||
// device directory that's at the same place earlier in the dir tree.
|
||||
linkContent = fmt.Sprintf("../../../%s", pciDeviceName)
|
||||
linkContent = fmt.Sprintf("../../../%s", pciPaths[pciDeviceName])
|
||||
case dent == "iommu_group":
|
||||
pciDeviceName, err := pciDeviceName(dir)
|
||||
if err != nil {
|
||||
@@ -190,7 +187,12 @@ func (fs *filesystem) mirrorSysDevicesDir(ctx context.Context, creds *auth.Crede
|
||||
if !exist {
|
||||
return nil, fmt.Errorf("no IOMMU group is found for device %v", pciDeviceName)
|
||||
}
|
||||
linkContent = fmt.Sprintf("../../../kernel/iommu_groups/%s", iommuGroupNum)
|
||||
// A PCI device path looks something like pci0000:00/0000:00:04.0. To
|
||||
// get to the /sys directory, we need to go up as many directories as
|
||||
// are in the pciPath plus one more for the "devices" directory.
|
||||
pciPathComponents := strings.Split(pciPaths[pciDeviceName], "/")
|
||||
upDirs := strings.Repeat("../", len(pciPathComponents)+1)
|
||||
linkContent = fmt.Sprintf("%skernel/iommu_groups/%s", upDirs, iommuGroupNum)
|
||||
default:
|
||||
continue
|
||||
}
|
||||
@@ -202,11 +204,11 @@ func (fs *filesystem) mirrorSysDevicesDir(ctx context.Context, creds *auth.Crede
|
||||
|
||||
// Infer a PCI device's name from its path.
|
||||
func pciDeviceName(pciDevicePath string) (string, error) {
|
||||
pciDeviceName := pciDeviceRegex.FindString(pciDevicePath)
|
||||
if pciDeviceName == "" {
|
||||
pciDeviceNames := pciDeviceRegex.FindAllString(pciDevicePath, -1)
|
||||
if len(pciDeviceNames) == 0 {
|
||||
return "", fmt.Errorf("no valid device name for the device path at %v", pciDevicePath)
|
||||
}
|
||||
return pciDeviceName, nil
|
||||
return pciDeviceNames[len(pciDeviceNames)-1], nil
|
||||
}
|
||||
|
||||
func hostFileMode(path string) (uint32, error) {
|
||||
@@ -214,6 +216,7 @@ func hostFileMode(path string) (uint32, error) {
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer unix.Close(fd)
|
||||
stat := unix.Stat_t{}
|
||||
if err := unix.Fstat(fd, &stat); err != nil {
|
||||
return 0, err
|
||||
|
||||
@@ -138,7 +138,11 @@ func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
return nil, nil, err
|
||||
}
|
||||
sysDevicesPath := path.Join(idata.TestSysfsPathPrefix, sysDevicesMainPath)
|
||||
sysDevicesSub, err := fs.mirrorSysDevicesDir(ctx, creds, sysDevicesPath, deviceToIOMMUGroup)
|
||||
pciPaths, err := pciDevicePaths(sysDevicesPath)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
sysDevicesSub, err := fs.mirrorSysDevicesDir(ctx, creds, sysDevicesPath, deviceToIOMMUGroup, pciPaths)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -146,7 +150,7 @@ func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
devicesSub[dir] = sub
|
||||
}
|
||||
|
||||
deviceDirs, err := fs.newDeviceClassDir(ctx, creds, []string{accelDevice, vfioDevice}, sysDevicesPath)
|
||||
deviceDirs, err := fs.newDeviceClassDir(ctx, creds, []string{accelDevice, vfioDevice}, sysDevicesPath, pciPaths)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -154,7 +158,7 @@ func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
for tpuDeviceType, symlinkDir := range deviceDirs {
|
||||
classSub[tpuDeviceType] = fs.newDir(ctx, creds, defaultSysDirMode, symlinkDir)
|
||||
}
|
||||
pciDevicesSub, err := fs.newBusPCIDevicesDir(ctx, creds, sysDevicesPath)
|
||||
pciDevicesSub, err := fs.newBusPCIDevicesDir(ctx, creds, pciPaths)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -162,7 +166,7 @@ func (fsType FilesystemType) GetFilesystem(ctx context.Context, vfsObj *vfs.Virt
|
||||
"devices": fs.newDir(ctx, creds, defaultSysDirMode, pciDevicesSub),
|
||||
})
|
||||
iommuPath := path.Join(idata.TestSysfsPathPrefix, iommuGroupSysPath)
|
||||
iommuGroups, err := fs.mirrorIOMMUGroups(ctx, creds, iommuPath)
|
||||
iommuGroups, err := fs.mirrorIOMMUGroups(ctx, creds, iommuPath, pciPaths)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -321,7 +325,7 @@ func kernelDir(ctx context.Context, fs *filesystem, creds *auth.Credentials) map
|
||||
}
|
||||
|
||||
// Recursively build out IOMMU directories from the host.
|
||||
func (fs *filesystem) mirrorIOMMUGroups(ctx context.Context, creds *auth.Credentials, dir string) (map[string]kernfs.Inode, error) {
|
||||
func (fs *filesystem) mirrorIOMMUGroups(ctx context.Context, creds *auth.Credentials, dir string, pciPaths map[string]string) (map[string]kernfs.Inode, error) {
|
||||
subs := map[string]kernfs.Inode{}
|
||||
dents, err := hostDirEntries(dir)
|
||||
if err != nil {
|
||||
@@ -340,7 +344,7 @@ func (fs *filesystem) mirrorIOMMUGroups(ctx context.Context, creds *auth.Credent
|
||||
}
|
||||
switch mode {
|
||||
case unix.S_IFDIR:
|
||||
contents, err := fs.mirrorIOMMUGroups(ctx, creds, absPath)
|
||||
contents, err := fs.mirrorIOMMUGroups(ctx, creds, absPath, pciPaths)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -349,8 +353,7 @@ func (fs *filesystem) mirrorIOMMUGroups(ctx context.Context, creds *auth.Credent
|
||||
subs[dent] = fs.newHostFile(ctx, creds, defaultSysMode, absPath)
|
||||
case unix.S_IFLNK:
|
||||
if pciDeviceRegex.MatchString(dent) {
|
||||
pciBus := pciBusFromAddress(dent)
|
||||
subs[dent] = kernfs.NewStaticSymlink(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), fmt.Sprintf("../../../../devices/pci%s/%s", pciBus, dent))
|
||||
subs[dent] = kernfs.NewStaticSymlink(ctx, creds, linux.UNNAMED_MAJOR, fs.devMinor, fs.NextIno(), fmt.Sprintf("../../../../devices/%s", pciPaths[dent]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,10 +186,11 @@ func TestEnableTPUProxyPathsV4(t *testing.T) {
|
||||
|
||||
type PCIDeviceInfo struct {
|
||||
// IOMMU group.
|
||||
group string
|
||||
pciPath string
|
||||
pciAddress string
|
||||
name string
|
||||
group string
|
||||
pciPath string
|
||||
pciAddress string
|
||||
name string
|
||||
nestedDeviceIndex int
|
||||
}
|
||||
|
||||
func (dev PCIDeviceInfo) path() string {
|
||||
@@ -218,22 +219,32 @@ func TestEnableTPUProxyPathsV5(t *testing.T) {
|
||||
|
||||
devices := []PCIDeviceInfo{
|
||||
PCIDeviceInfo{
|
||||
group: "0",
|
||||
pciPath: pciPath0,
|
||||
pciAddress: "0000:00:04.0",
|
||||
name: "vfio0",
|
||||
group: "0",
|
||||
pciPath: pciPath0,
|
||||
pciAddress: "0000:00:04.0",
|
||||
name: "vfio0",
|
||||
nestedDeviceIndex: -1,
|
||||
},
|
||||
PCIDeviceInfo{
|
||||
group: "1",
|
||||
pciPath: pciPath0,
|
||||
pciAddress: "0000:00:05.0",
|
||||
name: "vfio1",
|
||||
group: "1",
|
||||
pciPath: pciPath0,
|
||||
pciAddress: "0000:00:05.0",
|
||||
name: "vfio1",
|
||||
nestedDeviceIndex: -1,
|
||||
},
|
||||
PCIDeviceInfo{
|
||||
group: "2",
|
||||
pciPath: pciPath1,
|
||||
pciAddress: "0000:10:05.0",
|
||||
name: "vfio2",
|
||||
group: "2",
|
||||
pciPath: pciPath1,
|
||||
pciAddress: "0000:10:05.0",
|
||||
name: "vfio2",
|
||||
nestedDeviceIndex: 3,
|
||||
},
|
||||
PCIDeviceInfo{
|
||||
group: "3",
|
||||
pciPath: pciPath1,
|
||||
pciAddress: "0000:10:05.0/0000:03:00.1",
|
||||
name: "vfio3",
|
||||
nestedDeviceIndex: -1,
|
||||
},
|
||||
}
|
||||
for _, device := range devices {
|
||||
@@ -244,7 +255,7 @@ func TestEnableTPUProxyPathsV5(t *testing.T) {
|
||||
if err := os.Symlink(path.Join("..", "..", "..", device.pciAddress), path.Join(devicePath, "device")); err != nil {
|
||||
t.Fatalf("Failed to symlink device directory: %v", err)
|
||||
}
|
||||
if err := os.Symlink(path.Join("..", "..", "..", "devices", path.Base(device.pciPath), device.pciAddress), path.Join(busPath, device.pciAddress)); err != nil {
|
||||
if err := os.Symlink(path.Join("..", "..", "..", "devices", path.Base(device.pciPath), device.pciAddress), path.Join(busPath, path.Base(device.pciAddress))); err != nil {
|
||||
t.Fatalf("Failed to symlink bus directory: %v", err)
|
||||
}
|
||||
if err := os.Symlink(path.Join("..", "..", "devices", path.Base(device.pciPath), device.pciAddress, vfioDev, device.name), path.Join(sysClassPath, device.name)); err != nil {
|
||||
@@ -254,7 +265,7 @@ func TestEnableTPUProxyPathsV5(t *testing.T) {
|
||||
if err := os.MkdirAll(iommuPath, 0755); err != nil {
|
||||
t.Fatalf("Failed to create iommu_groups directory: %v", err)
|
||||
}
|
||||
if err := os.Symlink(path.Join("..", "..", "..", "..", "devices", path.Base(device.pciPath), device.pciAddress), path.Join(iommuPath, device.pciAddress)); err != nil {
|
||||
if err := os.Symlink(path.Join("..", "..", "..", "..", "devices", path.Base(device.pciPath), device.pciAddress), path.Join(iommuPath, path.Base(device.pciAddress))); err != nil {
|
||||
t.Fatalf("Failed to symlink iommu_group devices directory: %v", err)
|
||||
}
|
||||
if err := os.Symlink(path.Join("..", "..", "..", "kernel", "iommu_groups", device.group), path.Join(device.pciPath, device.pciAddress, "iommu_group")); err != nil {
|
||||
@@ -267,10 +278,15 @@ func TestEnableTPUProxyPathsV5(t *testing.T) {
|
||||
for _, device := range devices {
|
||||
// Validate PCI device symlinks.
|
||||
pop := s.PathOpAtRoot(path.Join("devices", path.Base(device.pciPath), device.pciAddress))
|
||||
s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{
|
||||
contents := map[string]testutil.DirentType{
|
||||
"iommu_group": linux.DT_LNK,
|
||||
vfioDev: linux.DT_DIR,
|
||||
})
|
||||
}
|
||||
if device.nestedDeviceIndex != -1 {
|
||||
deviceName := path.Base(devices[device.nestedDeviceIndex].pciAddress)
|
||||
contents[deviceName] = linux.DT_DIR
|
||||
}
|
||||
s.AssertAllDirentTypes(s.ListDirents(pop), contents)
|
||||
// Validate VFIO device symlinks.
|
||||
pop = s.PathOpAtRoot(path.Join("devices", path.Base(device.pciPath), device.pciAddress, vfioDev, device.name))
|
||||
s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{
|
||||
@@ -279,7 +295,7 @@ func TestEnableTPUProxyPathsV5(t *testing.T) {
|
||||
// Validate $IOMMU_GROUP/devices.
|
||||
pop = s.PathOpAtRoot(path.Join("kernel", "iommu_groups", string(device.group), "devices"))
|
||||
s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{
|
||||
device.pciAddress: linux.DT_LNK,
|
||||
path.Base(device.pciAddress): linux.DT_LNK,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1388,7 +1388,7 @@ func tpuProxyRegisterDevices(info *containerInfo, vfsObj *vfs.VirtualFilesystem)
|
||||
if err := tpuproxy.RegisterHostTPUDevices(vfsObj, allowedTPUDeviceIDs); err != nil {
|
||||
return fmt.Errorf("registering host TPU devices: %w", err)
|
||||
}
|
||||
if err := vfio.RegisterVFIODevice(vfsObj); err != nil {
|
||||
if err := vfio.RegisterVFIODevice(vfsObj, true /* useDevGofer */); err != nil {
|
||||
return fmt.Errorf("registering vfio driver: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user