nvproxy: track objects created by NV_ESC_RM_DUP_OBJECT

PiperOrigin-RevId: 704502046
This commit is contained in:
Jamie Liu
2024-12-09 18:59:36 -08:00
committed by gVisor bot
parent 0335cf778d
commit a55b3b2d90
5 changed files with 92 additions and 31 deletions
+3
View File
@@ -40,6 +40,9 @@ func (h Handle) String() string {
return fmt.Sprintf("%#x", h.Val)
}
// NV01_NULL_OBJECT is a Handle representing no object.
var NV01_NULL_OBJECT = Handle{0}
// P64 is NvP64, from src/common/sdk/nvidia/inc/nvtypes.h.
//
// +marshal
+28 -2
View File
@@ -493,6 +493,32 @@ func rmAllocOSDescriptor(fi *frontendIoctlState, ioctlParams *nvgpu.IoctlNVOS02P
return n, nil
}
func rmDupObject(fi *frontendIoctlState) (uintptr, error) {
var ioctlParams nvgpu.NVOS55Parameters
if fi.ioctlParamsSize != nvgpu.SizeofNVOS55Parameters {
return 0, linuxerr.EINVAL
}
if _, err := ioctlParams.CopyIn(fi.t, fi.ioctlParamsAddr); err != nil {
return 0, err
}
nvp := fi.fd.dev.nvp
nvp.objsLock()
n, err := frontendIoctlInvoke(fi, &ioctlParams)
if err == nil && ioctlParams.Status == nvgpu.NV_OK {
nvp.objDup(fi.ctx, ioctlParams.HClient, ioctlParams.HObject, ioctlParams.HParent, ioctlParams.HClientSrc, ioctlParams.HObjectSrc)
}
nvp.objsUnlock()
if err != nil {
return n, err
}
if _, err := ioctlParams.CopyOut(fi.t, fi.ioctlParamsAddr); err != nil {
return n, err
}
return n, nil
}
func rmFree(fi *frontendIoctlState) (uintptr, error) {
var ioctlParams nvgpu.NVOS00Parameters
if fi.ioctlParamsSize != nvgpu.SizeofNVOS00Parameters {
@@ -902,7 +928,7 @@ func rmAllocNoParams(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters
func rmAllocRootClient(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, isNVOS64 bool) (uintptr, error) {
return rmAllocSimpleParams(fi, ioctlParams, isNVOS64, func(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, rightsRequested nvgpu.RS_ACCESS_MASK, allocParams *nvgpu.Handle) {
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, ioctlParams.HObjectNew, ioctlParams.HClass, newRootClient(fi.fd, ioctlParams, rightsRequested, allocParams))
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, ioctlParams.HObjectNew, ioctlParams.HClass, newRootClient(fi.fd, ioctlParams, rightsRequested, allocParams), nvgpu.NV01_NULL_OBJECT /* parentH */)
if fi.fd.clients == nil {
fi.fd.clients = make(map[nvgpu.Handle]struct{})
}
@@ -928,7 +954,7 @@ func rmAllocEventOSEvent(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parame
allocParams.Data = nvgpu.P64(uint64(eventFile.hostFD))
n, err := rmAllocInvoke(fi, ioctlParams, &allocParams, isNVOS64, func(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, rightsRequested nvgpu.RS_ACCESS_MASK, allocParams *nvgpu.NV0005_ALLOC_PARAMETERS) {
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, ioctlParams.HObjectNew, ioctlParams.HClass, &osEvent{}, ioctlParams.HObjectParent)
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, ioctlParams.HObjectNew, ioctlParams.HClass, &miscObject{}, ioctlParams.HObjectParent)
})
if err != nil {
return n, err
@@ -326,7 +326,7 @@ func rmVidHeapControlAllocSize(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS32
n, err := frontendIoctlInvoke(fi, ioctlParams)
if err == nil && ioctlParams.Status == nvgpu.NV_OK {
// src/nvidia/src/kernel/mem_mgr/virtual_mem.c:virtmemConstruct_IMPL() => refAddDependant()
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, allocSizeParams.HMemory, nvgpu.NV50_MEMORY_VIRTUAL, &virtMem{}, ioctlParams.HObjectParent, ioctlParams.HVASpace)
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, allocSizeParams.HMemory, nvgpu.NV50_MEMORY_VIRTUAL, &miscObject{}, ioctlParams.HObjectParent, ioctlParams.HVASpace)
}
fi.fd.dev.nvp.objsUnlock()
allocSizeParams.Address = origAddress
+59 -27
View File
@@ -31,6 +31,7 @@ type object struct {
client *rootClient // may be == impl
class nvgpu.ClassID
handle nvgpu.Handle // in client.resources, and also nvp.clients if impl is rootClient
parent nvgpu.Handle
impl objectImpl
// The driver tracks parent/child relationships and "arbitrary dependency"
@@ -73,13 +74,15 @@ func (nvp *nvproxy) objsUnlock() {
// objAdd records the allocation of a driver object with class c and handle h,
// in the client with handle clientH, represented by oi. Each non-zero handle
// in deps is a dependency of the created object, such that the freeing of any
// of those objects also results in the freeing of the recorded object.
func (nvp *nvproxy) objAdd(ctx context.Context, clientH, h nvgpu.Handle, c nvgpu.ClassID, oi objectImpl, deps ...nvgpu.Handle) {
if h.Val == 0 {
log.Traceback("nvproxy: new object (class %v) has invalid handle 0", c)
// in parentH and deps is a dependency of the created object, such that the
// freeing of any of those objects also results in the freeing of the recorded
// object.
func (nvp *nvproxy) objAdd(ctx context.Context, clientH, h nvgpu.Handle, c nvgpu.ClassID, oi objectImpl, parentH nvgpu.Handle, deps ...nvgpu.Handle) {
if h == nvgpu.NV01_NULL_OBJECT {
log.Traceback("nvproxy: new object (class %v) has invalid handle %v", c, h)
return
}
var client *rootClient
// The driver forced NV01_ROOT and NV01_ROOT_NON_PRIV to NV01_ROOT_CLIENT,
// so we only need to check for the latter.
@@ -98,18 +101,29 @@ func (nvp *nvproxy) objAdd(ctx context.Context, clientH, h nvgpu.Handle, c nvgpu
return
}
}
o := oi.Object()
o.nvp = nvp
o.client = client
o.class = c
o.handle = h
o.parent = parentH
o.impl = oi
if _, ok := client.resources[h]; ok {
ctx.Warningf("nvproxy: handle %v:%v already in use", clientH, h)
}
client.resources[h] = o
if parentH != nvgpu.NV01_NULL_OBJECT {
parent, ok := client.resources[parentH]
if !ok {
log.Traceback("nvproxy: new object %v:%v (class %v) has invalid parent handle %v", clientH, h, c, parentH)
} else {
nvp.objDep(o, parent)
}
}
for _, depH := range deps {
if depH.Val == 0 /* aka NV01_NULL_OBJECT */ {
if depH == nvgpu.NV01_NULL_OBJECT {
continue
}
dep, ok := client.resources[depH]
@@ -119,8 +133,9 @@ func (nvp *nvproxy) objAdd(ctx context.Context, clientH, h nvgpu.Handle, c nvgpu
}
nvp.objDep(o, dep)
}
if ctx.IsLogging(log.Debug) {
ctx.Debugf("nvproxy: added object %v:%v (class %v) with dependencies %v", clientH, h, c, deps)
ctx.Debugf("nvproxy: added object %v:%v (class %v) with parent %v, dependencies %v", clientH, h, c, parentH, deps)
}
}
@@ -161,6 +176,31 @@ func (nvp *nvproxy) objDep(o1, o2 *object) {
o2.rdeps[o1] = struct{}{}
}
// objDup records the duplication of the driver object with handle srcH in the
// client with handle clientSrcH, to handle dstH in the client with handle
// clientDstH, with new parent parentDstH.
func (nvp *nvproxy) objDup(ctx context.Context, clientDstH, dstH, parentDstH, clientSrcH, srcH nvgpu.Handle) {
clientSrc, ok := nvp.clients[clientSrcH]
if !ok {
ctx.Warningf("nvproxy: duplicating object handle %v with unknown client handle %v", srcH, clientSrcH)
return
}
oSrc, ok := clientSrc.resources[srcH]
if !ok {
ctx.Warningf("nvproxy: duplicating object with unknown handle %v:%v", clientSrcH, srcH)
return
}
oDst := &miscObject{}
nvp.objAdd(ctx, clientDstH, dstH, oSrc.class, oDst, parentDstH)
parentSrc := clientSrc.resources[oSrc.parent]
// Copy all non-parent dependencies.
for dep := range oSrc.deps {
if dep != parentSrc {
nvp.objDep(oDst.Object(), dep)
}
}
}
// objFree marks an object and its transitive dependents as freed.
//
// Compare
@@ -279,6 +319,18 @@ func (o *rmAllocObject) Release(ctx context.Context) {
// no-op
}
// miscObject is an objectImpl tracking a driver object allocated by something
// other than an invocation of NV_ESC_RM_ALLOC, whose class is not represented
// by a more specific type.
type miscObject struct {
object
}
// Release implements objectImpl.Release.
func (o *miscObject) Release(ctx context.Context) {
// no-op
}
// rootClient is an objectImpl tracking a NV01_ROOT_CLIENT.
//
// +stateify savable
@@ -323,23 +375,3 @@ func (o *osDescMem) Release(ctx context.Context) {
}
})
}
// osEvent is an objectImpl tracking a NV01_EVENT_OS_EVENT.
type osEvent struct {
object
}
// Release implements objectImpl.Release.
func (o *osEvent) Release(ctx context.Context) {
// no-op
}
// virtMem is an objectImpl tracking a NV50_MEMORY_VIRTUAL.
type virtMem struct {
object
}
// Release implements objectImpl.Release.
func (o *virtMem) Release(ctx context.Context) {
// no-op
}
+1 -1
View File
@@ -180,7 +180,7 @@ func Init() {
nvgpu.NV_ESC_CHECK_VERSION_STR: feHandler(frontendIoctlSimple, compUtil), // nv_rm_api_version_t
nvgpu.NV_ESC_ATTACH_GPUS_TO_FD: feHandler(frontendIoctlSimple, compUtil), // NvU32 array containing GPU IDs
nvgpu.NV_ESC_SYS_PARAMS: feHandler(frontendIoctlSimple, compUtil), // nv_ioctl_sys_params_t
nvgpu.NV_ESC_RM_DUP_OBJECT: feHandler(frontendIoctlSimple, compUtil), // NVOS55_PARAMETERS
nvgpu.NV_ESC_RM_DUP_OBJECT: feHandler(rmDupObject, compUtil), // NVOS55_PARAMETERS
nvgpu.NV_ESC_RM_SHARE: feHandler(frontendIoctlSimple, compUtil), // NVOS57_PARAMETERS
nvgpu.NV_ESC_RM_UNMAP_MEMORY: feHandler(frontendIoctlSimple, compUtil), // NVOS34_PARAMETERS
nvgpu.NV_ESC_RM_UPDATE_DEVICE_MAPPING_INFO: feHandler(frontendIoctlSimple, compUtil), // NVOS56_PARAMETERS