gvisor.dev/gvisor@v0.0.0-20240520182842-f9d4d51c7e0f/pkg/sentry/fsimpl/sys/sys_test.go (about) 1 // Copyright 2019 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sys_test 16 17 import ( 18 "fmt" 19 "os" 20 "path" 21 "testing" 22 23 "github.com/google/go-cmp/cmp" 24 "gvisor.dev/gvisor/pkg/abi/linux" 25 "gvisor.dev/gvisor/pkg/sentry/fsimpl/sys" 26 "gvisor.dev/gvisor/pkg/sentry/fsimpl/testutil" 27 "gvisor.dev/gvisor/pkg/sentry/kernel" 28 "gvisor.dev/gvisor/pkg/sentry/kernel/auth" 29 "gvisor.dev/gvisor/pkg/sentry/vfs" 30 ) 31 32 const ( 33 vfioDev = "vfio-dev" 34 ) 35 36 func newTestSystem(t *testing.T, pciTestDir string) *testutil.System { 37 k, err := testutil.Boot() 38 if err != nil { 39 t.Fatalf("Failed to create test kernel: %v", err) 40 } 41 ctx := k.SupervisorContext() 42 creds := auth.CredentialsFromContext(ctx) 43 k.VFS().MustRegisterFilesystemType(sys.Name, sys.FilesystemType{}, &vfs.RegisterFilesystemTypeOptions{ 44 AllowUserMount: true, 45 }) 46 47 mountOpts := &vfs.MountOptions{ 48 GetFilesystemOptions: vfs.GetFilesystemOptions{ 49 InternalData: &sys.InternalData{ 50 EnableTPUProxyPaths: pciTestDir != "", 51 TestSysfsPathPrefix: pciTestDir, 52 }, 53 }, 54 } 55 56 mns, err := k.VFS().NewMountNamespace(ctx, creds, "", sys.Name, mountOpts, nil) 57 if err != nil { 58 t.Fatalf("Failed to create new mount namespace: %v", err) 59 } 60 return testutil.NewSystem(ctx, t, k.VFS(), mns) 61 } 62 63 func TestReadCPUFile(t *testing.T) { 64 s := newTestSystem(t, "" /*pciTestDir*/) 65 defer s.Destroy() 66 k := kernel.KernelFromContext(s.Ctx) 67 maxCPUCores := k.ApplicationCores() 68 69 expected := fmt.Sprintf("0-%d\n", maxCPUCores-1) 70 71 for _, fname := range []string{"online", "possible", "present"} { 72 pop := s.PathOpAtRoot(fmt.Sprintf("devices/system/cpu/%s", fname)) 73 fd, err := s.VFS.OpenAt(s.Ctx, s.Creds, pop, &vfs.OpenOptions{}) 74 if err != nil { 75 t.Fatalf("OpenAt(pop:%+v) = %+v failed: %v", pop, fd, err) 76 } 77 defer fd.DecRef(s.Ctx) 78 content, err := s.ReadToEnd(fd) 79 if err != nil { 80 t.Fatalf("Read failed: %v", err) 81 } 82 if diff := cmp.Diff(expected, content); diff != "" { 83 t.Fatalf("Read returned unexpected data:\n--- want\n+++ got\n%v", diff) 84 } 85 } 86 } 87 88 func TestSysRootContainsExpectedEntries(t *testing.T) { 89 s := newTestSystem(t, "" /*pciTestDir*/) 90 defer s.Destroy() 91 pop := s.PathOpAtRoot("/") 92 s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{ 93 "block": linux.DT_DIR, 94 "bus": linux.DT_DIR, 95 "class": linux.DT_DIR, 96 "dev": linux.DT_DIR, 97 "devices": linux.DT_DIR, 98 "firmware": linux.DT_DIR, 99 "fs": linux.DT_DIR, 100 "kernel": linux.DT_DIR, 101 "module": linux.DT_DIR, 102 "power": linux.DT_DIR, 103 }) 104 } 105 106 func TestCgroupMountpointExists(t *testing.T) { 107 // Note: The mountpoint is only created if cgroups are available. 108 s := newTestSystem(t, "" /*pciTestDir*/) 109 defer s.Destroy() 110 pop := s.PathOpAtRoot("/fs") 111 s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{ 112 "cgroup": linux.DT_DIR, 113 }) 114 pop = s.PathOpAtRoot("/fs/cgroup") 115 s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{ /*empty*/ }) 116 } 117 118 // Check that sysfs creates the required PCI paths for V4 TPUs. 119 func TestEnableTPUProxyPathsV4(t *testing.T) { 120 // Set up the fs tree that will be mirrored in the sentry. 121 sysfsTestDir := t.TempDir() 122 accelPath := path.Join(sysfsTestDir, "sys", "devices", "pci0000:00", "0000:00:04.0", "accel", "accel0") 123 if err := os.MkdirAll(accelPath, 0755); err != nil { 124 t.Fatalf("Failed to create accel directory: %v", err) 125 } 126 if err := os.Symlink(path.Join("..", "..", "..", "0000:00:04.0"), path.Join(accelPath, "0000:00:04.0")); err != nil { 127 t.Fatalf("Failed to symlink accel directory: %v", err) 128 } 129 if err := os.Symlink(path.Join("..", "..", "..", "0000:00:04.0"), path.Join(accelPath, "device")); err != nil { 130 t.Fatalf("Failed to symlink accel device directory: %v", err) 131 } 132 if _, err := os.Create(path.Join(accelPath, "chip_model")); err != nil { 133 t.Fatalf("Failed to create chip_model: %v", err) 134 } 135 if _, err := os.Create(path.Join(accelPath, "device_owner")); err != nil { 136 t.Fatalf("Failed to create device_owner: %v", err) 137 } 138 if _, err := os.Create(path.Join(accelPath, "pci_address")); err != nil { 139 t.Fatalf("Failed to create pci_address: %v", err) 140 } 141 busPath := path.Join(sysfsTestDir, "sys", "bus", "pci", "devices") 142 if err := os.MkdirAll(busPath, 0755); err != nil { 143 t.Fatalf("Failed to create bus directory: %v", err) 144 } 145 if err := os.Symlink(path.Join("..", "..", "..", "devices", "pci0000:00", "0000:00:04.0"), path.Join(busPath, "0000:00:04.0")); err != nil { 146 t.Fatalf("Failed to symlink bus directory: %v", err) 147 } 148 classAccelPath := path.Join(sysfsTestDir, "sys", "class", "accel") 149 if err := os.MkdirAll(classAccelPath, 0755); err != nil { 150 t.Fatalf("Failed to create accel directory: %v", err) 151 } 152 if err := os.Symlink(path.Join("..", "..", "devices", "pci0000:00", "0000:00:04.0", "accel", "accel0"), path.Join(classAccelPath, "accel0")); err != nil { 153 t.Fatalf("Failed to symlink accel directory: %v", err) 154 } 155 156 s := newTestSystem(t, sysfsTestDir) 157 defer s.Destroy() 158 159 pop := s.PathOpAtRoot("/devices/pci0000:00") 160 s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{ 161 "0000:00:04.0": linux.DT_DIR, 162 }) 163 pop = s.PathOpAtRoot("/devices/pci0000:00/0000:00:04.0/accel/accel0") 164 s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{ 165 "0000:00:04.0": linux.DT_LNK, 166 "device": linux.DT_LNK, 167 "chip_model": linux.DT_REG, 168 "device_owner": linux.DT_REG, 169 "pci_address": linux.DT_REG, 170 }) 171 pop = s.PathOpAtRoot("/bus/pci/devices") 172 s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{ 173 "0000:00:04.0": linux.DT_LNK, 174 }) 175 pop = s.PathOpAtRoot("/class/accel") 176 s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{ 177 "accel0": linux.DT_LNK, 178 }) 179 } 180 181 type PCIDeviceInfo struct { 182 // IOMMU group. 183 group string 184 pciPath string 185 pciAddress string 186 name string 187 } 188 189 func (dev PCIDeviceInfo) path() string { 190 return path.Join(dev.pciPath, dev.pciAddress, vfioDev, dev.name) 191 } 192 193 func TestEnableTPUProxyPathsV5(t *testing.T) { 194 // Set up the fs tree that will be mirrored in the sentry. 195 sysfsTestDir := t.TempDir() 196 pciPath := path.Join(sysfsTestDir, "sys", "devices", "pci0000:00") 197 if err := os.MkdirAll(pciPath, 0755); err != nil { 198 t.Fatalf("Failed to create PCI directory: %v", err) 199 } 200 busPath := path.Join(sysfsTestDir, "sys", "bus", "pci", "devices") 201 if err := os.MkdirAll(busPath, 0755); err != nil { 202 t.Fatalf("Failed to create bus directory: %v", err) 203 } 204 sysClassPath := path.Join(sysfsTestDir, "sys", "class", vfioDev) 205 if err := os.MkdirAll(sysClassPath, 0755); err != nil { 206 t.Fatalf("Failed to create class directory: %v", err) 207 } 208 209 devices := []PCIDeviceInfo{ 210 PCIDeviceInfo{ 211 group: "0", 212 pciPath: pciPath, 213 pciAddress: "0000:00:04.0", 214 name: "vfio0", 215 }, 216 PCIDeviceInfo{ 217 group: "1", 218 pciPath: pciPath, 219 pciAddress: "0000:00:05.0", 220 name: "vfio1", 221 }, 222 } 223 for _, device := range devices { 224 devicePath := device.path() 225 if err := os.MkdirAll(devicePath, 0755); err != nil { 226 t.Fatalf("Failed to create PCI device directory: %v", err) 227 } 228 if err := os.Symlink(path.Join("..", "..", "..", device.pciAddress), path.Join(devicePath, "device")); err != nil { 229 t.Fatalf("Failed to symlink device directory: %v", err) 230 } 231 if err := os.Symlink(path.Join("..", "..", "..", "devices", "pci0000:00", device.pciAddress), path.Join(busPath, device.pciAddress)); err != nil { 232 t.Fatalf("Failed to symlink bus directory: %v", err) 233 } 234 if err := os.Symlink(path.Join("..", "..", "devices", "pci0000:00", device.pciAddress, vfioDev, device.name), path.Join(sysClassPath, device.name)); err != nil { 235 t.Fatalf("Failed to symlink class directory: %v", err) 236 } 237 iommuPath := path.Join(sysfsTestDir, "sys", "kernel", "iommu_groups", device.group, "devices") 238 if err := os.MkdirAll(iommuPath, 0755); err != nil { 239 t.Fatalf("Failed to create iommu_groups directory: %v", err) 240 } 241 if err := os.Symlink(path.Join("..", "..", "..", "..", "devices", "pci0000:00", device.pciAddress), path.Join(iommuPath, device.pciAddress)); err != nil { 242 t.Fatalf("Failed to symlink iommu_group devices directory: %v", err) 243 } 244 if err := os.Symlink(path.Join("..", "..", "..", "kernel", "iommu_groups", device.group), path.Join(pciPath, device.pciAddress, "iommu_group")); err != nil { 245 t.Fatalf("Failed to symlink iommu_groups directory: %v", err) 246 } 247 } 248 s := newTestSystem(t, sysfsTestDir) 249 defer s.Destroy() 250 251 for _, device := range devices { 252 // Validate PCI device symlinks. 253 pop := s.PathOpAtRoot(path.Join("devices", "pci0000:00", device.pciAddress)) 254 s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{ 255 "iommu_group": linux.DT_LNK, 256 vfioDev: linux.DT_DIR, 257 }) 258 // Validate VFIO device symlinks. 259 pop = s.PathOpAtRoot(path.Join("devices", "pci0000:00", device.pciAddress, vfioDev, device.name)) 260 s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{ 261 "device": linux.DT_LNK, 262 }) 263 // Validate $IOMMU_GROUP/devices. 264 pop = s.PathOpAtRoot(path.Join("kernel", "iommu_groups", string(device.group), "devices")) 265 s.AssertAllDirentTypes(s.ListDirents(pop), map[string]testutil.DirentType{ 266 device.pciAddress: linux.DT_LNK, 267 }) 268 } 269 }