Skip to content

Commit a55b3b2

Browse files
nixprimegvisor-bot
authored andcommitted
nvproxy: track objects created by NV_ESC_RM_DUP_OBJECT
PiperOrigin-RevId: 704502046
1 parent 0335cf7 commit a55b3b2

File tree

5 files changed

+92
-31
lines changed

5 files changed

+92
-31
lines changed

pkg/abi/nvgpu/nvgpu.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ func (h Handle) String() string {
4040
return fmt.Sprintf("%#x", h.Val)
4141
}
4242

43+
// NV01_NULL_OBJECT is a Handle representing no object.
44+
var NV01_NULL_OBJECT = Handle{0}
45+
4346
// P64 is NvP64, from src/common/sdk/nvidia/inc/nvtypes.h.
4447
//
4548
// +marshal

pkg/sentry/devices/nvproxy/frontend.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,32 @@ func rmAllocOSDescriptor(fi *frontendIoctlState, ioctlParams *nvgpu.IoctlNVOS02P
493493
return n, nil
494494
}
495495

496+
func rmDupObject(fi *frontendIoctlState) (uintptr, error) {
497+
var ioctlParams nvgpu.NVOS55Parameters
498+
if fi.ioctlParamsSize != nvgpu.SizeofNVOS55Parameters {
499+
return 0, linuxerr.EINVAL
500+
}
501+
if _, err := ioctlParams.CopyIn(fi.t, fi.ioctlParamsAddr); err != nil {
502+
return 0, err
503+
}
504+
505+
nvp := fi.fd.dev.nvp
506+
nvp.objsLock()
507+
n, err := frontendIoctlInvoke(fi, &ioctlParams)
508+
if err == nil && ioctlParams.Status == nvgpu.NV_OK {
509+
nvp.objDup(fi.ctx, ioctlParams.HClient, ioctlParams.HObject, ioctlParams.HParent, ioctlParams.HClientSrc, ioctlParams.HObjectSrc)
510+
}
511+
nvp.objsUnlock()
512+
if err != nil {
513+
return n, err
514+
}
515+
516+
if _, err := ioctlParams.CopyOut(fi.t, fi.ioctlParamsAddr); err != nil {
517+
return n, err
518+
}
519+
return n, nil
520+
}
521+
496522
func rmFree(fi *frontendIoctlState) (uintptr, error) {
497523
var ioctlParams nvgpu.NVOS00Parameters
498524
if fi.ioctlParamsSize != nvgpu.SizeofNVOS00Parameters {
@@ -902,7 +928,7 @@ func rmAllocNoParams(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters
902928

903929
func rmAllocRootClient(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, isNVOS64 bool) (uintptr, error) {
904930
return rmAllocSimpleParams(fi, ioctlParams, isNVOS64, func(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, rightsRequested nvgpu.RS_ACCESS_MASK, allocParams *nvgpu.Handle) {
905-
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, ioctlParams.HObjectNew, ioctlParams.HClass, newRootClient(fi.fd, ioctlParams, rightsRequested, allocParams))
931+
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, ioctlParams.HObjectNew, ioctlParams.HClass, newRootClient(fi.fd, ioctlParams, rightsRequested, allocParams), nvgpu.NV01_NULL_OBJECT /* parentH */)
906932
if fi.fd.clients == nil {
907933
fi.fd.clients = make(map[nvgpu.Handle]struct{})
908934
}
@@ -928,7 +954,7 @@ func rmAllocEventOSEvent(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parame
928954
allocParams.Data = nvgpu.P64(uint64(eventFile.hostFD))
929955

930956
n, err := rmAllocInvoke(fi, ioctlParams, &allocParams, isNVOS64, func(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS64Parameters, rightsRequested nvgpu.RS_ACCESS_MASK, allocParams *nvgpu.NV0005_ALLOC_PARAMETERS) {
931-
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, ioctlParams.HObjectNew, ioctlParams.HClass, &osEvent{}, ioctlParams.HObjectParent)
957+
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, ioctlParams.HObjectNew, ioctlParams.HClass, &miscObject{}, ioctlParams.HObjectParent)
932958
})
933959
if err != nil {
934960
return n, err

pkg/sentry/devices/nvproxy/frontend_unsafe.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ func rmVidHeapControlAllocSize(fi *frontendIoctlState, ioctlParams *nvgpu.NVOS32
326326
n, err := frontendIoctlInvoke(fi, ioctlParams)
327327
if err == nil && ioctlParams.Status == nvgpu.NV_OK {
328328
// src/nvidia/src/kernel/mem_mgr/virtual_mem.c:virtmemConstruct_IMPL() => refAddDependant()
329-
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, allocSizeParams.HMemory, nvgpu.NV50_MEMORY_VIRTUAL, &virtMem{}, ioctlParams.HObjectParent, ioctlParams.HVASpace)
329+
fi.fd.dev.nvp.objAdd(fi.ctx, ioctlParams.HRoot, allocSizeParams.HMemory, nvgpu.NV50_MEMORY_VIRTUAL, &miscObject{}, ioctlParams.HObjectParent, ioctlParams.HVASpace)
330330
}
331331
fi.fd.dev.nvp.objsUnlock()
332332
allocSizeParams.Address = origAddress

pkg/sentry/devices/nvproxy/object.go

Lines changed: 59 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ type object struct {
3131
client *rootClient // may be == impl
3232
class nvgpu.ClassID
3333
handle nvgpu.Handle // in client.resources, and also nvp.clients if impl is rootClient
34+
parent nvgpu.Handle
3435
impl objectImpl
3536

3637
// The driver tracks parent/child relationships and "arbitrary dependency"
@@ -73,13 +74,15 @@ func (nvp *nvproxy) objsUnlock() {
7374

7475
// objAdd records the allocation of a driver object with class c and handle h,
7576
// in the client with handle clientH, represented by oi. Each non-zero handle
76-
// in deps is a dependency of the created object, such that the freeing of any
77-
// of those objects also results in the freeing of the recorded object.
78-
func (nvp *nvproxy) objAdd(ctx context.Context, clientH, h nvgpu.Handle, c nvgpu.ClassID, oi objectImpl, deps ...nvgpu.Handle) {
79-
if h.Val == 0 {
80-
log.Traceback("nvproxy: new object (class %v) has invalid handle 0", c)
77+
// in parentH and deps is a dependency of the created object, such that the
78+
// freeing of any of those objects also results in the freeing of the recorded
79+
// object.
80+
func (nvp *nvproxy) objAdd(ctx context.Context, clientH, h nvgpu.Handle, c nvgpu.ClassID, oi objectImpl, parentH nvgpu.Handle, deps ...nvgpu.Handle) {
81+
if h == nvgpu.NV01_NULL_OBJECT {
82+
log.Traceback("nvproxy: new object (class %v) has invalid handle %v", c, h)
8183
return
8284
}
85+
8386
var client *rootClient
8487
// The driver forced NV01_ROOT and NV01_ROOT_NON_PRIV to NV01_ROOT_CLIENT,
8588
// 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
98101
return
99102
}
100103
}
104+
101105
o := oi.Object()
102106
o.nvp = nvp
103107
o.client = client
104108
o.class = c
105109
o.handle = h
110+
o.parent = parentH
106111
o.impl = oi
107112
if _, ok := client.resources[h]; ok {
108113
ctx.Warningf("nvproxy: handle %v:%v already in use", clientH, h)
109114
}
110115
client.resources[h] = o
116+
117+
if parentH != nvgpu.NV01_NULL_OBJECT {
118+
parent, ok := client.resources[parentH]
119+
if !ok {
120+
log.Traceback("nvproxy: new object %v:%v (class %v) has invalid parent handle %v", clientH, h, c, parentH)
121+
} else {
122+
nvp.objDep(o, parent)
123+
}
124+
}
111125
for _, depH := range deps {
112-
if depH.Val == 0 /* aka NV01_NULL_OBJECT */ {
126+
if depH == nvgpu.NV01_NULL_OBJECT {
113127
continue
114128
}
115129
dep, ok := client.resources[depH]
@@ -119,8 +133,9 @@ func (nvp *nvproxy) objAdd(ctx context.Context, clientH, h nvgpu.Handle, c nvgpu
119133
}
120134
nvp.objDep(o, dep)
121135
}
136+
122137
if ctx.IsLogging(log.Debug) {
123-
ctx.Debugf("nvproxy: added object %v:%v (class %v) with dependencies %v", clientH, h, c, deps)
138+
ctx.Debugf("nvproxy: added object %v:%v (class %v) with parent %v, dependencies %v", clientH, h, c, parentH, deps)
124139
}
125140
}
126141

@@ -161,6 +176,31 @@ func (nvp *nvproxy) objDep(o1, o2 *object) {
161176
o2.rdeps[o1] = struct{}{}
162177
}
163178

179+
// objDup records the duplication of the driver object with handle srcH in the
180+
// client with handle clientSrcH, to handle dstH in the client with handle
181+
// clientDstH, with new parent parentDstH.
182+
func (nvp *nvproxy) objDup(ctx context.Context, clientDstH, dstH, parentDstH, clientSrcH, srcH nvgpu.Handle) {
183+
clientSrc, ok := nvp.clients[clientSrcH]
184+
if !ok {
185+
ctx.Warningf("nvproxy: duplicating object handle %v with unknown client handle %v", srcH, clientSrcH)
186+
return
187+
}
188+
oSrc, ok := clientSrc.resources[srcH]
189+
if !ok {
190+
ctx.Warningf("nvproxy: duplicating object with unknown handle %v:%v", clientSrcH, srcH)
191+
return
192+
}
193+
oDst := &miscObject{}
194+
nvp.objAdd(ctx, clientDstH, dstH, oSrc.class, oDst, parentDstH)
195+
parentSrc := clientSrc.resources[oSrc.parent]
196+
// Copy all non-parent dependencies.
197+
for dep := range oSrc.deps {
198+
if dep != parentSrc {
199+
nvp.objDep(oDst.Object(), dep)
200+
}
201+
}
202+
}
203+
164204
// objFree marks an object and its transitive dependents as freed.
165205
//
166206
// Compare
@@ -279,6 +319,18 @@ func (o *rmAllocObject) Release(ctx context.Context) {
279319
// no-op
280320
}
281321

322+
// miscObject is an objectImpl tracking a driver object allocated by something
323+
// other than an invocation of NV_ESC_RM_ALLOC, whose class is not represented
324+
// by a more specific type.
325+
type miscObject struct {
326+
object
327+
}
328+
329+
// Release implements objectImpl.Release.
330+
func (o *miscObject) Release(ctx context.Context) {
331+
// no-op
332+
}
333+
282334
// rootClient is an objectImpl tracking a NV01_ROOT_CLIENT.
283335
//
284336
// +stateify savable
@@ -323,23 +375,3 @@ func (o *osDescMem) Release(ctx context.Context) {
323375
}
324376
})
325377
}
326-
327-
// osEvent is an objectImpl tracking a NV01_EVENT_OS_EVENT.
328-
type osEvent struct {
329-
object
330-
}
331-
332-
// Release implements objectImpl.Release.
333-
func (o *osEvent) Release(ctx context.Context) {
334-
// no-op
335-
}
336-
337-
// virtMem is an objectImpl tracking a NV50_MEMORY_VIRTUAL.
338-
type virtMem struct {
339-
object
340-
}
341-
342-
// Release implements objectImpl.Release.
343-
func (o *virtMem) Release(ctx context.Context) {
344-
// no-op
345-
}

pkg/sentry/devices/nvproxy/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ func Init() {
180180
nvgpu.NV_ESC_CHECK_VERSION_STR: feHandler(frontendIoctlSimple, compUtil), // nv_rm_api_version_t
181181
nvgpu.NV_ESC_ATTACH_GPUS_TO_FD: feHandler(frontendIoctlSimple, compUtil), // NvU32 array containing GPU IDs
182182
nvgpu.NV_ESC_SYS_PARAMS: feHandler(frontendIoctlSimple, compUtil), // nv_ioctl_sys_params_t
183-
nvgpu.NV_ESC_RM_DUP_OBJECT: feHandler(frontendIoctlSimple, compUtil), // NVOS55_PARAMETERS
183+
nvgpu.NV_ESC_RM_DUP_OBJECT: feHandler(rmDupObject, compUtil), // NVOS55_PARAMETERS
184184
nvgpu.NV_ESC_RM_SHARE: feHandler(frontendIoctlSimple, compUtil), // NVOS57_PARAMETERS
185185
nvgpu.NV_ESC_RM_UNMAP_MEMORY: feHandler(frontendIoctlSimple, compUtil), // NVOS34_PARAMETERS
186186
nvgpu.NV_ESC_RM_UPDATE_DEVICE_MAPPING_INFO: feHandler(frontendIoctlSimple, compUtil), // NVOS56_PARAMETERS

0 commit comments

Comments
 (0)