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(¶ms, 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, ¶ms, &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(¶ms, 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, ¶ms); 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(¶ms, 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, ¶ms); 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(¶ms, 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, ¶ms); 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(¶ms, 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, ¶ms); 1227 if (status != NV_OK) 1228 return status; 1229 1230 return serverInterUnmap(pServer, ¶ms); 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