1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/include/internal/ob_x.h
5 * PURPOSE: Internal Inlined Functions for the Object Manager
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 #include "ex.h"
10
11 #define OBP_LOCK_STATE_PRE_ACQUISITION_EXCLUSIVE 0xAAAA1234
12 #define OBP_LOCK_STATE_PRE_ACQUISITION_SHARED 0xBBBB1234
13 #define OBP_LOCK_STATE_POST_ACQUISITION_EXCLUSIVE 0xCCCC1234
14 #define OBP_LOCK_STATE_POST_ACQUISITION_SHARED 0xDDDD1234
15 #define OBP_LOCK_STATE_RELEASED 0xEEEE1234
16 #define OBP_LOCK_STATE_INITIALIZED 0xFFFF1234
17
18 #define OBP_NAME_LOOKASIDE_MAX_SIZE 248
19
20 FORCEINLINE
21 ULONG
ObpValidateAttributes(IN ULONG Attributes,IN KPROCESSOR_MODE PreviousMode)22 ObpValidateAttributes(IN ULONG Attributes,
23 IN KPROCESSOR_MODE PreviousMode)
24 {
25 if (PreviousMode == KernelMode)
26 {
27 /* For kernel, allow any valid attributes */
28 return Attributes & OBJ_VALID_KERNEL_ATTRIBUTES;
29 }
30 else
31 {
32 /* For user, mask out kernel-only attributes */
33 return (Attributes & OBJ_VALID_ATTRIBUTES) &
34 ~(OBJ_KERNEL_HANDLE);
35 }
36 }
37
38 FORCEINLINE
39 ULONG
ObpSelectObjectLockSlot(IN POBJECT_HEADER ObjectHeader)40 ObpSelectObjectLockSlot(IN POBJECT_HEADER ObjectHeader)
41 {
42 /* We have 4 locks total, this will return a 0-index slot */
43 return (((ULONG_PTR)ObjectHeader) >> 8) & 3;
44 }
45
46 FORCEINLINE
47 VOID
ObpAcquireObjectLock(IN POBJECT_HEADER ObjectHeader)48 ObpAcquireObjectLock(IN POBJECT_HEADER ObjectHeader)
49 {
50 ULONG Slot;
51 POBJECT_TYPE ObjectType = ObjectHeader->Type;
52
53 /* Sanity check */
54 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
55
56 /* Pick a slot */
57 Slot = ObpSelectObjectLockSlot(ObjectHeader);
58
59 /* Enter a critical region and acquire the resource */
60 KeEnterCriticalRegion();
61 ExAcquireResourceExclusiveLite(&ObjectType->ObjectLocks[Slot], TRUE);
62 }
63
64 FORCEINLINE
65 VOID
ObpAcquireObjectLockShared(IN POBJECT_HEADER ObjectHeader)66 ObpAcquireObjectLockShared(IN POBJECT_HEADER ObjectHeader)
67 {
68 ULONG Slot;
69 POBJECT_TYPE ObjectType = ObjectHeader->Type;
70
71 /* Sanity check */
72 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
73
74 /* Pick a slot */
75 Slot = ObpSelectObjectLockSlot(ObjectHeader);
76
77 /* Enter a critical region and acquire the resource */
78 KeEnterCriticalRegion();
79 ExAcquireResourceSharedLite(&ObjectType->ObjectLocks[Slot], TRUE);
80 }
81
82 FORCEINLINE
83 VOID
ObpReleaseObjectLock(IN POBJECT_HEADER ObjectHeader)84 ObpReleaseObjectLock(IN POBJECT_HEADER ObjectHeader)
85 {
86 ULONG Slot;
87 POBJECT_TYPE ObjectType = ObjectHeader->Type;
88
89 /* Pick a slot */
90 Slot = ObpSelectObjectLockSlot(ObjectHeader);
91
92 /* Release the resource and leave a critical region */
93 ExReleaseResourceLite(&ObjectType->ObjectLocks[Slot]);
94 KeLeaveCriticalRegion();
95
96 /* Sanity check */
97 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
98 }
99
100 FORCEINLINE
101 POBJECT_HEADER_NAME_INFO
ObpReferenceNameInfo(IN POBJECT_HEADER ObjectHeader)102 ObpReferenceNameInfo(IN POBJECT_HEADER ObjectHeader)
103 {
104 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
105 ULONG NewValue, References;
106
107 /* Make sure we have name information at all */
108 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
109 if (!ObjectNameInfo) return NULL;
110
111 /* Get the number of references */
112 References = ObjectNameInfo->QueryReferences;
113 for (;;)
114 {
115 /* Check if the count is 0 and fail if so */
116 if (!References) return NULL;
117
118 /* Increment the number of references */
119 NewValue = InterlockedCompareExchange((PLONG)&ObjectNameInfo->
120 QueryReferences,
121 References + 1,
122 References);
123 if (NewValue == References) break;
124
125 /* We failed, try again */
126 References = NewValue;
127 }
128
129 /* Check for magic flag */
130 if (ObjectNameInfo->QueryReferences & 0x80000000)
131 {
132 /* FIXME: Unhandled*/
133 DbgPrint("OB: Unhandled path\n");
134 ASSERT(FALSE);
135 }
136
137 /* Return the name information */
138 return ObjectNameInfo;
139 }
140
141 FORCEINLINE
142 VOID
ObpDereferenceNameInfo(IN POBJECT_HEADER_NAME_INFO HeaderNameInfo)143 ObpDereferenceNameInfo(IN POBJECT_HEADER_NAME_INFO HeaderNameInfo)
144 {
145 POBJECT_DIRECTORY Directory;
146
147 /* Bail out if there's no info at all */
148 if (!HeaderNameInfo) return;
149
150 /* Remove a query reference and check if it was the last one */
151 if (!InterlockedDecrement((PLONG)&HeaderNameInfo->QueryReferences))
152 {
153 /* Check if we have a name */
154 if (HeaderNameInfo->Name.Buffer)
155 {
156 /* We can get rid of the object name now */
157 ExFreePoolWithTag(HeaderNameInfo->Name.Buffer, OB_NAME_TAG);
158 RtlInitEmptyUnicodeString(&HeaderNameInfo->Name, NULL, 0);
159 }
160
161 /* Check if the object has a directory associated to it */
162 Directory = HeaderNameInfo->Directory;
163 if (Directory)
164 {
165 /* Delete the directory */
166 HeaderNameInfo->Directory = NULL;
167 ObDereferenceObjectDeferDelete(Directory);
168 }
169 }
170 }
171
172 /**
173 * @brief
174 * Locks a directory for shared access.
175 * Used for reading members of the directory object.
176 *
177 * @param[in] Directory
178 * The directory to lock.
179 *
180 * @param[in] Context
181 * The lookup lock context.
182 */
183 FORCEINLINE
184 VOID
ObpAcquireDirectoryLockShared(IN POBJECT_DIRECTORY Directory,IN POBP_LOOKUP_CONTEXT Context)185 ObpAcquireDirectoryLockShared(IN POBJECT_DIRECTORY Directory,
186 IN POBP_LOOKUP_CONTEXT Context)
187 {
188 /* Update lock flag */
189 Context->LockStateSignature = OBP_LOCK_STATE_PRE_ACQUISITION_SHARED;
190
191 /* Acquire an shared directory lock */
192 KeEnterCriticalRegion();
193 ExAcquirePushLockShared(&Directory->Lock);
194
195 /* Update lock flag */
196 Context->LockStateSignature = OBP_LOCK_STATE_POST_ACQUISITION_SHARED;
197 }
198
199 /**
200 * @brief
201 * Locks a directory for exclusive access.
202 * Used for writing/reading members of the directory object.
203 *
204 * @param[in] Directory
205 * The directory to lock.
206 *
207 * @param[in] Context
208 * The lookup lock context.
209 */
210 FORCEINLINE
211 VOID
ObpAcquireDirectoryLockExclusive(IN POBJECT_DIRECTORY Directory,IN POBP_LOOKUP_CONTEXT Context)212 ObpAcquireDirectoryLockExclusive(IN POBJECT_DIRECTORY Directory,
213 IN POBP_LOOKUP_CONTEXT Context)
214 {
215 /* Update lock flag */
216 Context->LockStateSignature = OBP_LOCK_STATE_PRE_ACQUISITION_EXCLUSIVE;
217
218 /* Acquire an exclusive directory lock */
219 KeEnterCriticalRegion();
220 ExAcquirePushLockExclusive(&Directory->Lock);
221
222 /* Update lock flag */
223 Context->LockStateSignature = OBP_LOCK_STATE_POST_ACQUISITION_EXCLUSIVE;
224 }
225
226 /**
227 * @brief
228 * Unlocks a previously shared or exclusively locked directory.
229 *
230 * @param[in] Directory
231 * The directory to unlock.
232 *
233 * @param[in] Context
234 * The lookup lock context.
235 */
236 FORCEINLINE
237 VOID
ObpReleaseDirectoryLock(IN POBJECT_DIRECTORY Directory,IN POBP_LOOKUP_CONTEXT Context)238 ObpReleaseDirectoryLock(IN POBJECT_DIRECTORY Directory,
239 IN POBP_LOOKUP_CONTEXT Context)
240 {
241 /* Release the lock */
242 ExReleasePushLock(&Directory->Lock);
243 Context->LockStateSignature = OBP_LOCK_STATE_RELEASED;
244 KeLeaveCriticalRegion();
245 }
246
247 /**
248 * @brief
249 * Initializes a new object directory lookup context.
250 * Used for lookup operations (insertions/deletions) in a directory.
251 * Employed in conjunction with the directory locking functions.
252 *
253 * @param[in] Context
254 * The new lookup context to initialize.
255 */
256 FORCEINLINE
257 VOID
ObpInitializeLookupContext(IN POBP_LOOKUP_CONTEXT Context)258 ObpInitializeLookupContext(IN POBP_LOOKUP_CONTEXT Context)
259 {
260 /* Initialize a null context */
261 Context->Object = NULL;
262 Context->Directory = NULL;
263 Context->DirectoryLocked = FALSE;
264 Context->LockStateSignature = OBP_LOCK_STATE_INITIALIZED;
265 }
266
267 /**
268 * @brief
269 * Locks an object directory lookup context for performing
270 * lookup operations (insertions/deletions) in a directory.
271 * The directory is locked for exclusive access.
272 *
273 * @param[in] Context
274 * The lookup context to lock.
275 *
276 * @param[in] Directory
277 * The directory on which the lookup context applies.
278 */
279 FORCEINLINE
280 VOID
ObpAcquireLookupContextLock(IN POBP_LOOKUP_CONTEXT Context,IN POBJECT_DIRECTORY Directory)281 ObpAcquireLookupContextLock(IN POBP_LOOKUP_CONTEXT Context,
282 IN POBJECT_DIRECTORY Directory)
283 {
284 /* Acquire an exclusive directory lock and save its lock state */
285 ObpAcquireDirectoryLockExclusive(Directory, Context);
286 Context->Directory = Directory;
287 Context->DirectoryLocked = TRUE;
288 }
289
290 FORCEINLINE
291 VOID
ObpReleaseLookupContextObject(IN POBP_LOOKUP_CONTEXT Context)292 ObpReleaseLookupContextObject(IN POBP_LOOKUP_CONTEXT Context)
293 {
294 POBJECT_HEADER ObjectHeader;
295 POBJECT_HEADER_NAME_INFO HeaderNameInfo;
296
297 /* Check if we had an object */
298 if (Context->Object)
299 {
300 /* Get the object name information */
301 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Context->Object);
302 HeaderNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
303
304 /* Release the name information */
305 ObpDereferenceNameInfo(HeaderNameInfo);
306
307 /* Dereference the object */
308 ObDereferenceObject(Context->Object);
309 Context->Object = NULL;
310 }
311 }
312
313 /**
314 * @brief
315 * Releases an initialized object directory lookup context.
316 * Unlocks it if necessary, and dereferences the underlying object.
317 *
318 * @param[in] Context
319 * The lookup context to release.
320 */
321 FORCEINLINE
322 VOID
ObpReleaseLookupContext(IN POBP_LOOKUP_CONTEXT Context)323 ObpReleaseLookupContext(IN POBP_LOOKUP_CONTEXT Context)
324 {
325 /* Check if we came back with the directory locked */
326 if (Context->DirectoryLocked)
327 {
328 /* Release the directory lock */
329 ObpReleaseDirectoryLock(Context->Directory, Context);
330 Context->Directory = NULL;
331 Context->DirectoryLocked = FALSE;
332 }
333
334 /* Clear the context */
335 ObpReleaseLookupContextObject(Context);
336 }
337
338 FORCEINLINE
339 VOID
ObpEnterObjectTypeMutex(IN POBJECT_TYPE ObjectType)340 ObpEnterObjectTypeMutex(IN POBJECT_TYPE ObjectType)
341 {
342 /* Sanity check */
343 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
344
345 /* Enter a critical region and acquire the resource */
346 KeEnterCriticalRegion();
347 ExAcquireResourceExclusiveLite(&ObjectType->Mutex, TRUE);
348 }
349
350 FORCEINLINE
351 VOID
ObpLeaveObjectTypeMutex(IN POBJECT_TYPE ObjectType)352 ObpLeaveObjectTypeMutex(IN POBJECT_TYPE ObjectType)
353 {
354 /* Enter a critical region and acquire the resource */
355 ExReleaseResourceLite(&ObjectType->Mutex);
356 KeLeaveCriticalRegion();
357
358 /* Sanity check */
359 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
360 }
361
362 FORCEINLINE
363 VOID
ObpReleaseObjectCreateInformation(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)364 ObpReleaseObjectCreateInformation(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
365 {
366 /* Check if we have a security descriptor */
367 if (ObjectCreateInfo->SecurityDescriptor)
368 {
369 /* Release it */
370 SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
371 ObjectCreateInfo->ProbeMode,
372 TRUE);
373 ObjectCreateInfo->SecurityDescriptor = NULL;
374 }
375 }
376
377 FORCEINLINE
378 PVOID
ObpAllocateObjectCreateInfoBuffer(IN PP_NPAGED_LOOKASIDE_NUMBER Type)379 ObpAllocateObjectCreateInfoBuffer(IN PP_NPAGED_LOOKASIDE_NUMBER Type)
380 {
381 PVOID Buffer;
382 PNPAGED_LOOKASIDE_LIST List;
383 PKPRCB Prcb = KeGetCurrentPrcb();
384
385 /* Get the P list first */
386 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].P;
387
388 /* Attempt allocation */
389 List->L.TotalAllocates++;
390 Buffer = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
391 if (!Buffer)
392 {
393 /* Let the balancer know that the P list failed */
394 List->L.AllocateMisses++;
395
396 /* Try the L List */
397 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].L;
398 List->L.TotalAllocates++;
399 Buffer = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
400 if (!Buffer)
401 {
402 /* Let the balancer know the L list failed too */
403 List->L.AllocateMisses++;
404
405 /* Allocate it */
406 Buffer = List->L.Allocate(List->L.Type, List->L.Size, List->L.Tag);
407 }
408 }
409
410 /* Return buffer */
411 return Buffer;
412 }
413
414 FORCEINLINE
415 VOID
ObpFreeCapturedAttributes(IN PVOID Buffer,IN PP_NPAGED_LOOKASIDE_NUMBER Type)416 ObpFreeCapturedAttributes(IN PVOID Buffer,
417 IN PP_NPAGED_LOOKASIDE_NUMBER Type)
418 {
419 PNPAGED_LOOKASIDE_LIST List;
420 PKPRCB Prcb = KeGetCurrentPrcb();
421
422 /* Use the P List */
423 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].P;
424 List->L.TotalFrees++;
425
426 /* Check if the Free was within the Depth or not */
427 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
428 {
429 /* Let the balancer know */
430 List->L.FreeMisses++;
431
432 /* Use the L List */
433 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].L;
434 List->L.TotalFrees++;
435
436 /* Check if the Free was within the Depth or not */
437 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
438 {
439 /* All lists failed, use the pool */
440 List->L.FreeMisses++;
441 List->L.Free(Buffer);
442 }
443 else
444 {
445 /* The free was within the Depth */
446 InterlockedPushEntrySList(&List->L.ListHead,
447 (PSLIST_ENTRY)Buffer);
448 }
449 }
450 else
451 {
452 /* The free was within the Depth */
453 InterlockedPushEntrySList(&List->L.ListHead,
454 (PSLIST_ENTRY)Buffer);
455 }
456 }
457
458 FORCEINLINE
459 VOID
ObpFreeObjectCreateInformation(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)460 ObpFreeObjectCreateInformation(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
461 {
462 /* First release the attributes, then free them from the lookaside list */
463 ObpReleaseObjectCreateInformation(ObjectCreateInfo);
464 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
465 }
466
467 #if DBG
468 FORCEINLINE
469 VOID
ObpCalloutStart(IN PKIRQL CalloutIrql)470 ObpCalloutStart(IN PKIRQL CalloutIrql)
471 {
472 /* Save the callout IRQL */
473 *CalloutIrql = KeGetCurrentIrql();
474 }
475
476 FORCEINLINE
477 VOID
ObpCalloutEnd(IN KIRQL CalloutIrql,IN PCHAR Procedure,IN POBJECT_TYPE ObjectType,IN PVOID Object)478 ObpCalloutEnd(IN KIRQL CalloutIrql,
479 IN PCHAR Procedure,
480 IN POBJECT_TYPE ObjectType,
481 IN PVOID Object)
482 {
483 /* Detect IRQL change */
484 if (CalloutIrql != KeGetCurrentIrql())
485 {
486 /* Print error */
487 DbgPrint("OB: ObjectType: %wZ Procedure: %s Object: %p\n",
488 &ObjectType->Name, Procedure, Object);
489 DbgPrint(" Returned at %x IRQL, but was called at %x IRQL\n",
490 KeGetCurrentIrql(), CalloutIrql);
491 DbgBreakPoint();
492 }
493 }
494 #else
495 FORCEINLINE
496 VOID
ObpCalloutStart(IN PKIRQL CalloutIrql)497 ObpCalloutStart(IN PKIRQL CalloutIrql)
498 {
499 /* No-op */
500 UNREFERENCED_PARAMETER(CalloutIrql);
501 }
502
503 FORCEINLINE
504 VOID
ObpCalloutEnd(IN KIRQL CalloutIrql,IN PCHAR Procedure,IN POBJECT_TYPE ObjectType,IN PVOID Object)505 ObpCalloutEnd(IN KIRQL CalloutIrql,
506 IN PCHAR Procedure,
507 IN POBJECT_TYPE ObjectType,
508 IN PVOID Object)
509 {
510 UNREFERENCED_PARAMETER(CalloutIrql);
511 }
512 #endif
513