Add nested PCI device support and option to read directly from host dev files.

PiperOrigin-RevId: 670751194
This commit is contained in:
Lucas Manning
2024-09-03 16:51:13 -07:00
committed by gVisor bot
parent ae76d34ef5
commit 932d9dc64b
7 changed files with 173 additions and 109 deletions
+6 -6
View File
@@ -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)
}
+2 -2
View File
@@ -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",
+69 -27
View File
@@ -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,
})
}
+47 -44
View File
@@ -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
+11 -8
View File
@@ -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]))
}
}
}
+37 -21
View File
@@ -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
View File
@@ -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