1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2015-2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 
25 #include "nvlog_inc.h"
26 #include "resserv/resserv.h"
27 #include "resserv/rs_client.h"
28 #include "resserv/rs_server.h"
29 
30 #if !(RS_STANDALONE)
31 #include "os/os.h"
32 #include "resserv/rs_access_map.h"
33 #endif
34 
35 typedef enum
36 {
37     ALLOC_NEW_RESOURCE,
38     ALLOC_SHARED_RESOURCE
39 } ALLOC_TYPE;
40 
41 /**
42  * Allocate a new or shared resource in RM for this client
43  * @param[in]       pClient This client
44  * @param[in]       pServer The resource server instance
45  * @param[in]       pParams Parameters for the resource allocation
46  * @param[in,out]   phResource Server will assign a handle if it is 0
47  */
48 static NV_STATUS _clientAllocResourceHelper(RsClient *pClient, RsServer *pServer,
49                                             RS_RES_ALLOC_PARAMS_INTERNAL *pParams,
50                                             NvHandle *phResource);
51 
52 /**
53  * Add a resource reference to the client's resource hashmap
54  * @param[in] pClient This client
55  * @param[in] pServer The resource server that owns the resource ref
56  * @param[in] pParentRef   The resource's parent reference
57  * @param[in] hResource The resource's handle
58  * @param[in] classId   The resource's class
59  * @param[out] ppResourceRef The new resource reference
60  */
61 static NV_STATUS _clientConstructResourceRef(RsClient *pClient, RsServer *pServer, RsResourceRef *pParentRef,
62                                              NvHandle hResource, NvU32 classId, RsResourceRef **ppResourceRef);
63 
64 /**
65  * Release all CPU address mappings that reference this resource
66  *
67  * @param[in] pClient Client that owns the resource
68  * @param[in] pCallContext Caller information (which includes the resource reference
69  *                         whose mapping back references will be freed)
70  * @param[in] pLockInfo Information about which locks are already held, for recursive calls
71  */
72 static NV_STATUS _clientUnmapBackRefMappings(RsClient *pClient, CALL_CONTEXT *pCallContext, RS_LOCK_INFO *pLockInfo);
73 
74 static void _clientUnmapInterMappings(RsClient *pClient, CALL_CONTEXT *pCallContext, RS_LOCK_INFO *pLockInfo);
75 static void _clientUnmapInterBackRefMappings(RsClient *pClient, CALL_CONTEXT *pCallContext, RS_LOCK_INFO *pLockInfo);
76 
77 NV_STATUS
78 clientConstruct_IMPL
79 (
80     RsClient *pClient,
81     PORT_MEM_ALLOCATOR *pAllocator,
82     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
83 )
84 {
85     NV_STATUS status;
86     CLIENT_TYPE type;
87 
88     if (pParams->pSecInfo->privLevel >= RS_PRIV_LEVEL_KERNEL)
89         type = CLIENT_TYPE_KERNEL;
90     else
91         type = CLIENT_TYPE_USER;
92 
93     pClient->type = type;
94     pClient->hClient = pParams->hClient;
95 
96     mapInit(&pClient->resourceMap, pAllocator);
97     listInitIntrusive(&pClient->pendingFreeList);
98 
99     listInit(&pClient->accessBackRefList, pAllocator);
100 
101     pClient->handleGenIdx = 0;
102     status = clientSetHandleGenerator(pClient, 0, 0);
103     if (status != NV_OK)
104         return status;
105 
106     pClient->bActive = NV_TRUE;
107 
108     status = clientSetRestrictedRange(pClient, 0, 0);
109     if (status != NV_OK)
110         return status;
111 
112     return NV_OK;
113 }
114 
115 NV_STATUS
116 clientSetHandleGenerator_IMPL
117 (
118     RsClient *pClient,
119     NvHandle handleRangeStart,
120     NvHandle handleRangeSize
121 )
122 {
123     //
124     // on vGPU, when client uses RM allocated handles, post allocation of rmclient NV01_ROOT,
125     // NV01_DEVICE_0 is allocated which increment the handleGenIdx to 0x1.
126     // In order to avoid the handle clash, we split the default RM handle ranges between Guest RM
127     // (0xcaf00000, 0xcaf3ffff) and host RM (0xcaf40000, 0xcaf80000).
128     // Hence, we should take this overriding into consideration when the ranges over the default
129     // RM handle ranges.
130     //
131     NvBool bShrinkUnusedRange = ((pClient->handleRangeStart == handleRangeStart) &&
132                                  (pClient->handleGenIdx <= handleRangeSize));
133 
134     if (!((pClient->handleGenIdx == 0) || bShrinkUnusedRange))
135     {
136         return NV_ERR_INVALID_STATE;
137     }
138 
139     if ((handleRangeStart == 0) && (handleRangeSize == 0))
140     {
141         pClient->handleRangeStart = RS_UNIQUE_HANDLE_BASE;
142         pClient->handleRangeSize = RS_UNIQUE_HANDLE_RANGE;
143     }
144     else if ((handleRangeStart != 0) && (handleRangeSize != 0))
145     {
146         pClient->handleRangeStart = handleRangeStart;
147         pClient->handleRangeSize = handleRangeSize;
148     }
149     else
150     {
151         return NV_ERR_INVALID_PARAMETER;
152     }
153 
154     return NV_OK;
155 }
156 
157 NV_STATUS clientCanShareResource_IMPL
158 (
159     RsClient *pClient,
160     RsResourceRef *pResourceRef,
161     RS_SHARE_POLICY *pSharePolicy,
162     CALL_CONTEXT *pCallContext
163 )
164 {
165     NV_STATUS status = NV_OK;
166 
167     RS_ACCESS_MASK rightsNeeded;
168     RS_ACCESS_MASK *pRightsHeld;
169 
170     //
171     // If sharing, check that the client has the rights it is trying to share
172     // Revoking does not require this to allow revoking all rights without checking
173     //
174     if (!(pSharePolicy->action & RS_SHARE_ACTION_FLAG_REVOKE))
175     {
176         status = rsAccessCheckRights(pResourceRef, pClient, &pSharePolicy->accessMask);
177         if (status == NV_ERR_INSUFFICIENT_PERMISSIONS)
178         {
179             // Attempt to grant rights which aren't already owned
180             portMemCopy(&rightsNeeded, sizeof(rightsNeeded),
181                         &pSharePolicy->accessMask, sizeof(pSharePolicy->accessMask));
182 
183             pRightsHeld = rsAccessLookup(pResourceRef, pClient);
184             if (pRightsHeld != NULL)
185             {
186                 // Skip trying to grant rights already held
187                 RS_ACCESS_MASK_SUBTRACT(&rightsNeeded, pRightsHeld);
188             }
189 
190             status = rsAccessGrantRights(pResourceRef, pCallContext, pClient,
191                                          &rightsNeeded,    // pRightsRequested
192                                          NULL,             // pRightsRequired
193                                          NULL);            // pAllocParams
194         }
195     }
196 
197     return status;
198 }
199 
200 NV_STATUS
201 clientShareResource_IMPL
202 (
203     RsClient *pClient,
204     RsResourceRef *pResourceRef,
205     RS_SHARE_POLICY *pSharePolicy,
206     CALL_CONTEXT *pCallContext
207 )
208 {
209     RsServer *pServer = NULL;
210     RsShareList *pActiveList;
211     NV_STATUS status;
212 
213     status = clientCanShareResource(pClient, pResourceRef, pSharePolicy, pCallContext);
214     if (status != NV_OK)
215         return status;
216 
217     if (!pResourceRef->bSharePolicyListModified)
218     {
219         if (pSharePolicy->action & RS_SHARE_ACTION_FLAG_COMPOSE)
220         {
221             if (pCallContext != NULL)
222                 pServer = pCallContext->pServer;
223 
224             pActiveList = rsAccessGetActiveShareList(pResourceRef, pServer);
225             status = rsShareListCopy(&pResourceRef->sharePolicyList, pActiveList);
226             if (status != NV_OK)
227                 return status;
228         }
229 
230         pResourceRef->bSharePolicyListModified = NV_TRUE;
231     }
232 
233     if (!(pSharePolicy->action & RS_SHARE_ACTION_FLAG_COMPOSE))
234     {
235         listClear(&pResourceRef->sharePolicyList);
236     }
237 
238     if (pSharePolicy->action & RS_SHARE_ACTION_FLAG_REVOKE)
239     {
240         rsShareListRemove(&pResourceRef->sharePolicyList, pSharePolicy, NULL);
241     }
242     else
243     {
244         status = rsShareListInsert(&pResourceRef->sharePolicyList, pSharePolicy, NULL);
245     }
246 
247     return status;
248 }
249 
250 NV_STATUS
251 clientShareResourceTargetClient_IMPL
252 (
253     RsClient *pClient,
254     RsResourceRef *pResourceRef,
255     RS_SHARE_POLICY *pSharePolicy,
256     CALL_CONTEXT *pCallContext
257 )
258 {
259     NV_STATUS       status;
260     RS_ACCESS_MASK *pCurrentRights;
261 
262     // Special case: This should only be called when share policy is for own client
263     NV_ASSERT(pSharePolicy->type == RS_SHARE_TYPE_CLIENT);
264     NV_ASSERT(pSharePolicy->target == pClient->hClient);
265 
266     status = clientCanShareResource(pClient, pResourceRef, pSharePolicy, pCallContext);
267     if (status != NV_OK)
268         return status;
269 
270     pCurrentRights = rsAccessLookup(pResourceRef, pClient);
271 
272     if (pSharePolicy->action & RS_SHARE_ACTION_FLAG_REVOKE)
273     {
274         RS_ACCESS_MASK_SUBTRACT(pCurrentRights, &pSharePolicy->accessMask);
275     }
276     else
277     {
278         RS_ACCESS_MASK_UNION(pCurrentRights, &pSharePolicy->accessMask);
279     }
280 
281     return NV_OK;
282 }
283 
284 NV_STATUS
285 clientSetRestrictedRange_IMPL
286 (
287     RsClient *pClient,
288     NvHandle handleRangeStart,
289     NvU32 handleRangeSize
290 )
291 {
292     NvHandle hFirst = handleRangeStart;
293     NvHandle hLast;
294 
295     // Only allow modification if we haven't generated any handles
296     if (pClient->handleGenIdx != 0)
297         return NV_ERR_INVALID_STATE;
298 
299     if (handleRangeSize == 0)
300     {
301         if (handleRangeStart != 0)
302             return NV_ERR_INVALID_PARAMETER;
303 
304         pClient->handleRestrictRange = NV_RANGE_EMPTY;
305         return NV_OK;
306     }
307 
308     // Wrapping-around the reserved range is not supported
309     if (!portSafeAddU32(hFirst, handleRangeSize-1, &hLast))
310         return NV_ERR_INVALID_REQUEST;
311 
312     pClient->handleRestrictRange = rangeMake(hFirst, hLast);
313 
314     return NV_OK;
315 }
316 
317 void clientDestruct_IMPL
318 (
319     RsClient *pClient
320 )
321 {
322     NV_ASSERT(mapCount(&pClient->resourceMap) == 0);
323     mapDestroy(&pClient->resourceMap);
324 
325     NV_ASSERT(listCount(&pClient->accessBackRefList) == 0);
326     listDestroy(&pClient->accessBackRefList);
327 }
328 
329 NV_STATUS
330 clientGetResource_IMPL
331 (
332     RsClient *pClient,
333     NvHandle hResource,
334     NvU32 internalClassId,
335     RsResource **ppResource
336 )
337 {
338     NV_STATUS      status = NV_OK;
339     RsResourceRef *pResourceRef;
340     RsResource    *pResource;
341 
342     pResourceRef = mapFind(&pClient->resourceMap, hResource);
343     if (pResourceRef == NULL)
344     {
345         status = NV_ERR_OBJECT_NOT_FOUND;
346         pResource = NULL;
347         goto done;
348     }
349 
350     if (pResourceRef->internalClassId != internalClassId)
351     {
352         status = NV_ERR_INVALID_CLASS;
353         pResource = NULL;
354         goto done;
355     }
356 
357     pResource = pResourceRef->pResource;
358 
359 done:
360     if (ppResource != NULL)
361         *ppResource = pResource;
362 
363     return status;
364 }
365 
366 NV_STATUS
367 clientGetResourceByRef_IMPL
368 (
369     RsClient *pClient,
370     RsResourceRef *pResourceRef,
371     RsResource **ppResource
372 )
373 {
374     if (ppResource != NULL)
375         *ppResource = pResourceRef->pResource;
376 
377     return NV_OK;
378 }
379 
380 NV_STATUS
381 clientGetResourceRef_IMPL
382 (
383     RsClient *pClient,
384     NvHandle hResource,
385     RsResourceRef **ppResourceRef
386 )
387 {
388     RsResourceRef *pResourceRef;
389 
390     pResourceRef = mapFind(&pClient->resourceMap, hResource);
391     if (pResourceRef == NULL)
392         return NV_ERR_OBJECT_NOT_FOUND;
393 
394     if (ppResourceRef != NULL)
395         *ppResourceRef = pResourceRef;
396 
397     return NV_OK;
398 }
399 
400 NV_STATUS
401 clientGetResourceRefWithAccess_IMPL
402 (
403     RsClient *pClient,
404     NvHandle hResource,
405     const RS_ACCESS_MASK *pRightsRequired,
406     RsResourceRef **ppResourceRef
407 )
408 {
409     NV_STATUS status;
410     RsResourceRef *pResourceRef;
411 
412     status = clientGetResourceRef(pClient, hResource, &pResourceRef);
413     if (status != NV_OK)
414         return status;
415 
416     status = rsAccessCheckRights(pResourceRef, pClient, pRightsRequired);
417     if (status != NV_OK)
418         return status;
419 
420     if (ppResourceRef != NULL)
421         *ppResourceRef = pResourceRef;
422 
423     return NV_OK;
424 }
425 
426 NV_STATUS
427 clientGetResourceRefByType_IMPL
428 (
429     RsClient *pClient,
430     NvHandle hResource,
431     NvU32 internalClassId,
432     RsResourceRef **ppResourceRef
433 )
434 {
435     NV_STATUS status;
436     RsResourceRef *pResourceRef;
437 
438     status = clientGetResourceRef(pClient, hResource, &pResourceRef);
439     if (status != NV_OK)
440         return status;
441 
442     if (pResourceRef->internalClassId != internalClassId)
443         return NV_ERR_INVALID_OBJECT_HANDLE;
444 
445     if (ppResourceRef != NULL)
446         *ppResourceRef = pResourceRef;
447 
448     return NV_OK;
449 }
450 
451 NV_STATUS
452 clientValidate_IMPL
453 (
454     RsClient                *pClient,
455     const API_SECURITY_INFO *pSecInfo
456 )
457 {
458     return NV_OK;
459 }
460 
461 RS_PRIV_LEVEL
462 clientGetCachedPrivilege_IMPL
463 (
464     RsClient *pClient
465 )
466 {
467     // Non-functional, base class stubs
468     return RS_PRIV_LEVEL_USER;
469 }
470 
471 NvBool
472 clientIsAdmin_IMPL
473 (
474     RsClient *pClient,
475     RS_PRIV_LEVEL privLevel
476 )
477 {
478     // Non-functional, base class stubs
479     return NV_FALSE;
480 }
481 
482 NV_STATUS
483 clientAllocResource_IMPL
484 (
485     RsClient   *pClient,
486     RsServer   *pServer,
487     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
488 )
489 {
490     return _clientAllocResourceHelper(pClient, pServer, pParams, &pParams->hResource);
491 }
492 
493 NV_STATUS
494 clientCopyResource_IMPL
495 (
496     RsClient   *pClient,
497     RsServer   *pServer,
498     RS_RES_DUP_PARAMS_INTERNAL *pParams
499 )
500 {
501     RS_RES_ALLOC_PARAMS_INTERNAL params;
502     CALL_CONTEXT  callContext;
503     CALL_CONTEXT *pOldContext = NULL;
504 
505     RsClient *pClientDst = NULL;
506     RsResourceRef *pParentRef = NULL;
507 
508     NV_STATUS status;
509 
510     status = serverGetClientUnderLock(pServer, pParams->hClientDst, &pClientDst);
511     if (status != NV_OK)
512         return status;
513 
514     status = clientGetResourceRef(pClientDst, pParams->hParentDst, &pParentRef);
515     if (status != NV_OK)
516         return status;
517 
518     portMemSet(&callContext, 0, sizeof(callContext));
519     callContext.pServer = pServer;
520     callContext.pClient = pClient;
521     callContext.pResourceRef = pParams->pSrcRef;
522     callContext.pContextRef = pParentRef;
523     callContext.secInfo = *pParams->pSecInfo;
524     callContext.pLockInfo = pParams->pLockInfo;
525 
526     resservSwapTlsCallContext(&pOldContext, &callContext);
527 
528     //
529     // Kernel clients are allowed to dup anything, unless they request otherwise.
530     // Also, if access rights are disabled, owner client should still be able to dup.
531     // For anything else, check that the client has dup access on the object
532     //
533     if (((pParams->pSecInfo->privLevel < RS_PRIV_LEVEL_KERNEL) ||
534          (pParams->flags & NV04_DUP_HANDLE_FLAGS_REJECT_KERNEL_DUP_PRIVILEGE)) &&
535         (pServer->bRsAccessEnabled || (pParams->pSrcClient->hClient != pClient->hClient)))
536     {
537         RS_ACCESS_MASK rightsRequired;
538 
539         portMemSet(&rightsRequired, 0, sizeof(rightsRequired));
540         RS_ACCESS_MASK_ADD(&rightsRequired, RS_ACCESS_DUP_OBJECT);
541 
542         status = rsAccessCheckRights(pParams->pSrcRef, pClient, &rightsRequired);
543     }
544     else
545     {
546         // Server's globalInternalSharePolicyList applies Require policies even to kernel
547         RsShareListIter it = listIterAll(&pServer->globalInternalSharePolicyList);
548         while (listIterNext(&it))
549         {
550             RS_SHARE_POLICY *pSharePolicy = it.pValue;
551 
552             // We only care about failing Require policies which apply to Dup, ignore everything else
553             if ((pSharePolicy->action & RS_SHARE_ACTION_FLAG_REQUIRE) &&
554                 RS_ACCESS_MASK_TEST(&pSharePolicy->accessMask, RS_ACCESS_DUP_OBJECT) &&
555                 !resShareCallback(pParams->pSrcRef->pResource, pClient, pParentRef, pSharePolicy))
556             {
557                 status = NV_ERR_INVALID_REQUEST;
558                 break;
559             }
560         }
561     }
562 
563     resservRestoreTlsCallContext(pOldContext);
564 
565     if (status != NV_OK)
566         return status;
567 
568     portMemSet(&params, 0, sizeof(params));
569 
570     params.hClient = pClient->hClient;
571     params.hParent = pParams->hParentDst;
572     params.hResource = pParams->hResourceDst;
573     params.externalClassId = pParams->pSrcRef->externalClassId;
574     params.pSecInfo = pParams->pSecInfo;
575 
576     params.pSrcClient = pParams->pSrcClient;
577     params.pSrcRef = pParams->pSrcRef;
578     params.pAllocParams = pParams->pShareParams;
579     params.pLockInfo = pParams->pLockInfo;
580     params.allocFlags = pParams->flags;
581 
582     return _clientAllocResourceHelper(pClient, pServer, &params, &pParams->hResourceDst);
583 }
584 
585 static
586 NV_STATUS
587 _clientAllocResourceHelper
588 (
589     RsClient *pClient,
590     RsServer *pServer,
591     RS_RES_ALLOC_PARAMS_INTERNAL *pParams,
592     NvHandle *phResource
593 )
594 {
595     NV_STATUS       status;
596     NvHandle        hResource = *phResource;
597     NvU32           depth = 0;
598     RsResource     *pResource = NULL;
599     RsResourceRef  *pParentRef = NULL;
600     RsResourceRef  *pResourceRef = NULL;
601     CALL_CONTEXT    callContext;
602     CALL_CONTEXT   *pOldContext = NULL;
603     NvHandle        hParent = pParams->hParent;
604 
605     status = clientGetResourceRef(pClient, hParent, &pParentRef);
606     if (status != NV_OK && hParent != pClient->hClient && hParent != 0)
607         return status;
608 
609     status = _clientConstructResourceRef(pClient, pServer, pParentRef, hResource, pParams->externalClassId, &pResourceRef);
610     if (status != NV_OK)
611         goto fail;
612 
613     portMemSet(&callContext, 0, sizeof(callContext));
614     callContext.pServer = pServer;
615     callContext.pClient = pClient;
616     callContext.pResourceRef = pResourceRef;
617     callContext.pContextRef = pParams->pSrcRef;
618     callContext.pLockInfo = pParams->pLockInfo;
619 
620     if (pParams->pSecInfo == NULL)
621     {
622         status = NV_ERR_INVALID_ARGUMENT;
623         goto fail;
624     }
625     callContext.secInfo = *pParams->pSecInfo;
626 
627     resservSwapTlsCallContext(&pOldContext, &callContext);
628     status = resservResourceFactory(pServer->pAllocator, &callContext, pParams, &pResource);
629     resservRestoreTlsCallContext(pOldContext);
630 
631     if (status != NV_OK)
632         goto fail;
633 
634     // Clear free params implicitly set by constructor
635     resSetFreeParams(pResource, NULL, NULL);
636     pParams->pResourceRef = pResourceRef;
637 
638     //
639     // resConstruct_IMPL sets these fields but we need to set them again until
640     // Bug 2527351 is fixed
641     //
642     pResourceRef->pResource = pResource;
643     pResource->pResourceRef = pResourceRef;
644 
645     if (pParentRef != NULL)
646     {
647         depth = pParentRef->depth + 1;
648         pResourceRef->depth = depth;
649 
650         // Allow one additional level of depth to offset the depth used up by the RsClientResource at the root
651         // of the object hierarchy
652         if (RS_MAX_RESOURCE_DEPTH + 1 <= depth)
653         {
654             status = NV_ERR_ILLEGAL_ACTION;
655             goto fail;
656         }
657 
658         // Add this ref to the parent's child map
659         if (NV_OK != indexAdd(&pParentRef->childRefMap, pResourceRef->internalClassId, pResourceRef))
660         {
661             status = NV_ERR_INSUFFICIENT_RESOURCES;
662             goto fail;
663         }
664     }
665 
666     if (pServer->bRsAccessEnabled)
667     {
668         status = rsAccessGrantRights(pResourceRef, &callContext, pClient,
669                                      pParams->pRightsRequested,
670                                      pParams->pRightsRequired,
671                                      pParams->pAllocParams);
672         if (status != NV_OK)
673             goto fail;
674     }
675 
676     *phResource = hResource;
677 
678     return NV_OK;
679 
680 fail:
681     if (pResource != NULL)
682     {
683         RS_RES_FREE_PARAMS_INTERNAL params;
684         pOldContext = NULL;
685 
686         // First undo dependency tracking since it might access the resource
687         if (pResourceRef->pDependantSession != NULL)
688             sessionRemoveDependency(pResourceRef->pDependantSession, pResourceRef);
689 
690         if (pResourceRef->pSession != NULL)
691             sessionRemoveDependant(pResourceRef->pSession, pResourceRef);
692 
693         portMemSet(&params, 0, sizeof(params));
694         portMemSet(&callContext, 0, sizeof(callContext));
695         callContext.pServer = pServer;
696         callContext.pClient = pClient;
697         callContext.secInfo = *pParams->pSecInfo;
698         callContext.pResourceRef = pResourceRef;
699         callContext.pLockInfo = pParams->pLockInfo;
700 
701         resservSwapTlsCallContext(&pOldContext, &callContext);
702         resSetFreeParams(pResource, &callContext, &params);
703 
704         objDelete(pResource);
705         resservRestoreTlsCallContext(pOldContext);
706     }
707 
708     if (pResourceRef != NULL)
709     {
710         if (pParentRef != NULL)
711         {
712             indexRemove(&pParentRef->childRefMap, pResourceRef->internalClassId, pResourceRef);
713         }
714 
715         clientDestructResourceRef(pClient, pServer, pResourceRef);
716     }
717 
718     return status;
719 }
720 
721 static
722 NV_STATUS
723 _refCleanupDependencies
724 (
725     RsResourceRef *pResourceRef
726 )
727 {
728     RsResourceRef **ppIndepRef;
729     while (NULL != (ppIndepRef = multimapFirstItem(&pResourceRef->depBackRefMap)))
730     {
731         refRemoveDependant(*ppIndepRef, pResourceRef);
732     }
733 
734     return NV_OK;
735 }
736 
737 static
738 NV_STATUS
739 _refCleanupDependants
740 (
741     RsResourceRef *pResourceRef
742 )
743 {
744     RsResourceRef **ppDepRef;
745     while (NULL != (ppDepRef = multimapFirstItem(&pResourceRef->depRefMap)))
746     {
747         refRemoveDependant(pResourceRef, *ppDepRef);
748     }
749 
750     return NV_OK;
751 }
752 
753 NV_STATUS
754 clientFreeResource_IMPL
755 (
756     RsClient   *pClient,
757     RsServer   *pServer,
758     RS_RES_FREE_PARAMS_INTERNAL *pParams
759 )
760 {
761     NV_STATUS       status = NV_OK;
762     NV_STATUS       tmpStatus;
763     CALL_CONTEXT    callContext;
764     CALL_CONTEXT   *pOldContext = NULL;
765     RsResourceRef  *pClientRef = NULL;
766     RsResourceRef  *pParentRef = NULL;
767     RsResourceRef  *pResourceRef;
768     RsResource     *pResource;
769 
770     pResourceRef = mapFind(&pClient->resourceMap, pParams->hResource);
771     if (pResourceRef == NULL)
772         return NV_ERR_OBJECT_NOT_FOUND;
773 
774     if (refPendingFree(pResourceRef, pClient))
775         listRemove(&pClient->pendingFreeList, pResourceRef);
776 
777     pResource = pResourceRef->pResource;
778     pParentRef = pResourceRef->pParentRef;
779 
780     if (!pParams->bInvalidateOnly && pResourceRef->bInvalidated)
781         goto done;
782 
783     portMemSet(&callContext, 0, sizeof(callContext));
784     callContext.pClient = pClient;
785     callContext.pResourceRef = pResourceRef;
786     callContext.pServer = pServer;
787     callContext.pLockInfo = pParams->pLockInfo;
788 
789     // Some MODS tests don't set secInfo.
790     if (pParams->pSecInfo != NULL)
791         callContext.secInfo = *pParams->pSecInfo;
792 
793     resservSwapTlsCallContext(&pOldContext, &callContext);
794     resSetFreeParams(pResource, &callContext, pParams);
795 
796     resPreDestruct(pResource);
797 
798     // Remove all CPU mappings
799     clientUnmapResourceRefMappings(pClient, &callContext, pParams->pLockInfo);
800     _clientUnmapBackRefMappings(pClient, &callContext, pParams->pLockInfo);
801 
802     // Remove all inter-mappings
803     _clientUnmapInterMappings(pClient, &callContext, pParams->pLockInfo);
804     _clientUnmapInterBackRefMappings(pClient, &callContext, pParams->pLockInfo);
805 
806     // Remove this resource as a dependency from other resources
807     pResourceRef->bInvalidated = NV_TRUE;
808     _refCleanupDependencies(pResourceRef);
809 
810     if (pResourceRef->pDependantSession != NULL)
811         sessionRemoveDependency(pResourceRef->pDependantSession, pResourceRef);
812 
813     if (pResourceRef->pSession != NULL)
814         sessionRemoveDependant(pResourceRef->pSession, pResourceRef);
815 
816     status = serverFreeResourceRpcUnderLock(pServer, pParams);
817     NV_ASSERT(status == NV_OK);
818 
819     // NV_PRINTF(LEVEL_INFO, "hClient %x: Freeing hResource: %x\n",
820     //          pClient->hClient, pResourceRef->hResource);
821 
822     objDelete(pResource);
823 
824     pResourceRef->pResource = NULL;
825 
826     resservRestoreTlsCallContext(pOldContext);
827 
828 done:
829     if (!pParams->bInvalidateOnly)
830     {
831         // Remove this ref from its parent's child ref list
832         if (pParentRef != NULL)
833         {
834             multimapRemoveItemByKey(&pParentRef->childRefMap,
835                 pResourceRef->internalClassId, pResourceRef->hResource);
836         }
837 
838         pClientRef = mapFind(&pClient->resourceMap, pClient->hClient);
839         if (pClientRef != NULL)
840             refUncacheRef(pClientRef, pResourceRef);
841 
842         tmpStatus = clientDestructResourceRef(pClient, pServer, pResourceRef);
843         NV_ASSERT(tmpStatus == NV_OK);
844     }
845 
846     return status;
847 }
848 
849 NV_STATUS
850 clientUnmapMemory_IMPL
851 (
852     RsClient *pClient,
853     RsResourceRef *pResourceRef,
854     RS_LOCK_INFO  *pLockInfo,
855     RsCpuMapping **ppCpuMapping,
856     API_SECURITY_INFO *pSecInfo
857 )
858 {
859     NV_STATUS status;
860     CALL_CONTEXT callContext;
861     CALL_CONTEXT *pOldContext = NULL;
862     RsCpuMapping *pCpuMapping = *ppCpuMapping;
863 
864     portMemSet(&callContext, 0, sizeof(callContext));
865     callContext.pClient = pClient;
866     callContext.pResourceRef = pResourceRef;
867     callContext.pLockInfo = pLockInfo;
868 
869     // Some MODS tests don't set secInfo.
870     if (pSecInfo != NULL)
871         callContext.secInfo = *pSecInfo;
872 
873     resservSwapTlsCallContext(&pOldContext, &callContext);
874     status = resUnmap(pResourceRef->pResource, &callContext, pCpuMapping);
875     resservRestoreTlsCallContext(pOldContext);
876 
877     if (status != NV_OK)
878     {
879         NV_PRINTF(LEVEL_ERROR, "hClient %x: Failed to unmap cpu mapping: hResource: %x error: 0x%x\n",
880                 pClient->hClient,
881                 pResourceRef->hResource,
882                 status);
883 
884         if (pCpuMapping != NULL)
885         {
886             NV_PRINTF(LEVEL_ERROR, "hContext: %x\n",
887                       (pCpuMapping->pContextRef == NULL) ? 0 : pCpuMapping->pContextRef->hResource);
888         }
889     }
890 
891     refRemoveMapping(pResourceRef, pCpuMapping);
892     *ppCpuMapping = NULL;
893 
894     return status;
895 }
896 
897 NV_STATUS
898 clientInterMap_IMPL
899 (
900     RsClient *pClient,
901     RsResourceRef *pMapperRef,
902     RsResourceRef *pMappableRef,
903     RS_INTER_MAP_PARAMS *pParams
904 )
905 {
906     return NV_ERR_INVALID_CLIENT;
907 }
908 
909 void
910 clientInterUnmap_IMPL
911 (
912     RsClient *pClient,
913     RsResourceRef *pMapperRef,
914     RS_INTER_UNMAP_PARAMS *pParams
915 )
916 {
917     return;
918 }
919 
920 NV_STATUS
921 clientGenResourceHandle_IMPL
922 (
923     RsClient *pClient,
924     NvHandle *pHandle
925 )
926 {
927     NvHandle hFirst;
928     NvHandle hResource;
929     NV_STATUS status;
930 
931     NV_ASSERT(pClient->handleRangeStart != 0);
932     NV_ASSERT(pClient->handleRangeSize != 0);
933 
934     hResource = pClient->handleRangeStart + ((pClient->handleGenIdx++) % pClient->handleRangeSize);
935     status = clientValidateNewResourceHandle(pClient, hResource, NV_FALSE);
936     if (status == NV_OK)
937     {
938         goto done;
939     }
940 
941     hFirst = hResource;
942     do
943     {
944         hResource = pClient->handleRangeStart + ((pClient->handleGenIdx++) % pClient->handleRangeSize);
945         status = clientValidateNewResourceHandle(pClient, hResource, NV_FALSE);
946     } while(hResource != hFirst && status != NV_OK);
947 
948     if (status != NV_OK)
949         return NV_ERR_INSUFFICIENT_RESOURCES;
950 
951 done:
952     NV_ASSERT(hResource - pClient->handleRangeStart < pClient->handleRangeSize);
953 
954     *pHandle = hResource;
955     return NV_OK;
956 }
957 
958 NV_STATUS
959 clientAssignResourceHandle_IMPL
960 (
961     RsClient *pClient,
962     NvHandle *phResource
963 )
964 {
965     NV_STATUS status;
966 
967     if (phResource == NULL)
968         return NV_ERR_INVALID_ARGUMENT;
969 
970     if (*phResource == 0)
971     {
972         status = clientGenResourceHandle(pClient, phResource);
973     }
974     else
975     {
976         status = clientValidateNewResourceHandle(pClient, *phResource, NV_TRUE);
977     }
978 
979     return status;
980 
981 }
982 
983 static
984 NV_STATUS
985 _clientConstructResourceRef
986 (
987     RsClient *pClient,
988     RsServer *pServer,
989     RsResourceRef *pParentRef,
990     NvHandle hResource,
991     NvU32    externalClassId,
992     RsResourceRef **ppResourceRef
993 )
994 {
995     PORT_MEM_ALLOCATOR *pAllocator = pServer->pAllocator;
996     RsResourceRef *pResourceRef = mapInsertNew(&pClient->resourceMap, hResource);
997     if (pResourceRef == NULL)
998         return NV_ERR_INSUFFICIENT_RESOURCES;
999 
1000     if (!pClient->bResourceWarning && (mapCount(&pClient->resourceMap) >= RS_CLIENT_RESOURCE_WARNING_THRESHOLD))
1001     {
1002         NV_PRINTF(LEVEL_WARNING, "Client 0x%08x has allocated a large number of resources. [Current classid: 0x%04x]\n", pClient->hClient, externalClassId);
1003         NV_PRINTF(LEVEL_WARNING, "The client may be leaking resources. This warning can be ignored if the allocations were intentional.\n");
1004         pClient->bResourceWarning = NV_TRUE;
1005     }
1006 
1007     pResourceRef->pClient = pClient;
1008     pResourceRef->pResourceDesc = RsResInfoByExternalClassId(externalClassId);
1009     pResourceRef->externalClassId = externalClassId;
1010     pResourceRef->internalClassId = RsResInfoGetInternalClassId(pResourceRef->pResourceDesc);
1011     pResourceRef->pResource = NULL;
1012     pResourceRef->pParentRef = pParentRef;
1013     pResourceRef->hResource = hResource;
1014     pResourceRef->depth = 0;
1015 
1016     multimapInit(&pResourceRef->childRefMap, pAllocator);
1017     multimapInit(&pResourceRef->cachedRefMap, pAllocator);
1018     multimapInit(&pResourceRef->depRefMap, pAllocator);
1019     multimapInit(&pResourceRef->depBackRefMap, pAllocator);
1020     listInit(&pResourceRef->cpuMappings, pAllocator);
1021     listInit(&pResourceRef->backRefs, pAllocator);
1022     listInit(&pResourceRef->interMappings, pAllocator);
1023     listInit(&pResourceRef->interBackRefs, pAllocator);
1024     listInit(&pResourceRef->sharePolicyList, pAllocator);
1025 
1026     portAtomicExIncrementU64(&pServer->activeResourceCount);
1027 
1028     *ppResourceRef = pResourceRef;
1029     return NV_OK;
1030 }
1031 
1032 NV_STATUS
1033 clientDestructResourceRef_IMPL
1034 (
1035     RsClient *pClient,
1036     RsServer *pServer,
1037     RsResourceRef *pResourceRef
1038 )
1039 {
1040     NV_ASSERT(pResourceRef != NULL);
1041     NV_ASSERT(listCount(&pResourceRef->backRefs) == 0);
1042     NV_ASSERT(listCount(&pResourceRef->cpuMappings) == 0);
1043     NV_ASSERT(listCount(&pResourceRef->interBackRefs) == 0);
1044     NV_ASSERT(listCount(&pResourceRef->interMappings) == 0);
1045 
1046     listDestroy(&pResourceRef->backRefs);
1047     listDestroy(&pResourceRef->cpuMappings);
1048     listDestroy(&pResourceRef->interBackRefs);
1049     listDestroy(&pResourceRef->interMappings);
1050     listDestroy(&pResourceRef->sharePolicyList);
1051 
1052     // All children should be free
1053     NV_ASSERT(0 == multimapCountItems(&pResourceRef->childRefMap));
1054     multimapDestroy(&pResourceRef->childRefMap);
1055 
1056     // Nothing should be cached
1057     NV_ASSERT(0 == multimapCountItems(&pResourceRef->cachedRefMap));
1058     multimapDestroy(&pResourceRef->cachedRefMap);
1059 
1060     _refCleanupDependencies(pResourceRef);
1061     multimapDestroy(&pResourceRef->depBackRefMap);
1062 
1063     _refCleanupDependants(pResourceRef);
1064     multimapDestroy(&pResourceRef->depRefMap);
1065 
1066     mapRemove(&pClient->resourceMap, pResourceRef);
1067 
1068     portAtomicExDecrementU64(&pServer->activeResourceCount);
1069 
1070     return NV_OK;
1071 }
1072 
1073 NV_STATUS
1074 clientUnmapResourceRefMappings
1075 (
1076     RsClient *pClient,
1077     CALL_CONTEXT *pCallContext,
1078     RS_LOCK_INFO *pLockInfo
1079 )
1080 {
1081     RsResourceRef  *pResourceRef = pCallContext->pResourceRef;
1082     RsCpuMapping   *pCpuMapping;
1083     NV_STATUS status;
1084     RS_LOCK_INFO lockInfo;
1085     RS_CPU_UNMAP_PARAMS params;
1086 
1087     pCpuMapping = listHead(&pResourceRef->cpuMappings);
1088     while(pCpuMapping != NULL)
1089     {
1090         portMemSet(&params, 0, sizeof(params));
1091         portMemSet(&lockInfo, 0, sizeof(lockInfo));
1092 
1093         params.hClient = pClient->hClient;
1094         params.hDevice = (pCpuMapping->pContextRef == NULL)
1095             ? pClient->hClient
1096             : pCpuMapping->pContextRef->hResource;
1097         params.hMemory = pResourceRef->hResource;
1098         params.pLinearAddress = pCpuMapping->pLinearAddress;
1099         params.processId = pCpuMapping->processId;
1100         params.bTeardown = NV_TRUE;
1101         params.flags = pCpuMapping->flags;
1102         params.pSecInfo = &pCallContext->secInfo;
1103         params.pLockInfo = &lockInfo;
1104         lockInfo.pClient = pLockInfo->pClient;
1105         lockInfo.state = pLockInfo->state;
1106 
1107         // TODO: temp WAR for bug 2840284: deadlock during recursive free operation
1108         lockInfo.flags |= RS_LOCK_FLAGS_NO_CLIENT_LOCK;
1109 
1110         status = serverUnmap(pCallContext->pServer, params.hClient, params.hMemory, &params);
1111 
1112         if (status != NV_OK)
1113         {
1114             NV_PRINTF(LEVEL_ERROR, "Failed to auto-unmap (status=0x%x) hClient %x: hResource: %x\n",
1115                     status, pClient->hClient, pResourceRef->hResource);
1116             NV_PRINTF(LEVEL_ERROR, "hContext: %x at addr " NvP64_fmt "\n",
1117                     params.hDevice, params.pLinearAddress);
1118 
1119             if (pCpuMapping == listHead(&pResourceRef->cpuMappings))
1120             {
1121 #if !(RS_STANDALONE_TEST)
1122                 NV_ASSERT(0);
1123 #endif
1124                 refRemoveMapping(pResourceRef, pCpuMapping);
1125             }
1126         }
1127         pCpuMapping = listHead(&pResourceRef->cpuMappings);
1128     }
1129 
1130     return NV_OK;
1131 }
1132 
1133 NV_STATUS
1134 _clientUnmapBackRefMappings
1135 (
1136     RsClient *pClient,
1137     CALL_CONTEXT *pCallContext,
1138     RS_LOCK_INFO *pLockInfo
1139 )
1140 {
1141     NV_STATUS       status;
1142     RsResourceRef  *pResourceRef = pCallContext->pResourceRef;
1143     RS_CPU_MAPPING_BACK_REF *pBackRefItem;
1144     RS_LOCK_INFO lockInfo;
1145     RS_CPU_UNMAP_PARAMS params;
1146 
1147     pBackRefItem = listHead(&pResourceRef->backRefs);
1148     while(pBackRefItem != NULL)
1149     {
1150         RsCpuMapping *pCpuMapping = pBackRefItem->pCpuMapping;
1151         RsResourceRef *pBackRef = pBackRefItem->pBackRef;
1152 
1153         portMemSet(&params, 0, sizeof(params));
1154         portMemSet(&lockInfo, 0, sizeof(lockInfo));
1155 
1156         params.hClient = pClient->hClient;
1157         params.hDevice = (pCpuMapping->pContextRef == NULL)
1158             ? pClient->hClient
1159             : pCpuMapping->pContextRef->hResource;
1160         params.hMemory = pBackRef->hResource;
1161         params.pLinearAddress = pCpuMapping->pLinearAddress;
1162         params.processId = pCpuMapping->processId;
1163         params.bTeardown = NV_TRUE;
1164         params.flags = pCpuMapping->flags;
1165         params.pSecInfo = &pCallContext->secInfo;
1166         params.pLockInfo = &lockInfo;
1167 
1168         lockInfo.pClient = pLockInfo->pClient;
1169         lockInfo.state = pLockInfo->state;
1170 
1171         status = serverUnmap(pCallContext->pServer, pClient->hClient, pBackRef->hResource, &params);
1172         if (status != NV_OK)
1173         {
1174             NV_PRINTF(LEVEL_ERROR, "Failed to auto-unmap backref (status=0x%x) hClient %x: hResource: %x\n",
1175                     status, pClient->hClient, pBackRef->hResource);
1176             NV_PRINTF(LEVEL_ERROR, "hContext: %x at addr " NvP64_fmt "\n",
1177                     params.hDevice, params.pLinearAddress);
1178 
1179             if (pBackRefItem == listHead(&pResourceRef->backRefs))
1180             {
1181                 NV_ASSERT(0);
1182                 listRemove(&pResourceRef->backRefs, pBackRefItem);
1183             }
1184         }
1185 
1186         pBackRefItem = listHead(&pResourceRef->backRefs);
1187     }
1188 
1189     return NV_OK;
1190 }
1191 
1192 static NV_STATUS
1193 _unmapInterMapping
1194 (
1195     RsServer *pServer,
1196     RsClient *pClient,
1197     RsResourceRef *pMapperRef,
1198     RsInterMapping *pMapping,
1199     RS_LOCK_INFO *pLockInfo,
1200     API_SECURITY_INFO *pSecInfo
1201 )
1202 {
1203     RS_INTER_UNMAP_PARAMS params;
1204     RS_LOCK_INFO lockInfo;
1205     NV_STATUS status;
1206 
1207     portMemSet(&params, 0, sizeof(params));
1208     portMemSet(&lockInfo, 0, sizeof(lockInfo));
1209 
1210     params.hClient = pClient->hClient;
1211     params.hMapper = pMapperRef->hResource;
1212     params.hDevice = pMapping->pContextRef->hResource;
1213     params.hMappable = pMapping->pMappableRef->hResource;
1214     params.flags = pMapping->flags;
1215     params.dmaOffset = pMapping->dmaOffset;
1216     params.pMemDesc = pMapping->pMemDesc;
1217     params.pSecInfo = pSecInfo;
1218     params.pLockInfo = &lockInfo;
1219 
1220     lockInfo.pClient = pLockInfo->pClient;
1221     lockInfo.pContextRef = (pLockInfo->pContextRef != NULL)
1222         ? pLockInfo->pContextRef
1223         : pMapping->pContextRef;
1224     lockInfo.state = pLockInfo->state;
1225 
1226     status = serverUpdateLockFlagsForInterAutoUnmap(pServer, &params);
1227     if (status != NV_OK)
1228         return status;
1229 
1230     return serverInterUnmap(pServer, &params);
1231 }
1232 
1233 void
1234 _clientUnmapInterMappings
1235 (
1236     RsClient *pClient,
1237     CALL_CONTEXT *pCallContext,
1238     RS_LOCK_INFO *pLockInfo
1239 )
1240 {
1241     NV_STATUS status;
1242     RsResourceRef *pMapperRef = pCallContext->pResourceRef;
1243     RsInterMapping *pMapping;
1244 
1245     pMapping = listHead(&pMapperRef->interMappings);
1246     while (pMapping != NULL)
1247     {
1248         status = _unmapInterMapping(pCallContext->pServer, pClient, pMapperRef,
1249                                     pMapping, pLockInfo, &pCallContext->secInfo);
1250         if (status != NV_OK)
1251         {
1252             NV_PRINTF(LEVEL_ERROR, "Failed to auto-unmap (status=0x%x) hClient %x: hMapper: %x\n",
1253                       status, pClient->hClient, pMapperRef->hResource);
1254             NV_PRINTF(LEVEL_ERROR, "hMappable: %x hContext: %x\n",
1255                       pMapping->pMappableRef->hResource, pMapping->pContextRef->hResource);
1256 
1257             if (pMapping == listHead(&pMapperRef->interMappings))
1258             {
1259                 NV_ASSERT(0);
1260                 refRemoveInterMapping(pMapperRef, pMapping);
1261             }
1262         }
1263 
1264         pMapping = listHead(&pMapperRef->interMappings);
1265     }
1266 }
1267 
1268 void
1269 _clientUnmapInterBackRefMappings
1270 (
1271     RsClient *pClient,
1272     CALL_CONTEXT *pCallContext,
1273     RS_LOCK_INFO *pLockInfo
1274 )
1275 {
1276     NV_STATUS status;
1277     RS_INTER_MAPPING_BACK_REF *pBackRefItem;
1278 
1279     RsResourceRef *pResourceRef = pCallContext->pResourceRef;
1280 
1281     pBackRefItem = listHead(&pResourceRef->interBackRefs);
1282     while (pBackRefItem != NULL)
1283     {
1284         RsResourceRef *pMapperRef = pBackRefItem->pMapperRef;
1285         RsInterMapping *pMapping = pBackRefItem->pMapping;
1286 
1287         status = _unmapInterMapping(pCallContext->pServer, pClient, pMapperRef,
1288                                     pMapping, pLockInfo, &pCallContext->secInfo);
1289         if (status != NV_OK)
1290         {
1291             NV_PRINTF(LEVEL_ERROR, "Failed to auto-unmap backref (status=0x%x) hClient %x: hMapper: %x\n",
1292                       status, pClient->hClient, pMapperRef->hResource);
1293             NV_PRINTF(LEVEL_ERROR, "hMappable: %x hContext: %x\n",
1294                       pMapping->pMappableRef->hResource, pMapping->pContextRef->hResource);
1295 
1296             if (pBackRefItem == listHead(&pResourceRef->interBackRefs))
1297             {
1298                 NV_ASSERT(0);
1299                 refRemoveInterMapping(pMapperRef, pMapping);
1300             }
1301         }
1302 
1303         pBackRefItem = listHead(&pResourceRef->interBackRefs);
1304     }
1305 }
1306 
1307 NV_STATUS
1308 indexAdd
1309 (
1310     RsIndex *pIndex,
1311     NvU32 index,
1312     RsResourceRef *pResourceRef
1313 )
1314 {
1315     NV_ASSERT(pResourceRef != NULL && pResourceRef->hResource != 0);
1316 
1317     if (NULL == multimapFindSubmap(pIndex, index))
1318     {
1319         if (NULL == multimapInsertSubmap(pIndex, index))
1320             return NV_ERR_INSUFFICIENT_RESOURCES;
1321     }
1322 
1323     if (NULL == multimapInsertItemValue(pIndex, index, pResourceRef->hResource,
1324                                         &pResourceRef))
1325         return NV_ERR_INSUFFICIENT_RESOURCES;
1326 
1327     return NV_OK;
1328 }
1329 
1330 NV_STATUS
1331 indexRemove
1332 (
1333     RsIndex *pIndex,
1334     NvU32 index,
1335     RsResourceRef *pResourceRef
1336 )
1337 {
1338     RsResourceRef **ppResourceRef;
1339 
1340     NV_ASSERT(pResourceRef != NULL && pResourceRef->hResource != 0);
1341 
1342     ppResourceRef = multimapFindItem(pIndex, index, pResourceRef->hResource);
1343     if (ppResourceRef == NULL)
1344         return NV_ERR_OBJECT_NOT_FOUND;
1345 
1346     multimapRemoveItem(pIndex, ppResourceRef);
1347 
1348     return NV_OK;
1349 }
1350 
1351 NV_STATUS
1352 clientValidateNewResourceHandle_IMPL
1353 (
1354     RsClient *pClient,
1355     NvHandle  hResource,
1356     NvBool    bRestrict
1357 )
1358 {
1359     //
1360     // Resource handle should not be the same as the client handle
1361     // because some control calls pass hClient in the hObject field
1362     //
1363     if (pClient->hClient == hResource || hResource == 0)
1364         return NV_ERR_INVALID_OBJECT_HANDLE;
1365 
1366     if (bRestrict && !rangeIsEmpty(pClient->handleRestrictRange))
1367     {
1368         NV_RANGE requestedRange = rangeMake(hResource, hResource);
1369         if (rangeContains(pClient->handleRestrictRange, requestedRange))
1370             return NV_ERR_INVALID_OBJECT_HANDLE;
1371     }
1372 
1373     if (clientGetResourceRef(pClient, hResource, NULL) == NV_OK)
1374         return NV_ERR_INSERT_DUPLICATE_NAME;
1375 
1376     return NV_OK;
1377 }
1378 
1379 NV_STATUS
1380 clientresConstruct_IMPL
1381 (
1382     RsClientResource *pClientRes,
1383     CALL_CONTEXT *pCallContext,
1384     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
1385 )
1386 {
1387     RsClient *pClient = pCallContext->pClient;
1388     RsResourceRef *pResourceRef = pCallContext->pResourceRef;
1389 
1390     // Client proxy resource must have the same handle as its client
1391     if (pClient->hClient != pResourceRef->hResource)
1392         return NV_ERR_INVALID_OBJECT_HANDLE;
1393 
1394     pClientRes->pClient = pCallContext->pClient;
1395     return NV_OK;
1396 }
1397 
1398 void
1399 clientresDestruct_IMPL
1400 (
1401     RsClientResource *pClientRes
1402 )
1403 {
1404 }
1405 
1406 RsIndexIter
1407 indexRefIter
1408 (
1409     RsIndex *pIndex,
1410     NvU32 index
1411 )
1412 {
1413     RsIndexIter it;
1414     RsIndexSubmap *pSubmap;
1415 
1416     portMemSet(&it, 0, sizeof(it));
1417     NV_ASSERT(pIndex);
1418 
1419     pSubmap = multimapFindSubmap(pIndex, index);
1420     if (pSubmap != NULL)
1421         it = multimapSubmapIterItems(pIndex, pSubmap);
1422 
1423     return it;
1424 }
1425 
1426 RsIndexIter
1427 indexRefIterAll
1428 (
1429     RsIndex *pIndex
1430 )
1431 {
1432     NV_ASSERT(pIndex);
1433     return multimapItemIterAll(pIndex);
1434 }
1435 
1436 NvBool
1437 indexRefIterNext
1438 (
1439     RsIndexIter *pIt
1440 )
1441 {
1442     return multimapItemIterNext(pIt);
1443 }
1444 
1445 RS_ITERATOR
1446 clientRefIter
1447 (
1448     RsClient *pClient,
1449     RsResourceRef *pScopeRef,
1450     NvU32 internalClassId,
1451     RS_ITER_TYPE type,
1452     NvBool bExactMatch
1453 )
1454 {
1455     RS_ITERATOR it;
1456     RsIndex *pIndex = NULL;
1457     NvBool bChildrenOnly = (type == RS_ITERATE_CHILDREN);
1458     NvBool bCachedOnly = (type == RS_ITERATE_CACHED);
1459     NvBool bDependantsOnly = (type == RS_ITERATE_DEPENDANTS);
1460     portMemSet(&it, 0, sizeof(it));
1461 
1462     if (pClient == NULL)
1463     {
1464         NV_ASSERT(0);
1465         return it;
1466     }
1467 
1468     if (pScopeRef == NULL)
1469     {
1470         if (NV_OK != clientGetResourceRef(pClient, pClient->hClient, &pScopeRef))
1471             return it;
1472     }
1473 
1474     if (bChildrenOnly || bCachedOnly || bDependantsOnly)
1475     {
1476         NvBool bIterAll = (internalClassId == 0) || !bExactMatch;
1477 
1478         if (bChildrenOnly)
1479         {
1480             pIndex = &pScopeRef->childRefMap;
1481         }
1482         else if (bCachedOnly)
1483         {
1484             pIndex = &pScopeRef->cachedRefMap;
1485         }
1486         else if (bDependantsOnly)
1487         {
1488             pIndex = &pScopeRef->depRefMap;
1489         }
1490 
1491         if (!bIterAll && multimapFindSubmap(pIndex, internalClassId) == NULL)
1492             goto done;
1493 
1494         it.idxIt = (bIterAll)
1495             ? indexRefIterAll(pIndex)
1496             : indexRefIter(pIndex, internalClassId);
1497     }
1498     else
1499     {
1500         // Match descendants of the scope resource (specific class / any class)
1501         it.mapIt = mapIterAll(&pClient->resourceMap);
1502     }
1503 
1504     it.pClient = pClient;
1505     it.pScopeRef = pScopeRef;
1506     it.internalClassId = internalClassId;
1507     it.type = type;
1508     it.bExactMatch = bExactMatch;
1509 
1510 done:
1511     return it;
1512 }
1513 
1514 RS_ORDERED_ITERATOR
1515 clientRefOrderedIter
1516 (
1517     RsClient *pClient,
1518     RsResourceRef *pScopeRef,
1519     NvU32 internalClassId,
1520     NvBool bExactMatch
1521 )
1522 {
1523     RS_ORDERED_ITERATOR it;
1524     RsIndex *pIndex = NULL;
1525     portMemSet(&it, 0, sizeof(it));
1526 
1527     if (pClient == NULL)
1528     {
1529         NV_ASSERT(0);
1530         return it;
1531     }
1532 
1533     if (pScopeRef == NULL)
1534     {
1535         if (NV_OK != clientGetResourceRef(pClient, pClient->hClient, &pScopeRef))
1536             return it;
1537     }
1538 
1539     it.depth = -1;
1540     pIndex = &pScopeRef->childRefMap;
1541     it.idxIt[0] = indexRefIterAll(pIndex);
1542 
1543     it.pClient = pClient;
1544     it.pScopeRef = pScopeRef;
1545     it.internalClassId = internalClassId;
1546     it.bExactMatch = bExactMatch;
1547 
1548     return it;
1549 }
1550 
1551 NvBool
1552 clientRefOrderedIterNext
1553 (
1554     RsClient *pClient,
1555     RS_ORDERED_ITERATOR *pIt
1556 )
1557 {
1558     RsResourceRef *pResourceRef;
1559     NvBool bNext;
1560 
1561     if ((pIt == NULL) || (pIt->pClient != pClient) || pIt->pScopeRef == NULL)
1562     {
1563         // Iterator not initialized or nothing to iterate over
1564         NV_ASSERT(pIt != NULL && pIt->pClient == NULL);
1565         return NV_FALSE;
1566     }
1567 
1568     // Iterate over the scope reference if the scope is not the client
1569     if (pIt->depth == -1)
1570     {
1571         pIt->depth = 0;
1572         if ((pIt->pScopeRef->hResource != pIt->pClient->hClient) &&
1573             ((pIt->internalClassId == 0) || (pIt->internalClassId == pIt->pScopeRef->internalClassId)) &&
1574             (pIt->pScopeRef->pResource != NULL))
1575         {
1576             pIt->pResourceRef = pIt->pScopeRef;
1577             return NV_TRUE;
1578         }
1579     }
1580 
1581     pIt->pResourceRef = NULL;
1582 
1583     bNext = NV_TRUE;
1584     while (1)
1585     {
1586         // Get the next sibling, or else backtrack to parent and get its next sibling
1587         do
1588         {
1589             if (!bNext)
1590                 --pIt->depth;
1591             bNext = indexRefIterNext(&pIt->idxIt[pIt->depth]);
1592         } while (!bNext && pIt->depth != 0);
1593 
1594         if (!bNext)
1595             break;
1596 
1597         pResourceRef = *pIt->idxIt[pIt->depth].pValue;
1598 
1599         // Iterate over this resource's children next (up to max depth)
1600         if (pIt->depth < RS_MAX_RESOURCE_DEPTH)
1601         {
1602             ++pIt->depth;
1603             pIt->idxIt[pIt->depth] = indexRefIterAll(&pResourceRef->childRefMap);
1604         }
1605 
1606         if (refHasAncestor(pResourceRef, pIt->pScopeRef))
1607         {
1608             NvBool bMatch = NV_TRUE;
1609             if (pIt->internalClassId != 0)
1610             {
1611                 if (pIt->bExactMatch && (pIt->internalClassId != pResourceRef->internalClassId))
1612                     bMatch = NV_FALSE;
1613 
1614                 if (!pIt->bExactMatch && objDynamicCastById(pResourceRef->pResource, pIt->internalClassId) == NULL)
1615                     bMatch = NV_FALSE;
1616             }
1617 
1618             if (bMatch && (pResourceRef->pResource != NULL))
1619             {
1620                 pIt->pResourceRef = pResourceRef;
1621                 return NV_TRUE;
1622             }
1623         }
1624     }
1625 
1626     return NV_FALSE;
1627 }
1628 
1629 NvBool
1630 clientRefIterNext
1631 (
1632     RsClient *pClient,
1633     RS_ITERATOR *pIt
1634 )
1635 {
1636     RsResourceRef *pResourceRef;
1637     NvBool bLoop;
1638     NvBool bUseIdx;
1639 
1640     if ((pIt == NULL) || (pIt->pClient != pClient) || pIt->pScopeRef == NULL)
1641     {
1642         // Iterator not initialized or nothing to iterate over
1643         NV_ASSERT(pIt != NULL && pIt->pClient == NULL);
1644         return NV_FALSE;
1645     }
1646 
1647     bUseIdx = (pIt->type == RS_ITERATE_CACHED) ||
1648               (pIt->type == RS_ITERATE_CHILDREN) ||
1649               (pIt->type == RS_ITERATE_DEPENDANTS);
1650 
1651     pIt->pResourceRef = NULL;
1652 
1653     bLoop = bUseIdx ? indexRefIterNext(&pIt->idxIt) : mapIterNext(&pIt->mapIt);
1654     while (bLoop)
1655     {
1656         pResourceRef = bUseIdx ? *pIt->idxIt.pValue : pIt->mapIt.pValue;
1657 
1658         if (bUseIdx ||
1659             ((pResourceRef == pIt->pScopeRef) ||
1660              (refHasAncestor(pResourceRef, pIt->pScopeRef))))
1661         {
1662             NvBool bMatch = NV_TRUE;
1663             if (pIt->internalClassId != 0)
1664             {
1665                 if (pIt->bExactMatch && (pIt->internalClassId != pResourceRef->internalClassId))
1666                     bMatch = NV_FALSE;
1667 
1668                 if (!pIt->bExactMatch && objDynamicCastById(pResourceRef->pResource, pIt->internalClassId) == NULL)
1669                     bMatch = NV_FALSE;
1670             }
1671 
1672             if (bMatch && (pResourceRef->pResource != NULL))
1673             {
1674                 pIt->pResourceRef = pResourceRef;
1675                 return NV_TRUE;
1676             }
1677         }
1678 
1679         bLoop = bUseIdx ? indexRefIterNext(&pIt->idxIt) : mapIterNext(&pIt->mapIt);
1680     }
1681 
1682     return NV_FALSE;
1683 }
1684 
1685 NV_STATUS
1686 clientPostProcessPendingFreeList_IMPL
1687 (
1688     RsClient *pClient,
1689     RsResourceRef **ppFirstLowPriRef
1690 )
1691 {
1692     if (ppFirstLowPriRef != NULL)
1693         *ppFirstLowPriRef = NULL;
1694 
1695     return NV_OK;
1696 }
1697 
1698 NV_STATUS
1699 clientAddAccessBackRef_IMPL
1700 (
1701     RsClient *pClient,
1702     RsResourceRef *pResourceRef
1703 )
1704 {
1705     AccessBackRef *pAccessBackRef = listPrependNew(&pClient->accessBackRefList);;
1706 
1707     if (pAccessBackRef == NULL)
1708         return NV_ERR_INSUFFICIENT_RESOURCES;
1709 
1710     pAccessBackRef->hClient = pResourceRef->pClient->hClient;
1711     pAccessBackRef->hResource = pResourceRef->hResource;
1712 
1713     return NV_OK;
1714 }
1715 
1716 void clientFreeAccessBackRefs_IMPL
1717 (
1718     RsClient *pClient,
1719     RsServer *pServer
1720 )
1721 {
1722     AccessBackRef *pAccessBackRef;
1723     NV_STATUS      status;
1724 
1725     while ((pAccessBackRef = listHead(&pClient->accessBackRefList)) != NULL)
1726     {
1727         RsClient *pSharedClient;
1728 
1729         //
1730         // Remove access rights entry if client/resource pair is still in use
1731         // so that another client doesn't get unauthorized access to them
1732         //
1733         status = serverGetClientUnderLock(pServer, pAccessBackRef->hClient, &pSharedClient);
1734         if (status == NV_OK)
1735         {
1736             RsResourceRef *pResourceRef;
1737 
1738             status = clientGetResourceRef(pSharedClient, pAccessBackRef->hResource, &pResourceRef);
1739             if (status == NV_OK)
1740             {
1741                 RS_SHARE_POLICY revokePolicy;
1742 
1743                 revokePolicy.type = RS_SHARE_TYPE_CLIENT;
1744                 revokePolicy.target = pClient->hClient;
1745                 revokePolicy.action = RS_SHARE_ACTION_FLAG_REVOKE;
1746                 RS_ACCESS_MASK_FILL(&revokePolicy.accessMask);
1747 
1748                 // Check the resource's share policy for matching client policies
1749                 rsShareListRemove(&pResourceRef->sharePolicyList, &revokePolicy, NULL);
1750             }
1751         }
1752 
1753         listRemove(&pClient->accessBackRefList, pAccessBackRef);
1754     }
1755 }
1756