Files
Jamie LiuandgVisor bot 134f74b24b Add support for nvidia-imex.
- Add /proc/devices.

- Provide /proc/driver/nvidia/params when nvproxy is enabled. CUDA-using
  applications already try to open this file, but silently tolerate its
  non-existence. However, both the IMEX daemon and IMEX-using applications are
  believed to require this file for ImexChannelCount. (libnvidia-container
  additionally provides /proc/driver/nvidia/{registry,version}, but we have yet
  to see any application use these.)

- Add new capability nvconf.CapFabricIMEXManagement. When enabled, provide
  /proc/driver/nvidia/capabilities/fabric-imex-mgmt and the corresponding
  /dev/nvidia-caps/nvidia-cap#.

- Add support for /dev/nvidia-caps-imex-channels/ (irrespective of the new
  capability, since IMEX-using applications need this directory as well).

- Allow devutil.GoferClient.OpenAt() to take a relative path (i.e. containing
  more than one path component) rather than only a basename, since this is
  needed to open /dev/nvidia-caps/*.

- Add nvproxy support for all known-required controls, and all allocation
  classes to which those controls correspond.

This CL is specifically for nvidia-imex, the "NVIDIA IMEX Service for NVLink
Networks" (or "IMEX daemon"); applications using IMEX haven't been tested yet,
and may require additional allocation classes / control commands, or some
existing ones marked as requiring CapFabricIMEXManagement as being enabled more
broadly.

PiperOrigin-RevId: 859286209
2026-01-21 15:25:28 -08:00

107 lines
3.0 KiB
Go

// Copyright 2026 The gVisor Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package proc
import (
"fmt"
"path"
"gvisor.dev/gvisor/pkg/context"
"gvisor.dev/gvisor/pkg/fspath"
"gvisor.dev/gvisor/pkg/sentry/devices/nvproxy"
"gvisor.dev/gvisor/pkg/sentry/fsimpl/kernfs"
"gvisor.dev/gvisor/pkg/sentry/kernel"
"gvisor.dev/gvisor/pkg/sentry/kernel/auth"
)
func (fs *filesystem) addNvproxyFiles(ctx context.Context, root *auth.Credentials, k *kernel.Kernel, contents map[string]kernfs.Inode) {
procInfo := nvproxy.ProcfsInfoFromVFS(k.VFS())
if procInfo == nil {
return
}
if _, ok := contents["driver"]; ok {
panic("conflicting definition for /proc/driver")
}
// Build a dynamic filesystem tree ...
type dir struct {
parent *dir
name string
children map[string]any // *dir or string
}
dirName := func(d *dir) string {
var b fspath.Builder
for d.name != "" {
b.PrependComponent(d.name)
d = d.parent
}
return b.String()
}
nvidiaDir := &dir{
children: make(map[string]any),
}
for relpath, data := range procInfo.StaticFiles {
pit := fspath.Parse(relpath).Begin
d := nvidiaDir
for pit.NextOk() {
pc := pit.String()
subdirAny := d.children[pc]
var subdir *dir
if subdirAny == nil {
subdir = &dir{
parent: d,
name: pc,
children: make(map[string]any),
}
d.children[pc] = subdir
} else {
subdir, _ = subdirAny.(*dir)
if subdir == nil {
panic(fmt.Sprintf("nvproxy.ProcfsInfoFromVFS(): %s is both directory and file", path.Join(dirName(d), pc)))
}
}
pit = pit.Next()
d = subdir
}
pc := pit.String()
if _, ok := d.children[pc]; ok {
panic(fmt.Sprintf("nvproxy.ProcfsInfoFromVFS(): %s is specified multiple times", path.Join(dirName(d), pc)))
}
d.children[pc] = data
}
// ... then convert the tree to inodes.
var inodeFromNode func(node any) kernfs.Inode
inodeFromNode = func(node any) kernfs.Inode {
switch node := node.(type) {
case *dir:
childInodes := make(map[string]kernfs.Inode)
for childName, child := range node.children {
childInodes[childName] = inodeFromNode(child)
}
return fs.newStaticDir(ctx, root, childInodes)
case string:
// Real /proc/driver/nvidia/registry has mode 644, but we don't
// support writes.
return fs.newInode(ctx, root, 0o444, newStaticFile(node))
default:
panic(fmt.Sprintf("unexpected node type %T", node))
}
}
contents["driver"] = fs.newStaticDir(ctx, root, map[string]kernfs.Inode{
"nvidia": inodeFromNode(nvidiaDir),
})
}