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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 470 ObpCalloutStart(IN PKIRQL CalloutIrql) 471 { 472 /* Save the callout IRQL */ 473 *CalloutIrql = KeGetCurrentIrql(); 474 } 475 476 FORCEINLINE 477 VOID 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 497 ObpCalloutStart(IN PKIRQL CalloutIrql) 498 { 499 /* No-op */ 500 UNREFERENCED_PARAMETER(CalloutIrql); 501 } 502 503 FORCEINLINE 504 VOID 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