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