1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2018-2022 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 #include "rmapi/rs_utils.h"
24 #include "rmapi/rmapi.h"
25 #include "core/locks.h"
26 
27 NV_STATUS
serverutilGetResourceRef(NvHandle hClient,NvHandle hObject,RsResourceRef ** ppResourceRef)28 serverutilGetResourceRef
29 (
30     NvHandle                 hClient,
31     NvHandle                 hObject,
32     RsResourceRef          **ppResourceRef
33 )
34 {
35     RsResourceRef    *pResourceRef;
36     RsClient         *pRsClient;
37     NV_STATUS         status;
38 
39     *ppResourceRef = NULL;
40 
41     status = serverGetClientUnderLock(&g_resServ, hClient, &pRsClient);
42     if (status != NV_OK)
43         return NV_ERR_INVALID_CLIENT;
44 
45     status = clientGetResourceRef(pRsClient, hObject, &pResourceRef);
46     if (status != NV_OK)
47         return status;
48 
49     *ppResourceRef = pResourceRef;
50 
51     return NV_OK;
52 }
53 
54 NV_STATUS
serverutilGetResourceRefWithType(NvHandle hClient,NvHandle hObject,NvU32 internalClassId,RsResourceRef ** ppResourceRef)55 serverutilGetResourceRefWithType
56 (
57     NvHandle            hClient,
58     NvHandle            hObject,
59     NvU32               internalClassId,
60     RsResourceRef     **ppResourceRef
61 )
62 {
63     if (serverutilGetResourceRef(hClient, hObject, ppResourceRef) != NV_OK)
64     {
65         return NV_ERR_OBJECT_NOT_FOUND;
66     }
67 
68     if (!objDynamicCastById((*ppResourceRef)->pResource, internalClassId))
69     {
70         return NV_ERR_INVALID_OBJECT_HANDLE;
71     }
72 
73     return NV_OK;
74 }
75 
76 NV_STATUS
serverutilGetResourceRefWithParent(NvHandle hClient,NvHandle hParent,NvHandle hObject,NvU32 internalClassId,RsResourceRef ** ppResourceRef)77 serverutilGetResourceRefWithParent
78 (
79     NvHandle            hClient,
80     NvHandle            hParent,
81     NvHandle            hObject,
82     NvU32               internalClassId,
83     RsResourceRef     **ppResourceRef
84 )
85 {
86     NvHandle hFoundParent;
87 
88     if (serverutilGetResourceRef(hClient, hObject, ppResourceRef) != NV_OK)
89     {
90         return NV_ERR_OBJECT_NOT_FOUND;
91     }
92 
93     hFoundParent = (*ppResourceRef)->pParentRef ? (*ppResourceRef)->pParentRef->hResource : 0;
94 
95     if (!objDynamicCastById((*ppResourceRef)->pResource, internalClassId) ||
96         hFoundParent != hParent)
97     {
98         return NV_ERR_INVALID_OBJECT_HANDLE;
99     }
100 
101     return NV_OK;
102 }
103 
104 RmClient
serverutilGetClientUnderLock(NvHandle hClient)105 *serverutilGetClientUnderLock
106 (
107     NvHandle hClient
108 )
109 {
110     NV_STATUS status;
111     RsClient *pRsClient;
112 
113     status = serverGetClientUnderLock(&g_resServ, hClient, &pRsClient);
114     if (status != NV_OK)
115         return NULL;
116 
117     return dynamicCast(pRsClient, RmClient);
118 }
119 
120 RmClient
serverutilGetFirstClientUnderLock(void)121 **serverutilGetFirstClientUnderLock
122 (
123     void
124 )
125 {
126     RmClient **ppClient;
127 
128     //
129     // Resource server's client list is not protected by any RM locks
130     // so, as a WAR, we access a lock-protected shadow client list. This avoids
131     // the race condition where a client is freed while a DPC is iterating
132     // through the client list.
133     //
134     ppClient = listHead(&g_clientListBehindGpusLock);
135     if (NULL == ppClient)
136         return NULL;
137 
138     return ppClient;
139 }
140 
141 RmClient
serverutilGetNextClientUnderLock(RmClient ** ppClient)142 **serverutilGetNextClientUnderLock
143 (
144     RmClient **ppClient
145 )
146 {
147     //
148     // Resource server's client list is not protected by any RM locks
149     // so, as a WAR, we access a lock-protected shadow client list. This avoids
150     // the race condition where a client is freed while a DPC is iterating
151     // through the client list.
152     //
153     ppClient = listNext(&g_clientListBehindGpusLock, ppClient);
154     if (NULL == ppClient)
155         return NULL;
156 
157     return ppClient;
158 }
159 
160 RsResourceRef *
serverutilFindChildRefByType(NvHandle hClient,NvHandle hParent,NvU32 internalClassId,NvBool bExactMatch)161 serverutilFindChildRefByType
162 (
163     NvHandle hClient,
164     NvHandle hParent,
165     NvU32 internalClassId,
166     NvBool bExactMatch
167 )
168 {
169     NV_STATUS status;
170     RsClient *pRsClient;
171     RsResourceRef *pResourceRef;
172     RsResourceRef *pParentRef;
173 
174     status = serverGetClientUnderLock(&g_resServ, hClient, &pRsClient);
175     if (status != NV_OK)
176         return NULL;
177 
178     status = clientGetResourceRef(pRsClient, hParent, &pParentRef);
179     if (status != NV_OK)
180     {
181         return NULL;
182     }
183 
184     status = refFindChildOfType(pParentRef, internalClassId, bExactMatch, &pResourceRef);
185     if (status != NV_OK)
186     {
187         return NULL;
188     }
189 
190     return pResourceRef;
191 }
192 
193 RS_ITERATOR
serverutilRefIter(NvHandle hClient,NvHandle hScopedObject,NvU32 internalClassId,RS_ITER_TYPE iterType,NvBool bExactMatch)194 serverutilRefIter
195 (
196     NvHandle hClient,
197     NvHandle hScopedObject,
198     NvU32 internalClassId,
199     RS_ITER_TYPE iterType,
200     NvBool bExactMatch
201 )
202 {
203     NV_STATUS      status;
204     RsClient      *pRsClient;
205     RsResourceRef *pScopedRef = NULL;
206     RS_ITERATOR    it;
207 
208     portMemSet(&it, 0, sizeof(it));
209 
210     status = serverGetClientUnderLock(&g_resServ, hClient, &pRsClient);
211     if (status != NV_OK)
212         return it;
213 
214     if (hScopedObject != NV01_NULL_OBJECT)
215     {
216         status = clientGetResourceRef(pRsClient, hScopedObject, &pScopedRef);
217         if (status != NV_OK)
218         {
219             return it;
220         }
221     }
222 
223     return clientRefIter(pRsClient, pScopedRef, internalClassId, iterType, bExactMatch);
224 }
225 
226 NvBool
serverutilValidateNewResourceHandle(NvHandle hClient,NvHandle hObject)227 serverutilValidateNewResourceHandle
228 (
229     NvHandle hClient,
230     NvHandle hObject
231 )
232 {
233     RmClient *pClient = serverutilGetClientUnderLock(hClient);
234 
235     return ((pClient != NULL) &&
236             (NV_OK == clientValidateNewResourceHandle(staticCast(pClient, RsClient), hObject, NV_TRUE)));
237 }
238 
239 NV_STATUS
serverutilGenResourceHandle(NvHandle hClient,NvHandle * returnHandle)240 serverutilGenResourceHandle
241 (
242     NvHandle    hClient,
243     NvHandle   *returnHandle
244 )
245 {
246     NV_STATUS status;
247     RmClient *pClient;
248 
249     // LOCK TEST: we should have the API lock here
250     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
251 
252     pClient = serverutilGetClientUnderLock(hClient);
253 
254     if (pClient == NULL)
255         return NV_ERR_INVALID_CLIENT;
256 
257     status = clientGenResourceHandle(staticCast(pClient, RsClient), returnHandle);
258     return status;
259 }
260 
261 RS_SHARE_ITERATOR
serverutilShareIter(NvU32 internalClassId)262 serverutilShareIter
263 (
264     NvU32 internalClassId
265 )
266 {
267     return serverShareIter(&g_resServ, internalClassId);
268 }
269 
270 NvBool
serverutilShareIterNext(RS_SHARE_ITERATOR * pIt)271 serverutilShareIterNext
272 (
273     RS_SHARE_ITERATOR* pIt
274 )
275 {
276     return serverShareIterNext(pIt);
277 }
278 
279 NV_STATUS
serverutilGetClientHandlesFromPid(NvU32 procID,NvU32 subProcessID,ClientHandlesList * pClientList)280 serverutilGetClientHandlesFromPid
281 (
282     NvU32               procID,
283     NvU32               subProcessID,
284     ClientHandlesList   *pClientList
285 )
286 {
287     RmClient **ppClient;
288     RmClient  *pClient;
289 
290     // If the list passed in has old elements, lets clear its elements.
291     if (listCount(pClientList))
292     {
293         // Clear & free nodes in temp list
294         listDestroy(pClientList);
295     }
296 
297     for (ppClient = serverutilGetFirstClientUnderLock();
298          ppClient;
299          ppClient = serverutilGetNextClientUnderLock(ppClient))
300     {
301         RsClient *pRsClient;
302 
303         pClient = *ppClient;
304         pRsClient = staticCast(pClient, RsClient);
305 
306         if ((pClient->ProcID == procID) &&
307             (pClient->SubProcessID == subProcessID))
308         {
309              if (listAppendValue(pClientList,
310                                  &pRsClient->hClient) == NULL)
311              {
312                 listClear(pClientList);
313                 return NV_ERR_INSUFFICIENT_RESOURCES;
314              }
315         }
316     }
317 
318     return NV_OK;
319 }
320 
321 NvBool
serverutilMappingFilterCurrentUserProc(RsCpuMapping * pMapping)322 serverutilMappingFilterCurrentUserProc
323 (
324     RsCpuMapping *pMapping
325 )
326 {
327     return (!pMapping->pPrivate->bKernel &&
328             (pMapping->processId == osGetCurrentProcess()));
329 }
330 
331 NvBool
serverutilMappingFilterKernel(RsCpuMapping * pMapping)332 serverutilMappingFilterKernel
333 (
334     RsCpuMapping *pMapping
335 )
336 {
337     return pMapping->pPrivate->bKernel;
338 }
339 
340 
341 NV_STATUS
serverutilAcquireClient(NvHandle hClient,LOCK_ACCESS_TYPE access,RmClient ** ppClient)342 serverutilAcquireClient
343 (
344     NvHandle hClient,
345     LOCK_ACCESS_TYPE access,
346     RmClient **ppClient
347 )
348 {
349     RsClient *pRsClient;
350     RmClient *pClient;
351 
352     // LOCK TEST: we should have the API lock here
353     LOCK_ASSERT_AND_RETURN(rmapiLockIsOwner());
354 
355     if (NV_OK != serverAcquireClient(&g_resServ, hClient, access, &pRsClient))
356         return NV_ERR_INVALID_CLIENT;
357 
358     pClient = dynamicCast(pRsClient, RmClient);
359     if (pClient == NULL)
360     {
361         serverReleaseClient(&g_resServ, access, pRsClient);
362         return NV_ERR_INVALID_CLIENT;
363     }
364 
365     *ppClient = pClient;
366     return NV_OK;
367 }
368 
369 void
serverutilReleaseClient(LOCK_ACCESS_TYPE access,RmClient * pClient)370 serverutilReleaseClient
371 (
372     LOCK_ACCESS_TYPE access,
373     RmClient *pClient
374 )
375 {
376     serverReleaseClient(&g_resServ, access, staticCast(pClient, RsClient));
377 }
378