1 /* 2 * ReactOS kernel 3 * Copyright (C) 2017 ReactOS Team 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 */ 19 /* 20 * COPYRIGHT: See COPYING in the top level directory 21 * PROJECT: ReactOS kernel 22 * FILE: sdk/lib/drivers/rxce/rxce.c 23 * PURPOSE: RXCE library 24 * PROGRAMMER: Pierre Schweitzer (pierre@reactos.org) 25 */ 26 27 /* INCLUDES *****************************************************************/ 28 29 #include <rx.h> 30 #include <pseh/pseh2.h> 31 #include <dfs.h> 32 33 #define NDEBUG 34 #include <debug.h> 35 36 VOID 37 RxAssert( 38 PVOID Assert, 39 PVOID File, 40 ULONG Line, 41 PVOID Message); 42 43 VOID 44 NTAPI 45 RxCreateSrvCallCallBack( 46 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context); 47 48 NTSTATUS 49 RxFinishSrvCallConstruction( 50 PMRX_SRVCALLDOWN_STRUCTURE Calldown); 51 52 VOID 53 NTAPI 54 RxFinishSrvCallConstructionDispatcher( 55 IN PVOID Context); 56 57 NTSTATUS 58 RxInsertWorkQueueItem( 59 PRDBSS_DEVICE_OBJECT pMRxDeviceObject, 60 WORK_QUEUE_TYPE WorkQueueType, 61 PRX_WORK_QUEUE_ITEM WorkQueueItem); 62 63 PVOID 64 RxNewMapUserBuffer( 65 PRX_CONTEXT RxContext); 66 67 VOID 68 NTAPI 69 RxpDestroySrvCall( 70 IN PVOID Context); 71 72 VOID 73 RxpDispatchChangeBufferingStateRequests( 74 PSRV_CALL SrvCall, 75 PSRV_OPEN SrvOpen, 76 PLIST_ENTRY DiscardedRequests); 77 78 VOID 79 NTAPI 80 RxScavengerTimerRoutine( 81 PVOID Context); 82 83 VOID 84 NTAPI 85 RxTimerDispatch( 86 _In_ struct _KDPC *Dpc, 87 _In_opt_ PVOID DeferredContext, 88 _In_opt_ PVOID SystemArgument1, 89 _In_opt_ PVOID SystemArgument2); 90 91 VOID 92 NTAPI 93 RxWorkItemDispatcher( 94 PVOID Context); 95 96 PVOID 97 NTAPI 98 _RxAllocatePoolWithTag( 99 _In_ POOL_TYPE PoolType, 100 _In_ SIZE_T NumberOfBytes, 101 _In_ ULONG Tag); 102 103 VOID 104 NTAPI 105 _RxFreePool( 106 _In_ PVOID Buffer); 107 108 VOID 109 NTAPI 110 _RxFreePoolWithTag( 111 _In_ PVOID Buffer, 112 _In_ ULONG Tag); 113 114 extern ULONG ReadAheadGranularity; 115 116 volatile LONG RxNumberOfActiveFcbs = 0; 117 ULONG SerialNumber = 1; 118 PVOID RxNull = NULL; 119 volatile ULONG RxContextSerialNumberCounter; 120 BOOLEAN RxStopOnLoudCompletion = TRUE; 121 BOOLEAN RxSrvCallConstructionDispatcherActive = FALSE; 122 LIST_ENTRY RxSrvCalldownList; 123 RX_SPIN_LOCK RxStrucSupSpinLock; 124 #if 0 125 ULONG RdbssReferenceTracingValue = (RDBSS_REF_TRACK_SRVCALL | RDBSS_REF_TRACK_NETROOT | 126 RDBSS_REF_TRACK_VNETROOT | RDBSS_REF_TRACK_NETFOBX | 127 RDBSS_REF_TRACK_NETFCB | RDBSS_REF_TRACK_SRVOPEN | 128 RX_PRINT_REF_TRACKING); 129 #else 130 ULONG RdbssReferenceTracingValue = 0; 131 #endif 132 LARGE_INTEGER RxWorkQueueWaitInterval[RxMaximumWorkQueue]; 133 LARGE_INTEGER RxSpinUpDispatcherWaitInterval; 134 RX_DISPATCHER RxDispatcher; 135 RX_WORK_QUEUE_DISPATCHER RxDispatcherWorkQueues; 136 FAST_MUTEX RxLowIoPagingIoSyncMutex; 137 BOOLEAN RxContinueFromAssert = TRUE; 138 ULONG RxExplodePoolTags = 1; 139 LARGE_INTEGER RxTimerInterval; 140 RX_SPIN_LOCK RxTimerLock; 141 LIST_ENTRY RxTimerQueueHead; 142 LIST_ENTRY RxRecurrentWorkItemsList; 143 KDPC RxTimerDpc; 144 KTIMER RxTimer; 145 ULONG RxTimerTickCount; 146 FAST_MUTEX RxContextPerFileSerializationMutex; 147 #if DBG 148 BOOLEAN DumpDispatchRoutine = TRUE; 149 #else 150 BOOLEAN DumpDispatchRoutine = FALSE; 151 #endif 152 153 #if RDBSS_ASSERTS 154 #ifdef ASSERT 155 #undef ASSERT 156 #endif 157 158 #define ASSERT(exp) \ 159 if (!(exp)) \ 160 { \ 161 RxAssert(#exp, __FILE__, __LINE__, NULL); \ 162 } 163 #endif 164 165 #if RX_POOL_WRAPPER 166 #undef RxAllocatePool 167 #undef RxAllocatePoolWithTag 168 #undef RxFreePool 169 170 #define RxAllocatePool(P, S) _RxAllocatePoolWithTag(P, S, 0) 171 #define RxAllocatePoolWithTag _RxAllocatePoolWithTag 172 #define RxFreePool _RxFreePool 173 #define RxFreePoolWithTag _RxFreePoolWithTag 174 #endif 175 176 /* FUNCTIONS ****************************************************************/ 177 178 /* 179 * @implemented 180 */ 181 NTSTATUS 182 NTAPI 183 RxAcquireExclusiveFcbResourceInMRx( 184 _Inout_ PMRX_FCB Fcb) 185 { 186 return RxAcquireExclusiveFcb(NULL, (PFCB)Fcb); 187 } 188 189 /* 190 * @implemented 191 */ 192 BOOLEAN 193 NTAPI 194 RxAcquireFcbForLazyWrite( 195 PVOID Context, 196 BOOLEAN Wait) 197 { 198 PFCB Fcb; 199 BOOLEAN Ret; 200 201 PAGED_CODE(); 202 203 Fcb = Context; 204 /* The received context is a FCB */ 205 ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB); 206 ASSERT_CORRECT_FCB_STRUCTURE(Fcb); 207 ASSERT(Fcb->Specific.Fcb.LazyWriteThread == NULL); 208 209 /* Acquire the paging resource (shared) */ 210 Ret = ExAcquireResourceSharedLite(Fcb->Header.PagingIoResource, Wait); 211 if (Ret) 212 { 213 /* Update tracker information */ 214 Fcb->PagingIoResourceFile = __FILE__; 215 Fcb->PagingIoResourceLine = __LINE__; 216 /* Lazy writer thread is the current one */ 217 Fcb->Specific.Fcb.LazyWriteThread = PsGetCurrentThread(); 218 219 /* There is no top level IRP */ 220 ASSERT(RxIsThisTheTopLevelIrp(NULL)); 221 /* Now, there will be! */ 222 Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP, 223 Fcb->RxDeviceObject, TRUE); 224 /* In case of failure, release the lock and reset everything */ 225 if (!Ret) 226 { 227 Fcb->PagingIoResourceFile = NULL; 228 Fcb->PagingIoResourceLine = 0; 229 ExReleaseResourceLite(Fcb->Header.PagingIoResource); 230 Fcb->Specific.Fcb.LazyWriteThread = NULL; 231 } 232 } 233 234 return Ret; 235 } 236 237 /* 238 * @implemented 239 */ 240 BOOLEAN 241 NTAPI 242 RxAcquireFcbForReadAhead( 243 PVOID Context, 244 BOOLEAN Wait) 245 { 246 PFCB Fcb; 247 BOOLEAN Ret; 248 249 PAGED_CODE(); 250 251 Fcb = Context; 252 /* The received context is a FCB */ 253 ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB); 254 ASSERT_CORRECT_FCB_STRUCTURE(Fcb); 255 256 Ret = ExAcquireResourceSharedLite(Fcb->Header.Resource, Wait); 257 if (Ret) 258 { 259 /* There is no top level IRP */ 260 ASSERT(RxIsThisTheTopLevelIrp(NULL)); 261 /* Now, there will be! */ 262 Ret = RxTryToBecomeTheTopLevelIrp(NULL, (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP, 263 Fcb->RxDeviceObject, TRUE); 264 /* In case of failure, release the lock and reset everything */ 265 if (!Ret) 266 { 267 ExReleaseResourceLite(Fcb->Header.Resource); 268 } 269 } 270 271 return Ret; 272 } 273 274 VOID 275 NTAPI 276 RxAcquireFileForNtCreateSection( 277 PFILE_OBJECT FileObject) 278 { 279 UNIMPLEMENTED; 280 } 281 282 NTSTATUS 283 NTAPI 284 RxAcquireForCcFlush( 285 PFILE_OBJECT FileObject, 286 PDEVICE_OBJECT DeviceObject) 287 { 288 UNIMPLEMENTED; 289 return STATUS_NOT_IMPLEMENTED; 290 } 291 292 /* 293 * @implemented 294 */ 295 VOID 296 RxAddVirtualNetRootToNetRoot( 297 PNET_ROOT NetRoot, 298 PV_NET_ROOT VNetRoot) 299 { 300 PAGED_CODE(); 301 302 DPRINT("RxAddVirtualNetRootToNetRoot(%p, %p)\n", NetRoot, VNetRoot); 303 304 /* Insert in the VNetRoot list - make sure lock is held */ 305 ASSERT(RxIsPrefixTableLockExclusive(NetRoot->SrvCall->RxDeviceObject->pRxNetNameTable)); 306 307 VNetRoot->pNetRoot = (PMRX_NET_ROOT)NetRoot; 308 ++NetRoot->NumberOfVirtualNetRoots; 309 InsertTailList(&NetRoot->VirtualNetRoots, &VNetRoot->NetRootListEntry); 310 } 311 312 /* 313 * @implemented 314 */ 315 PVOID 316 RxAllocateFcbObject( 317 PRDBSS_DEVICE_OBJECT RxDeviceObject, 318 NODE_TYPE_CODE NodeType, 319 POOL_TYPE PoolType, 320 ULONG NameSize, 321 PVOID AlreadyAllocatedObject) 322 { 323 PFCB Fcb; 324 PFOBX Fobx; 325 PSRV_OPEN SrvOpen; 326 PVOID Buffer, PAPNBuffer; 327 PNON_PAGED_FCB NonPagedFcb; 328 PMINIRDR_DISPATCH Dispatch; 329 ULONG NonPagedSize, FobxSize, SrvOpenSize, FcbSize; 330 331 PAGED_CODE(); 332 333 Dispatch = RxDeviceObject->Dispatch; 334 335 NonPagedSize = 0; 336 FobxSize = 0; 337 SrvOpenSize = 0; 338 FcbSize = 0; 339 340 Fcb = NULL; 341 Fobx = NULL; 342 SrvOpen = NULL; 343 NonPagedFcb = NULL; 344 PAPNBuffer = NULL; 345 346 /* If we ask for FOBX, just allocate FOBX and its extension if asked */ 347 if (NodeType == RDBSS_NTC_FOBX) 348 { 349 FobxSize = sizeof(FOBX); 350 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION)) 351 { 352 FobxSize += QuadAlign(Dispatch->MRxFobxSize); 353 } 354 } 355 /* If we ask for SRV_OPEN, also allocate the "internal" FOBX and the extensions if asked */ 356 else if (NodeType == RDBSS_NTC_SRVOPEN || NodeType == RDBSS_NTC_INTERNAL_SRVOPEN) 357 { 358 SrvOpenSize = sizeof(SRV_OPEN); 359 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION)) 360 { 361 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize); 362 } 363 364 FobxSize = sizeof(FOBX); 365 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION)) 366 { 367 FobxSize += QuadAlign(Dispatch->MRxFobxSize); 368 } 369 } 370 /* Otherwise, we're asked to allocate a FCB */ 371 else 372 { 373 /* So, allocate the FCB and its extension if asked */ 374 FcbSize = sizeof(FCB); 375 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION)) 376 { 377 FcbSize += QuadAlign(Dispatch->MRxFcbSize); 378 } 379 380 /* If we're asked to allocate from nonpaged, also allocate the NON_PAGED_FCB 381 * Otherwise, it will be allocated later on, specifically 382 */ 383 if (PoolType == NonPagedPool) 384 { 385 NonPagedSize = sizeof(NON_PAGED_FCB); 386 } 387 388 /* And if it's not for a rename operation also allcoate the internal SRV_OPEN and FOBX and their extensions */ 389 if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB) 390 { 391 SrvOpenSize = sizeof(SRV_OPEN); 392 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION)) 393 { 394 SrvOpenSize += QuadAlign(Dispatch->MRxSrvOpenSize); 395 } 396 397 FobxSize = sizeof(FOBX); 398 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION)) 399 { 400 FobxSize += QuadAlign(Dispatch->MRxFobxSize); 401 } 402 } 403 } 404 405 /* If we already have a buffer, go ahead */ 406 if (AlreadyAllocatedObject != NULL) 407 { 408 Buffer = AlreadyAllocatedObject; 409 } 410 /* Otherwise, allocate it */ 411 else 412 { 413 Buffer = RxAllocatePoolWithTag(PoolType, NameSize + FcbSize + SrvOpenSize + FobxSize + NonPagedSize, RX_FCB_POOLTAG); 414 if (Buffer == NULL) 415 { 416 return NULL; 417 } 418 } 419 420 /* Now, get the pointers - FOBX is easy */ 421 if (NodeType == RDBSS_NTC_FOBX) 422 { 423 Fobx = Buffer; 424 } 425 /* SRV_OPEN first, FOBX next */ 426 else if (NodeType == RDBSS_NTC_SRVOPEN) 427 { 428 SrvOpen = Buffer; 429 Fobx = Add2Ptr(Buffer, SrvOpenSize); 430 } 431 else if (NodeType == RDBSS_NTC_INTERNAL_SRVOPEN) 432 { 433 SrvOpen = Buffer; 434 } 435 else 436 { 437 /* FCB first, and if needed, SRV_OPEN next, FOBX last */ 438 Fcb = Buffer; 439 if (NodeType != RDBSS_NTC_OPENTARGETDIR_FCB) 440 { 441 SrvOpen = Add2Ptr(Buffer, FcbSize); 442 Fobx = Add2Ptr(Buffer, FcbSize + SrvOpenSize); 443 } 444 445 /* If we were not allocated from non paged, allocate the NON_PAGED_FCB now */ 446 if (PoolType != NonPagedPool) 447 { 448 NonPagedFcb = RxAllocatePoolWithTag(NonPagedPool, sizeof(NON_PAGED_FCB), RX_NONPAGEDFCB_POOLTAG); 449 if (NonPagedFcb == NULL) 450 { 451 RxFreePoolWithTag(Buffer, RX_FCB_POOLTAG); 452 return NULL; 453 } 454 455 PAPNBuffer = Add2Ptr(Buffer, FcbSize + SrvOpenSize + FobxSize); 456 } 457 /* Otherwise, just point at the right place in what has been allocated previously */ 458 else 459 { 460 NonPagedFcb = Add2Ptr(Fobx, FobxSize); 461 PAPNBuffer = Add2Ptr(Fobx, FobxSize + NonPagedSize); 462 } 463 } 464 465 /* If we have allocated a SRV_OPEN, initialize it */ 466 if (SrvOpen != NULL) 467 { 468 ZeroAndInitializeNodeType(SrvOpen, RDBSS_NTC_SRVOPEN, SrvOpenSize); 469 470 if (NodeType == RDBSS_NTC_SRVOPEN) 471 { 472 SrvOpen->InternalFobx = Fobx; 473 } 474 else 475 { 476 SrvOpen->InternalFobx = NULL; 477 SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED; 478 } 479 480 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_SRV_OPEN_EXTENSION)) 481 { 482 SrvOpen->Context = Add2Ptr(SrvOpen, sizeof(SRV_OPEN)); 483 } 484 485 InitializeListHead(&SrvOpen->SrvOpenQLinks); 486 } 487 488 /* If we have allocated a FOBX, initialize it */ 489 if (Fobx != NULL) 490 { 491 ZeroAndInitializeNodeType(Fobx, RDBSS_NTC_FOBX, FobxSize); 492 493 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FOBX_EXTENSION)) 494 { 495 Fobx->Context = Add2Ptr(Fobx, sizeof(FOBX)); 496 } 497 } 498 499 /* If we have allocated a FCB, initialize it */ 500 if (Fcb != NULL) 501 { 502 ZeroAndInitializeNodeType(Fcb, RDBSS_STORAGE_NTC(FileTypeNotYetKnown), FcbSize); 503 504 Fcb->NonPaged = NonPagedFcb; 505 ZeroAndInitializeNodeType(Fcb->NonPaged, RDBSS_NTC_NONPAGED_FCB, sizeof(NON_PAGED_FCB)); 506 #if DBG 507 Fcb->CopyOfNonPaged = NonPagedFcb; 508 NonPagedFcb->FcbBackPointer = Fcb; 509 #endif 510 511 Fcb->InternalSrvOpen = SrvOpen; 512 Fcb->InternalFobx = Fobx; 513 514 Fcb->PrivateAlreadyPrefixedName.Length = NameSize; 515 Fcb->PrivateAlreadyPrefixedName.MaximumLength = NameSize; 516 Fcb->PrivateAlreadyPrefixedName.Buffer = PAPNBuffer; 517 518 if (BooleanFlagOn(Dispatch->MRxFlags, RDBSS_MANAGE_FCB_EXTENSION)) 519 { 520 Fcb->Context = Add2Ptr(Fcb, sizeof(FCB)); 521 } 522 523 ZeroAndInitializeNodeType(&Fcb->FcbTableEntry, RDBSS_NTC_FCB_TABLE_ENTRY, sizeof(RX_FCB_TABLE_ENTRY)); 524 525 InterlockedIncrement(&RxNumberOfActiveFcbs); 526 InterlockedIncrement((volatile long *)&RxDeviceObject->NumberOfActiveFcbs); 527 528 ExInitializeFastMutex(&NonPagedFcb->AdvancedFcbHeaderMutex); 529 FsRtlSetupAdvancedHeader(Fcb, &NonPagedFcb->AdvancedFcbHeaderMutex); 530 } 531 532 DPRINT("Allocated %p\n", Buffer); 533 534 return Buffer; 535 } 536 537 /* 538 * @implemented 539 */ 540 PVOID 541 RxAllocateObject( 542 NODE_TYPE_CODE NodeType, 543 PMINIRDR_DISPATCH MRxDispatch, 544 ULONG NameLength) 545 { 546 ULONG Tag, ObjectSize; 547 PVOID Object, *Extension; 548 PRX_PREFIX_ENTRY PrefixEntry; 549 USHORT StructSize, ExtensionSize; 550 551 PAGED_CODE(); 552 553 /* Select the node to allocate and always deal with the fact we may have to manage its extension */ 554 ExtensionSize = 0; 555 switch (NodeType) 556 { 557 case RDBSS_NTC_SRVCALL: 558 Tag = RX_SRVCALL_POOLTAG; 559 StructSize = sizeof(SRV_CALL); 560 if (MRxDispatch != NULL && BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION)) 561 { 562 ExtensionSize = QuadAlign(MRxDispatch->MRxSrvCallSize); 563 } 564 break; 565 566 case RDBSS_NTC_NETROOT: 567 Tag = RX_NETROOT_POOLTAG; 568 StructSize = sizeof(NET_ROOT); 569 if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_NET_ROOT_EXTENSION)) 570 { 571 ExtensionSize = QuadAlign(MRxDispatch->MRxNetRootSize); 572 } 573 break; 574 575 case RDBSS_NTC_V_NETROOT: 576 Tag = RX_V_NETROOT_POOLTAG; 577 StructSize = sizeof(V_NET_ROOT); 578 if (BooleanFlagOn(MRxDispatch->MRxFlags, RDBSS_MANAGE_V_NET_ROOT_EXTENSION)) 579 { 580 ExtensionSize = QuadAlign(MRxDispatch->MRxVNetRootSize); 581 } 582 break; 583 584 default: 585 ASSERT(FALSE); 586 break; 587 } 588 589 /* Now, allocate the object */ 590 ObjectSize = ExtensionSize + StructSize + NameLength; 591 Object = RxAllocatePoolWithTag(NonPagedPool, ObjectSize, Tag); 592 if (Object == NULL) 593 { 594 return NULL; 595 } 596 /* Initialize it */ 597 ZeroAndInitializeNodeType(Object, NodeType, ObjectSize); 598 599 /* For SRV_CALL and NETROOT, the name points to the prefix table name */ 600 switch (NodeType) 601 { 602 case RDBSS_NTC_SRVCALL: 603 PrefixEntry = &((PSRV_CALL)Object)->PrefixEntry; 604 Extension = &((PSRV_CALL)Object)->Context; 605 ((PSRV_CALL)Object)->pSrvCallName = &PrefixEntry->Prefix; 606 break; 607 608 case RDBSS_NTC_NETROOT: 609 PrefixEntry = &((PNET_ROOT)Object)->PrefixEntry; 610 Extension = &((PNET_ROOT)Object)->Context; 611 ((PNET_ROOT)Object)->pNetRootName = &PrefixEntry->Prefix; 612 break; 613 614 case RDBSS_NTC_V_NETROOT: 615 PrefixEntry = &((PV_NET_ROOT)Object)->PrefixEntry; 616 Extension = &((PV_NET_ROOT)Object)->Context; 617 break; 618 619 default: 620 ASSERT(FALSE); 621 break; 622 } 623 624 /* Set the prefix table unicode string */ 625 RtlZeroMemory(PrefixEntry, sizeof(RX_PREFIX_ENTRY)); 626 PrefixEntry->NodeTypeCode = RDBSS_NTC_PREFIX_ENTRY; 627 PrefixEntry->NodeByteSize = sizeof(RX_PREFIX_ENTRY); 628 PrefixEntry->Prefix.Length = NameLength; 629 PrefixEntry->Prefix.MaximumLength = NameLength; 630 PrefixEntry->Prefix.Buffer = Add2Ptr(Object, ExtensionSize + StructSize); 631 632 /* Return the extension if we are asked to manage it */ 633 if (ExtensionSize != 0) 634 { 635 *Extension = Add2Ptr(Object, StructSize); 636 } 637 638 return Object; 639 } 640 641 /* 642 * @implemented 643 */ 644 VOID 645 RxAssert( 646 PVOID Assert, 647 PVOID File, 648 ULONG Line, 649 PVOID Message) 650 { 651 CHAR Response[2]; 652 CONTEXT Context; 653 654 /* If we're not asked to continue, just stop the system */ 655 if (!RxContinueFromAssert) 656 { 657 KeBugCheckEx(RDBSS_FILE_SYSTEM, RDBSS_BUG_CHECK_ASSERT | Line, 0, 0, 0); 658 } 659 660 /* Otherwise, capture context to offer the user to dump it */ 661 RtlCaptureContext(&Context); 662 663 /* Loop until the user hits 'i' */ 664 while (TRUE) 665 { 666 /* If no file provided, use empty name */ 667 if (File == NULL) 668 { 669 File = ""; 670 } 671 672 /* If no message provided, use empty one */ 673 if (Message == NULL) 674 { 675 Message = ""; 676 } 677 678 /* Display the message */ 679 DbgPrint("\n*** Assertion failed: %s%s\n*** Source File: %s, line %ld\n\n", Message, Assert, File, Line); 680 /* And ask the user */ 681 DbgPrompt("Break, Ignore (bi)? ", Response, sizeof(Response)); 682 /* If he asks for ignore, quit 683 * In case of invalid input, ask again 684 */ 685 if (Response[0] != 'B' && Response[0] != 'b') 686 { 687 if (Response[0] == 'I' || Response[0] == 'i') 688 { 689 return; 690 } 691 692 continue; 693 } 694 695 /* Break: offer the user to dump the context and break */ 696 DbgPrint("Execute '!cxr %lx' to dump context\n", &Context); 697 DbgBreakPoint(); 698 699 /* Continue looping, so that after dump, execution can continue (with ignore) */ 700 } 701 } 702 703 /* 704 * @implemented 705 */ 706 VOID 707 NTAPI 708 RxBootstrapWorkerThreadDispatcher( 709 IN PVOID WorkQueue) 710 { 711 PRX_WORK_QUEUE RxWorkQueue; 712 713 PAGED_CODE(); 714 715 RxWorkQueue = WorkQueue; 716 RxpWorkerThreadDispatcher(RxWorkQueue, NULL); 717 } 718 719 /* 720 * @implemented 721 */ 722 VOID 723 RxCancelBlockingOperation( 724 IN OUT PRX_CONTEXT RxContext) 725 { 726 PFOBX Fobx; 727 BOOLEAN PostRequest; 728 729 PAGED_CODE(); 730 731 Fobx = (PFOBX)RxContext->pFobx; 732 PostRequest = FALSE; 733 734 /* Acquire the pipe mutex */ 735 ExAcquireFastMutex(&RxContextPerFileSerializationMutex); 736 737 /* If that's a blocking pipe operation which is not the CCB one, then handle it */ 738 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION) && 739 RxContext->RxContextSerializationQLinks.Flink != NULL && 740 RxContext != CONTAINING_RECORD(&Fobx->Specific.NamedPipe.ReadSerializationQueue, RX_CONTEXT, RxContextSerializationQLinks) && 741 RxContext != CONTAINING_RECORD(&Fobx->Specific.NamedPipe.WriteSerializationQueue, RX_CONTEXT, RxContextSerializationQLinks)) 742 { 743 /* Clear it! */ 744 ClearFlag(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION); 745 746 /* Drop it off the list */ 747 RemoveEntryList(&RxContext->RxContextSerializationQLinks); 748 RxContext->RxContextSerializationQLinks.Flink = NULL; 749 RxContext->RxContextSerializationQLinks.Blink = NULL; 750 751 /* Set we've been cancelled */ 752 RxContext->IoStatusBlock.Status = STATUS_CANCELLED; 753 754 /* 755 * If it's async, we'll post completion, otherwise, we signal to waiters 756 * it's being cancelled 757 */ 758 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION)) 759 { 760 PostRequest = TRUE; 761 } 762 else 763 { 764 RxSignalSynchronousWaiter(RxContext); 765 } 766 } 767 768 /* Done */ 769 ExReleaseFastMutex(&RxContextPerFileSerializationMutex); 770 771 /* Post if async */ 772 if (PostRequest) 773 { 774 RxFsdPostRequest(RxContext); 775 } 776 } 777 778 /* 779 * @implemented 780 */ 781 NTSTATUS 782 NTAPI 783 RxChangeBufferingState( 784 PSRV_OPEN SrvOpen, 785 PVOID Context, 786 BOOLEAN ComputeNewState) 787 { 788 PFCB Fcb; 789 NTSTATUS Status, MiniStatus; 790 ULONG NewBufferingState, OldBufferingState; 791 792 PAGED_CODE(); 793 794 DPRINT("RxChangeBufferingState(%p, %p, %d)\n", SrvOpen, Context, ComputeNewState); 795 796 Fcb = (PFCB)SrvOpen->pFcb; 797 ASSERT(NodeTypeIsFcb(Fcb)); 798 /* First of all, mark that buffering state is changing */ 799 SetFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING); 800 801 /* Assume success */ 802 Status = STATUS_SUCCESS; 803 _SEH2_TRY 804 { 805 /* If we're asked to compute a new state, ask the mini-rdr for it */ 806 if (ComputeNewState) 807 { 808 MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxComputeNewBufferingState, 809 ((PMRX_SRV_OPEN)SrvOpen, Context, &NewBufferingState)); 810 if (MiniStatus != STATUS_SUCCESS) 811 { 812 NewBufferingState = 0; 813 } 814 } 815 else 816 { 817 /* If not, use SRV_OPEN state */ 818 NewBufferingState = SrvOpen->BufferingFlags; 819 } 820 821 /* If no shared access, and if we're not asked to compute a new state, use maximum flags set */ 822 if ((Fcb->ShareAccess.SharedRead + Fcb->ShareAccess.SharedWrite + Fcb->ShareAccess.SharedDelete) == 0 && !ComputeNewState) 823 { 824 SetFlag(NewBufferingState, FCB_STATE_BUFFERING_STATE_WITH_NO_SHARES); 825 } 826 827 /* If there's a lock operation to complete, clear that flag */ 828 if (Fcb->OutstandingLockOperationsCount != 0) 829 { 830 ClearFlag(NewBufferingState, FCB_STATE_LOCK_BUFFERING_ENABLED); 831 } 832 833 /* Get the old state */ 834 OldBufferingState = Fcb->FcbState & FCB_STATE_BUFFERING_STATE_MASK; 835 DPRINT("ChangeBufferingState %x -> %x (%x)\n", OldBufferingState, NewBufferingState, SrvOpen->BufferingFlags); 836 837 /* If we're dropping write cache, then flush the FCB */ 838 if (BooleanFlagOn(OldBufferingState, FCB_STATE_WRITECACHING_ENABLED) && 839 !BooleanFlagOn(NewBufferingState, FCB_STATE_WRITECACHING_ENABLED)) 840 { 841 DPRINT("Flushing\n"); 842 843 Status = RxFlushFcbInSystemCache(Fcb, TRUE); 844 } 845 846 /* If we're dropping read cache, then purge */ 847 if (Fcb->UncleanCount == 0 || 848 (BooleanFlagOn(OldBufferingState, FCB_STATE_READCACHING_ENABLED) && 849 !BooleanFlagOn(NewBufferingState, FCB_STATE_READCACHING_ENABLED)) || 850 BooleanFlagOn(NewBufferingState, FCB_STATE_DELETE_ON_CLOSE)) 851 { 852 DPRINT("Purging\n"); 853 854 if (!NT_SUCCESS(Status)) 855 { 856 DPRINT("Previous flush failed with status: %lx\n", Status); 857 } 858 859 CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, TRUE); 860 } 861 862 /* If there's already a change pending in SRV_OPEN */ 863 if (ComputeNewState && BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) 864 { 865 /* If there's a FOBX at least */ 866 if (!IsListEmpty(&SrvOpen->FobxList)) 867 { 868 PRX_CONTEXT RxContext; 869 870 /* Create a fake context to pass to the mini-rdr */ 871 RxContext = RxCreateRxContext(NULL, Fcb->RxDeviceObject, RX_CONTEXT_FLAG_MUST_SUCCEED_NONBLOCKING | RX_CONTEXT_FLAG_WAIT); 872 if (RxContext != NULL) 873 { 874 PFOBX Fobx; 875 876 RxContext->pFcb = RX_GET_MRX_FCB(Fcb); 877 878 /* Give the first FOBX */ 879 Fobx = CONTAINING_RECORD(SrvOpen->FobxList.Flink, FOBX, FobxQLinks); 880 RxContext->pFobx = (PMRX_FOBX)Fobx; 881 RxContext->pRelevantSrvOpen = Fobx->pSrvOpen; 882 883 /* If there was a delayed close, perform it */ 884 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_CLOSE_DELAYED)) 885 { 886 DPRINT("Oplock break close for %p\n", SrvOpen); 887 888 RxCloseAssociatedSrvOpen(Fobx, RxContext); 889 } 890 /* Otherwise, inform the mini-rdr about completion */ 891 else 892 { 893 MINIRDR_CALL_THROUGH(MiniStatus, Fcb->MRxDispatch, MRxCompleteBufferingStateChangeRequest, 894 (RxContext, (PMRX_SRV_OPEN)SrvOpen, Context)); 895 (void)MiniStatus; 896 } 897 898 RxDereferenceAndDeleteRxContext(RxContext); 899 } 900 } 901 } 902 903 /* Set the new state */ 904 Fcb->FcbState ^= (NewBufferingState ^ Fcb->FcbState) & FCB_STATE_BUFFERING_STATE_MASK; 905 } 906 _SEH2_FINALLY 907 { 908 /* Job done, clear the flag */ 909 ClearFlag(Fcb->FcbState, FCB_STATE_BUFFERSTATE_CHANGING); 910 911 if (!BooleanFlagOn(NewBufferingState, FCB_STATE_FILETIMECACHEING_ENABLED)) 912 { 913 ClearFlag(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET); 914 } 915 } 916 _SEH2_END; 917 918 return Status; 919 } 920 921 NTSTATUS 922 RxCheckVNetRootCredentials( 923 PRX_CONTEXT RxContext, 924 PV_NET_ROOT VNetRoot, 925 PLUID LogonId, 926 PUNICODE_STRING UserName, 927 PUNICODE_STRING UserDomain, 928 PUNICODE_STRING Password, 929 ULONG Flags) 930 { 931 PAGED_CODE(); 932 933 /* If that's a UNC name, there's nothing to process */ 934 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME) && 935 (BooleanFlagOn(VNetRoot->Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE) || 936 Flags != 0)) 937 { 938 return STATUS_MORE_PROCESSING_REQUIRED; 939 } 940 941 /* Compare the logon ID in the VNetRoot with the one provided */ 942 if (RtlCompareMemory(&VNetRoot->LogonId, LogonId, sizeof(LUID)) != sizeof(LUID)) 943 { 944 return STATUS_MORE_PROCESSING_REQUIRED; 945 } 946 947 /* No credential provided? That's OK */ 948 if (UserName == NULL && UserDomain == NULL && Password == NULL) 949 { 950 return STATUS_SUCCESS; 951 } 952 953 /* Left to do! */ 954 UNIMPLEMENTED; 955 return STATUS_NOT_IMPLEMENTED; 956 } 957 958 NTSTATUS 959 RxCompleteRequest( 960 PRX_CONTEXT Context, 961 NTSTATUS Status) 962 { 963 PIRP Irp; 964 965 PAGED_CODE(); 966 967 DPRINT("RxCompleteRequest(%p, %lx)\n", Context, Status); 968 969 ASSERT(Context != NULL); 970 ASSERT(Context->CurrentIrp != NULL); 971 Irp = Context->CurrentIrp; 972 973 /* Debug what the caller asks for */ 974 if (Context->LoudCompletionString != NULL) 975 { 976 DPRINT("LoudCompletion: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString); 977 /* Does the user asks to stop on failed completion */ 978 if (!NT_SUCCESS(Status) && RxStopOnLoudCompletion) 979 { 980 DPRINT1("LoudFailure: %lx/%lx with %wZ\n", Status, Irp->IoStatus.Information, Context->LoudCompletionString); 981 } 982 } 983 984 /* Complete for real */ 985 Context->CurrentIrp = NULL; 986 RxCompleteRequest_Real(Context, Irp, Status); 987 988 DPRINT("Status: %lx\n", Status); 989 return Status; 990 } 991 992 /* 993 * @implemented 994 */ 995 VOID 996 RxCompleteRequest_Real( 997 IN PRX_CONTEXT RxContext, 998 IN PIRP Irp, 999 IN NTSTATUS Status) 1000 { 1001 CCHAR Boost; 1002 KIRQL OldIrql; 1003 PIO_STACK_LOCATION Stack; 1004 1005 DPRINT("RxCompleteRequest_Real(%p, %p, %lx)\n", RxContext, Irp, Status); 1006 1007 /* Nothing to complete, just free context */ 1008 if (Irp == NULL) 1009 { 1010 DPRINT("NULL IRP for %p\n", RxContext); 1011 if (RxContext != NULL) 1012 { 1013 RxDereferenceAndDeleteRxContext_Real(RxContext); 1014 } 1015 1016 return; 1017 } 1018 1019 /* Remove cancel routine */ 1020 IoAcquireCancelSpinLock(&OldIrql); 1021 IoSetCancelRoutine(Irp, NULL); 1022 IoReleaseCancelSpinLock(OldIrql); 1023 1024 /* Select the boost, given the success/paging operation */ 1025 if (NT_SUCCESS(Status) || !BooleanFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO)) 1026 { 1027 Boost = IO_DISK_INCREMENT; 1028 } 1029 else 1030 { 1031 Irp->IoStatus.Information = 0; 1032 Boost = IO_NO_INCREMENT; 1033 } 1034 Irp->IoStatus.Status = Status; 1035 1036 if (RxContext != NULL) 1037 { 1038 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION); 1039 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL) 1040 { 1041 DPRINT("Completing: MN: %d, Context: %p, IRP: %p, Status: %lx, Info: %lx, #%lx\n", 1042 RxContext->MinorFunction, RxContext, Irp, 1043 Status, Irp->IoStatus.Information, RxContext->SerialNumber); 1044 } 1045 } 1046 1047 /* If that's an opening, there might be a canonical name allocated, 1048 * if completion isn't pending, release it 1049 */ 1050 Stack = IoGetCurrentIrpStackLocation(Irp); 1051 if (Stack->MajorFunction == IRP_MJ_CREATE && Status != STATUS_PENDING && 1052 RxContext != NULL) 1053 { 1054 if (BooleanFlagOn(RxContext->Create.Flags, 2)) 1055 { 1056 Stack->FileObject->FileName.Length += sizeof(WCHAR); 1057 } 1058 1059 RxpPrepareCreateContextForReuse(RxContext); 1060 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL); 1061 } 1062 1063 /* If it's a write, validate the correct behavior of the operation */ 1064 if (Stack->MajorFunction == IRP_MJ_WRITE) 1065 { 1066 if (NT_SUCCESS(Irp->IoStatus.Status)) 1067 { 1068 ASSERT(Irp->IoStatus.Information <= Stack->Parameters.Write.Length); 1069 } 1070 } 1071 1072 /* If it's pending, make sure IRP is marked as such */ 1073 if (RxContext != NULL) 1074 { 1075 if (RxContext->PendingReturned) 1076 { 1077 ASSERT(BooleanFlagOn(Stack->Control, SL_PENDING_RETURNED)); 1078 } 1079 } 1080 1081 /* Complete now */ 1082 DPRINT("Completing IRP with %x/%x\n", Irp->IoStatus.Status, Irp->IoStatus.Information); 1083 IoCompleteRequest(Irp, Boost); 1084 1085 /* If there's a context, dereference it */ 1086 if (RxContext != NULL) 1087 { 1088 RxDereferenceAndDeleteRxContext_Real(RxContext); 1089 } 1090 } 1091 1092 /* 1093 * @implemented 1094 */ 1095 VOID 1096 RxCompleteSrvOpenKeyAssociation( 1097 IN OUT PSRV_OPEN SrvOpen) 1098 { 1099 PSRV_CALL SrvCall; 1100 1101 SrvCall = (PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall; 1102 /* Only handle requests if opening was a success */ 1103 if (SrvOpen->Condition == Condition_Good) 1104 { 1105 KIRQL OldIrql; 1106 BOOLEAN ProcessChange; 1107 LIST_ENTRY DiscardedRequests; 1108 1109 /* Initialize our discarded requests list */ 1110 InitializeListHead(&DiscardedRequests); 1111 1112 RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager); 1113 1114 /* Transfer our requests in the SRV_CALL */ 1115 RxTransferList(&SrvCall->BufferingManager.SrvOpenLists[0], &SrvOpen->SrvOpenKeyList); 1116 1117 /* Was increased in RxInitiateSrvOpenKeyAssociation(), opening is done */ 1118 InterlockedDecrement(&SrvCall->BufferingManager.NumberOfOutstandingOpens); 1119 1120 /* Dispatch requests and get the discarded ones */ 1121 RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &DiscardedRequests); 1122 1123 RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager); 1124 1125 /* Is there still anything to process? */ 1126 KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql); 1127 if (IsListEmpty(&SrvCall->BufferingManager.HandlerList)) 1128 { 1129 ProcessChange = FALSE; 1130 } 1131 else 1132 { 1133 ProcessChange = (SrvCall->BufferingManager.HandlerInactive == FALSE); 1134 if (ProcessChange) 1135 { 1136 SrvCall->BufferingManager.HandlerInactive = TRUE; 1137 } 1138 } 1139 KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql); 1140 1141 /* Yes? Go ahead! */ 1142 if (ProcessChange) 1143 { 1144 RxReferenceSrvCall(SrvCall); 1145 RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue, 1146 &SrvCall->BufferingManager.HandlerWorkItem, 1147 RxProcessChangeBufferingStateRequests, SrvCall); 1148 } 1149 1150 /* And discard left requests */ 1151 RxpDiscardChangeBufferingStateRequests(&DiscardedRequests); 1152 } 1153 else 1154 { 1155 InterlockedDecrement(&SrvCall->BufferingManager.NumberOfOutstandingOpens); 1156 } 1157 } 1158 1159 /* 1160 * @implemented 1161 */ 1162 NTSTATUS 1163 RxConstructNetRoot( 1164 IN PRX_CONTEXT RxContext, 1165 IN PSRV_CALL SrvCall, 1166 IN PNET_ROOT NetRoot, 1167 IN PV_NET_ROOT VirtualNetRoot, 1168 OUT PLOCK_HOLDING_STATE LockHoldingState) 1169 { 1170 NTSTATUS Status; 1171 PRX_PREFIX_TABLE PrefixTable; 1172 PMRX_CREATENETROOT_CONTEXT Context; 1173 RX_BLOCK_CONDITION RootCondition, VRootCondition; 1174 1175 PAGED_CODE(); 1176 1177 DPRINT("RxConstructNetRoot(%p, %p, %p, %p, %p)\n", RxContext, SrvCall, NetRoot, 1178 VirtualNetRoot, LockHoldingState); 1179 1180 /* Validate the lock is exclusively held */ 1181 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable; 1182 ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld); 1183 1184 /* Allocate the context */ 1185 Context = RxAllocatePoolWithTag(PagedPool, sizeof(MRX_CREATENETROOT_CONTEXT), RX_SRVCALL_POOLTAG); 1186 if (Context == NULL) 1187 { 1188 return STATUS_INSUFFICIENT_RESOURCES; 1189 } 1190 1191 /* We can release lock now */ 1192 RxReleasePrefixTableLock(PrefixTable); 1193 *LockHoldingState = LHS_LockNotHeld; 1194 1195 RootCondition = Condition_Bad; 1196 VRootCondition = Condition_Bad; 1197 1198 /* Initialize the context */ 1199 RtlZeroMemory(Context, sizeof(MRX_CREATENETROOT_CONTEXT)); 1200 KeInitializeEvent(&Context->FinishEvent, SynchronizationEvent, FALSE); 1201 Context->RxContext = RxContext; 1202 Context->pVNetRoot = VirtualNetRoot; 1203 Context->Callback = RxCreateNetRootCallBack; 1204 1205 /* And call the mini-rdr */ 1206 MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch, MRxCreateVNetRoot, (Context)); 1207 if (Status == STATUS_PENDING) 1208 { 1209 /* Wait for the mini-rdr to be done */ 1210 KeWaitForSingleObject(&Context->FinishEvent, Executive, KernelMode, FALSE, NULL); 1211 /* Update the structures condition according to mini-rdr return */ 1212 if (NT_SUCCESS(Context->NetRootStatus)) 1213 { 1214 if (NT_SUCCESS(Context->VirtualNetRootStatus)) 1215 { 1216 RootCondition = Condition_Good; 1217 VRootCondition = Condition_Good; 1218 Status = STATUS_SUCCESS; 1219 } 1220 else 1221 { 1222 RootCondition = Condition_Good; 1223 Status = Context->VirtualNetRootStatus; 1224 } 1225 } 1226 else 1227 { 1228 Status = Context->VirtualNetRootStatus; 1229 if (NT_SUCCESS(Status)) 1230 { 1231 Status = Context->NetRootStatus; 1232 } 1233 } 1234 } 1235 else 1236 { 1237 /* It has to return STATUS_PENDING! */ 1238 ASSERT(FALSE); 1239 } 1240 1241 /* Acquire lock again - for caller lock status will remain unchanged */ 1242 ASSERT(*LockHoldingState == LHS_LockNotHeld); 1243 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE); 1244 *LockHoldingState = LHS_ExclusiveLockHeld; 1245 1246 /* Do the transition to the condition got from mini-rdr */ 1247 RxTransitionNetRoot(NetRoot, RootCondition); 1248 RxTransitionVNetRoot(VirtualNetRoot, VRootCondition); 1249 1250 /* Context is not longer needed */ 1251 RxFreePoolWithTag(Context, RX_SRVCALL_POOLTAG); 1252 1253 DPRINT("Status: %x\n", Status); 1254 1255 return Status; 1256 } 1257 1258 /* 1259 * @implemented 1260 */ 1261 NTSTATUS 1262 RxConstructSrvCall( 1263 IN PRX_CONTEXT RxContext, 1264 IN PSRV_CALL SrvCall, 1265 OUT PLOCK_HOLDING_STATE LockHoldingState) 1266 { 1267 NTSTATUS Status; 1268 PRX_PREFIX_TABLE PrefixTable; 1269 PRDBSS_DEVICE_OBJECT RxDeviceObject; 1270 PMRX_SRVCALLDOWN_STRUCTURE Calldown; 1271 PMRX_SRVCALL_CALLBACK_CONTEXT CallbackContext; 1272 1273 PAGED_CODE(); 1274 1275 DPRINT("RxConstructSrvCall(%p, %p, %p)\n", RxContext, SrvCall, LockHoldingState); 1276 1277 /* Validate the lock is exclusively held */ 1278 RxDeviceObject = RxContext->RxDeviceObject; 1279 PrefixTable = RxDeviceObject->pRxNetNameTable; 1280 ASSERT(*LockHoldingState == LHS_ExclusiveLockHeld); 1281 1282 /* Allocate the context for mini-rdr */ 1283 Calldown = RxAllocatePoolWithTag(NonPagedPool, sizeof(MRX_SRVCALLDOWN_STRUCTURE), RX_SRVCALL_POOLTAG); 1284 if (Calldown == NULL) 1285 { 1286 SrvCall->Context = NULL; 1287 SrvCall->Condition = Condition_Bad; 1288 RxReleasePrefixTableLock(PrefixTable); 1289 *LockHoldingState = LHS_LockNotHeld; 1290 return STATUS_INSUFFICIENT_RESOURCES; 1291 } 1292 1293 /* Initialize it */ 1294 RtlZeroMemory(Calldown, sizeof(MRX_SRVCALLDOWN_STRUCTURE)); 1295 1296 SrvCall->Context = NULL; 1297 SrvCall->Condition = Condition_InTransition; 1298 1299 RxReleasePrefixTableLock(PrefixTable); 1300 *LockHoldingState = LHS_LockNotHeld; 1301 1302 CallbackContext = &Calldown->CallbackContexts[0]; 1303 DPRINT("CalldownContext %p for %wZ\n", CallbackContext, &RxDeviceObject->DeviceName); 1304 DPRINT("With calldown %p and SrvCall %p\n", Calldown, SrvCall); 1305 CallbackContext->SrvCalldownStructure = Calldown; 1306 CallbackContext->CallbackContextOrdinal = 0; 1307 CallbackContext->RxDeviceObject = RxDeviceObject; 1308 1309 RxReferenceSrvCall(SrvCall); 1310 1311 /* If we're async, we'll post, otherwise, we'll have to wait for completion */ 1312 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION)) 1313 { 1314 RxPrePostIrp(RxContext, RxContext->CurrentIrp); 1315 } 1316 else 1317 { 1318 KeInitializeEvent(&Calldown->FinishEvent, SynchronizationEvent, FALSE); 1319 } 1320 1321 Calldown->NumberToWait = 1; 1322 Calldown->NumberRemaining = 1; 1323 Calldown->RxContext = RxContext; 1324 Calldown->SrvCall = (PMRX_SRV_CALL)SrvCall; 1325 Calldown->CallBack = RxCreateSrvCallCallBack; 1326 Calldown->BestFinisher = NULL; 1327 CallbackContext->Status = STATUS_BAD_NETWORK_PATH; 1328 InitializeListHead(&Calldown->SrvCalldownList); 1329 1330 /* Call the mini-rdr */ 1331 ASSERT(RxDeviceObject->Dispatch != NULL); 1332 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH); 1333 ASSERT(RxDeviceObject->Dispatch->MRxCreateSrvCall != NULL); 1334 Status = RxDeviceObject->Dispatch->MRxCreateSrvCall((PMRX_SRV_CALL)SrvCall, CallbackContext); 1335 /* It has to return STATUS_PENDING! */ 1336 ASSERT(Status == STATUS_PENDING); 1337 1338 /* No async, start completion */ 1339 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION)) 1340 { 1341 KeWaitForSingleObject(&Calldown->FinishEvent, Executive, KernelMode, FALSE, NULL); 1342 1343 /* Finish construction - we'll notify mini-rdr it's the winner */ 1344 Status = RxFinishSrvCallConstruction(Calldown); 1345 if (!NT_SUCCESS(Status)) 1346 { 1347 RxReleasePrefixTableLock(PrefixTable); 1348 *LockHoldingState = LHS_LockNotHeld; 1349 } 1350 else 1351 { 1352 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable)); 1353 *LockHoldingState = LHS_ExclusiveLockHeld; 1354 } 1355 } 1356 1357 DPRINT("RxConstructSrvCall() = Status: %x\n", Status); 1358 return Status; 1359 } 1360 1361 /* 1362 * @implemented 1363 */ 1364 NTSTATUS 1365 RxConstructVirtualNetRoot( 1366 IN PRX_CONTEXT RxContext, 1367 IN PUNICODE_STRING CanonicalName, 1368 IN NET_ROOT_TYPE NetRootType, 1369 OUT PV_NET_ROOT *VirtualNetRootPointer, 1370 OUT PLOCK_HOLDING_STATE LockHoldingState, 1371 OUT PRX_CONNECTION_ID RxConnectionId) 1372 { 1373 NTSTATUS Status; 1374 PV_NET_ROOT VNetRoot; 1375 RX_BLOCK_CONDITION Condition; 1376 UNICODE_STRING LocalNetRootName, FilePathName; 1377 1378 PAGED_CODE(); 1379 1380 ASSERT(*LockHoldingState != LHS_LockNotHeld); 1381 1382 VNetRoot = NULL; 1383 Condition = Condition_Bad; 1384 /* Before creating the VNetRoot, try to find the appropriate connection */ 1385 Status = RxFindOrCreateConnections(RxContext, CanonicalName, NetRootType, 1386 &LocalNetRootName, &FilePathName, 1387 LockHoldingState, RxConnectionId); 1388 /* Found and active */ 1389 if (Status == STATUS_CONNECTION_ACTIVE) 1390 { 1391 /* We need a new VNetRoot */ 1392 VNetRoot = RxCreateVNetRoot(RxContext, (PNET_ROOT)RxContext->Create.pVNetRoot->pNetRoot, 1393 CanonicalName, &LocalNetRootName, &FilePathName, RxConnectionId); 1394 if (VNetRoot != NULL) 1395 { 1396 RxReferenceVNetRoot(VNetRoot); 1397 } 1398 1399 /* Dereference previous VNetRoot */ 1400 RxDereferenceVNetRoot(RxContext->Create.pVNetRoot->pNetRoot, *LockHoldingState); 1401 /* Reset and start construct (new structures will replace old ones) */ 1402 RxContext->Create.pSrvCall = NULL; 1403 RxContext->Create.pNetRoot = NULL; 1404 RxContext->Create.pVNetRoot = NULL; 1405 1406 /* Construct new NetRoot */ 1407 if (VNetRoot != NULL) 1408 { 1409 Status = RxConstructNetRoot(RxContext, (PSRV_CALL)VNetRoot->pNetRoot->pSrvCall, 1410 (PNET_ROOT)VNetRoot->pNetRoot, VNetRoot, LockHoldingState); 1411 if (NT_SUCCESS(Status)) 1412 { 1413 Condition = Condition_Good; 1414 } 1415 } 1416 else 1417 { 1418 Status = STATUS_INSUFFICIENT_RESOURCES; 1419 } 1420 } 1421 else 1422 { 1423 /* If it failed creating the connection, leave */ 1424 if (Status != STATUS_SUCCESS) 1425 { 1426 if (*LockHoldingState != LHS_LockNotHeld) 1427 { 1428 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable); 1429 *LockHoldingState = LHS_LockNotHeld; 1430 } 1431 1432 *VirtualNetRootPointer = VNetRoot; 1433 DPRINT("RxConstructVirtualNetRoot() = Status: %x\n", Status); 1434 return Status; 1435 } 1436 1437 *LockHoldingState = LHS_ExclusiveLockHeld; 1438 1439 VNetRoot = (PV_NET_ROOT)RxContext->Create.pVNetRoot; 1440 Condition = Condition_Good; 1441 } 1442 1443 /* We have a non stable VNetRoot - transition it */ 1444 if (VNetRoot != NULL && !StableCondition(VNetRoot->Condition)) 1445 { 1446 RxTransitionVNetRoot(VNetRoot, Condition); 1447 } 1448 1449 /* If recreation failed */ 1450 if (Status != STATUS_SUCCESS) 1451 { 1452 /* Dereference potential VNetRoot */ 1453 if (VNetRoot != NULL) 1454 { 1455 ASSERT(*LockHoldingState != LHS_LockNotHeld); 1456 RxDereferenceVNetRoot(VNetRoot, *LockHoldingState); 1457 VNetRoot = NULL; 1458 } 1459 1460 /* Release lock */ 1461 if (*LockHoldingState != LHS_LockNotHeld) 1462 { 1463 RxReleasePrefixTableLock(RxContext->RxDeviceObject->pRxNetNameTable); 1464 *LockHoldingState = LHS_LockNotHeld; 1465 } 1466 1467 /* Set NULL ptr */ 1468 *VirtualNetRootPointer = VNetRoot; 1469 return Status; 1470 } 1471 1472 /* Return the allocated VNetRoot */ 1473 *VirtualNetRootPointer = VNetRoot; 1474 return Status; 1475 } 1476 1477 /* 1478 * @implemented 1479 */ 1480 PFCB 1481 RxCreateNetFcb( 1482 IN PRX_CONTEXT RxContext, 1483 IN PV_NET_ROOT VNetRoot, 1484 IN PUNICODE_STRING Name) 1485 { 1486 PFCB Fcb; 1487 BOOLEAN FakeFcb; 1488 PNET_ROOT NetRoot; 1489 POOL_TYPE PoolType; 1490 NODE_TYPE_CODE NodeType; 1491 PIO_STACK_LOCATION Stack; 1492 PRDBSS_DEVICE_OBJECT RxDeviceObject; 1493 1494 PAGED_CODE(); 1495 1496 /* We need a decent VNetRoot */ 1497 ASSERT(VNetRoot != NULL && NodeType(VNetRoot) == RDBSS_NTC_V_NETROOT); 1498 1499 NetRoot = (PNET_ROOT)VNetRoot->pNetRoot; 1500 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT); 1501 ASSERT((PMRX_NET_ROOT)NetRoot == RxContext->Create.pNetRoot); 1502 1503 RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject; 1504 ASSERT(RxDeviceObject == RxContext->RxDeviceObject); 1505 1506 Stack = RxContext->CurrentIrpSp; 1507 1508 /* Do we need to create a fake FCB? Like for renaming */ 1509 FakeFcb = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY) && 1510 !BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_SUPPORTS_SYMBOLIC_LINKS); 1511 ASSERT(FakeFcb || RxIsFcbTableLockExclusive(&NetRoot->FcbTable)); 1512 1513 PoolType = (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE) ? NonPagedPool : PagedPool); 1514 NodeType = (FakeFcb) ? RDBSS_NTC_OPENTARGETDIR_FCB : RDBSS_STORAGE_NTC(FileTypeNotYetKnown); 1515 1516 /* Allocate the FCB */ 1517 Fcb = RxAllocateFcbObject(RxDeviceObject, NodeType, PoolType, 1518 NetRoot->InnerNamePrefix.Length + Name->Length, NULL); 1519 if (Fcb == NULL) 1520 { 1521 return NULL; 1522 } 1523 1524 /* Initialize the FCB */ 1525 Fcb->CachedNetRootType = NetRoot->Type; 1526 Fcb->RxDeviceObject = RxDeviceObject; 1527 Fcb->MRxDispatch = RxDeviceObject->Dispatch; 1528 Fcb->VNetRoot = VNetRoot; 1529 Fcb->pNetRoot = VNetRoot->pNetRoot; 1530 1531 InitializeListHead(&Fcb->SrvOpenList); 1532 Fcb->SrvOpenListVersion = 0; 1533 1534 Fcb->FcbTableEntry.Path.Length = Name->Length; 1535 Fcb->FcbTableEntry.Path.MaximumLength = Name->Length; 1536 Fcb->FcbTableEntry.Path.Buffer = Add2Ptr(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Length); 1537 RtlMoveMemory(Fcb->PrivateAlreadyPrefixedName.Buffer, NetRoot->InnerNamePrefix.Buffer, 1538 NetRoot->InnerNamePrefix.Length); 1539 RtlMoveMemory(Fcb->FcbTableEntry.Path.Buffer, Name->Buffer, Name->Length); 1540 1541 /* Copy back parameters from RxContext */ 1542 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH)) 1543 { 1544 Fcb->FcbState |= FCB_STATE_ADDEDBACKSLASH; 1545 } 1546 1547 InitializeListHead(&Fcb->NonPaged->TransitionWaitList); 1548 1549 if (BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE)) 1550 { 1551 Fcb->FcbState |= FCB_STATE_PAGING_FILE; 1552 } 1553 1554 if (RxContext->MajorFunction == IRP_MJ_CREATE && BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_SPECIAL_PATH)) 1555 { 1556 Fcb->FcbState |= FCB_STATE_SPECIAL_PATH; 1557 } 1558 1559 Fcb->Header.Resource = &Fcb->NonPaged->HeaderResource; 1560 ExInitializeResourceLite(Fcb->Header.Resource); 1561 1562 Fcb->Header.PagingIoResource = &Fcb->NonPaged->PagingIoResource; 1563 ExInitializeResourceLite(Fcb->Header.PagingIoResource); 1564 1565 Fcb->BufferedLocks.Resource = &Fcb->NonPaged->BufferedLocksResource; 1566 ExInitializeResourceLite(Fcb->BufferedLocks.Resource); 1567 1568 /* Fake FCB doesn't go in prefix table */ 1569 if (FakeFcb) 1570 { 1571 Fcb->FcbState |= (FCB_STATE_FAKEFCB | FCB_STATE_NAME_ALREADY_REMOVED); 1572 InitializeListHead(&Fcb->FcbTableEntry.HashLinks); 1573 DPRINT("Fake FCB: %p\n", Fcb); 1574 } 1575 else 1576 { 1577 RxFcbTableInsertFcb(&NetRoot->FcbTable, Fcb); 1578 } 1579 1580 RxReferenceVNetRoot(VNetRoot); 1581 InterlockedIncrement((volatile long *)&Fcb->pNetRoot->NumberOfFcbs); 1582 1583 Fcb->ulFileSizeVersion = 0; 1584 1585 DPRINT("FCB %p for %wZ\n", Fcb, &Fcb->FcbTableEntry.Path); 1586 RxReferenceNetFcb(Fcb); 1587 1588 return Fcb; 1589 } 1590 1591 /* 1592 * @implemented 1593 */ 1594 PMRX_FOBX 1595 NTAPI 1596 RxCreateNetFobx( 1597 OUT PRX_CONTEXT RxContext, 1598 IN PMRX_SRV_OPEN MrxSrvOpen) 1599 { 1600 PFCB Fcb; 1601 PFOBX Fobx; 1602 ULONG Flags; 1603 PNET_ROOT NetRoot; 1604 PSRV_OPEN SrvOpen; 1605 POOL_TYPE PoolType; 1606 1607 PAGED_CODE(); 1608 1609 SrvOpen = (PSRV_OPEN)MrxSrvOpen; 1610 ASSERT(NodeType(SrvOpen) == RDBSS_NTC_SRVOPEN); 1611 ASSERT(NodeTypeIsFcb(SrvOpen->Fcb)); 1612 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb)); 1613 1614 Fcb = SrvOpen->Fcb; 1615 PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool); 1616 /* Can we use pre-allocated FOBX? */ 1617 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_FOBX_USED) && Fcb->InternalSrvOpen == (PSRV_OPEN)MrxSrvOpen) 1618 { 1619 Fobx = Fcb->InternalFobx; 1620 /* Call allocate to initialize the FOBX */ 1621 RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx); 1622 /* Mark it used now */ 1623 Fcb->FcbState |= FCB_STATE_FOBX_USED; 1624 Flags = FOBX_FLAG_ENCLOSED_ALLOCATED; 1625 } 1626 else if (!BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED)) 1627 { 1628 Fobx = SrvOpen->InternalFobx; 1629 /* Call allocate to initialize the FOBX */ 1630 RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, Fobx); 1631 /* Mark it used now */ 1632 SrvOpen->Flags |= SRVOPEN_FLAG_FOBX_USED; 1633 Flags = FOBX_FLAG_ENCLOSED_ALLOCATED; 1634 } 1635 else 1636 { 1637 /* Last case, we cannot, allocate a FOBX */ 1638 Fobx = RxAllocateFcbObject(Fcb->RxDeviceObject, RDBSS_NTC_FOBX, PoolType, 0, NULL); 1639 Flags = 0; 1640 } 1641 1642 /* Allocation failed! */ 1643 if (Fobx == NULL) 1644 { 1645 return NULL; 1646 } 1647 1648 /* Set flags */ 1649 Fobx->Flags = Flags; 1650 1651 /* Initialize throttling */ 1652 NetRoot = (PNET_ROOT)RxContext->Create.pNetRoot; 1653 if (NetRoot != NULL) 1654 { 1655 if (NetRoot->DeviceType == FILE_DEVICE_DISK) 1656 { 1657 RxInitializeThrottlingState(&Fobx->Specific.DiskFile.LockThrottlingState, 1658 NetRoot->DiskParameters.LockThrottlingParameters.Increment, 1659 NetRoot->DiskParameters.LockThrottlingParameters.MaximumDelay); 1660 } 1661 else if (NetRoot->DeviceType == FILE_DEVICE_NAMED_PIPE) 1662 { 1663 RxInitializeThrottlingState(&Fobx->Specific.NamedPipe.ThrottlingState, 1664 NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.Increment, 1665 NetRoot->NamedPipeParameters.PipeReadThrottlingParameters.MaximumDelay); 1666 } 1667 } 1668 1669 /* Propagate flags fron RxContext */ 1670 if (BooleanFlagOn(RxContext->Create.Flags, RX_CONTEXT_CREATE_FLAG_UNC_NAME)) 1671 { 1672 Fobx->Flags |= FOBX_FLAG_UNC_NAME; 1673 } 1674 1675 if (BooleanFlagOn(RxContext->Create.NtCreateParameters.CreateOptions, FILE_OPEN_FOR_BACKUP_INTENT)) 1676 { 1677 Fobx->Flags |= FOBX_FLAG_BACKUP_INTENT; 1678 } 1679 1680 /* Continue init */ 1681 Fobx->FobxSerialNumber = 0; 1682 Fobx->SrvOpen = (PSRV_OPEN)MrxSrvOpen; 1683 Fobx->NodeReferenceCount = 1; 1684 Fobx->RxDeviceObject = Fcb->RxDeviceObject; 1685 1686 RxReferenceSrvOpen(SrvOpen); 1687 InterlockedIncrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs); 1688 1689 InsertTailList(&SrvOpen->FobxList, &Fobx->FobxQLinks); 1690 InitializeListHead(&Fobx->ScavengerFinalizationList); 1691 InitializeListHead(&Fobx->ClosePendingList); 1692 1693 Fobx->CloseTime.QuadPart = 0; 1694 Fobx->fOpenCountDecremented = FALSE; 1695 1696 DPRINT("FOBX %p for SRV_OPEN %p FCB %p\n", Fobx, Fobx->SrvOpen, Fobx->SrvOpen->pFcb); 1697 1698 return (PMRX_FOBX)Fobx; 1699 } 1700 1701 /* 1702 * @implemented 1703 */ 1704 PNET_ROOT 1705 RxCreateNetRoot( 1706 IN PSRV_CALL SrvCall, 1707 IN PUNICODE_STRING Name, 1708 IN ULONG NetRootFlags, 1709 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId) 1710 { 1711 PNET_ROOT NetRoot; 1712 USHORT CaseInsensitiveLength; 1713 PRX_PREFIX_TABLE PrefixTable; 1714 1715 DPRINT("RxCreateNetRoot(%p, %wZ, %x, %p)\n", SrvCall, Name, NetRootFlags, RxConnectionId); 1716 1717 PAGED_CODE(); 1718 1719 /* We need a SRV_CALL */ 1720 ASSERT(SrvCall != NULL); 1721 1722 PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable; 1723 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable)); 1724 1725 /* Get name length */ 1726 CaseInsensitiveLength = SrvCall->PrefixEntry.Prefix.Length + Name->Length; 1727 if (CaseInsensitiveLength > MAXUSHORT) 1728 { 1729 return NULL; 1730 } 1731 1732 /* Allocate the NetRoot */ 1733 NetRoot = RxAllocateObject(RDBSS_NTC_NETROOT, SrvCall->RxDeviceObject->Dispatch, 1734 CaseInsensitiveLength); 1735 if (NetRoot == NULL) 1736 { 1737 return NULL; 1738 } 1739 1740 /* Construct name */ 1741 RtlMoveMemory(Add2Ptr(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Length), 1742 Name->Buffer, Name->Length); 1743 if (SrvCall->PrefixEntry.Prefix.Length != 0) 1744 { 1745 RtlMoveMemory(NetRoot->PrefixEntry.Prefix.Buffer, SrvCall->PrefixEntry.Prefix.Buffer, 1746 SrvCall->PrefixEntry.Prefix.Length); 1747 } 1748 1749 if (!BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS)) 1750 { 1751 CaseInsensitiveLength = SrvCall->PrefixEntry.CaseInsensitiveLength; 1752 } 1753 /* Inisert in prefix table */ 1754 RxPrefixTableInsertName(PrefixTable, &NetRoot->PrefixEntry, NetRoot, 1755 (PULONG)&NetRoot->NodeReferenceCount, CaseInsensitiveLength, 1756 RxConnectionId); 1757 1758 /* Prepare the FCB table */ 1759 RxInitializeFcbTable(&NetRoot->FcbTable, TRUE); 1760 1761 InitializeListHead(&NetRoot->TransitionWaitList); 1762 InitializeListHead(&NetRoot->ScavengerFinalizationList); 1763 InitializeListHead(&NetRoot->VirtualNetRoots); 1764 1765 RxInitializePurgeSyncronizationContext(&NetRoot->PurgeSyncronizationContext); 1766 1767 NetRoot->SerialNumberForEnum = SerialNumber++; 1768 NetRoot->Flags |= NetRootFlags; 1769 NetRoot->DiskParameters.ClusterSize = 1; 1770 NetRoot->DiskParameters.ReadAheadGranularity = ReadAheadGranularity; 1771 NetRoot->SrvCall = SrvCall; 1772 1773 RxReferenceSrvCall(SrvCall); 1774 1775 DPRINT("NetRootName: %wZ (%p)\n", NetRoot->pNetRootName, NetRoot); 1776 return NetRoot; 1777 } 1778 1779 /* 1780 * @implemented 1781 */ 1782 VOID 1783 NTAPI 1784 RxCreateNetRootCallBack( 1785 IN PMRX_CREATENETROOT_CONTEXT CreateNetRootContext) 1786 { 1787 PAGED_CODE(); 1788 1789 KeSetEvent(&CreateNetRootContext->FinishEvent, IO_NETWORK_INCREMENT, FALSE); 1790 } 1791 1792 /* 1793 * @implemented 1794 */ 1795 PRX_CONTEXT 1796 NTAPI 1797 RxCreateRxContext( 1798 IN PIRP Irp, 1799 IN PRDBSS_DEVICE_OBJECT RxDeviceObject, 1800 IN ULONG InitialContextFlags) 1801 { 1802 KIRQL OldIrql; 1803 PRX_CONTEXT Context; 1804 1805 ASSERT(RxDeviceObject != NULL); 1806 1807 DPRINT("RxCreateRxContext(%p, %p, %u)\n", Irp, RxDeviceObject, InitialContextFlags); 1808 1809 #if DBG 1810 InterlockedIncrement((volatile LONG *)&RxFsdEntryCount); 1811 #endif 1812 InterlockedIncrement((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts); 1813 1814 /* Allocate the context from our lookaside list */ 1815 Context = ExAllocateFromNPagedLookasideList(&RxContextLookasideList); 1816 if (Context == NULL) 1817 { 1818 return NULL; 1819 } 1820 1821 /* Zero it */ 1822 RtlZeroMemory(Context, sizeof(RX_CONTEXT)); 1823 1824 /* It was allocated on NP pool, keep track of it! */ 1825 SetFlag(Context->Flags, RX_CONTEXT_FLAG_FROM_POOL); 1826 /* And initialize it */ 1827 RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, Context); 1828 ASSERT((Context->MajorFunction != IRP_MJ_CREATE) || !BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_MUST_SUCCEED_ALLOCATED)); 1829 1830 /* Add it to our global list */ 1831 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql); 1832 InsertTailList(&RxActiveContexts, &Context->ContextListEntry); 1833 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql); 1834 1835 DPRINT("Context: %p\n", Context); 1836 return Context; 1837 } 1838 1839 /* 1840 * @implemented 1841 */ 1842 PSRV_CALL 1843 RxCreateSrvCall( 1844 IN PRX_CONTEXT RxContext, 1845 IN PUNICODE_STRING Name, 1846 IN PUNICODE_STRING InnerNamePrefix OPTIONAL, 1847 IN PRX_CONNECTION_ID RxConnectionId) 1848 { 1849 ULONG NameLength; 1850 PSRV_CALL SrvCall; 1851 1852 PAGED_CODE(); 1853 1854 DPRINT("RxCreateSrvCall(%p, %wZ, %wZ, %p)\n", RxContext, Name, InnerNamePrefix, RxConnectionId); 1855 1856 ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable)); 1857 1858 /* Get the name length */ 1859 NameLength = Name->Length + 2 * sizeof(WCHAR); 1860 if (InnerNamePrefix != NULL) 1861 { 1862 NameLength += InnerNamePrefix->Length; 1863 } 1864 1865 /* Allocate the object */ 1866 SrvCall = RxAllocateObject(RDBSS_NTC_SRVCALL, NULL, NameLength); 1867 if (SrvCall == NULL) 1868 { 1869 return NULL; 1870 } 1871 1872 /* Initialize it */ 1873 SrvCall->SerialNumberForEnum = SerialNumber++; 1874 SrvCall->RxDeviceObject = RxContext->RxDeviceObject; 1875 RxInitializeBufferingManager(SrvCall); 1876 InitializeListHead(&SrvCall->TransitionWaitList); 1877 InitializeListHead(&SrvCall->ScavengerFinalizationList); 1878 RxInitializePurgeSyncronizationContext(&SrvCall->PurgeSyncronizationContext); 1879 RxInitializeSrvCallParameters(RxContext, SrvCall); 1880 RtlMoveMemory(SrvCall->PrefixEntry.Prefix.Buffer, Name->Buffer, Name->Length); 1881 SrvCall->PrefixEntry.Prefix.MaximumLength = Name->Length + 2 * sizeof(WCHAR); 1882 SrvCall->PrefixEntry.Prefix.Length = Name->Length; 1883 RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &SrvCall->PrefixEntry, 1884 SrvCall, (PULONG)&SrvCall->NodeReferenceCount, Name->Length, RxConnectionId); 1885 1886 DPRINT("SrvCallName: %wZ (%p)\n", SrvCall->pSrvCallName, SrvCall); 1887 return SrvCall; 1888 } 1889 1890 /* 1891 * @implemented 1892 */ 1893 VOID 1894 NTAPI 1895 RxCreateSrvCallCallBack( 1896 IN OUT PMRX_SRVCALL_CALLBACK_CONTEXT Context) 1897 { 1898 KIRQL OldIrql; 1899 PSRV_CALL SrvCall; 1900 PRX_CONTEXT RxContext; 1901 ULONG NumberRemaining; 1902 BOOLEAN StartDispatcher; 1903 PMRX_SRVCALLDOWN_STRUCTURE Calldown; 1904 1905 DPRINT("RxCreateSrvCallCallBack(%p)\n", Context); 1906 1907 /* Get our context structures */ 1908 Calldown = Context->SrvCalldownStructure; 1909 SrvCall = (PSRV_CALL)Calldown->SrvCall; 1910 1911 /* If it is a success, that's the winner */ 1912 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql); 1913 if (Context->Status == STATUS_SUCCESS) 1914 { 1915 Calldown->BestFinisherOrdinal = Context->CallbackContextOrdinal; 1916 Calldown->BestFinisher = Context->RxDeviceObject; 1917 } 1918 NumberRemaining = --Calldown->NumberRemaining; 1919 SrvCall->Status = Context->Status; 1920 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql); 1921 1922 /* Still some to ask, keep going */ 1923 if (NumberRemaining != 0) 1924 { 1925 return; 1926 } 1927 1928 /* If that's not async, signal we're done */ 1929 RxContext = Calldown->RxContext; 1930 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION)) 1931 { 1932 KeSetEvent(&Calldown->FinishEvent, IO_NETWORK_INCREMENT, FALSE); 1933 return; 1934 } 1935 /* If that's a mailslot, finish construction, no more to do */ 1936 else if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CREATE_MAILSLOT)) 1937 { 1938 RxFinishSrvCallConstruction(Calldown); 1939 return; 1940 } 1941 1942 /* Queue our finish call for delayed completion */ 1943 DPRINT("Queuing RxFinishSrvCallConstruction() call\n"); 1944 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql); 1945 InsertTailList(&RxSrvCalldownList, &Calldown->SrvCalldownList); 1946 StartDispatcher = !RxSrvCallConstructionDispatcherActive; 1947 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql); 1948 1949 /* If we have to start dispatcher, go ahead */ 1950 if (StartDispatcher) 1951 { 1952 NTSTATUS Status; 1953 1954 Status = RxDispatchToWorkerThread(RxFileSystemDeviceObject, CriticalWorkQueue, 1955 RxFinishSrvCallConstructionDispatcher, &RxSrvCalldownList); 1956 if (!NT_SUCCESS(Status)) 1957 { 1958 /* It failed - run it manually.... */ 1959 RxFinishSrvCallConstructionDispatcher(NULL); 1960 } 1961 } 1962 } 1963 1964 /* 1965 * @implemented 1966 */ 1967 PSRV_OPEN 1968 RxCreateSrvOpen( 1969 IN PV_NET_ROOT VNetRoot, 1970 IN OUT PFCB Fcb) 1971 { 1972 ULONG Flags; 1973 PSRV_OPEN SrvOpen; 1974 POOL_TYPE PoolType; 1975 1976 PAGED_CODE(); 1977 1978 ASSERT(NodeTypeIsFcb(Fcb)); 1979 ASSERT(RxIsFcbAcquiredExclusive(Fcb)); 1980 1981 PoolType = (BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE) ? NonPagedPool : PagedPool); 1982 1983 _SEH2_TRY 1984 { 1985 SrvOpen = Fcb->InternalSrvOpen; 1986 /* Check whethet we have to allocate a new SRV_OPEN */ 1987 if (Fcb->InternalSrvOpen == NULL || BooleanFlagOn(Fcb->FcbState, FCB_STATE_SRVOPEN_USED) || 1988 BooleanFlagOn(Fcb->InternalSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED) || 1989 !IsListEmpty(&Fcb->InternalSrvOpen->SrvOpenQLinks)) 1990 { 1991 /* Proceed */ 1992 SrvOpen = RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject, 1993 RDBSS_NTC_SRVOPEN, PoolType, 0, NULL); 1994 Flags = 0; 1995 } 1996 else 1997 { 1998 /* Otherwise, just use internal one and initialize it */ 1999 RxAllocateFcbObject(Fcb->VNetRoot->NetRoot->pSrvCall->RxDeviceObject, 2000 RDBSS_NTC_INTERNAL_SRVOPEN, PoolType, 0, 2001 Fcb->InternalSrvOpen); 2002 Fcb->FcbState |= FCB_STATE_SRVOPEN_USED; 2003 Flags = SRVOPEN_FLAG_ENCLOSED_ALLOCATED | SRVOPEN_FLAG_FOBX_USED; 2004 } 2005 2006 /* If SrvOpen was properly allocated, initialize it */ 2007 if (SrvOpen != NULL) 2008 { 2009 SrvOpen->Flags = Flags; 2010 SrvOpen->pFcb = RX_GET_MRX_FCB(Fcb); 2011 SrvOpen->pAlreadyPrefixedName = &Fcb->PrivateAlreadyPrefixedName; 2012 SrvOpen->pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot; 2013 SrvOpen->ulFileSizeVersion = Fcb->ulFileSizeVersion; 2014 SrvOpen->NodeReferenceCount = 1; 2015 2016 RxReferenceVNetRoot(VNetRoot); 2017 RxReferenceNetFcb(Fcb); 2018 2019 InsertTailList(&Fcb->SrvOpenList, &SrvOpen->SrvOpenQLinks); 2020 ++Fcb->SrvOpenListVersion; 2021 2022 InitializeListHead(&SrvOpen->ScavengerFinalizationList); 2023 InitializeListHead(&SrvOpen->TransitionWaitList); 2024 InitializeListHead(&SrvOpen->FobxList); 2025 InitializeListHead(&SrvOpen->SrvOpenKeyList); 2026 } 2027 } 2028 _SEH2_FINALLY 2029 { 2030 if (_SEH2_AbnormalTermination()) 2031 { 2032 if (SrvOpen != NULL) 2033 { 2034 RxFinalizeSrvOpen(SrvOpen, TRUE, TRUE); 2035 SrvOpen = NULL; 2036 } 2037 } 2038 else 2039 { 2040 DPRINT("SrvOpen %p for FCB %p\n", SrvOpen, SrvOpen->pFcb); 2041 } 2042 } 2043 _SEH2_END; 2044 2045 return SrvOpen; 2046 } 2047 2048 /* 2049 * @implemented 2050 */ 2051 PV_NET_ROOT 2052 RxCreateVNetRoot( 2053 IN PRX_CONTEXT RxContext, 2054 IN PNET_ROOT NetRoot, 2055 IN PUNICODE_STRING CanonicalName, 2056 IN PUNICODE_STRING LocalNetRootName, 2057 IN PUNICODE_STRING FilePath, 2058 IN PRX_CONNECTION_ID RxConnectionId) 2059 { 2060 NTSTATUS Status; 2061 PV_NET_ROOT VNetRoot; 2062 USHORT CaseInsensitiveLength; 2063 2064 PAGED_CODE(); 2065 2066 DPRINT("RxCreateVNetRoot(%p, %p, %wZ, %wZ, %wZ, %p)\n", RxContext, NetRoot, CanonicalName, 2067 LocalNetRootName, FilePath, RxConnectionId); 2068 2069 /* Lock must be held exclusively */ 2070 ASSERT(RxIsPrefixTableLockExclusive(RxContext->RxDeviceObject->pRxNetNameTable)); 2071 2072 /* Check for overflow */ 2073 if (LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length > MAXUSHORT) 2074 { 2075 return NULL; 2076 } 2077 2078 /* Get name length and allocate VNetRoot */ 2079 CaseInsensitiveLength = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length; 2080 VNetRoot = RxAllocateObject(RDBSS_NTC_V_NETROOT, NetRoot->SrvCall->RxDeviceObject->Dispatch, 2081 CaseInsensitiveLength); 2082 if (VNetRoot == NULL) 2083 { 2084 return NULL; 2085 } 2086 2087 /* Initialize its connection parameters */ 2088 Status = RxInitializeVNetRootParameters(RxContext, &VNetRoot->LogonId, &VNetRoot->SessionId, 2089 &VNetRoot->pUserName, &VNetRoot->pUserDomainName, 2090 &VNetRoot->pPassword, &VNetRoot->Flags); 2091 if (!NT_SUCCESS(Status)) 2092 { 2093 RxUninitializeVNetRootParameters(VNetRoot->pUserName, VNetRoot->pUserDomainName, 2094 VNetRoot->pPassword, &VNetRoot->Flags); 2095 RxFreeObject(VNetRoot); 2096 2097 return NULL; 2098 } 2099 2100 /* Set name */ 2101 RtlMoveMemory(VNetRoot->PrefixEntry.Prefix.Buffer, CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length); 2102 2103 VNetRoot->PrefixOffsetInBytes = LocalNetRootName->Length + NetRoot->PrefixEntry.Prefix.Length; 2104 VNetRoot->NamePrefix.Buffer = Add2Ptr(VNetRoot->PrefixEntry.Prefix.Buffer, VNetRoot->PrefixOffsetInBytes); 2105 VNetRoot->NamePrefix.Length = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes; 2106 VNetRoot->NamePrefix.MaximumLength = VNetRoot->PrefixEntry.Prefix.Length - VNetRoot->PrefixOffsetInBytes; 2107 2108 InitializeListHead(&VNetRoot->TransitionWaitList); 2109 InitializeListHead(&VNetRoot->ScavengerFinalizationList); 2110 2111 if (!BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_FILENAMES)) 2112 { 2113 USHORT i; 2114 2115 if (BooleanFlagOn(NetRoot->SrvCall->Flags, SRVCALL_FLAG_CASE_INSENSITIVE_NETROOTS)) 2116 { 2117 CaseInsensitiveLength = NetRoot->PrefixEntry.CaseInsensitiveLength; 2118 } 2119 else 2120 { 2121 CaseInsensitiveLength = NetRoot->SrvCall->PrefixEntry.CaseInsensitiveLength; 2122 } 2123 2124 for (i = 1; i < CanonicalName->Length / sizeof(WCHAR); ++i) 2125 { 2126 if (CanonicalName->Buffer[i] != OBJ_NAME_PATH_SEPARATOR) 2127 { 2128 break; 2129 } 2130 } 2131 2132 CaseInsensitiveLength += (i * sizeof(WCHAR)); 2133 } 2134 2135 /* Insert in prefix table */ 2136 RxPrefixTableInsertName(RxContext->RxDeviceObject->pRxNetNameTable, &VNetRoot->PrefixEntry, 2137 VNetRoot, (PULONG)&VNetRoot->NodeReferenceCount, CaseInsensitiveLength, 2138 RxConnectionId); 2139 2140 RxReferenceNetRoot(NetRoot); 2141 RxAddVirtualNetRootToNetRoot(NetRoot, VNetRoot); 2142 2143 /* Finish init */ 2144 VNetRoot->SerialNumberForEnum = SerialNumber++; 2145 VNetRoot->UpperFinalizationDone = FALSE; 2146 VNetRoot->ConnectionFinalizationDone = FALSE; 2147 VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0; 2148 2149 DPRINT("NamePrefix: %wZ\n", &VNetRoot->NamePrefix); 2150 DPRINT("PrefixEntry: %wZ\n", &VNetRoot->PrefixEntry.Prefix); 2151 2152 return VNetRoot; 2153 } 2154 2155 /* 2156 * @implemented 2157 */ 2158 VOID 2159 RxDereference( 2160 IN OUT PVOID Instance, 2161 IN LOCK_HOLDING_STATE LockHoldingState) 2162 { 2163 LONG RefCount; 2164 NODE_TYPE_CODE NodeType; 2165 PNODE_TYPE_AND_SIZE Node; 2166 2167 PAGED_CODE(); 2168 2169 RxAcquireScavengerMutex(); 2170 2171 /* Check we have a node we can handle */ 2172 NodeType = NodeType(Instance); 2173 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) || 2174 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) || 2175 (NodeType == RDBSS_NTC_FOBX)); 2176 2177 Node = (PNODE_TYPE_AND_SIZE)Instance; 2178 RefCount = InterlockedDecrement((volatile long *)&Node->NodeReferenceCount); 2179 ASSERT(RefCount >= 0); 2180 2181 /* Trace refcount */ 2182 switch (NodeType) 2183 { 2184 case RDBSS_NTC_SRVCALL: 2185 PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount); 2186 break; 2187 2188 case RDBSS_NTC_NETROOT: 2189 PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount); 2190 break; 2191 2192 case RDBSS_NTC_V_NETROOT: 2193 PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount); 2194 break; 2195 2196 case RDBSS_NTC_SRVOPEN: 2197 PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount); 2198 break; 2199 2200 case RDBSS_NTC_FOBX: 2201 PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount); 2202 break; 2203 2204 default: 2205 ASSERT(FALSE); 2206 break; 2207 } 2208 2209 /* No need to free - still in use */ 2210 if (RefCount > 1) 2211 { 2212 RxReleaseScavengerMutex(); 2213 return; 2214 } 2215 2216 /* We have to be locked exclusively */ 2217 if (LockHoldingState != LHS_ExclusiveLockHeld) 2218 { 2219 if ((NodeType == RDBSS_NTC_FOBX && RefCount == 0) || 2220 (NodeType >= RDBSS_NTC_SRVCALL && NodeType <= RDBSS_NTC_V_NETROOT)) 2221 { 2222 RxpMarkInstanceForScavengedFinalization(Instance); 2223 } 2224 2225 RxReleaseScavengerMutex(); 2226 return; 2227 } 2228 else 2229 { 2230 if (BooleanFlagOn(NodeType, RX_SCAVENGER_MASK)) 2231 { 2232 RxpUndoScavengerFinalizationMarking(Instance); 2233 } 2234 } 2235 2236 RxReleaseScavengerMutex(); 2237 2238 /* Now, deallocate the memory */ 2239 switch (NodeType) 2240 { 2241 case RDBSS_NTC_SRVCALL: 2242 { 2243 PSRV_CALL SrvCall; 2244 2245 SrvCall = (PSRV_CALL)Instance; 2246 2247 ASSERT(SrvCall->RxDeviceObject != NULL); 2248 ASSERT(RxIsPrefixTableLockAcquired(SrvCall->RxDeviceObject->pRxNetNameTable)); 2249 RxFinalizeSrvCall(SrvCall, TRUE, TRUE); 2250 break; 2251 } 2252 2253 case RDBSS_NTC_NETROOT: 2254 { 2255 PNET_ROOT NetRoot; 2256 2257 NetRoot = (PNET_ROOT)Instance; 2258 2259 ASSERT(NetRoot->pSrvCall->RxDeviceObject != NULL); 2260 ASSERT(RxIsPrefixTableLockAcquired(NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable)); 2261 RxFinalizeNetRoot(NetRoot, TRUE, TRUE); 2262 break; 2263 } 2264 2265 case RDBSS_NTC_V_NETROOT: 2266 { 2267 PV_NET_ROOT VNetRoot; 2268 2269 VNetRoot = (PV_NET_ROOT)Instance; 2270 2271 ASSERT(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject != NULL); 2272 ASSERT(RxIsPrefixTableLockAcquired(VNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable)); 2273 RxFinalizeVNetRoot(VNetRoot, TRUE, TRUE); 2274 break; 2275 } 2276 2277 case RDBSS_NTC_SRVOPEN: 2278 { 2279 PSRV_OPEN SrvOpen; 2280 2281 SrvOpen = (PSRV_OPEN)Instance; 2282 2283 ASSERT(RxIsFcbAcquired(SrvOpen->Fcb)); 2284 if (SrvOpen->OpenCount == 0) 2285 { 2286 RxFinalizeSrvOpen(SrvOpen, FALSE, FALSE); 2287 } 2288 break; 2289 } 2290 2291 case RDBSS_NTC_FOBX: 2292 { 2293 PFOBX Fobx; 2294 2295 Fobx = (PFOBX)Instance; 2296 2297 ASSERT(RxIsFcbAcquired(Fobx->SrvOpen->Fcb)); 2298 RxFinalizeNetFobx(Fobx, TRUE, FALSE); 2299 break; 2300 } 2301 } 2302 } 2303 2304 /* 2305 * @implemented 2306 */ 2307 VOID 2308 NTAPI 2309 RxDereferenceAndDeleteRxContext_Real( 2310 IN PRX_CONTEXT RxContext) 2311 { 2312 KIRQL OldIrql; 2313 ULONG RefCount; 2314 BOOLEAN Allocated; 2315 PRX_CONTEXT StopContext = NULL; 2316 2317 /* Make sure we really have a context */ 2318 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql); 2319 ASSERT(RxContext->NodeTypeCode == RDBSS_NTC_RX_CONTEXT); 2320 RefCount = InterlockedDecrement((volatile LONG *)&RxContext->ReferenceCount); 2321 /* If refcount is 0, start releasing stuff that needs spinlock held */ 2322 if (RefCount == 0) 2323 { 2324 PRDBSS_DEVICE_OBJECT RxDeviceObject; 2325 2326 Allocated = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_FROM_POOL); 2327 2328 /* If that's stop context from DO, remove it */ 2329 RxDeviceObject = RxContext->RxDeviceObject; 2330 if (RxDeviceObject->StartStopContext.pStopContext == RxContext) 2331 { 2332 RxDeviceObject->StartStopContext.pStopContext = NULL; 2333 } 2334 else 2335 { 2336 /* Remove it from the list */ 2337 ASSERT((RxContext->ContextListEntry.Flink->Blink == &RxContext->ContextListEntry) && 2338 (RxContext->ContextListEntry.Blink->Flink == &RxContext->ContextListEntry)); 2339 RemoveEntryList(&RxContext->ContextListEntry); 2340 2341 /* If that was the last active context, save the stop context */ 2342 if (InterlockedExchangeAdd((volatile LONG *)&RxDeviceObject->NumberOfActiveContexts, -1) == 0) 2343 { 2344 if (RxDeviceObject->StartStopContext.pStopContext != NULL) 2345 { 2346 StopContext = RxDeviceObject->StartStopContext.pStopContext; 2347 } 2348 } 2349 } 2350 } 2351 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql); 2352 2353 /* Now, deal with what can be done without spinlock held */ 2354 if (RefCount == 0) 2355 { 2356 /* Refcount shouldn't have changed */ 2357 ASSERT(RxContext->ReferenceCount == 0); 2358 /* Reset everything that can be */ 2359 RxPrepareContextForReuse(RxContext); 2360 2361 #ifdef RDBSS_TRACKER 2362 ASSERT(RxContext->AcquireReleaseFcbTrackerX == 0); 2363 #endif 2364 /* If that was the last active, set the event */ 2365 if (StopContext != NULL) 2366 { 2367 StopContext->Flags &= ~RX_CONTEXT_FLAG_RECURSIVE_CALL; 2368 KeSetEvent(&StopContext->SyncEvent, IO_NO_INCREMENT, FALSE); 2369 } 2370 2371 #if DBG 2372 /* Is ShadowCrit still owned? Shouldn't happen! */ 2373 if (RxContext->ShadowCritOwner != 0) 2374 { 2375 DPRINT1("ShadowCritOwner not null! %lx\n", RxContext->ShadowCritOwner); 2376 ASSERT(FALSE); 2377 } 2378 #endif 2379 2380 /* If it was allocated, free it */ 2381 if (Allocated) 2382 { 2383 ExFreeToNPagedLookasideList(&RxContextLookasideList, RxContext); 2384 } 2385 } 2386 } 2387 2388 VOID 2389 NTAPI 2390 RxDispatchChangeBufferingStateRequests( 2391 PVOID Context) 2392 { 2393 UNIMPLEMENTED; 2394 } 2395 2396 /* 2397 * @implemented 2398 */ 2399 NTSTATUS 2400 NTAPI 2401 RxDispatchToWorkerThread( 2402 IN PRDBSS_DEVICE_OBJECT pMRxDeviceObject, 2403 IN WORK_QUEUE_TYPE WorkQueueType, 2404 IN PRX_WORKERTHREAD_ROUTINE Routine, 2405 IN PVOID pContext) 2406 { 2407 NTSTATUS Status; 2408 PRX_WORK_DISPATCH_ITEM DispatchItem; 2409 2410 /* Allocate a bit of context */ 2411 DispatchItem = RxAllocatePoolWithTag(PagedPool, sizeof(RX_WORK_DISPATCH_ITEM), RX_WORKQ_POOLTAG); 2412 if (DispatchItem == NULL) 2413 { 2414 return STATUS_INSUFFICIENT_RESOURCES; 2415 } 2416 2417 /* Set all the routines, the one our dispatcher will call, the one ntoskrnl will call */ 2418 DispatchItem->DispatchRoutine = Routine; 2419 DispatchItem->DispatchRoutineParameter = pContext; 2420 DispatchItem->WorkQueueItem.WorkerRoutine = RxWorkItemDispatcher; 2421 DispatchItem->WorkQueueItem.Parameter = DispatchItem; 2422 2423 /* Insert item */ 2424 Status = RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, &DispatchItem->WorkQueueItem); 2425 if (!NT_SUCCESS(Status)) 2426 { 2427 RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG); 2428 DPRINT1("RxInsertWorkQueueItem failed! Queue: %ld, Routine: %p, Context: %p, Status: %lx\n", WorkQueueType, Routine, pContext, Status); 2429 } 2430 2431 DPRINT("Dispatching: %p, %p\n", Routine, pContext); 2432 2433 return Status; 2434 } 2435 2436 /* 2437 * @implemented 2438 */ 2439 VOID 2440 RxExclusivePrefixTableLockToShared( 2441 PRX_PREFIX_TABLE Table) 2442 { 2443 PAGED_CODE(); 2444 2445 ExConvertExclusiveToSharedLite(&Table->TableLock); 2446 } 2447 2448 /* 2449 * @implemented 2450 */ 2451 VOID 2452 RxExtractServerName( 2453 IN PUNICODE_STRING FilePathName, 2454 OUT PUNICODE_STRING SrvCallName, 2455 OUT PUNICODE_STRING RestOfName) 2456 { 2457 USHORT i, Length; 2458 2459 PAGED_CODE(); 2460 2461 ASSERT(SrvCallName != NULL); 2462 2463 /* SrvCall name will start from the begin up to the first separator */ 2464 SrvCallName->Buffer = FilePathName->Buffer; 2465 for (i = 1; i < FilePathName->Length / sizeof(WCHAR); ++i) 2466 { 2467 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR) 2468 { 2469 break; 2470 } 2471 } 2472 2473 /* Compute length */ 2474 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[i] - (ULONG_PTR)FilePathName->Buffer); 2475 SrvCallName->MaximumLength = Length; 2476 SrvCallName->Length = Length; 2477 2478 /* Return the rest if asked */ 2479 if (RestOfName != NULL) 2480 { 2481 Length = (USHORT)((ULONG_PTR)&FilePathName->Buffer[FilePathName->Length / sizeof(WCHAR)] - (ULONG_PTR)FilePathName->Buffer[i]); 2482 RestOfName->Buffer = &FilePathName->Buffer[i]; 2483 RestOfName->MaximumLength = Length; 2484 RestOfName->Length = Length; 2485 } 2486 } 2487 2488 /* 2489 * @implemented 2490 */ 2491 NTSTATUS 2492 RxFcbTableInsertFcb( 2493 IN OUT PRX_FCB_TABLE FcbTable, 2494 IN OUT PFCB Fcb) 2495 { 2496 PAGED_CODE(); 2497 2498 /* We deal with the table, make sure it's locked */ 2499 ASSERT(RxIsFcbTableLockExclusive(FcbTable)); 2500 2501 /* Compute the hash */ 2502 Fcb->FcbTableEntry.HashValue = RxTableComputePathHashValue(&Fcb->FcbTableEntry.Path); 2503 2504 RxReferenceNetFcb(Fcb); 2505 2506 /* If no length, it will be our null entry */ 2507 if (Fcb->FcbTableEntry.Path.Length == 0) 2508 { 2509 FcbTable->TableEntryForNull = &Fcb->FcbTableEntry; 2510 } 2511 /* Otherwise, insert in the appropriate bucket */ 2512 else 2513 { 2514 InsertTailList(FCB_HASH_BUCKET(FcbTable, Fcb->FcbTableEntry.HashValue), 2515 &Fcb->FcbTableEntry.HashLinks); 2516 } 2517 2518 /* Propagate the change by incrementing the version number */ 2519 InterlockedIncrement((volatile long *)&FcbTable->Version); 2520 2521 return STATUS_SUCCESS; 2522 } 2523 2524 /* 2525 * @implemented 2526 */ 2527 PFCB 2528 RxFcbTableLookupFcb( 2529 IN PRX_FCB_TABLE FcbTable, 2530 IN PUNICODE_STRING Path) 2531 { 2532 PFCB Fcb; 2533 PRX_FCB_TABLE_ENTRY TableEntry; 2534 2535 PAGED_CODE(); 2536 2537 /* No path - easy, that's null entry */ 2538 if (Path == NULL) 2539 { 2540 TableEntry = FcbTable->TableEntryForNull; 2541 } 2542 else 2543 { 2544 ULONG Hash; 2545 PLIST_ENTRY HashBucket, ListEntry; 2546 2547 /* Otherwise, compute the hash value and find the associated bucket */ 2548 Hash = RxTableComputePathHashValue(Path); 2549 HashBucket = FCB_HASH_BUCKET(FcbTable, Hash); 2550 /* If the bucket is empty, it means there's no entry yet */ 2551 if (IsListEmpty(HashBucket)) 2552 { 2553 TableEntry = NULL; 2554 } 2555 else 2556 { 2557 /* Otherwise, browse all the entry */ 2558 for (ListEntry = HashBucket->Flink; 2559 ListEntry != HashBucket; 2560 ListEntry = ListEntry->Flink) 2561 { 2562 TableEntry = CONTAINING_RECORD(ListEntry, RX_FCB_TABLE_ENTRY, HashLinks); 2563 InterlockedIncrement(&FcbTable->Compares); 2564 2565 /* If entry hash and string are equal, thatt's the one! */ 2566 if (TableEntry->HashValue == Hash && 2567 TableEntry->Path.Length == Path->Length && 2568 RtlEqualUnicodeString(Path, &TableEntry->Path, FcbTable->CaseInsensitiveMatch)) 2569 { 2570 break; 2571 } 2572 } 2573 2574 /* We reached the end? Not found */ 2575 if (ListEntry == HashBucket) 2576 { 2577 TableEntry = NULL; 2578 } 2579 } 2580 } 2581 2582 InterlockedIncrement(&FcbTable->Lookups); 2583 2584 /* If table entry isn't null, return the FCB */ 2585 if (TableEntry != NULL) 2586 { 2587 Fcb = CONTAINING_RECORD(TableEntry, FCB, FcbTableEntry); 2588 RxReferenceNetFcb(Fcb); 2589 } 2590 else 2591 { 2592 Fcb = NULL; 2593 InterlockedIncrement(&FcbTable->FailedLookups); 2594 } 2595 2596 return Fcb; 2597 } 2598 2599 /* 2600 * @implemented 2601 */ 2602 NTSTATUS 2603 RxFcbTableRemoveFcb( 2604 IN OUT PRX_FCB_TABLE FcbTable, 2605 IN OUT PFCB Fcb) 2606 { 2607 PAGED_CODE(); 2608 2609 ASSERT(RxIsPrefixTableLockExclusive(FcbTable)); 2610 2611 /* If no path, then remove entry for null */ 2612 if (Fcb->FcbTableEntry.Path.Length == 0) 2613 { 2614 FcbTable->TableEntryForNull = NULL; 2615 } 2616 /* Otherwise, remove from the bucket */ 2617 else 2618 { 2619 RemoveEntryList(&Fcb->FcbTableEntry.HashLinks); 2620 } 2621 2622 /* Reset its list entry */ 2623 InitializeListHead(&Fcb->FcbTableEntry.HashLinks); 2624 2625 /* Propagate the change by incrementing the version number */ 2626 InterlockedIncrement((volatile long *)&FcbTable->Version); 2627 2628 return STATUS_SUCCESS; 2629 } 2630 2631 /* 2632 * @implemented 2633 */ 2634 NTSTATUS 2635 NTAPI 2636 RxFinalizeConnection( 2637 IN OUT PNET_ROOT NetRoot, 2638 IN OUT PV_NET_ROOT VNetRoot OPTIONAL, 2639 IN LOGICAL ForceFilesClosed) 2640 { 2641 NTSTATUS Status; 2642 PRX_PREFIX_TABLE PrefixTable; 2643 ULONG UncleanAny, UncleanDir; 2644 LONG FilesOpen, AdditionalRef; 2645 BOOLEAN PrefixLocked, FcbTableLocked, ForceClose; 2646 2647 PAGED_CODE(); 2648 2649 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT); 2650 2651 /* Get a BOOLEAN out of LOGICAL 2652 * -1 is like FALSE but also drops extra V_NET_ROOT reference in case of failure 2653 */ 2654 ForceClose = (ForceFilesClosed == TRUE ? TRUE : FALSE); 2655 2656 /* First, delete any notification change */ 2657 Status = RxCancelNotifyChangeDirectoryRequestsForVNetRoot(VNetRoot, ForceClose); 2658 /* If it failed, continue if forced */ 2659 if (Status != STATUS_SUCCESS && !ForceFilesClosed) 2660 { 2661 return Status; 2662 } 2663 /* Reset status, in case notification deletion failed */ 2664 Status = STATUS_SUCCESS; 2665 2666 PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable; 2667 2668 PrefixLocked = FALSE; 2669 FcbTableLocked = FALSE; 2670 FilesOpen = 0; 2671 AdditionalRef = 0; 2672 UncleanAny = 0; 2673 UncleanDir = 0; 2674 _SEH2_TRY 2675 { 2676 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE); 2677 PrefixLocked = TRUE; 2678 2679 RxReferenceNetRoot(NetRoot); 2680 2681 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE); 2682 FcbTableLocked = TRUE; 2683 2684 /* If our V_NET_ROOT wasn't finalized yet, proceed! */ 2685 if (!VNetRoot->ConnectionFinalizationDone) 2686 { 2687 USHORT Bucket; 2688 PRX_FCB_TABLE FcbTable; 2689 2690 DPRINT("Finalizing connection %p: %wZ\n", NetRoot, &NetRoot->PrefixEntry.Prefix); 2691 2692 /* We'll browse all its associated FCB to check whether they're open/orphaned */ 2693 FcbTable = &NetRoot->FcbTable; 2694 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket) 2695 { 2696 PLIST_ENTRY BucketList, Entry; 2697 2698 BucketList = &FcbTable->HashBuckets[Bucket]; 2699 Entry = BucketList->Flink; 2700 while (Entry != BucketList) 2701 { 2702 PFCB Fcb; 2703 2704 Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks); 2705 Entry = Entry->Flink; 2706 2707 /* FCB for this connection, go ahead */ 2708 if (Fcb->VNetRoot == VNetRoot) 2709 { 2710 /* It's still open, and no force? Fail and keep track */ 2711 if (Fcb->UncleanCount > 0 && !ForceClose) 2712 { 2713 Status = STATUS_CONNECTION_IN_USE; 2714 if (NodeType(Fcb) == RDBSS_NTC_STORAGE_TYPE_DIRECTORY) 2715 { 2716 ++UncleanDir; 2717 } 2718 else 2719 { 2720 ++UncleanAny; 2721 } 2722 } 2723 else 2724 { 2725 /* Else, force purge */ 2726 ASSERT(NodeTypeIsFcb(Fcb)); 2727 2728 Status = RxAcquireExclusiveFcb(NULL, Fcb); 2729 ASSERT(Status == STATUS_SUCCESS); 2730 2731 ClearFlag(Fcb->FcbState, FCB_STATE_COLLAPSING_ENABLED); 2732 2733 RxScavengeRelatedFobxs(Fcb); 2734 RxPurgeFcb(Fcb); 2735 2736 /* We don't need to release FCB lock, FCB finalize will take care of it */ 2737 } 2738 } 2739 } 2740 } 2741 2742 /* No files left, our V_NET_ROOT is finalized */ 2743 if (VNetRoot->NumberOfFobxs == 0) 2744 { 2745 VNetRoot->ConnectionFinalizationDone = TRUE; 2746 } 2747 } 2748 2749 /* Keep Number of open files and track of the extra reference */ 2750 FilesOpen = VNetRoot->NumberOfFobxs; 2751 AdditionalRef = VNetRoot->AdditionalReferenceForDeleteFsctlTaken; 2752 /* If force close, caller doesn't want to keep connection alive 2753 * and wants it totally close, so drop the V_NET_ROOT too 2754 */ 2755 if (ForceClose) 2756 { 2757 RxFinalizeVNetRoot(VNetRoot, FALSE, TRUE); 2758 } 2759 } 2760 _SEH2_FINALLY 2761 { 2762 /* Release what was acquired */ 2763 if (FcbTableLocked) 2764 { 2765 RxReleaseFcbTableLock(&NetRoot->FcbTable); 2766 } 2767 2768 /* If close is forced, only fix status if there are open files */ 2769 if (ForceClose) 2770 { 2771 if (Status != STATUS_SUCCESS && UncleanAny != 0) 2772 { 2773 Status = STATUS_FILES_OPEN; 2774 } 2775 } 2776 /* Else, fix status and fail closing if there are open files */ 2777 else 2778 { 2779 if ((Status != STATUS_SUCCESS && UncleanAny != 0) || FilesOpen > 0) 2780 { 2781 Status = STATUS_FILES_OPEN; 2782 } 2783 } 2784 2785 DPRINT("UncleanAny: %ld, UncleanDir: %ld, FilesOpen: %ld\n", UncleanAny, UncleanDir, FilesOpen); 2786 2787 /* If we're are asked to remove the extra ref, or if closing was a success, do it; 2788 * only if it was still referenced! 2789 */ 2790 if ((ForceFilesClosed == 0xFF || Status == STATUS_SUCCESS) && AdditionalRef != 0) 2791 { 2792 VNetRoot->AdditionalReferenceForDeleteFsctlTaken = 0; 2793 RxDereferenceVNetRoot(VNetRoot, LHS_ExclusiveLockHeld); 2794 } 2795 2796 if (PrefixLocked) 2797 { 2798 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld); 2799 RxReleasePrefixTableLock(PrefixTable); 2800 } 2801 } 2802 _SEH2_END; 2803 2804 return Status; 2805 } 2806 2807 /* 2808 * @implemented 2809 */ 2810 VOID 2811 RxFinalizeFcbTable( 2812 IN OUT PRX_FCB_TABLE FcbTable) 2813 { 2814 USHORT Bucket; 2815 2816 PAGED_CODE(); 2817 2818 /* Just delete the lock */ 2819 ExDeleteResourceLite(&FcbTable->TableLock); 2820 2821 /* And make sure (checked) that the table is really empty... */ 2822 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket) 2823 { 2824 ASSERT(IsListEmpty(&FcbTable->HashBuckets[Bucket])); 2825 } 2826 } 2827 2828 /* 2829 * @implemented 2830 */ 2831 BOOLEAN 2832 RxFinalizeNetFcb( 2833 OUT PFCB ThisFcb, 2834 IN BOOLEAN RecursiveFinalize, 2835 IN BOOLEAN ForceFinalize, 2836 IN LONG ReferenceCount) 2837 { 2838 PAGED_CODE(); 2839 2840 DPRINT("RxFinalizeNetFcb(%p, %d, %d, %d)\n", ThisFcb, RecursiveFinalize, ForceFinalize, ReferenceCount); 2841 DPRINT("Finalize: %wZ\n", &ThisFcb->FcbTableEntry.Path); 2842 2843 /* Make sure we have an exclusively acquired FCB */ 2844 ASSERT_CORRECT_FCB_STRUCTURE(ThisFcb); 2845 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb)); 2846 2847 /* We shouldn't force finalization... */ 2848 ASSERT(!ForceFinalize); 2849 2850 /* If recurisve, finalize all the associated SRV_OPEN */ 2851 if (RecursiveFinalize) 2852 { 2853 PLIST_ENTRY ListEntry; 2854 2855 for (ListEntry = ThisFcb->SrvOpenList.Flink; 2856 ListEntry != &ThisFcb->SrvOpenList; 2857 ListEntry = ListEntry->Flink) 2858 { 2859 PSRV_OPEN SrvOpen; 2860 2861 SrvOpen = CONTAINING_RECORD(ListEntry, SRV_OPEN, SrvOpenQLinks); 2862 RxFinalizeSrvOpen(SrvOpen, TRUE, ForceFinalize); 2863 } 2864 } 2865 /* If FCB is still in use, that's over */ 2866 else 2867 { 2868 if (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0) 2869 { 2870 ASSERT(ReferenceCount > 0); 2871 2872 return FALSE; 2873 } 2874 } 2875 2876 ASSERT(ReferenceCount >= 1); 2877 2878 /* If FCB is still referenced, that's over - unless you force it and want to BSOD somewhere */ 2879 if (ReferenceCount != 1 && !ForceFinalize) 2880 { 2881 return FALSE; 2882 } 2883 2884 ASSERT(ForceFinalize || ((ThisFcb->OpenCount == 0) && (ThisFcb->UncleanCount == 0))); 2885 2886 DPRINT("Finalizing FCB open: %d (%d)\n", ThisFcb->OpenCount, ForceFinalize); 2887 2888 /* If finalization was not already initiated, go ahead */ 2889 if (!ThisFcb->UpperFinalizationDone) 2890 { 2891 /* Free any FCB_LOCK */ 2892 if (NodeType(ThisFcb) == RDBSS_NTC_STORAGE_TYPE_FILE) 2893 { 2894 FsRtlUninitializeFileLock(&ThisFcb->Specific.Fcb.FileLock); 2895 2896 while (ThisFcb->BufferedLocks.List != NULL) 2897 { 2898 PFCB_LOCK Entry; 2899 2900 Entry = ThisFcb->BufferedLocks.List; 2901 ThisFcb->BufferedLocks.List = Entry->Next; 2902 2903 RxFreePool(Entry); 2904 } 2905 } 2906 2907 /* If not orphaned, it still has a NET_ROOT and potentially is still in a table */ 2908 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED)) 2909 { 2910 PNET_ROOT NetRoot; 2911 2912 NetRoot = (PNET_ROOT)ThisFcb->pNetRoot; 2913 2914 ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable)); 2915 /* So, remove it */ 2916 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED)) 2917 { 2918 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb); 2919 } 2920 } 2921 2922 ThisFcb->UpperFinalizationDone = TRUE; 2923 } 2924 2925 ASSERT(ReferenceCount >= 1); 2926 2927 /* Even if forced, don't allow broken free */ 2928 if (ReferenceCount != 1) 2929 { 2930 return FALSE; 2931 } 2932 2933 /* Now, release everything */ 2934 if (ThisFcb->pBufferingStateChangeCompletedEvent != NULL) 2935 { 2936 RxFreePool(ThisFcb->pBufferingStateChangeCompletedEvent); 2937 } 2938 2939 if (ThisFcb->MRxDispatch != NULL) 2940 { 2941 ThisFcb->MRxDispatch->MRxDeallocateForFcb(RX_GET_MRX_FCB(ThisFcb)); 2942 } 2943 2944 ExDeleteResourceLite(ThisFcb->BufferedLocks.Resource); 2945 ExDeleteResourceLite(ThisFcb->Header.Resource); 2946 ExDeleteResourceLite(ThisFcb->Header.PagingIoResource); 2947 2948 InterlockedDecrement((volatile long *)&ThisFcb->pNetRoot->NumberOfFcbs); 2949 RxDereferenceVNetRoot(ThisFcb->VNetRoot, LHS_LockNotHeld); 2950 2951 ASSERT(IsListEmpty(&ThisFcb->FcbTableEntry.HashLinks)); 2952 ASSERT(!ThisFcb->fMiniInited); 2953 2954 /* And free the object */ 2955 RxFreeFcbObject(ThisFcb); 2956 2957 return TRUE; 2958 } 2959 2960 /* 2961 * @implemented 2962 */ 2963 BOOLEAN 2964 RxFinalizeNetFobx( 2965 _Out_ PFOBX ThisFobx, 2966 _In_ BOOLEAN RecursiveFinalize, 2967 _In_ BOOLEAN ForceFinalize) 2968 { 2969 PFCB Fcb; 2970 PSRV_OPEN SrvOpen; 2971 2972 PAGED_CODE(); 2973 2974 ASSERT(NodeType(ThisFobx) == RDBSS_NTC_FOBX); 2975 2976 /* Only finalize if forced or if there's no ref left */ 2977 if (ThisFobx->NodeReferenceCount != 0 && 2978 !ForceFinalize) 2979 { 2980 return FALSE; 2981 } 2982 2983 DPRINT("Finalize Fobx: %p (with %d ref), forced: %d\n", ThisFobx, ThisFobx->NodeReferenceCount, ForceFinalize); 2984 2985 SrvOpen = ThisFobx->SrvOpen; 2986 Fcb = SrvOpen->Fcb; 2987 /* If it wasn't finalized yet, do it */ 2988 if (!ThisFobx->UpperFinalizationDone) 2989 { 2990 ASSERT(NodeType(SrvOpen->Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB); 2991 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb)); 2992 2993 /* Remove it from the SRV_OPEN */ 2994 RemoveEntryList(&ThisFobx->FobxQLinks); 2995 2996 /* If we were used to browse a directory, free the query buffer */ 2997 if (BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_FREE_UNICODE)) 2998 { 2999 RxFreePoolWithTag(ThisFobx->UnicodeQueryTemplate.Buffer, RX_DIRCTL_POOLTAG); 3000 } 3001 3002 /* Notify the mini-rdr */ 3003 if (Fcb->MRxDispatch != NULL && Fcb->MRxDispatch->MRxDeallocateForFobx != NULL) 3004 { 3005 Fcb->MRxDispatch->MRxDeallocateForFobx((PMRX_FOBX)ThisFobx); 3006 } 3007 3008 /* If the SRV_OPEN wasn't closed yet, do it */ 3009 if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_SRVOPEN_CLOSED)) 3010 { 3011 NTSTATUS Status; 3012 3013 Status = RxCloseAssociatedSrvOpen(ThisFobx, FALSE); 3014 DPRINT("Closing SRV_OPEN %p for %p: %x\n", SrvOpen, ThisFobx, Status); 3015 } 3016 3017 /* Finalization done */ 3018 ThisFobx->UpperFinalizationDone = TRUE; 3019 } 3020 3021 /* If we're still referenced, don't go any further! */ 3022 if (ThisFobx->NodeReferenceCount != 0) 3023 { 3024 return FALSE; 3025 } 3026 3027 /* At that point, everything should be closed */ 3028 ASSERT(IsListEmpty(&ThisFobx->ClosePendingList)); 3029 3030 /* Was the FOBX allocated with another object? 3031 * If so, mark the buffer free in said object 3032 */ 3033 if (ThisFobx == Fcb->InternalFobx) 3034 { 3035 ClearFlag(Fcb->FcbState, FCB_STATE_FOBX_USED); 3036 } 3037 else if (ThisFobx == SrvOpen->InternalFobx) 3038 { 3039 ClearFlag(SrvOpen->Flags, SRVOPEN_FLAG_FOBX_USED); 3040 } 3041 3042 ThisFobx->pSrvOpen = NULL; 3043 3044 /* A FOBX less */ 3045 InterlockedDecrement((volatile long *)&SrvOpen->pVNetRoot->NumberOfFobxs); 3046 3047 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld); 3048 3049 /* If it wasn't allocated with another object, free the FOBX */ 3050 if (!BooleanFlagOn(ThisFobx->Flags, FOBX_FLAG_ENCLOSED_ALLOCATED)) 3051 { 3052 RxFreeFcbObject(ThisFobx); 3053 } 3054 3055 return TRUE; 3056 } 3057 3058 /* 3059 * @implemented 3060 */ 3061 BOOLEAN 3062 RxFinalizeNetRoot( 3063 OUT PNET_ROOT ThisNetRoot, 3064 IN BOOLEAN RecursiveFinalize, 3065 IN BOOLEAN ForceFinalize) 3066 { 3067 PSRV_CALL SrvCall; 3068 PRX_FCB_TABLE FcbTable; 3069 PRX_PREFIX_TABLE PrefixTable; 3070 3071 PAGED_CODE(); 3072 3073 ASSERT(NodeType(ThisNetRoot) == RDBSS_NTC_NETROOT); 3074 3075 PrefixTable = ThisNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable; 3076 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable)); 3077 3078 /* If sme finalization is already ongoing, leave */ 3079 if (BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS)) 3080 { 3081 return FALSE; 3082 } 3083 3084 /* Mark we're finalizing */ 3085 SetFlag(ThisNetRoot->Flags, NETROOT_FLAG_FINALIZATION_IN_PROGRESS); 3086 3087 FcbTable = &ThisNetRoot->FcbTable; 3088 /* Did caller asked us to finalize any associated FCB? */ 3089 if (RecursiveFinalize) 3090 { 3091 USHORT Bucket; 3092 3093 /* Browse all the FCBs in our FCB table */ 3094 RxAcquireFcbTableLockExclusive(FcbTable, TRUE); 3095 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket) 3096 { 3097 PLIST_ENTRY HashBucket, ListEntry; 3098 3099 HashBucket = &FcbTable->HashBuckets[Bucket]; 3100 ListEntry = HashBucket->Flink; 3101 while (ListEntry != HashBucket) 3102 { 3103 PFCB Fcb; 3104 3105 Fcb = CONTAINING_RECORD(ListEntry, FCB, FcbTableEntry.HashLinks); 3106 ASSERT(NodeTypeIsFcb(Fcb)); 3107 3108 ListEntry = ListEntry->Flink; 3109 3110 /* If the FCB isn't orphaned, then, it's time to purge it */ 3111 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED)) 3112 { 3113 NTSTATUS Status; 3114 3115 Status = RxAcquireExclusiveFcb(NULL, Fcb); 3116 ASSERT(Status == STATUS_SUCCESS); 3117 RxPurgeFcb(Fcb); 3118 } 3119 } 3120 } 3121 RxReleaseFcbTableLock(FcbTable); 3122 } 3123 3124 /* Only finalize if forced or if there's a single ref left */ 3125 if (ThisNetRoot->NodeReferenceCount != 1 && !ForceFinalize) 3126 { 3127 return FALSE; 3128 } 3129 3130 DPRINT("Finalizing NetRoot %p for %wZ\n", ThisNetRoot, &ThisNetRoot->PrefixEntry.Prefix); 3131 3132 /* If we're still referenced, don't go any further! */ 3133 if (ThisNetRoot->NodeReferenceCount != 1) 3134 { 3135 return FALSE; 3136 } 3137 3138 /* Finalize the FCB table (and make sure it's empty!) */ 3139 RxFinalizeFcbTable(FcbTable); 3140 3141 /* If name wasn't remove already, do it now */ 3142 if (!BooleanFlagOn(ThisNetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED)) 3143 { 3144 RxRemovePrefixTableEntry(PrefixTable, &ThisNetRoot->PrefixEntry); 3145 } 3146 3147 /* Delete the object */ 3148 SrvCall = (PSRV_CALL)ThisNetRoot->pSrvCall; 3149 RxFreeObject(ThisNetRoot); 3150 3151 /* And dereference the associated SRV_CALL */ 3152 if (SrvCall != NULL) 3153 { 3154 RxDereferenceSrvCall(SrvCall, LHS_ExclusiveLockHeld); 3155 } 3156 3157 return TRUE; 3158 } 3159 3160 /* 3161 * @implemented 3162 */ 3163 BOOLEAN 3164 RxFinalizeSrvCall( 3165 OUT PSRV_CALL ThisSrvCall, 3166 IN BOOLEAN RecursiveFinalize, 3167 IN BOOLEAN ForceFinalize) 3168 { 3169 PRX_PREFIX_TABLE PrefixTable; 3170 3171 PAGED_CODE(); 3172 3173 ASSERT(NodeType(ThisSrvCall) == RDBSS_NTC_SRVCALL); 3174 3175 PrefixTable = ThisSrvCall->RxDeviceObject->pRxNetNameTable; 3176 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable)); 3177 3178 /* Only finalize if forced or if there's a single ref left */ 3179 if (ThisSrvCall->NodeReferenceCount != 1 && 3180 !ForceFinalize) 3181 { 3182 return FALSE; 3183 } 3184 3185 DPRINT("Finalizing SrvCall %p for %wZ\n", ThisSrvCall, &ThisSrvCall->PrefixEntry.Prefix); 3186 3187 /* If it wasn't finalized yet, do it */ 3188 if (!ThisSrvCall->UpperFinalizationDone) 3189 { 3190 BOOLEAN WillFree; 3191 3192 /* Remove ourselves from prefix table */ 3193 RxRemovePrefixTableEntry(PrefixTable, &ThisSrvCall->PrefixEntry); 3194 3195 /* Remember our third arg, in case we get queued for later execution */ 3196 if (ForceFinalize) 3197 { 3198 SetFlag(ThisSrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED); 3199 } 3200 3201 /* And done */ 3202 ThisSrvCall->UpperFinalizationDone = TRUE; 3203 3204 /* Would defered execution free the object? */ 3205 WillFree = (ThisSrvCall->NodeReferenceCount == 1); 3206 3207 /* If we have a device object */ 3208 if (ThisSrvCall->RxDeviceObject != NULL) 3209 { 3210 NTSTATUS Status; 3211 3212 /* If we're not executing in the RDBSS thread, queue for execution within the thread */ 3213 if (RxGetRDBSSProcess() != IoGetCurrentProcess()) 3214 { 3215 /* Extra ref, as usual */ 3216 InterlockedIncrement((volatile long *)&ThisSrvCall->NodeReferenceCount); 3217 /* And dispatch */ 3218 RxDispatchToWorkerThread(ThisSrvCall->RxDeviceObject, DelayedWorkQueue, RxpDestroySrvCall, ThisSrvCall); 3219 3220 /* Return to the caller, in advance, whether we're freeing the object or not */ 3221 return WillFree; 3222 } 3223 3224 /* If in the right thread already, call the mini-rdr */ 3225 MINIRDR_CALL_THROUGH(Status, ThisSrvCall->RxDeviceObject->Dispatch, 3226 MRxFinalizeSrvCall, ((PMRX_SRV_CALL)ThisSrvCall, ForceFinalize)); 3227 (void)Status; 3228 } 3229 } 3230 3231 /* If we're still referenced, don't go any further! */ 3232 if (ThisSrvCall->NodeReferenceCount != 1) 3233 { 3234 return FALSE; 3235 } 3236 3237 /* Don't leak */ 3238 if (ThisSrvCall->pDomainName != NULL) 3239 { 3240 RxFreePool(ThisSrvCall->pDomainName); 3241 } 3242 3243 /* And free! */ 3244 RxTearDownBufferingManager(ThisSrvCall); 3245 RxFreeObject(ThisSrvCall); 3246 3247 return TRUE; 3248 } 3249 3250 /* 3251 * @implemented 3252 */ 3253 BOOLEAN 3254 RxFinalizeSrvOpen( 3255 OUT PSRV_OPEN ThisSrvOpen, 3256 IN BOOLEAN RecursiveFinalize, 3257 IN BOOLEAN ForceFinalize) 3258 { 3259 PFCB Fcb; 3260 3261 PAGED_CODE(); 3262 3263 /* We have to have a SRV_OPEN */ 3264 ASSERT(NodeType(ThisSrvOpen) == RDBSS_NTC_SRVOPEN); 3265 3266 /* If that's a recursive finalization, finalize any related FOBX */ 3267 if (RecursiveFinalize) 3268 { 3269 PLIST_ENTRY ListEntry; 3270 3271 ListEntry = ThisSrvOpen->FobxList.Flink; 3272 while (ListEntry != &ThisSrvOpen->FobxList) 3273 { 3274 PFOBX Fobx; 3275 3276 Fobx = CONTAINING_RECORD(ListEntry, FOBX, FobxQLinks); 3277 ListEntry = ListEntry->Flink; 3278 RxFinalizeNetFobx(Fobx, TRUE, ForceFinalize); 3279 } 3280 } 3281 3282 /* If we have still references, don't finalize unless forced */ 3283 if (ThisSrvOpen->NodeReferenceCount != 0 && 3284 !ForceFinalize) 3285 { 3286 return FALSE; 3287 } 3288 3289 DPRINT("Finalize SRV_OPEN: %p (with %d ref), forced: %d\n", ThisSrvOpen, ThisSrvOpen->NodeReferenceCount, ForceFinalize); 3290 3291 /* Only finalize if closed, or if it wasn't already done and SRV_OPEN is in a bad shape */ 3292 Fcb = (PFCB)ThisSrvOpen->pFcb; 3293 if ((!ThisSrvOpen->UpperFinalizationDone && ThisSrvOpen->Condition != Condition_Good) || 3294 BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_CLOSED)) 3295 { 3296 PV_NET_ROOT VNetRoot; 3297 3298 /* Associated FCB can't be fake one */ 3299 ASSERT(NodeType(Fcb) != RDBSS_NTC_OPENTARGETDIR_FCB); 3300 ASSERT(RxIsFcbAcquiredExclusive (Fcb)); 3301 3302 /* Purge any pending operation */ 3303 RxPurgeChangeBufferingStateRequestsForSrvOpen(ThisSrvOpen); 3304 3305 /* If the FCB wasn't orphaned, inform the mini-rdr about close */ 3306 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_ORPHANED)) 3307 { 3308 NTSTATUS Status; 3309 3310 MINIRDR_CALL_THROUGH(Status, Fcb->MRxDispatch, MRxForceClosed, ((PMRX_SRV_OPEN)ThisSrvOpen)); 3311 (void)Status; 3312 } 3313 3314 /* Remove ourselves from the FCB */ 3315 RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks); 3316 InitializeListHead(&ThisSrvOpen->SrvOpenQLinks); 3317 ++Fcb->SrvOpenListVersion; 3318 3319 /* If we have a V_NET_ROOT, dereference it */ 3320 VNetRoot = (PV_NET_ROOT)ThisSrvOpen->pVNetRoot; 3321 if (VNetRoot != NULL) 3322 { 3323 InterlockedDecrement((volatile long *)&VNetRoot->pNetRoot->NumberOfSrvOpens); 3324 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld); 3325 ThisSrvOpen->pVNetRoot = NULL; 3326 } 3327 3328 /* Finalization done */ 3329 ThisSrvOpen->UpperFinalizationDone = TRUE; 3330 } 3331 3332 /* Don't free memory if still referenced */ 3333 if (ThisSrvOpen->NodeReferenceCount != 0) 3334 { 3335 return FALSE; 3336 } 3337 3338 /* No key association left */ 3339 ASSERT(IsListEmpty(&ThisSrvOpen->SrvOpenKeyList)); 3340 3341 /* If we're still in some FCB, remove us */ 3342 if (!IsListEmpty(&ThisSrvOpen->SrvOpenQLinks)) 3343 { 3344 RemoveEntryList(&ThisSrvOpen->SrvOpenQLinks); 3345 } 3346 3347 /* If enclosed allocation, mark the memory zone free */ 3348 if (BooleanFlagOn(ThisSrvOpen->Flags, SRVOPEN_FLAG_ENCLOSED_ALLOCATED)) 3349 { 3350 ClearFlag(Fcb->FcbState, FCB_STATE_SRVOPEN_USED); 3351 } 3352 /* Otherwise, free the memory */ 3353 else 3354 { 3355 RxFreeFcbObject(ThisSrvOpen); 3356 } 3357 3358 RxDereferenceNetFcb(Fcb); 3359 3360 return TRUE; 3361 } 3362 3363 /* 3364 * @implemented 3365 */ 3366 BOOLEAN 3367 RxFinalizeVNetRoot( 3368 OUT PV_NET_ROOT ThisVNetRoot, 3369 IN BOOLEAN RecursiveFinalize, 3370 IN BOOLEAN ForceFinalize) 3371 { 3372 PNET_ROOT NetRoot; 3373 PRX_PREFIX_TABLE PrefixTable; 3374 3375 PAGED_CODE(); 3376 3377 ASSERT(NodeType(ThisVNetRoot) == RDBSS_NTC_V_NETROOT); 3378 3379 PrefixTable = ThisVNetRoot->pNetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable; 3380 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable)); 3381 3382 /* Only finalize if forced or if there's a single ref left */ 3383 if (ThisVNetRoot->NodeReferenceCount != 1 && 3384 !ForceFinalize) 3385 { 3386 return FALSE; 3387 } 3388 3389 DPRINT("Finalizing VNetRoot %p for %wZ\n", ThisVNetRoot, &ThisVNetRoot->PrefixEntry.Prefix); 3390 3391 NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot; 3392 /* If it wasn't finalized yet, do it */ 3393 if (!ThisVNetRoot->UpperFinalizationDone) 3394 { 3395 ASSERT(NodeType(NetRoot) == RDBSS_NTC_NETROOT); 3396 3397 /* Reference the NetRoot so that it doesn't disappear */ 3398 RxReferenceNetRoot(NetRoot); 3399 RxOrphanSrvOpens(ThisVNetRoot); 3400 /* Remove us from the available VNetRoot for NetRoot */ 3401 RxRemoveVirtualNetRootFromNetRoot(NetRoot, ThisVNetRoot); 3402 /* Remove extra ref */ 3403 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld); 3404 3405 /* Remove ourselves from prefix table */ 3406 RxRemovePrefixTableEntry(PrefixTable, &ThisVNetRoot->PrefixEntry); 3407 3408 /* Finalization done */ 3409 ThisVNetRoot->UpperFinalizationDone = TRUE; 3410 } 3411 3412 /* If we're still referenced, don't go any further! */ 3413 if (ThisVNetRoot->NodeReferenceCount != 1) 3414 { 3415 return FALSE; 3416 } 3417 3418 /* If there's an associated device, notify mini-rdr */ 3419 if (NetRoot->pSrvCall->RxDeviceObject != NULL) 3420 { 3421 NTSTATUS Status; 3422 3423 MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch, 3424 MRxFinalizeVNetRoot, ((PMRX_V_NET_ROOT)ThisVNetRoot, FALSE)); 3425 (void)Status; 3426 } 3427 3428 /* Free parameters */ 3429 RxUninitializeVNetRootParameters(ThisVNetRoot->pUserName, ThisVNetRoot->pUserDomainName, 3430 ThisVNetRoot->pPassword, &ThisVNetRoot->Flags); 3431 /* Dereference our NetRoot, we won't reference it anymore */ 3432 RxDereferenceNetRoot(NetRoot, LHS_ExclusiveLockHeld); 3433 3434 /* And free the object! */ 3435 RxFreePoolWithTag(ThisVNetRoot, RX_V_NETROOT_POOLTAG); 3436 3437 return TRUE; 3438 } 3439 3440 NTSTATUS 3441 RxFindOrConstructVirtualNetRoot( 3442 IN PRX_CONTEXT RxContext, 3443 IN PUNICODE_STRING CanonicalName, 3444 IN NET_ROOT_TYPE NetRootType, 3445 IN PUNICODE_STRING RemainingName) 3446 { 3447 ULONG Flags; 3448 NTSTATUS Status; 3449 PVOID Container; 3450 BOOLEAN Construct; 3451 PV_NET_ROOT VNetRoot; 3452 RX_CONNECTION_ID ConnectionID; 3453 PRDBSS_DEVICE_OBJECT RxDeviceObject; 3454 LOCK_HOLDING_STATE LockHoldingState; 3455 3456 PAGED_CODE(); 3457 3458 RxDeviceObject = RxContext->RxDeviceObject; 3459 ASSERT(RxDeviceObject->Dispatch != NULL); 3460 ASSERT(NodeType(RxDeviceObject->Dispatch) == RDBSS_NTC_MINIRDR_DISPATCH); 3461 3462 /* Ask the mini-rdr for connection ID */ 3463 ConnectionID.SessionID = 0; 3464 if (RxDeviceObject->Dispatch->MRxGetConnectionId != NULL) 3465 { 3466 Status = RxDeviceObject->Dispatch->MRxGetConnectionId(RxContext, &ConnectionID); 3467 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED) 3468 { 3469 /* mini-rdr is expected not to fail - unless it's not implemented */ 3470 DPRINT1("Failed to initialize connection ID\n"); 3471 ASSERT(FALSE); 3472 } 3473 } 3474 3475 RxContext->Create.NetNamePrefixEntry = NULL; 3476 3477 Status = STATUS_MORE_PROCESSING_REQUIRED; 3478 RxAcquirePrefixTableLockShared(RxDeviceObject->pRxNetNameTable, TRUE); 3479 LockHoldingState = LHS_SharedLockHeld; 3480 Construct = TRUE; 3481 Flags = 0; 3482 3483 /* We will try twice to find a matching VNetRoot: shared locked and then exlusively locked */ 3484 while (TRUE) 3485 { 3486 PNET_ROOT NetRoot; 3487 PV_NET_ROOT SavedVNetRoot; 3488 3489 /* Look in prefix table */ 3490 Container = RxPrefixTableLookupName(RxDeviceObject->pRxNetNameTable, CanonicalName, RemainingName, &ConnectionID); 3491 if (Container != NULL) 3492 { 3493 /* If that's not a VNetRoot, that's a SrvCall, not interesting, loop again */ 3494 if (NodeType(Container) != RDBSS_NTC_V_NETROOT) 3495 { 3496 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL); 3497 RxDereferenceSrvCall(Container, LockHoldingState); 3498 } 3499 else 3500 { 3501 VNetRoot = Container; 3502 NetRoot = VNetRoot->NetRoot; 3503 3504 /* If the matching VNetRoot isn't in a good shape, there's something wrong - fail */ 3505 if ((NetRoot->Condition != Condition_InTransition && NetRoot->Condition != Condition_Good) || 3506 NetRoot->SrvCall->RxDeviceObject != RxContext->RxDeviceObject) 3507 { 3508 Status = STATUS_BAD_NETWORK_PATH; 3509 SavedVNetRoot = NULL; 3510 } 3511 else 3512 { 3513 LUID LogonId; 3514 ULONG SessionId; 3515 PUNICODE_STRING UserName, UserDomain, Password; 3516 3517 /* We can reuse if we use same credentials */ 3518 Status = RxInitializeVNetRootParameters(RxContext, &LogonId, 3519 &SessionId, &UserName, 3520 &UserDomain, &Password, 3521 &Flags); 3522 if (NT_SUCCESS(Status)) 3523 { 3524 SavedVNetRoot = VNetRoot; 3525 Status = RxCheckVNetRootCredentials(RxContext, VNetRoot, 3526 &LogonId, UserName, 3527 UserDomain, Password, 3528 Flags); 3529 if (Status == STATUS_MORE_PROCESSING_REQUIRED) 3530 { 3531 PLIST_ENTRY ListEntry; 3532 3533 for (ListEntry = NetRoot->VirtualNetRoots.Flink; 3534 ListEntry != &NetRoot->VirtualNetRoots; 3535 ListEntry = ListEntry->Flink) 3536 { 3537 SavedVNetRoot = CONTAINING_RECORD(ListEntry, V_NET_ROOT, NetRootListEntry); 3538 Status = RxCheckVNetRootCredentials(RxContext, SavedVNetRoot, 3539 &LogonId, UserName, 3540 UserDomain, Password, 3541 Flags); 3542 if (Status != STATUS_MORE_PROCESSING_REQUIRED) 3543 { 3544 break; 3545 } 3546 } 3547 3548 if (ListEntry == &NetRoot->VirtualNetRoots) 3549 { 3550 SavedVNetRoot = NULL; 3551 } 3552 } 3553 3554 if (!NT_SUCCESS(Status)) 3555 { 3556 SavedVNetRoot = NULL; 3557 } 3558 3559 RxUninitializeVNetRootParameters(UserName, UserDomain, Password, &Flags); 3560 } 3561 } 3562 3563 /* We'll fail, if we had referenced a VNetRoot, dereference it */ 3564 if (Status != STATUS_MORE_PROCESSING_REQUIRED && !NT_SUCCESS(Status)) 3565 { 3566 if (SavedVNetRoot == NULL) 3567 { 3568 RxDereferenceVNetRoot(VNetRoot, LockHoldingState); 3569 } 3570 } 3571 /* Reference VNetRoot we'll keep, and dereference current */ 3572 else if (SavedVNetRoot != VNetRoot) 3573 { 3574 RxDereferenceVNetRoot(VNetRoot, LockHoldingState); 3575 if (SavedVNetRoot != NULL) 3576 { 3577 RxReferenceVNetRoot(SavedVNetRoot); 3578 } 3579 } 3580 } 3581 3582 /* We may have found something, or we fail hard, so don't attempt to create a VNetRoot */ 3583 if (Status != STATUS_MORE_PROCESSING_REQUIRED) 3584 { 3585 Construct = FALSE; 3586 break; 3587 } 3588 } 3589 3590 /* If we're locked exclusive, we won't loop again, it was the second pass */ 3591 if (LockHoldingState != LHS_SharedLockHeld) 3592 { 3593 break; 3594 } 3595 3596 /* Otherwise, prepare for second pass, exclusive, making sure we can acquire without delay */ 3597 if (RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, FALSE)) 3598 { 3599 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable); 3600 LockHoldingState = LHS_ExclusiveLockHeld; 3601 break; 3602 } 3603 3604 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable); 3605 RxAcquirePrefixTableLockExclusive(RxDeviceObject->pRxNetNameTable, TRUE); 3606 LockHoldingState = LHS_ExclusiveLockHeld; 3607 } 3608 3609 /* We didn't fail, and didn't find any VNetRoot, construct one */ 3610 if (Construct) 3611 { 3612 ASSERT(LockHoldingState == LHS_ExclusiveLockHeld); 3613 3614 Status = RxConstructVirtualNetRoot(RxContext, CanonicalName, NetRootType, &VNetRoot, &LockHoldingState, &ConnectionID); 3615 ASSERT(Status != STATUS_SUCCESS || LockHoldingState != LHS_LockNotHeld); 3616 3617 if (Status == STATUS_SUCCESS) 3618 { 3619 DPRINT("CanonicalName: %wZ (%d)\n", CanonicalName, CanonicalName->Length); 3620 DPRINT("VNetRoot: %wZ (%d)\n", &VNetRoot->PrefixEntry.Prefix, VNetRoot->PrefixEntry.Prefix.Length); 3621 ASSERT(CanonicalName->Length >= VNetRoot->PrefixEntry.Prefix.Length); 3622 3623 RemainingName->Buffer = Add2Ptr(CanonicalName->Buffer, VNetRoot->PrefixEntry.Prefix.Length); 3624 RemainingName->Length = CanonicalName->Length - VNetRoot->PrefixEntry.Prefix.Length; 3625 RemainingName->MaximumLength = RemainingName->Length; 3626 3627 if (BooleanFlagOn(Flags, VNETROOT_FLAG_CSCAGENT_INSTANCE)) 3628 { 3629 DPRINT("CSC instance, VNetRoot: %p\n", VNetRoot); 3630 } 3631 VNetRoot->Flags |= Flags; 3632 } 3633 } 3634 3635 /* Release the prefix table - caller expects it to be released */ 3636 if (LockHoldingState != LHS_LockNotHeld) 3637 { 3638 RxReleasePrefixTableLock(RxDeviceObject->pRxNetNameTable); 3639 } 3640 3641 /* If we failed creating, quit */ 3642 if (Status != STATUS_SUCCESS) 3643 { 3644 DPRINT1("RxFindOrConstructVirtualNetRoot() = Status: %x\n", Status); 3645 return Status; 3646 } 3647 3648 /* Otherwise, wait until the VNetRoot is stable */ 3649 DPRINT("Waiting for stable condition for: %p\n", VNetRoot); 3650 RxWaitForStableVNetRoot(VNetRoot, RxContext); 3651 /* It's all good, update the RX_CONTEXT with all our structs */ 3652 if (VNetRoot->Condition == Condition_Good) 3653 { 3654 PNET_ROOT NetRoot; 3655 3656 NetRoot = VNetRoot->NetRoot; 3657 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot; 3658 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot; 3659 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)NetRoot->SrvCall; 3660 } 3661 else 3662 { 3663 RxDereferenceVNetRoot(VNetRoot, LHS_LockNotHeld); 3664 RxContext->Create.pVNetRoot = NULL; 3665 Status = STATUS_BAD_NETWORK_PATH; 3666 } 3667 3668 return Status; 3669 } 3670 3671 /* 3672 * @implemented 3673 */ 3674 NTSTATUS 3675 RxFindOrCreateConnections( 3676 _In_ PRX_CONTEXT RxContext, 3677 _In_ PUNICODE_STRING CanonicalName, 3678 _In_ NET_ROOT_TYPE NetRootType, 3679 _Out_ PUNICODE_STRING LocalNetRootName, 3680 _Out_ PUNICODE_STRING FilePathName, 3681 _Inout_ PLOCK_HOLDING_STATE LockState, 3682 _In_ PRX_CONNECTION_ID RxConnectionId) 3683 { 3684 PVOID Container; 3685 PSRV_CALL SrvCall; 3686 PNET_ROOT NetRoot; 3687 PV_NET_ROOT VNetRoot; 3688 NTSTATUS Status = STATUS_UNSUCCESSFUL; 3689 PRX_PREFIX_TABLE PrefixTable; 3690 UNICODE_STRING RemainingName, NetRootName; 3691 3692 PAGED_CODE(); 3693 3694 DPRINT("RxFindOrCreateConnections(%p, %wZ, %x, %p, %p, %p, %p)\n", 3695 RxContext, CanonicalName, NetRootType, LocalNetRootName, 3696 FilePathName, LockState, RxConnectionId); 3697 3698 *FilePathName = *CanonicalName; 3699 LocalNetRootName->Length = 0; 3700 LocalNetRootName->MaximumLength = 0; 3701 LocalNetRootName->Buffer = CanonicalName->Buffer; 3702 3703 /* UNC path, split it */ 3704 if (FilePathName->Buffer[1] == ';') 3705 { 3706 BOOLEAN Slash; 3707 USHORT i, Length; 3708 3709 Slash = FALSE; 3710 for (i = 2; i < FilePathName->Length / sizeof(WCHAR); ++i) 3711 { 3712 if (FilePathName->Buffer[i] == OBJ_NAME_PATH_SEPARATOR) 3713 { 3714 Slash = TRUE; 3715 break; 3716 } 3717 } 3718 3719 if (!Slash) 3720 { 3721 return STATUS_OBJECT_NAME_INVALID; 3722 } 3723 3724 FilePathName->Buffer = &FilePathName->Buffer[i]; 3725 Length = (USHORT)((ULONG_PTR)FilePathName->Buffer - (ULONG_PTR)LocalNetRootName->Buffer); 3726 LocalNetRootName->Length = Length; 3727 LocalNetRootName->MaximumLength = Length; 3728 FilePathName->Length -= Length; 3729 3730 DPRINT("CanonicalName: %wZ\n", CanonicalName); 3731 DPRINT(" -> FilePathName: %wZ\n", FilePathName); 3732 DPRINT(" -> LocalNetRootName: %wZ\n", LocalNetRootName); 3733 } 3734 3735 Container = NULL; 3736 PrefixTable = RxContext->RxDeviceObject->pRxNetNameTable; 3737 3738 _SEH2_TRY 3739 { 3740 RetryLookup: 3741 ASSERT(*LockState != LHS_LockNotHeld); 3742 3743 /* If previous lookup left something, dereference it */ 3744 if (Container != NULL) 3745 { 3746 switch (NodeType(Container)) 3747 { 3748 case RDBSS_NTC_SRVCALL: 3749 RxDereferenceSrvCall(Container, *LockState); 3750 break; 3751 3752 case RDBSS_NTC_NETROOT: 3753 RxDereferenceNetRoot(Container, *LockState); 3754 break; 3755 3756 case RDBSS_NTC_V_NETROOT: 3757 RxDereferenceVNetRoot(Container, *LockState); 3758 break; 3759 3760 default: 3761 /* Should never happen */ 3762 ASSERT(FALSE); 3763 break; 3764 } 3765 } 3766 3767 /* Look for our NetRoot in prefix table */ 3768 Container = RxPrefixTableLookupName(PrefixTable, FilePathName, &RemainingName, RxConnectionId); 3769 DPRINT("Container %p for path %wZ\n", Container, FilePathName); 3770 3771 while (TRUE) 3772 { 3773 UNICODE_STRING SrvCallName; 3774 3775 SrvCall = NULL; 3776 NetRoot = NULL; 3777 VNetRoot = NULL; 3778 3779 /* Assume we didn't succeed */ 3780 RxContext->Create.pVNetRoot = NULL; 3781 RxContext->Create.pNetRoot = NULL; 3782 RxContext->Create.pSrvCall = NULL; 3783 RxContext->Create.Type = NetRootType; 3784 3785 /* If we found something */ 3786 if (Container != NULL) 3787 { 3788 /* A VNetRoot */ 3789 if (NodeType(Container) == RDBSS_NTC_V_NETROOT) 3790 { 3791 VNetRoot = Container; 3792 /* Use its NetRoot */ 3793 NetRoot = VNetRoot->NetRoot; 3794 3795 /* If it's not stable, wait for it to be stable */ 3796 if (NetRoot->Condition == Condition_InTransition) 3797 { 3798 RxReleasePrefixTableLock(PrefixTable); 3799 DPRINT("Waiting for stable condition for: %p\n", NetRoot); 3800 RxWaitForStableNetRoot(NetRoot, RxContext); 3801 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE); 3802 *LockState = LHS_ExclusiveLockHeld; 3803 3804 /* Now that's it's ok, retry lookup to find what we want */ 3805 if (NetRoot->Condition == Condition_Good) 3806 { 3807 goto RetryLookup; 3808 } 3809 } 3810 3811 /* Is the associated netroot good? */ 3812 if (NetRoot->Condition == Condition_Good) 3813 { 3814 SrvCall = (PSRV_CALL)NetRoot->pSrvCall; 3815 3816 /* If it is, and SrvCall as well, then, we have our active connection */ 3817 if (SrvCall->Condition == Condition_Good && 3818 SrvCall->RxDeviceObject == RxContext->RxDeviceObject) 3819 { 3820 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot; 3821 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot; 3822 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall; 3823 3824 Status = STATUS_CONNECTION_ACTIVE; 3825 _SEH2_LEAVE; 3826 } 3827 } 3828 3829 /* If VNetRoot was well constructed, it means the connection is active */ 3830 if (VNetRoot->ConstructionStatus == STATUS_SUCCESS) 3831 { 3832 Status = STATUS_CONNECTION_ACTIVE; 3833 } 3834 else 3835 { 3836 Status = VNetRoot->ConstructionStatus; 3837 } 3838 3839 RxDereferenceVNetRoot(VNetRoot, *LockState); 3840 _SEH2_LEAVE; 3841 } 3842 /* Can only be a SrvCall */ 3843 else 3844 { 3845 ASSERT(NodeType(Container) == RDBSS_NTC_SRVCALL); 3846 SrvCall = Container; 3847 3848 /* Wait for the SRV_CALL to be stable */ 3849 if (SrvCall->Condition == Condition_InTransition) 3850 { 3851 RxReleasePrefixTableLock(PrefixTable); 3852 DPRINT("Waiting for stable condition for: %p\n", SrvCall); 3853 RxWaitForStableSrvCall(SrvCall, RxContext); 3854 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE); 3855 *LockState = LHS_ExclusiveLockHeld; 3856 3857 /* It went good, loop again to find what we look for */ 3858 if (SrvCall->Condition == Condition_Good) 3859 { 3860 goto RetryLookup; 3861 } 3862 } 3863 3864 /* If it's not good... */ 3865 if (SrvCall->Condition != Condition_Good) 3866 { 3867 /* But SRV_CALL was well constructed, assume a connection was active */ 3868 if (SrvCall->Status == STATUS_SUCCESS) 3869 { 3870 Status = STATUS_CONNECTION_ACTIVE; 3871 } 3872 else 3873 { 3874 Status = SrvCall->Status; 3875 } 3876 3877 RxDereferenceSrvCall(SrvCall, *LockState); 3878 _SEH2_LEAVE; 3879 } 3880 } 3881 } 3882 3883 /* If we found a SRV_CALL not matching our DO, quit */ 3884 if (SrvCall != NULL && SrvCall->Condition == Condition_Good && 3885 SrvCall->RxDeviceObject != RxContext->RxDeviceObject) 3886 { 3887 RxDereferenceSrvCall(SrvCall, *LockState); 3888 Status = STATUS_BAD_NETWORK_NAME; 3889 _SEH2_LEAVE; 3890 } 3891 3892 /* Now, we want exclusive lock */ 3893 if (*LockState == LHS_SharedLockHeld) 3894 { 3895 if (!RxAcquirePrefixTableLockExclusive(PrefixTable, FALSE)) 3896 { 3897 RxReleasePrefixTableLock(PrefixTable); 3898 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE); 3899 *LockState = LHS_ExclusiveLockHeld; 3900 goto RetryLookup; 3901 } 3902 3903 RxReleasePrefixTableLock(PrefixTable); 3904 *LockState = LHS_ExclusiveLockHeld; 3905 } 3906 3907 ASSERT(*LockState == LHS_ExclusiveLockHeld); 3908 3909 /* If we reach that point, we found something, no need to create something */ 3910 if (Container != NULL) 3911 { 3912 break; 3913 } 3914 3915 /* Get the name for the SRV_CALL */ 3916 RxExtractServerName(FilePathName, &SrvCallName, NULL); 3917 DPRINT(" -> SrvCallName: %wZ\n", &SrvCallName); 3918 /* And create the SRV_CALL */ 3919 SrvCall = RxCreateSrvCall(RxContext, &SrvCallName, NULL, RxConnectionId); 3920 if (SrvCall == NULL) 3921 { 3922 Status = STATUS_INSUFFICIENT_RESOURCES; 3923 _SEH2_LEAVE; 3924 } 3925 3926 /* Reset RX_CONTEXT, so far, connection creation isn't a success */ 3927 RxReferenceSrvCall(SrvCall); 3928 RxContext->Create.pVNetRoot = NULL; 3929 RxContext->Create.pNetRoot = NULL; 3930 RxContext->Create.pSrvCall = NULL; 3931 RxContext->Create.Type = NetRootType; 3932 Container = SrvCall; 3933 3934 /* Construct SRV_CALL, ie, use mini-rdr */ 3935 Status = RxConstructSrvCall(RxContext, SrvCall, LockState); 3936 ASSERT(Status != STATUS_SUCCESS || RxIsPrefixTableLockAcquired(PrefixTable)); 3937 if (Status != STATUS_SUCCESS) 3938 { 3939 DPRINT1("RxConstructSrvCall() = Status: %x\n", Status); 3940 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE); 3941 RxDereferenceSrvCall(SrvCall, *LockState); 3942 RxReleasePrefixTableLock(PrefixTable); 3943 _SEH2_LEAVE; 3944 } 3945 3946 /* Loop again to make use of SRV_CALL stable condition wait */ 3947 } 3948 3949 /* At that point, we have a stable SRV_CALL (either found or constructed) */ 3950 ASSERT((NodeType(SrvCall) == RDBSS_NTC_SRVCALL) && (SrvCall->Condition == Condition_Good)); 3951 ASSERT(NetRoot == NULL && VNetRoot == NULL); 3952 ASSERT(SrvCall->RxDeviceObject == RxContext->RxDeviceObject); 3953 3954 /* Call mini-rdr to get NetRoot name */ 3955 SrvCall->RxDeviceObject->Dispatch->MRxExtractNetRootName(FilePathName, (PMRX_SRV_CALL)SrvCall, &NetRootName, NULL); 3956 /* And create the NetRoot with that name */ 3957 NetRoot = RxCreateNetRoot(SrvCall, &NetRootName, 0, RxConnectionId); 3958 if (NetRoot == NULL) 3959 { 3960 Status = STATUS_INSUFFICIENT_RESOURCES; 3961 _SEH2_LEAVE; 3962 } 3963 NetRoot->Type = NetRootType; 3964 3965 RxDereferenceSrvCall(SrvCall, *LockState); 3966 3967 /* Finally, create the associated VNetRoot */ 3968 VNetRoot = RxCreateVNetRoot(RxContext, NetRoot, CanonicalName, LocalNetRootName, FilePathName, RxConnectionId); 3969 if (VNetRoot == NULL) 3970 { 3971 RxFinalizeNetRoot(NetRoot, TRUE, TRUE); 3972 Status = STATUS_INSUFFICIENT_RESOURCES; 3973 _SEH2_LEAVE; 3974 } 3975 RxReferenceVNetRoot(VNetRoot); 3976 3977 /* We're get closer! */ 3978 NetRoot->Condition = Condition_InTransition; 3979 RxContext->Create.pSrvCall = (PMRX_SRV_CALL)SrvCall; 3980 RxContext->Create.pNetRoot = (PMRX_NET_ROOT)NetRoot; 3981 RxContext->Create.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot; 3982 3983 /* Construct the NetRoot, involving the mini-rdr now that we have our three control structs */ 3984 Status = RxConstructNetRoot(RxContext, SrvCall, NetRoot, VNetRoot, LockState); 3985 if (!NT_SUCCESS(Status)) 3986 { 3987 RxTransitionVNetRoot(VNetRoot, Condition_Bad); 3988 DPRINT1("RxConstructNetRoot failed Ctxt: %p, VNet: %p, Status: %lx, Condition: %d\n", RxContext, VNetRoot, Status, VNetRoot->Condition); 3989 RxDereferenceVNetRoot(VNetRoot, *LockState); 3990 3991 RxContext->Create.pNetRoot = NULL; 3992 RxContext->Create.pVNetRoot = NULL; 3993 } 3994 else 3995 { 3996 PIO_STACK_LOCATION Stack; 3997 3998 ASSERT(*LockState == LHS_ExclusiveLockHeld); 3999 4000 Stack = RxContext->CurrentIrpSp; 4001 if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_CREATE_TREE_CONNECTION)) 4002 { 4003 RxExclusivePrefixTableLockToShared(PrefixTable); 4004 *LockState = LHS_SharedLockHeld; 4005 } 4006 } 4007 } 4008 _SEH2_FINALLY 4009 { 4010 if (Status != STATUS_SUCCESS && Status != STATUS_CONNECTION_ACTIVE) 4011 { 4012 if (*LockState != LHS_LockNotHeld) 4013 { 4014 RxReleasePrefixTableLock(PrefixTable); 4015 *LockState = LHS_LockNotHeld; 4016 } 4017 } 4018 } 4019 _SEH2_END; 4020 4021 DPRINT("RxFindOrCreateConnections() = Status: %x\n", Status); 4022 return Status; 4023 } 4024 4025 /* 4026 * @implemented 4027 */ 4028 VOID 4029 NTAPI 4030 RxFinishFcbInitialization( 4031 IN OUT PMRX_FCB Fcb, 4032 IN RX_FILE_TYPE FileType, 4033 IN PFCB_INIT_PACKET InitPacket OPTIONAL) 4034 { 4035 RX_FILE_TYPE OldType; 4036 4037 PAGED_CODE(); 4038 4039 DPRINT("RxFinishFcbInitialization(%p, %x, %p)\n", Fcb, FileType, InitPacket); 4040 4041 OldType = NodeType(Fcb); 4042 NodeType(Fcb) = FileType; 4043 /* If mini-rdr already did the job for mailslot attributes, 0 the rest */ 4044 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_TIME_AND_SIZE_ALREADY_SET) && FileType == RDBSS_NTC_MAILSLOT) 4045 { 4046 FILL_IN_FCB((PFCB)Fcb, 0, 0, 0, 0, 0, 0, 0, 0, 0); 4047 } 4048 /* Otherwise, if mini-rdr provided us with an init packet, copy its data */ 4049 else if (InitPacket != NULL) 4050 { 4051 FILL_IN_FCB((PFCB)Fcb, *InitPacket->pAttributes, *InitPacket->pNumLinks, 4052 InitPacket->pCreationTime->QuadPart, InitPacket->pLastAccessTime->QuadPart, 4053 InitPacket->pLastWriteTime->QuadPart, InitPacket->pLastChangeTime->QuadPart, 4054 InitPacket->pAllocationSize->QuadPart, InitPacket->pFileSize->QuadPart, 4055 InitPacket->pValidDataLength->QuadPart); 4056 } 4057 4058 if (FileType != RDBSS_NTC_STORAGE_TYPE_UNKNOWN && 4059 FileType != RDBSS_NTC_STORAGE_TYPE_DIRECTORY) 4060 { 4061 /* If our FCB newly points to a file, initiliaze everything related */ 4062 if (FileType == RDBSS_NTC_STORAGE_TYPE_FILE) 4063 4064 { 4065 if (OldType != RDBSS_NTC_STORAGE_TYPE_FILE) 4066 { 4067 RxInitializeLowIoPerFcbInfo(&((PFCB)Fcb)->Specific.Fcb.LowIoPerFcbInfo); 4068 FsRtlInitializeFileLock(&((PFCB)Fcb)->Specific.Fcb.FileLock, RxLockOperationCompletion, 4069 RxUnlockOperation); 4070 4071 ((PFCB)Fcb)->BufferedLocks.List = NULL; 4072 ((PFCB)Fcb)->BufferedLocks.PendingLockOps = 0; 4073 4074 Fcb->Header.IsFastIoPossible = FastIoIsQuestionable; 4075 } 4076 } 4077 /* If not a file, validate type */ 4078 else 4079 { 4080 ASSERT(FileType >= RDBSS_NTC_SPOOLFILE && FileType <= RDBSS_NTC_MAILSLOT); 4081 } 4082 } 4083 } 4084 4085 /* 4086 * @implemented 4087 */ 4088 NTSTATUS 4089 RxFinishSrvCallConstruction( 4090 PMRX_SRVCALLDOWN_STRUCTURE Calldown) 4091 { 4092 NTSTATUS Status; 4093 PSRV_CALL SrvCall; 4094 PRX_CONTEXT Context; 4095 RX_BLOCK_CONDITION Condition; 4096 PRX_PREFIX_TABLE PrefixTable; 4097 4098 DPRINT("RxFinishSrvCallConstruction(%p)\n", Calldown); 4099 4100 SrvCall = (PSRV_CALL)Calldown->SrvCall; 4101 Context = Calldown->RxContext; 4102 PrefixTable = Context->RxDeviceObject->pRxNetNameTable; 4103 4104 /* We have a winner, notify him */ 4105 if (Calldown->BestFinisher != NULL) 4106 { 4107 DPRINT("Notify the winner: %p (%wZ)\n", Calldown->BestFinisher, &Calldown->BestFinisher->DeviceName); 4108 4109 ASSERT(SrvCall->RxDeviceObject == Calldown->BestFinisher); 4110 4111 MINIRDR_CALL_THROUGH(Status, Calldown->BestFinisher->Dispatch, 4112 MRxSrvCallWinnerNotify, 4113 ((PMRX_SRV_CALL)SrvCall, TRUE, 4114 Calldown->CallbackContexts[Calldown->BestFinisherOrdinal].RecommunicateContext)); 4115 if (Status != STATUS_SUCCESS) 4116 { 4117 Condition = Condition_Bad; 4118 } 4119 else 4120 { 4121 Condition = Condition_Good; 4122 } 4123 } 4124 /* Otherwise, just fail our SRV_CALL */ 4125 else 4126 { 4127 Status = Calldown->CallbackContexts[0].Status; 4128 Condition = Condition_Bad; 4129 } 4130 4131 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE); 4132 RxTransitionSrvCall(SrvCall, Condition); 4133 RxFreePoolWithTag(Calldown, RX_SRVCALL_POOLTAG); 4134 4135 /* If async, finish it here, otherwise, caller has already finished the stuff */ 4136 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION)) 4137 { 4138 DPRINT("Finishing async call\n"); 4139 4140 RxReleasePrefixTableLock(PrefixTable); 4141 4142 /* Make sure we weren't cancelled in-between */ 4143 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_CANCELLED)) 4144 { 4145 Status = STATUS_CANCELLED; 4146 } 4147 4148 /* In case that was a create, context can be reused */ 4149 if (Context->MajorFunction == IRP_MJ_CREATE) 4150 { 4151 RxpPrepareCreateContextForReuse(Context); 4152 } 4153 4154 /* If that's a failure, reset everything and return failure */ 4155 if (Status != STATUS_SUCCESS) 4156 { 4157 Context->MajorFunction = Context->CurrentIrpSp->MajorFunction; 4158 if (Context->MajorFunction == IRP_MJ_DEVICE_CONTROL) 4159 { 4160 if (Context->Info.Buffer != NULL) 4161 { 4162 RxFreePool(Context->Info.Buffer); 4163 Context->Info.Buffer = NULL; 4164 } 4165 } 4166 Context->CurrentIrp->IoStatus.Information = 0; 4167 Context->CurrentIrp->IoStatus.Status = Status; 4168 RxCompleteRequest(Context, Status); 4169 } 4170 /* Otherwise, call resume routine and done! */ 4171 else 4172 { 4173 Status = Context->ResumeRoutine(Context); 4174 if (Status != STATUS_PENDING) 4175 { 4176 RxCompleteRequest(Context, Status); 4177 } 4178 4179 DPRINT("Not completing, pending\n"); 4180 } 4181 } 4182 4183 RxDereferenceSrvCall(SrvCall, LHS_LockNotHeld); 4184 return Status; 4185 } 4186 4187 /* 4188 * @implemented 4189 */ 4190 VOID 4191 NTAPI 4192 RxFinishSrvCallConstructionDispatcher( 4193 IN PVOID Context) 4194 { 4195 KIRQL OldIrql; 4196 BOOLEAN Direct, KeepLoop; 4197 4198 DPRINT("RxFinishSrvCallConstructionDispatcher(%p)\n", Context); 4199 4200 /* In case of failure of starting dispatcher, context is not set 4201 * We keep track of it to fail associated SRV_CALL 4202 */ 4203 Direct = (Context == NULL); 4204 4205 /* Separated thread, loop forever */ 4206 while (TRUE) 4207 { 4208 PLIST_ENTRY ListEntry; 4209 PMRX_SRVCALLDOWN_STRUCTURE Calldown; 4210 4211 /* If there are no SRV_CALL to finalize left, just finish thread */ 4212 KeAcquireSpinLock(&RxStrucSupSpinLock, &OldIrql); 4213 if (IsListEmpty(&RxSrvCalldownList)) 4214 { 4215 KeepLoop = FALSE; 4216 RxSrvCallConstructionDispatcherActive = FALSE; 4217 } 4218 /* Otherwise, get the SRV_CALL to finish construction */ 4219 else 4220 { 4221 ListEntry = RemoveHeadList(&RxSrvCalldownList); 4222 KeepLoop = TRUE; 4223 } 4224 KeReleaseSpinLock(&RxStrucSupSpinLock, OldIrql); 4225 4226 /* Nothing to do */ 4227 if (!KeepLoop) 4228 { 4229 break; 4230 } 4231 4232 /* If direct is set, reset the finisher to avoid electing a winner 4233 * and fail SRV_CALL (see upper comment) 4234 */ 4235 Calldown = CONTAINING_RECORD(ListEntry, MRX_SRVCALLDOWN_STRUCTURE, SrvCalldownList); 4236 if (Direct) 4237 { 4238 Calldown->BestFinisher = NULL; 4239 } 4240 /* Finish SRV_CALL construction */ 4241 RxFinishSrvCallConstruction(Calldown); 4242 } 4243 } 4244 4245 /* 4246 * @implemented 4247 */ 4248 NTSTATUS 4249 RxFlushFcbInSystemCache( 4250 IN PFCB Fcb, 4251 IN BOOLEAN SynchronizeWithLazyWriter) 4252 { 4253 IO_STATUS_BLOCK IoStatus; 4254 4255 PAGED_CODE(); 4256 4257 /* Deal with Cc */ 4258 CcFlushCache(&Fcb->NonPaged->SectionObjectPointers, NULL, 0, &IoStatus); 4259 /* If we're asked to sync with LW, do it in case of success */ 4260 if (SynchronizeWithLazyWriter && NT_SUCCESS(IoStatus.Status)) 4261 { 4262 RxAcquirePagingIoResource((PRX_CONTEXT)NULL, Fcb); 4263 RxReleasePagingIoResource((PRX_CONTEXT)NULL, Fcb); 4264 } 4265 4266 DPRINT("Flushing for FCB %p returns %lx\n", Fcb, IoStatus.Status); 4267 return IoStatus.Status; 4268 } 4269 4270 /* 4271 * @implemented 4272 */ 4273 VOID 4274 RxFreeFcbObject( 4275 PVOID Object) 4276 { 4277 PAGED_CODE(); 4278 4279 DPRINT("Freeing %p\n", Object); 4280 4281 /* If that's a FOBX/SRV_OPEN, nothing to do, just free it */ 4282 if (NodeType(Object) == RDBSS_NTC_FOBX || NodeType(Object) == RDBSS_NTC_SRVOPEN) 4283 { 4284 RxFreePoolWithTag(Object, RX_FCB_POOLTAG); 4285 } 4286 /* If that's a FCB... */ 4287 else if (NodeTypeIsFcb(Object)) 4288 { 4289 PFCB Fcb; 4290 PRDBSS_DEVICE_OBJECT DeviceObject; 4291 4292 Fcb = (PFCB)Object; 4293 DeviceObject = Fcb->RxDeviceObject; 4294 4295 /* Delete per stream contexts */ 4296 FsRtlTeardownPerStreamContexts(&Fcb->Header); 4297 4298 SetFlag(Fcb->Header.Flags, FSRTL_FLAG_ACQUIRE_MAIN_RSRC_SH); 4299 4300 /* If there was a non-paged FCB allocated, free it */ 4301 if (!BooleanFlagOn(Fcb->FcbState, FCB_STATE_PAGING_FILE)) 4302 { 4303 RxFreePoolWithTag(Fcb->NonPaged, RX_NONPAGEDFCB_POOLTAG); 4304 } 4305 4306 /* Free the FCB */ 4307 RxFreePool(Fcb); 4308 4309 /* Update statistics */ 4310 InterlockedDecrement(&RxNumberOfActiveFcbs); 4311 InterlockedDecrement((volatile long *)&DeviceObject->NumberOfActiveFcbs); 4312 } 4313 } 4314 4315 /* 4316 * @implemented 4317 */ 4318 VOID 4319 RxFreeObject( 4320 PVOID pObject) 4321 { 4322 PAGED_CODE(); 4323 4324 /* First, perform a few sanity checks if we're dealing with a SRV_CALL or a NET_ROOT */ 4325 if (NodeType(pObject) == RDBSS_NTC_SRVCALL) 4326 { 4327 PSRV_CALL SrvCall; 4328 PRDBSS_DEVICE_OBJECT DeviceObject; 4329 4330 SrvCall = (PSRV_CALL)pObject; 4331 DeviceObject = SrvCall->RxDeviceObject; 4332 if (DeviceObject != NULL) 4333 { 4334 if (!BooleanFlagOn(DeviceObject->Dispatch->MRxFlags, RDBSS_MANAGE_SRV_CALL_EXTENSION)) 4335 { 4336 ASSERT(SrvCall->Context == NULL); 4337 } 4338 4339 ASSERT(SrvCall->Context2 == NULL); 4340 4341 SrvCall->RxDeviceObject = NULL; 4342 } 4343 } 4344 else if (NodeType(pObject) == RDBSS_NTC_NETROOT) 4345 { 4346 PNET_ROOT NetRoot; 4347 4348 NetRoot = (PNET_ROOT)pObject; 4349 NetRoot->pSrvCall = NULL; 4350 NetRoot->NodeTypeCode = NodeType(pObject) | 0xF000; 4351 } 4352 4353 /* And just free the object */ 4354 RxFreePool(pObject); 4355 } 4356 4357 /* 4358 * @implemented 4359 */ 4360 VOID 4361 RxGatherRequestsForSrvOpen( 4362 IN OUT PSRV_CALL SrvCall, 4363 IN PSRV_OPEN SrvOpen, 4364 IN OUT PLIST_ENTRY RequestsListHead) 4365 { 4366 KIRQL OldIrql; 4367 LIST_ENTRY Discarded, *Entry; 4368 PCHANGE_BUFFERING_STATE_REQUEST Request; 4369 4370 /* Dispatch any pending operation first */ 4371 RxpDispatchChangeBufferingStateRequests(SrvCall, SrvOpen, &Discarded); 4372 4373 /* Then, get any entry related to our key and SRV_OPEN */ 4374 KeAcquireSpinLock(&SrvCall->BufferingManager.SpinLock, &OldIrql); 4375 Entry = SrvCall->BufferingManager.HandlerList.Flink; 4376 while (Entry != &SrvCall->BufferingManager.HandlerList) 4377 { 4378 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry); 4379 Entry = Entry->Flink; 4380 if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen) 4381 { 4382 RemoveEntryList(&Request->ListEntry); 4383 InsertTailList(RequestsListHead, &Request->ListEntry); 4384 } 4385 } 4386 KeReleaseSpinLock(&SrvCall->BufferingManager.SpinLock, OldIrql); 4387 4388 /* Perform the same search in the last change list */ 4389 Entry = SrvCall->BufferingManager.LastChanceHandlerList.Flink; 4390 while (Entry != &SrvCall->BufferingManager.LastChanceHandlerList) 4391 { 4392 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry); 4393 Entry = Entry->Flink; 4394 if (Request->SrvOpenKey == SrvOpen->Key && Request->SrvOpen == SrvOpen) 4395 { 4396 RemoveEntryList(&Request->ListEntry); 4397 InsertTailList(RequestsListHead, &Request->ListEntry); 4398 } 4399 } 4400 4401 /* Discard the discarded requests */ 4402 RxpDiscardChangeBufferingStateRequests(&Discarded); 4403 } 4404 4405 /* 4406 * @implemented 4407 */ 4408 PRDBSS_DEVICE_OBJECT 4409 RxGetDeviceObjectOfInstance( 4410 PVOID Instance) 4411 { 4412 NODE_TYPE_CODE NodeType; 4413 PRDBSS_DEVICE_OBJECT DeviceObject; 4414 4415 PAGED_CODE(); 4416 4417 /* We only handle a few object types */ 4418 NodeType = NodeType(Instance); 4419 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) || 4420 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) || (NodeType == RDBSS_NTC_FOBX)); 4421 4422 /* Get the device object depending on the object */ 4423 switch (NodeType) 4424 { 4425 case RDBSS_NTC_FOBX: 4426 { 4427 PFOBX Fobx; 4428 4429 Fobx = (PFOBX)Instance; 4430 DeviceObject = Fobx->RxDeviceObject; 4431 break; 4432 } 4433 4434 case RDBSS_NTC_SRVCALL: 4435 { 4436 PSRV_CALL SrvCall; 4437 4438 SrvCall = (PSRV_CALL)Instance; 4439 DeviceObject = SrvCall->RxDeviceObject; 4440 break; 4441 } 4442 4443 case RDBSS_NTC_NETROOT: 4444 { 4445 PNET_ROOT NetRoot; 4446 4447 NetRoot = (PNET_ROOT)Instance; 4448 DeviceObject = NetRoot->pSrvCall->RxDeviceObject; 4449 break; 4450 } 4451 4452 case RDBSS_NTC_V_NETROOT: 4453 { 4454 PV_NET_ROOT VNetRoot; 4455 4456 VNetRoot = (PV_NET_ROOT)Instance; 4457 DeviceObject = VNetRoot->pNetRoot->pSrvCall->RxDeviceObject; 4458 break; 4459 } 4460 4461 case RDBSS_NTC_SRVOPEN: 4462 { 4463 PSRV_OPEN SrvOpen; 4464 4465 SrvOpen = (PSRV_OPEN)Instance; 4466 DeviceObject = ((PFCB)SrvOpen->pFcb)->RxDeviceObject; 4467 break; 4468 } 4469 4470 default: 4471 DeviceObject = NULL; 4472 break; 4473 } 4474 4475 /* Job done */ 4476 return DeviceObject; 4477 } 4478 4479 /* 4480 * @implemented 4481 */ 4482 VOID 4483 RxGetFileSizeWithLock( 4484 IN PFCB Fcb, 4485 OUT PLONGLONG FileSize) 4486 { 4487 PAGED_CODE(); 4488 4489 *FileSize = Fcb->Header.FileSize.QuadPart; 4490 } 4491 4492 /* 4493 * @implemented 4494 */ 4495 PEPROCESS 4496 NTAPI 4497 RxGetRDBSSProcess( 4498 VOID) 4499 { 4500 return RxData.OurProcess; 4501 } 4502 4503 /* 4504 * @implemented 4505 */ 4506 NTSTATUS 4507 RxInitializeBufferingManager( 4508 PSRV_CALL SrvCall) 4509 { 4510 KeInitializeSpinLock(&SrvCall->BufferingManager.SpinLock); 4511 InitializeListHead(&SrvCall->BufferingManager.DispatcherList); 4512 InitializeListHead(&SrvCall->BufferingManager.HandlerList); 4513 InitializeListHead(&SrvCall->BufferingManager.LastChanceHandlerList); 4514 SrvCall->BufferingManager.DispatcherActive = FALSE; 4515 SrvCall->BufferingManager.HandlerInactive = FALSE; 4516 SrvCall->BufferingManager.LastChanceHandlerActive = FALSE; 4517 SrvCall->BufferingManager.NumberOfOutstandingOpens = 0; 4518 InitializeListHead(&SrvCall->BufferingManager.SrvOpenLists[0]); 4519 ExInitializeFastMutex(&SrvCall->BufferingManager.Mutex); 4520 4521 return STATUS_SUCCESS; 4522 } 4523 4524 /* 4525 * @implemented 4526 */ 4527 VOID 4528 NTAPI 4529 RxInitializeContext( 4530 IN PIRP Irp, 4531 IN PRDBSS_DEVICE_OBJECT RxDeviceObject, 4532 IN ULONG InitialContextFlags, 4533 IN OUT PRX_CONTEXT RxContext) 4534 { 4535 PIO_STACK_LOCATION Stack; 4536 4537 /* Initialize our various fields */ 4538 RxContext->NodeTypeCode = RDBSS_NTC_RX_CONTEXT; 4539 RxContext->NodeByteSize = sizeof(RX_CONTEXT); 4540 RxContext->ReferenceCount = 1; 4541 RxContext->SerialNumber = InterlockedExchangeAdd((volatile LONG *)&RxContextSerialNumberCounter, 1); 4542 RxContext->RxDeviceObject = RxDeviceObject; 4543 KeInitializeEvent(&RxContext->SyncEvent, SynchronizationEvent, FALSE); 4544 RxInitializeScavengerEntry(&RxContext->ScavengerEntry); 4545 InitializeListHead(&RxContext->BlockedOperations); 4546 RxContext->MRxCancelRoutine = NULL; 4547 RxContext->ResumeRoutine = NULL; 4548 RxContext->Flags |= InitialContextFlags; 4549 RxContext->CurrentIrp = Irp; 4550 RxContext->LastExecutionThread = PsGetCurrentThread(); 4551 RxContext->OriginalThread = RxContext->LastExecutionThread; 4552 4553 /* If've got no IRP, mark RX_CONTEXT */ 4554 if (Irp == NULL) 4555 { 4556 RxContext->CurrentIrpSp = NULL; 4557 RxContext->MajorFunction = IRP_MJ_MAXIMUM_FUNCTION + 1; 4558 RxContext->MinorFunction = 0; 4559 } 4560 else 4561 { 4562 /* Otherwise, first determine whether we are performing async operation */ 4563 Stack = IoGetCurrentIrpStackLocation(Irp); 4564 if (Stack->FileObject != NULL) 4565 { 4566 PFCB Fcb; 4567 4568 Fcb = Stack->FileObject->FsContext; 4569 if (!IoIsOperationSynchronous(Irp) || 4570 ((Fcb != NULL && NodeTypeIsFcb(Fcb)) && 4571 (Stack->MajorFunction == IRP_MJ_READ || Stack->MajorFunction == IRP_MJ_WRITE || Stack->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) && 4572 (Fcb->pNetRoot != NULL && (Fcb->pNetRoot->Type == NET_ROOT_PIPE)))) 4573 { 4574 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION; 4575 } 4576 } 4577 4578 if (Stack->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && Stack->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY) 4579 { 4580 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION; 4581 } 4582 if (Stack->MajorFunction == IRP_MJ_DEVICE_CONTROL) 4583 { 4584 RxContext->Flags |= RX_CONTEXT_FLAG_ASYNC_OPERATION; 4585 } 4586 4587 /* Set proper flags if TopLevl IRP/Device */ 4588 if (!RxIsThisTheTopLevelIrp(Irp)) 4589 { 4590 RxContext->Flags |= RX_CONTEXT_FLAG_RECURSIVE_CALL; 4591 } 4592 if (RxGetTopDeviceObjectIfRdbssIrp() == RxDeviceObject) 4593 { 4594 RxContext->Flags |= RX_CONTEXT_FLAG_THIS_DEVICE_TOP_LEVEL; 4595 } 4596 4597 /* Copy stack information */ 4598 RxContext->MajorFunction = Stack->MajorFunction; 4599 RxContext->MinorFunction = Stack->MinorFunction; 4600 ASSERT(RxContext->MajorFunction <= IRP_MJ_MAXIMUM_FUNCTION); 4601 RxContext->CurrentIrpSp = Stack; 4602 4603 /* If we have a FO associated, learn for more */ 4604 if (Stack->FileObject != NULL) 4605 { 4606 PFCB Fcb; 4607 PFOBX Fobx; 4608 4609 /* Get the FCB and CCB (FOBX) */ 4610 Fcb = Stack->FileObject->FsContext; 4611 Fobx = Stack->FileObject->FsContext2; 4612 RxContext->pFcb = (PMRX_FCB)Fcb; 4613 if (Fcb != NULL && NodeTypeIsFcb(Fcb)) 4614 { 4615 RxContext->NonPagedFcb = Fcb->NonPaged; 4616 } 4617 4618 /* We have a FOBX, this not a DFS opening, keep track of it */ 4619 if (Fobx != NULL && Fobx != UIntToPtr(DFS_OPEN_CONTEXT) && Fobx != UIntToPtr(DFS_DOWNLEVEL_OPEN_CONTEXT)) 4620 { 4621 RxContext->pFobx = (PMRX_FOBX)Fobx; 4622 RxContext->pRelevantSrvOpen = Fobx->pSrvOpen; 4623 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX) 4624 { 4625 RxContext->FobxSerialNumber = InterlockedIncrement((volatile LONG *)&Fobx->FobxSerialNumber); 4626 } 4627 } 4628 else 4629 { 4630 RxContext->pFobx = NULL; 4631 } 4632 4633 /* In case of directory change notification, Fobx may be a VNetRoot, take note of that */ 4634 if (RxContext->MajorFunction == IRP_MJ_DIRECTORY_CONTROL && RxContext->MinorFunction == IRP_MN_NOTIFY_CHANGE_DIRECTORY && 4635 Fobx != NULL) 4636 { 4637 PV_NET_ROOT VNetRoot = NULL; 4638 4639 if (Fobx->NodeTypeCode == RDBSS_NTC_FOBX) 4640 { 4641 VNetRoot = Fcb->VNetRoot; 4642 } 4643 else if (Fobx->NodeTypeCode == RDBSS_NTC_V_NETROOT) 4644 { 4645 VNetRoot = (PV_NET_ROOT)Fobx; 4646 } 4647 4648 if (VNetRoot != NULL) 4649 { 4650 RxContext->NotifyChangeDirectory.pVNetRoot = (PMRX_V_NET_ROOT)VNetRoot; 4651 } 4652 } 4653 4654 /* Remember if that's a write through file */ 4655 RxContext->RealDevice = Stack->FileObject->DeviceObject; 4656 if (BooleanFlagOn(Stack->FileObject->Flags, FO_WRITE_THROUGH)) 4657 { 4658 RxContext->Flags |= RX_CONTEXT_FLAG_WRITE_THROUGH; 4659 } 4660 } 4661 } 4662 4663 if (RxContext->MajorFunction != IRP_MJ_DEVICE_CONTROL) 4664 { 4665 DPRINT("New Ctxt: %p for MN: %d, IRP: %p, THRD: %p, FCB: %p, FOBX:%p #%lx\n", 4666 RxContext, RxContext->MinorFunction, Irp, 4667 PsGetCurrentThread(), RxContext->pFcb, RxContext->pFobx, 4668 RxContext->SerialNumber); 4669 } 4670 } 4671 4672 /* 4673 * @implemented 4674 */ 4675 VOID 4676 NTAPI 4677 RxInitializeDebugSupport( 4678 VOID) 4679 { 4680 /* Nothing to do */ 4681 } 4682 4683 /* 4684 * @implemented 4685 */ 4686 NTSTATUS 4687 NTAPI 4688 RxInitializeDispatcher( 4689 VOID) 4690 { 4691 NTSTATUS Status; 4692 HANDLE ThreadHandle; 4693 4694 PAGED_CODE(); 4695 4696 RxFileSystemDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0; 4697 RxFileSystemDeviceObject->DispatcherContext.pTearDownEvent = NULL; 4698 4699 /* Set appropriate timeouts: 10s & 60s */ 4700 RxWorkQueueWaitInterval[CriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10; 4701 RxWorkQueueWaitInterval[DelayedWorkQueue].QuadPart = -10 * 1000 * 1000 * 10; 4702 RxWorkQueueWaitInterval[HyperCriticalWorkQueue].QuadPart = -10 * 1000 * 1000 * 10; 4703 RxSpinUpDispatcherWaitInterval.QuadPart = -60 * 1000 * 1000 * 10; 4704 4705 RxDispatcher.NumberOfProcessors = 1; 4706 RxDispatcher.OwnerProcess = IoGetCurrentProcess(); 4707 RxDispatcher.pWorkQueueDispatcher = &RxDispatcherWorkQueues; 4708 4709 /* Initialize our dispatchers */ 4710 Status = RxInitializeWorkQueueDispatcher(RxDispatcher.pWorkQueueDispatcher); 4711 if (!NT_SUCCESS(Status)) 4712 { 4713 return Status; 4714 } 4715 4716 Status = RxInitializeMRxDispatcher(RxFileSystemDeviceObject); 4717 if (!NT_SUCCESS(Status)) 4718 { 4719 return Status; 4720 } 4721 4722 /* And start them */ 4723 RxDispatcher.State = RxDispatcherActive; 4724 InitializeListHead(&RxDispatcher.SpinUpRequests); 4725 KeInitializeSpinLock(&RxDispatcher.SpinUpRequestsLock); 4726 KeInitializeEvent(&RxDispatcher.SpinUpRequestsEvent, 0, 0); 4727 KeInitializeEvent(&RxDispatcher.SpinUpRequestsTearDownEvent, 0, 0); 4728 Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL, 4729 NULL, NULL, RxSpinUpRequestsDispatcher, &RxDispatcher); 4730 if (NT_SUCCESS(Status)) 4731 { 4732 ZwClose(ThreadHandle); 4733 } 4734 4735 return Status; 4736 } 4737 4738 /* 4739 * @implemented 4740 */ 4741 VOID 4742 RxInitializeFcbTable( 4743 IN OUT PRX_FCB_TABLE FcbTable, 4744 IN BOOLEAN CaseInsensitiveMatch) 4745 { 4746 USHORT i; 4747 4748 PAGED_CODE(); 4749 4750 FcbTable->NodeTypeCode = RDBSS_NTC_FCB_TABLE; 4751 FcbTable->NodeByteSize = sizeof(RX_FCB_TABLE); 4752 4753 ExInitializeResourceLite(&FcbTable->TableLock); 4754 FcbTable->CaseInsensitiveMatch = CaseInsensitiveMatch; 4755 FcbTable->Version = 0; 4756 FcbTable->TableEntryForNull = NULL; 4757 4758 FcbTable->NumberOfBuckets = RX_FCB_TABLE_NUMBER_OF_HASH_BUCKETS; 4759 for (i = 0; i < FcbTable->NumberOfBuckets; ++i) 4760 { 4761 InitializeListHead(&FcbTable->HashBuckets[i]); 4762 } 4763 4764 FcbTable->Lookups = 0; 4765 FcbTable->FailedLookups = 0; 4766 FcbTable->Compares = 0; 4767 } 4768 4769 /* 4770 * @implemented 4771 */ 4772 VOID 4773 NTAPI 4774 RxInitializeLowIoContext( 4775 OUT PLOWIO_CONTEXT LowIoContext, 4776 IN ULONG Operation) 4777 { 4778 PRX_CONTEXT RxContext; 4779 PIO_STACK_LOCATION Stack; 4780 4781 PAGED_CODE(); 4782 4783 RxContext = CONTAINING_RECORD(LowIoContext, RX_CONTEXT, LowIoContext); 4784 ASSERT(LowIoContext == &RxContext->LowIoContext); 4785 4786 Stack = RxContext->CurrentIrpSp; 4787 4788 KeInitializeEvent(&RxContext->SyncEvent, NotificationEvent, FALSE); 4789 RxContext->LowIoContext.ResourceThreadId = (ERESOURCE_THREAD)PsGetCurrentThread(); 4790 RxContext->LowIoContext.Operation = Operation; 4791 4792 switch (Operation) 4793 { 4794 case LOWIO_OP_READ: 4795 case LOWIO_OP_WRITE: 4796 /* In case of RW, set a canary, to make sure these fields are properly set 4797 * they will be asserted when lowio request will be submit to mini-rdr 4798 * See LowIoSubmit() 4799 */ 4800 RxContext->LowIoContext.ParamsFor.ReadWrite.ByteOffset = 0xFFFFFFEE; 4801 RxContext->LowIoContext.ParamsFor.ReadWrite.ByteCount = 0xEEEEEEEE; 4802 RxContext->LowIoContext.ParamsFor.ReadWrite.Key = Stack->Parameters.Read.Key; 4803 4804 /* Keep track of paging IOs */ 4805 if (BooleanFlagOn(RxContext->CurrentIrp->Flags, IRP_PAGING_IO)) 4806 { 4807 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = LOWIO_READWRITEFLAG_PAGING_IO; 4808 } 4809 else 4810 { 4811 RxContext->LowIoContext.ParamsFor.ReadWrite.Flags = 0; 4812 } 4813 4814 break; 4815 4816 case LOWIO_OP_FSCTL: 4817 case LOWIO_OP_IOCTL: 4818 /* This will be initialized later on with a call to RxLowIoPopulateFsctlInfo() */ 4819 RxContext->LowIoContext.ParamsFor.FsCtl.Flags = 0; 4820 RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = 0; 4821 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = NULL; 4822 RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = 0; 4823 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL; 4824 RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = 0; 4825 break; 4826 4827 /* Nothing to do for these */ 4828 case LOWIO_OP_SHAREDLOCK: 4829 case LOWIO_OP_EXCLUSIVELOCK: 4830 case LOWIO_OP_UNLOCK: 4831 case LOWIO_OP_UNLOCK_MULTIPLE: 4832 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY: 4833 case LOWIO_OP_CLEAROUT: 4834 break; 4835 4836 default: 4837 /* Should never happen */ 4838 ASSERT(FALSE); 4839 break; 4840 } 4841 } 4842 4843 /* 4844 * @implemented 4845 */ 4846 VOID 4847 RxInitializeLowIoPerFcbInfo( 4848 PLOWIO_PER_FCB_INFO LowIoPerFcbInfo) 4849 { 4850 PAGED_CODE(); 4851 4852 InitializeListHead(&LowIoPerFcbInfo->PagingIoReadsOutstanding); 4853 InitializeListHead(&LowIoPerFcbInfo->PagingIoWritesOutstanding); 4854 } 4855 4856 /* 4857 * @implemented 4858 */ 4859 NTSTATUS 4860 RxInitializeMRxDispatcher( 4861 IN OUT PRDBSS_DEVICE_OBJECT pMRxDeviceObject) 4862 { 4863 PAGED_CODE(); 4864 4865 pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads = 0; 4866 pMRxDeviceObject->DispatcherContext.pTearDownEvent = NULL; 4867 4868 return STATUS_SUCCESS; 4869 } 4870 4871 /* 4872 * @implemented 4873 */ 4874 VOID 4875 RxInitializePrefixTable( 4876 IN OUT PRX_PREFIX_TABLE ThisTable, 4877 IN ULONG TableSize OPTIONAL, 4878 IN BOOLEAN CaseInsensitiveMatch) 4879 { 4880 PAGED_CODE(); 4881 4882 if (TableSize == 0) 4883 { 4884 TableSize = RX_PREFIX_TABLE_DEFAULT_LENGTH; 4885 } 4886 4887 ThisTable->NodeTypeCode = RDBSS_NTC_PREFIX_TABLE; 4888 ThisTable->NodeByteSize = sizeof(RX_PREFIX_TABLE); 4889 InitializeListHead(&ThisTable->MemberQueue); 4890 ThisTable->Version = 0; 4891 ThisTable->TableEntryForNull = NULL; 4892 ThisTable->IsNetNameTable = FALSE; 4893 ThisTable->CaseInsensitiveMatch = CaseInsensitiveMatch; 4894 ThisTable->TableSize = TableSize; 4895 4896 if (TableSize > 0) 4897 { 4898 USHORT i; 4899 4900 for (i = 0; i < RX_PREFIX_TABLE_DEFAULT_LENGTH; ++i) 4901 { 4902 InitializeListHead(&ThisTable->HashBuckets[i]); 4903 } 4904 } 4905 } 4906 4907 /* 4908 * @implemented 4909 */ 4910 VOID 4911 RxInitializePurgeSyncronizationContext( 4912 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncronizationContext) 4913 { 4914 PAGED_CODE(); 4915 4916 InitializeListHead(&PurgeSyncronizationContext->ContextsAwaitingPurgeCompletion); 4917 PurgeSyncronizationContext->PurgeInProgress = FALSE; 4918 } 4919 4920 NTSTATUS 4921 RxInitializeSrvCallParameters( 4922 IN PRX_CONTEXT RxContext, 4923 IN OUT PSRV_CALL SrvCall) 4924 { 4925 PAGED_CODE(); 4926 4927 SrvCall->pPrincipalName = NULL; 4928 4929 /* We only have stuff to initialize for file opening from DFS */ 4930 if (RxContext->MajorFunction != IRP_MJ_CREATE || RxContext->Create.EaLength == 0) 4931 { 4932 return STATUS_SUCCESS; 4933 } 4934 4935 ASSERT(RxContext->Create.EaBuffer != NULL); 4936 4937 UNIMPLEMENTED; 4938 return STATUS_NOT_IMPLEMENTED; 4939 } 4940 4941 /* 4942 * @implemented 4943 */ 4944 NTSTATUS 4945 NTAPI 4946 RxInitializeRxTimer( 4947 VOID) 4948 { 4949 PAGED_CODE(); 4950 4951 RxTimerInterval.QuadPart = -550000; 4952 KeInitializeSpinLock(&RxTimerLock); 4953 InitializeListHead(&RxTimerQueueHead); 4954 InitializeListHead(&RxRecurrentWorkItemsList); 4955 KeInitializeDpc(&RxTimerDpc, RxTimerDispatch, NULL); 4956 KeInitializeTimer(&RxTimer); 4957 RxTimerTickCount = 0; 4958 4959 return STATUS_SUCCESS; 4960 } 4961 4962 NTSTATUS 4963 RxInitializeVNetRootParameters( 4964 PRX_CONTEXT RxContext, 4965 OUT LUID *LogonId, 4966 OUT PULONG SessionId, 4967 OUT PUNICODE_STRING *UserNamePtr, 4968 OUT PUNICODE_STRING *UserDomainNamePtr, 4969 OUT PUNICODE_STRING *PasswordPtr, 4970 OUT PULONG Flags) 4971 { 4972 NTSTATUS Status; 4973 PACCESS_TOKEN Token; 4974 4975 PAGED_CODE(); 4976 4977 DPRINT("RxInitializeVNetRootParameters(%p, %p, %p, %p, %p, %p, %p)\n", RxContext, 4978 LogonId, SessionId, UserNamePtr, UserDomainNamePtr, PasswordPtr, Flags); 4979 4980 *UserNamePtr = NULL; 4981 *UserDomainNamePtr = NULL; 4982 *PasswordPtr = NULL; 4983 /* By default, that's not CSC instance */ 4984 *Flags &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE; 4985 4986 Token = SeQuerySubjectContextToken(&RxContext->Create.NtCreateParameters.SecurityContext->AccessState->SubjectSecurityContext); 4987 if (SeTokenIsRestricted(Token)) 4988 { 4989 return STATUS_ACCESS_DENIED; 4990 } 4991 4992 /* Get LogonId */ 4993 Status = SeQueryAuthenticationIdToken(Token, LogonId); 4994 if (!NT_SUCCESS(Status)) 4995 { 4996 return Status; 4997 } 4998 4999 /* And SessionId */ 5000 Status = SeQuerySessionIdToken(Token, SessionId); 5001 if (!NT_SUCCESS(Status)) 5002 { 5003 return Status; 5004 } 5005 5006 if (RxContext->Create.UserName.Buffer != NULL) 5007 { 5008 UNIMPLEMENTED; 5009 Status = STATUS_NOT_IMPLEMENTED; 5010 goto Leave; 5011 } 5012 5013 /* Deal with connection credentials */ 5014 if (RxContext->Create.UserDomainName.Buffer != NULL) 5015 { 5016 UNIMPLEMENTED; 5017 Status = STATUS_NOT_IMPLEMENTED; 5018 goto Leave; 5019 } 5020 5021 if (RxContext->Create.Password.Buffer != NULL) 5022 { 5023 UNIMPLEMENTED; 5024 Status = STATUS_NOT_IMPLEMENTED; 5025 goto Leave; 5026 } 5027 5028 Leave: 5029 if (NT_SUCCESS(Status)) 5030 { 5031 /* If that's a CSC instance, mark it as such */ 5032 if (RxIsThisACscAgentOpen(RxContext)) 5033 { 5034 *Flags |= VNETROOT_FLAG_CSCAGENT_INSTANCE; 5035 } 5036 return Status; 5037 } 5038 5039 return Status; 5040 } 5041 5042 /* 5043 * @implemented 5044 */ 5045 VOID 5046 RxInitializeWorkQueue( 5047 PRX_WORK_QUEUE WorkQueue, 5048 WORK_QUEUE_TYPE WorkQueueType, 5049 ULONG MaximumNumberOfWorkerThreads, 5050 ULONG MinimumNumberOfWorkerThreads) 5051 { 5052 PAGED_CODE(); 5053 5054 WorkQueue->Type = WorkQueueType; 5055 WorkQueue->MaximumNumberOfWorkerThreads = MaximumNumberOfWorkerThreads; 5056 WorkQueue->MinimumNumberOfWorkerThreads = MinimumNumberOfWorkerThreads; 5057 5058 WorkQueue->State = RxWorkQueueActive; 5059 WorkQueue->SpinUpRequestPending = FALSE; 5060 WorkQueue->pRundownContext = NULL; 5061 WorkQueue->NumberOfWorkItemsDispatched = 0; 5062 WorkQueue->NumberOfWorkItemsToBeDispatched = 0; 5063 WorkQueue->CumulativeQueueLength = 0; 5064 WorkQueue->NumberOfSpinUpRequests = 0; 5065 WorkQueue->NumberOfActiveWorkerThreads = 0; 5066 WorkQueue->NumberOfIdleWorkerThreads = 0; 5067 WorkQueue->NumberOfFailedSpinUpRequests = 0; 5068 WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse = 0; 5069 WorkQueue->WorkQueueItemForTearDownWorkQueue.List.Flink = NULL; 5070 WorkQueue->WorkQueueItemForTearDownWorkQueue.WorkerRoutine = NULL; 5071 WorkQueue->WorkQueueItemForTearDownWorkQueue.Parameter = NULL; 5072 WorkQueue->WorkQueueItemForTearDownWorkQueue.pDeviceObject = NULL; 5073 WorkQueue->WorkQueueItemForSpinUpWorkerThread.List.Flink = NULL; 5074 WorkQueue->WorkQueueItemForSpinUpWorkerThread.WorkerRoutine = NULL; 5075 WorkQueue->WorkQueueItemForSpinUpWorkerThread.Parameter = NULL; 5076 WorkQueue->WorkQueueItemForSpinUpWorkerThread.pDeviceObject = NULL; 5077 WorkQueue->WorkQueueItemForSpinDownWorkerThread.List.Flink = NULL; 5078 WorkQueue->WorkQueueItemForSpinDownWorkerThread.WorkerRoutine = NULL; 5079 WorkQueue->WorkQueueItemForSpinDownWorkerThread.Parameter = NULL; 5080 WorkQueue->WorkQueueItemForSpinDownWorkerThread.pDeviceObject = NULL; 5081 5082 KeInitializeQueue(&WorkQueue->Queue, MaximumNumberOfWorkerThreads); 5083 KeInitializeSpinLock(&WorkQueue->SpinLock); 5084 } 5085 5086 /* 5087 * @implemented 5088 */ 5089 NTSTATUS 5090 RxInitializeWorkQueueDispatcher( 5091 PRX_WORK_QUEUE_DISPATCHER Dispatcher) 5092 { 5093 NTSTATUS Status; 5094 ULONG MaximumNumberOfWorkerThreads; 5095 5096 PAGED_CODE(); 5097 5098 /* Number of threads will depend on system capacity */ 5099 if (MmQuerySystemSize() != MmLargeSystem) 5100 { 5101 MaximumNumberOfWorkerThreads = 5; 5102 } 5103 else 5104 { 5105 MaximumNumberOfWorkerThreads = 10; 5106 } 5107 5108 /* Initialize the work queues */ 5109 RxInitializeWorkQueue(&Dispatcher->WorkQueue[CriticalWorkQueue], CriticalWorkQueue, 5110 MaximumNumberOfWorkerThreads, 1); 5111 RxInitializeWorkQueue(&Dispatcher->WorkQueue[DelayedWorkQueue], DelayedWorkQueue, 2, 1); 5112 RxInitializeWorkQueue(&Dispatcher->WorkQueue[HyperCriticalWorkQueue], HyperCriticalWorkQueue, 5, 1); 5113 5114 /* And start the worker threads */ 5115 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[HyperCriticalWorkQueue], 5116 RxBootstrapWorkerThreadDispatcher, 5117 &Dispatcher->WorkQueue[HyperCriticalWorkQueue]); 5118 if (!NT_SUCCESS(Status)) 5119 { 5120 return Status; 5121 } 5122 5123 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[CriticalWorkQueue], 5124 RxBootstrapWorkerThreadDispatcher, 5125 &Dispatcher->WorkQueue[CriticalWorkQueue]); 5126 if (!NT_SUCCESS(Status)) 5127 { 5128 return Status; 5129 } 5130 5131 Status = RxSpinUpWorkerThread(&Dispatcher->WorkQueue[DelayedWorkQueue], 5132 RxBootstrapWorkerThreadDispatcher, 5133 &Dispatcher->WorkQueue[DelayedWorkQueue]); 5134 return Status; 5135 } 5136 5137 /* 5138 * @implemented 5139 */ 5140 VOID 5141 RxInitiateSrvOpenKeyAssociation( 5142 IN OUT PSRV_OPEN SrvOpen) 5143 { 5144 PRX_BUFFERING_MANAGER BufferingManager; 5145 5146 PAGED_CODE(); 5147 5148 SrvOpen->Key = NULL; 5149 5150 /* Just keep track of the opening request */ 5151 BufferingManager = &((PSRV_CALL)((PFCB)SrvOpen->pFcb)->VNetRoot->pNetRoot->pSrvCall)->BufferingManager; 5152 InterlockedIncrement(&BufferingManager->NumberOfOutstandingOpens); 5153 5154 InitializeListHead(&SrvOpen->SrvOpenKeyList); 5155 } 5156 5157 /* 5158 * @implemented 5159 */ 5160 NTSTATUS 5161 RxInsertWorkQueueItem( 5162 PRDBSS_DEVICE_OBJECT pMRxDeviceObject, 5163 WORK_QUEUE_TYPE WorkQueueType, 5164 PRX_WORK_QUEUE_ITEM WorkQueueItem) 5165 { 5166 KIRQL OldIrql; 5167 NTSTATUS Status; 5168 BOOLEAN SpinUpThreads; 5169 PRX_WORK_QUEUE WorkQueue; 5170 5171 /* No dispatcher, nothing to insert */ 5172 if (RxDispatcher.State != RxDispatcherActive) 5173 { 5174 return STATUS_UNSUCCESSFUL; 5175 } 5176 5177 /* Get the work queue */ 5178 WorkQueue = &RxDispatcher.pWorkQueueDispatcher->WorkQueue[WorkQueueType]; 5179 5180 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql); 5181 /* Only insert if the work queue is in decent state */ 5182 if (WorkQueue->State != RxWorkQueueActive || pMRxDeviceObject->DispatcherContext.pTearDownEvent != NULL) 5183 { 5184 Status = STATUS_UNSUCCESSFUL; 5185 } 5186 else 5187 { 5188 SpinUpThreads = FALSE; 5189 WorkQueueItem->pDeviceObject = pMRxDeviceObject; 5190 InterlockedIncrement(&pMRxDeviceObject->DispatcherContext.NumberOfWorkerThreads); 5191 WorkQueue->CumulativeQueueLength += WorkQueue->NumberOfWorkItemsToBeDispatched; 5192 InterlockedIncrement(&WorkQueue->NumberOfWorkItemsToBeDispatched); 5193 5194 /* If required (and possible!), spin up a new worker thread */ 5195 if (WorkQueue->NumberOfIdleWorkerThreads < WorkQueue->NumberOfWorkItemsToBeDispatched && 5196 WorkQueue->NumberOfActiveWorkerThreads < WorkQueue->MaximumNumberOfWorkerThreads && 5197 !WorkQueue->SpinUpRequestPending) 5198 { 5199 WorkQueue->SpinUpRequestPending = TRUE; 5200 SpinUpThreads = TRUE; 5201 } 5202 5203 Status = STATUS_SUCCESS; 5204 } 5205 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql); 5206 5207 /* If we failed, return and still not insert item */ 5208 if (!NT_SUCCESS(Status)) 5209 { 5210 return Status; 5211 } 5212 5213 /* All fine, insert the item */ 5214 KeInsertQueue(&WorkQueue->Queue, &WorkQueueItem->List); 5215 5216 /* And start a new worker thread if needed */ 5217 if (SpinUpThreads) 5218 { 5219 RxSpinUpWorkerThreads(WorkQueue); 5220 } 5221 5222 return Status; 5223 } 5224 5225 BOOLEAN 5226 RxIsThisACscAgentOpen( 5227 IN PRX_CONTEXT RxContext) 5228 { 5229 BOOLEAN CscAgent; 5230 5231 CscAgent = FALSE; 5232 5233 /* Client Side Caching is DFS stuff - we don't support it */ 5234 if (RxContext->Create.EaLength != 0) 5235 { 5236 UNIMPLEMENTED; 5237 } 5238 5239 if (RxContext->Create.NtCreateParameters.DfsNameContext != NULL && 5240 ((PDFS_NAME_CONTEXT)RxContext->Create.NtCreateParameters.DfsNameContext)->NameContextType == 0xAAAAAAAA) 5241 { 5242 CscAgent = TRUE; 5243 } 5244 5245 return CscAgent; 5246 } 5247 5248 VOID 5249 RxLockUserBuffer( 5250 IN PRX_CONTEXT RxContext, 5251 IN LOCK_OPERATION Operation, 5252 IN ULONG BufferLength) 5253 { 5254 PIRP Irp; 5255 PMDL Mdl = NULL; 5256 5257 PAGED_CODE(); 5258 5259 _SEH2_TRY 5260 { 5261 Irp = RxContext->CurrentIrp; 5262 /* If we already have a MDL, make sure it's locked */ 5263 if (Irp->MdlAddress != NULL) 5264 { 5265 ASSERT(RxLowIoIsMdlLocked(Irp->MdlAddress)); 5266 } 5267 else 5268 { 5269 /* That likely means the driver asks for buffered IOs - we don't support it! */ 5270 ASSERT(!BooleanFlagOn(Irp->Flags, IRP_INPUT_OPERATION)); 5271 5272 /* If we have a real length */ 5273 if (BufferLength > 0) 5274 { 5275 /* Allocate a MDL and lock it */ 5276 Mdl = IoAllocateMdl(Irp->UserBuffer, BufferLength, FALSE, FALSE, Irp); 5277 if (Mdl == NULL) 5278 { 5279 RxContext->StoredStatus = STATUS_INSUFFICIENT_RESOURCES; 5280 ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES); 5281 } 5282 5283 MmProbeAndLockPages(Mdl, Irp->RequestorMode, Operation); 5284 } 5285 } 5286 } 5287 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 5288 { 5289 NTSTATUS Status; 5290 5291 Status = _SEH2_GetExceptionCode(); 5292 5293 /* Free the possible MDL we have allocated */ 5294 IoFreeMdl(Mdl); 5295 Irp->MdlAddress = NULL; 5296 5297 RxContext->Flags |= RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT; 5298 5299 /* Fix status */ 5300 if (!FsRtlIsNtstatusExpected(Status)) 5301 { 5302 Status = STATUS_INVALID_USER_BUFFER; 5303 } 5304 5305 RxContext->IoStatusBlock.Status = Status; 5306 ExRaiseStatus(Status); 5307 } 5308 _SEH2_END; 5309 } 5310 5311 /* 5312 * @implemented 5313 */ 5314 NTSTATUS 5315 RxLowIoCompletionTail( 5316 IN PRX_CONTEXT RxContext) 5317 { 5318 NTSTATUS Status; 5319 USHORT Operation; 5320 5321 PAGED_CODE(); 5322 5323 DPRINT("RxLowIoCompletionTail(%p)\n", RxContext); 5324 5325 /* Only continue if we're at APC_LEVEL or lower */ 5326 if (RxShouldPostCompletion() && 5327 !BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_CAN_COMPLETE_AT_DPC_LEVEL)) 5328 { 5329 return STATUS_MORE_PROCESSING_REQUIRED; 5330 } 5331 5332 /* Call the completion routine */ 5333 DPRINT("Calling completion routine: %p\n", RxContext->LowIoContext.CompletionRoutine); 5334 Status = RxContext->LowIoContext.CompletionRoutine(RxContext); 5335 if (Status == STATUS_MORE_PROCESSING_REQUIRED || Status == STATUS_RETRY) 5336 { 5337 return Status; 5338 } 5339 5340 /* If it was a RW operation, for a paging file ... */ 5341 Operation = RxContext->LowIoContext.Operation; 5342 if (Operation == LOWIO_OP_READ || Operation == LOWIO_OP_WRITE) 5343 { 5344 /* Remove ourselves from the list and resume operations */ 5345 if (BooleanFlagOn(RxContext->LowIoContext.ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO)) 5346 { 5347 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex); 5348 RemoveEntryList(&RxContext->RxContextSerializationQLinks); 5349 RxContext->RxContextSerializationQLinks.Flink = NULL; 5350 RxContext->RxContextSerializationQLinks.Blink = NULL; 5351 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex); 5352 RxResumeBlockedOperations_ALL(RxContext); 5353 } 5354 } 5355 else 5356 { 5357 /* Sanity check: we had known operation */ 5358 ASSERT(Operation < LOWIO_OP_MAXIMUM); 5359 } 5360 5361 /* If not sync operation, complete now. Otherwise, caller has already completed */ 5362 if (!BooleanFlagOn(RxContext->LowIoContext.Flags, LOWIO_CONTEXT_FLAG_SYNCCALL)) 5363 { 5364 RxCompleteRequest(RxContext, Status); 5365 } 5366 5367 DPRINT("Status: %x\n", Status); 5368 return Status; 5369 } 5370 5371 /* 5372 * @implemented 5373 */ 5374 NTSTATUS 5375 NTAPI 5376 RxLowIoPopulateFsctlInfo( 5377 IN PRX_CONTEXT RxContext) 5378 { 5379 PMDL Mdl; 5380 PIRP Irp; 5381 UCHAR Method; 5382 PIO_STACK_LOCATION Stack; 5383 5384 PAGED_CODE(); 5385 5386 DPRINT("RxLowIoPopulateFsctlInfo(%p)\n", RxContext); 5387 5388 Irp = RxContext->CurrentIrp; 5389 Stack = RxContext->CurrentIrpSp; 5390 5391 /* Copy stack parameters */ 5392 RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode = Stack->Parameters.FileSystemControl.FsControlCode; 5393 RxContext->LowIoContext.ParamsFor.FsCtl.InputBufferLength = Stack->Parameters.FileSystemControl.InputBufferLength; 5394 RxContext->LowIoContext.ParamsFor.FsCtl.OutputBufferLength = Stack->Parameters.FileSystemControl.OutputBufferLength; 5395 RxContext->LowIoContext.ParamsFor.FsCtl.MinorFunction = Stack->MinorFunction; 5396 Method = METHOD_FROM_CTL_CODE(RxContext->LowIoContext.ParamsFor.FsCtl.FsControlCode); 5397 5398 /* Same buffer in case of buffered */ 5399 if (Method == METHOD_BUFFERED) 5400 { 5401 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer; 5402 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->AssociatedIrp.SystemBuffer; 5403 5404 return STATUS_SUCCESS; 5405 } 5406 5407 /* Two buffers for neither */ 5408 if (Method == METHOD_NEITHER) 5409 { 5410 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Stack->Parameters.FileSystemControl.Type3InputBuffer; 5411 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = Irp->UserBuffer; 5412 5413 return STATUS_SUCCESS; 5414 } 5415 5416 /* Only IN/OUT remain */ 5417 ASSERT(Method == METHOD_IN_DIRECT || Method == METHOD_OUT_DIRECT); 5418 5419 /* Use system buffer for input */ 5420 RxContext->LowIoContext.ParamsFor.FsCtl.pInputBuffer = Irp->AssociatedIrp.SystemBuffer; 5421 /* And MDL for output */ 5422 Mdl = Irp->MdlAddress; 5423 if (Mdl != NULL) 5424 { 5425 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority); 5426 if (RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer == NULL) 5427 { 5428 return STATUS_INSUFFICIENT_RESOURCES; 5429 } 5430 } 5431 else 5432 { 5433 RxContext->LowIoContext.ParamsFor.FsCtl.pOutputBuffer = NULL; 5434 } 5435 5436 return STATUS_SUCCESS; 5437 } 5438 5439 NTSTATUS 5440 NTAPI 5441 RxLowIoSubmit( 5442 IN PRX_CONTEXT RxContext, 5443 IN PLOWIO_COMPLETION_ROUTINE CompletionRoutine) 5444 { 5445 NTSTATUS Status; 5446 USHORT Operation; 5447 BOOLEAN Synchronous; 5448 PLOWIO_CONTEXT LowIoContext; 5449 5450 DPRINT("RxLowIoSubmit(%p, %p)\n", RxContext, CompletionRoutine); 5451 5452 PAGED_CODE(); 5453 5454 LowIoContext = &RxContext->LowIoContext; 5455 Synchronous = !BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_ASYNC_OPERATION); 5456 5457 LowIoContext->CompletionRoutine = CompletionRoutine; 5458 5459 Status = STATUS_SUCCESS; 5460 Operation = LowIoContext->Operation; 5461 switch (Operation) 5462 { 5463 case LOWIO_OP_READ: 5464 case LOWIO_OP_WRITE: 5465 /* Check that the parameters were properly set by caller 5466 * See comment in RxInitializeLowIoContext() 5467 */ 5468 ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteOffset != 0xFFFFFFEE); 5469 ASSERT(LowIoContext->ParamsFor.ReadWrite.ByteCount != 0xEEEEEEEE); 5470 5471 /* Lock the buffer */ 5472 RxLockUserBuffer(RxContext, 5473 (Operation == LOWIO_OP_READ ? IoWriteAccess : IoReadAccess), 5474 LowIoContext->ParamsFor.ReadWrite.ByteCount); 5475 if (RxNewMapUserBuffer(RxContext) == NULL) 5476 { 5477 return STATUS_INSUFFICIENT_RESOURCES; 5478 } 5479 LowIoContext->ParamsFor.ReadWrite.Buffer = RxContext->CurrentIrp->MdlAddress; 5480 5481 /* If that's a paging IO, initialize serial operation */ 5482 if (BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags, LOWIO_READWRITEFLAG_PAGING_IO)) 5483 { 5484 PFCB Fcb; 5485 5486 Fcb = (PFCB)RxContext->pFcb; 5487 5488 ExAcquireFastMutexUnsafe(&RxLowIoPagingIoSyncMutex); 5489 RxContext->BlockedOpsMutex = &RxLowIoPagingIoSyncMutex; 5490 if (Operation == LOWIO_OP_READ) 5491 { 5492 InsertTailList(&Fcb->Specific.Fcb.PagingIoReadsOutstanding, &RxContext->RxContextSerializationQLinks); 5493 } 5494 else 5495 { 5496 InsertTailList(&Fcb->Specific.Fcb.PagingIoWritesOutstanding, &RxContext->RxContextSerializationQLinks); 5497 } 5498 5499 ExReleaseFastMutexUnsafe(&RxLowIoPagingIoSyncMutex); 5500 } 5501 5502 break; 5503 5504 case LOWIO_OP_FSCTL: 5505 case LOWIO_OP_IOCTL: 5506 /* Set FSCTL/IOCTL parameters */ 5507 Status = RxLowIoPopulateFsctlInfo(RxContext); 5508 /* Check whether we're consistent: a length means a buffer */ 5509 if (NT_SUCCESS(Status)) 5510 { 5511 if ((LowIoContext->ParamsFor.FsCtl.InputBufferLength > 0 && 5512 LowIoContext->ParamsFor.FsCtl.pInputBuffer == NULL) || 5513 (LowIoContext->ParamsFor.FsCtl.OutputBufferLength > 0 && 5514 LowIoContext->ParamsFor.FsCtl.pOutputBuffer == NULL)) 5515 { 5516 Status = STATUS_INVALID_PARAMETER; 5517 } 5518 } 5519 break; 5520 5521 /* Nothing to do */ 5522 case LOWIO_OP_SHAREDLOCK: 5523 case LOWIO_OP_EXCLUSIVELOCK: 5524 case LOWIO_OP_UNLOCK: 5525 case LOWIO_OP_UNLOCK_MULTIPLE: 5526 case LOWIO_OP_NOTIFY_CHANGE_DIRECTORY: 5527 case LOWIO_OP_CLEAROUT: 5528 break; 5529 5530 default: 5531 ASSERT(FALSE); 5532 Status = STATUS_INVALID_PARAMETER; 5533 break; 5534 } 5535 5536 /* No need to perform extra init in case of posting */ 5537 RxContext->Flags |= RX_CONTEXT_FLAG_NO_PREPOSTING_NEEDED; 5538 5539 /* Preflight checks were OK, time to submit */ 5540 if (NT_SUCCESS(Status)) 5541 { 5542 PMINIRDR_DISPATCH Dispatch; 5543 5544 if (!Synchronous) 5545 { 5546 InterlockedIncrement((volatile long *)&RxContext->ReferenceCount); 5547 /* If not synchronous, we're likely to return before the operation is finished */ 5548 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)) 5549 { 5550 IoMarkIrpPending(RxContext->CurrentIrp); 5551 } 5552 } 5553 5554 Dispatch = RxContext->RxDeviceObject->Dispatch; 5555 if (Dispatch != NULL) 5556 { 5557 /* We'll try to execute until the mini-rdr doesn't return pending */ 5558 do 5559 { 5560 RxContext->IoStatusBlock.Information = 0; 5561 5562 MINIRDR_CALL(Status, RxContext, Dispatch, MRxLowIOSubmit[Operation], (RxContext)); 5563 if (Status == STATUS_PENDING) 5564 { 5565 /* Unless it's not synchronous, caller will be happy with pending op */ 5566 if (!Synchronous) 5567 { 5568 return Status; 5569 } 5570 5571 RxWaitSync(RxContext); 5572 Status = RxContext->IoStatusBlock.Status; 5573 } 5574 else 5575 { 5576 if (!Synchronous) 5577 { 5578 /* We had marked the IRP pending, whereas the operation finished, drop that */ 5579 if (Status != STATUS_RETRY) 5580 { 5581 if (!BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_IN_FSP)) 5582 { 5583 RxContext->CurrentIrpSp->Flags &= ~SL_PENDING_RETURNED; 5584 } 5585 5586 InterlockedDecrement((volatile long *)&RxContext->ReferenceCount); 5587 } 5588 } 5589 } 5590 } while (Status == STATUS_PENDING); 5591 } 5592 else 5593 { 5594 Status = STATUS_INVALID_PARAMETER; 5595 } 5596 } 5597 5598 /* Call completion and return */ 5599 RxContext->IoStatusBlock.Status = Status; 5600 LowIoContext->Flags |= LOWIO_CONTEXT_FLAG_SYNCCALL; 5601 return RxLowIoCompletionTail(RxContext); 5602 } 5603 5604 /* 5605 * @implemented 5606 */ 5607 PVOID 5608 RxMapSystemBuffer( 5609 IN PRX_CONTEXT RxContext) 5610 { 5611 PIRP Irp; 5612 5613 PAGED_CODE(); 5614 5615 Irp = RxContext->CurrentIrp; 5616 /* We should have a MDL (buffered IOs are not supported!) */ 5617 if (Irp->MdlAddress != NULL) 5618 { 5619 ASSERT(FALSE); 5620 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 5621 } 5622 5623 /* Just return system buffer */ 5624 return Irp->AssociatedIrp.SystemBuffer; 5625 } 5626 5627 /* 5628 * @implemented 5629 */ 5630 VOID 5631 RxMarkFobxOnCleanup( 5632 PFOBX pFobx, 5633 PBOOLEAN NeedPurge) 5634 { 5635 PFCB Fcb; 5636 PFOBX ScavengerFobx; 5637 LARGE_INTEGER TickCount; 5638 PRDBSS_SCAVENGER Scavenger; 5639 5640 PAGED_CODE(); 5641 5642 /* No FOBX, nothing to mark */ 5643 if (pFobx == NULL) 5644 { 5645 return; 5646 } 5647 5648 /* Query time for close */ 5649 KeQueryTickCount(&TickCount); 5650 5651 Fcb = (PFCB)pFobx->pSrvOpen->pFcb; 5652 ASSERT(NodeTypeIsFcb(Fcb)); 5653 5654 Scavenger = Fcb->RxDeviceObject->pRdbssScavenger; 5655 RxAcquireScavengerMutex(); 5656 5657 ScavengerFobx = NULL; 5658 /* If that's not a file, or even not a disk resource, just mark as dormant */ 5659 if (NodeType(Fcb) != RDBSS_NTC_STORAGE_TYPE_FILE || Fcb->VNetRoot->pNetRoot->DeviceType != FILE_DEVICE_DISK) 5660 { 5661 SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT); 5662 InitializeListHead(&pFobx->ClosePendingList); 5663 ++Scavenger->NumberOfDormantFiles; 5664 } 5665 else 5666 { 5667 ASSERT(Scavenger->NumberOfDormantFiles >= 0); 5668 /* If we're about to reach the maximum dormant of FOBX */ 5669 if (Scavenger->NumberOfDormantFiles >= Scavenger->MaximumNumberOfDormantFiles) 5670 { 5671 /* This should never be wrong... */ 5672 if (!IsListEmpty(&Scavenger->ClosePendingFobxsList)) 5673 { 5674 /* Then, take the first from the list (oldest) and save it for later purge */ 5675 ScavengerFobx = CONTAINING_RECORD(Scavenger->ClosePendingFobxsList.Flink, FOBX, ClosePendingList); 5676 if (ScavengerFobx->pSrvOpen != NULL && ScavengerFobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb)) 5677 { 5678 *NeedPurge = TRUE; 5679 ScavengerFobx = NULL; 5680 } 5681 else 5682 { 5683 RxReferenceNetFobx(ScavengerFobx); 5684 } 5685 } 5686 } 5687 5688 /* Mark ourselves as dormant */ 5689 SetFlag(pFobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT); 5690 pFobx->CloseTime.QuadPart = TickCount.QuadPart; 5691 5692 /* And insert us in the list of dormant files */ 5693 InsertTailList(&Scavenger->ClosePendingFobxsList, &pFobx->ClosePendingList); 5694 /* If scavenger was inactive, start it */ 5695 if (Scavenger->NumberOfDormantFiles++ == 0 && Scavenger->State == RDBSS_SCAVENGER_INACTIVE) 5696 { 5697 Scavenger->State = RDBSS_SCAVENGER_DORMANT; 5698 RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem, RxScavengerTimerRoutine, 5699 Fcb->RxDeviceObject, Scavenger->TimeLimit); 5700 } 5701 } 5702 5703 RxReleaseScavengerMutex(); 5704 5705 /* If we had reached max */ 5706 if (ScavengerFobx != NULL) 5707 { 5708 NTSTATUS Status; 5709 5710 /* Purge the oldest FOBX */ 5711 Status = RxPurgeFobxFromCache(ScavengerFobx); 5712 if (Status != STATUS_SUCCESS) 5713 { 5714 *NeedPurge = TRUE; 5715 } 5716 } 5717 } 5718 5719 /* 5720 * @implemented 5721 */ 5722 VOID 5723 RxMarkFobxOnClose( 5724 PFOBX Fobx) 5725 { 5726 PFCB Fcb; 5727 PRDBSS_SCAVENGER Scavenger; 5728 5729 PAGED_CODE(); 5730 5731 /* No FOBX, nothing to mark */ 5732 if (Fobx == NULL) 5733 { 5734 return; 5735 } 5736 5737 Fcb = (PFCB)Fobx->pSrvOpen->pFcb; 5738 ASSERT(NodeTypeIsFcb(Fcb)); 5739 5740 Scavenger = Fcb->RxDeviceObject->pRdbssScavenger; 5741 5742 RxAcquireScavengerMutex(); 5743 /* Only mark it if it was already marked as dormant */ 5744 if (BooleanFlagOn(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT)) 5745 { 5746 /* If FCB wasn't already decrement, do it now */ 5747 if (!Fobx->fOpenCountDecremented) 5748 { 5749 Fcb = (PFCB)Fobx->pSrvOpen->pFcb; 5750 ASSERT(NodeTypeIsFcb(Fcb)); 5751 InterlockedDecrement((volatile long *)&Fcb->OpenCount); 5752 5753 Fobx->fOpenCountDecremented = TRUE; 5754 } 5755 5756 /* We're no longer dormant */ 5757 InterlockedDecrement(&Scavenger->NumberOfDormantFiles); 5758 ClearFlag(Fobx->Flags, FOBX_FLAG_MARKED_AS_DORMANT); 5759 } 5760 5761 /* If we were inserted in the scavenger, drop ourselves out */ 5762 if (!IsListEmpty(&Fobx->ClosePendingList)) 5763 { 5764 RemoveEntryList(&Fobx->ClosePendingList); 5765 InitializeListHead(&Fobx->ClosePendingList); 5766 } 5767 5768 RxReleaseScavengerMutex(); 5769 } 5770 5771 /* 5772 * @implemented 5773 */ 5774 PVOID 5775 RxNewMapUserBuffer( 5776 PRX_CONTEXT RxContext) 5777 { 5778 PIRP Irp; 5779 5780 PAGED_CODE(); 5781 5782 Irp = RxContext->CurrentIrp; 5783 if (Irp->MdlAddress != NULL) 5784 { 5785 return MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority); 5786 } 5787 5788 return Irp->UserBuffer; 5789 } 5790 5791 BOOLEAN 5792 NTAPI 5793 RxNoOpAcquire( 5794 IN PVOID Fcb, 5795 IN BOOLEAN Wait) 5796 { 5797 UNIMPLEMENTED; 5798 return FALSE; 5799 } 5800 5801 VOID 5802 NTAPI 5803 RxNoOpRelease( 5804 IN PVOID Fcb) 5805 { 5806 UNIMPLEMENTED; 5807 } 5808 5809 VOID 5810 RxOrphanThisFcb( 5811 PFCB Fcb) 5812 { 5813 UNIMPLEMENTED; 5814 } 5815 5816 VOID 5817 RxOrphanSrvOpens( 5818 IN PV_NET_ROOT ThisVNetRoot) 5819 { 5820 PFCB Fcb; 5821 USHORT Bucket; 5822 PNET_ROOT NetRoot; 5823 PRX_FCB_TABLE FcbTable; 5824 PRX_PREFIX_TABLE PrefixTable; 5825 5826 PAGED_CODE(); 5827 5828 /* Mailslot won't have any SRV_OPEN (to orphan) */ 5829 NetRoot = (PNET_ROOT)ThisVNetRoot->pNetRoot; 5830 if (NetRoot->Type == NET_ROOT_MAILSLOT) 5831 { 5832 return; 5833 } 5834 5835 PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable; 5836 ASSERT(RxIsPrefixTableLockExclusive(PrefixTable)); 5837 5838 FcbTable = &NetRoot->FcbTable; 5839 RxAcquireFcbTableLockExclusive(FcbTable, TRUE); 5840 5841 _SEH2_TRY 5842 { 5843 /* Now, we'll browse all the FCBs attached, and orphan related SRV_OPENs */ 5844 for (Bucket = 0; Bucket < FcbTable->NumberOfBuckets; ++Bucket) 5845 { 5846 PLIST_ENTRY BucketList, Entry; 5847 5848 BucketList = &FcbTable->HashBuckets[Bucket]; 5849 Entry = BucketList->Flink; 5850 while (Entry != BucketList) 5851 { 5852 Fcb = CONTAINING_RECORD(Entry, FCB, FcbTableEntry.HashLinks); 5853 Entry = Entry->Flink; 5854 5855 ASSERT(NodeTypeIsFcb(Fcb)); 5856 RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE); 5857 } 5858 } 5859 5860 /* Of course, don't forget about NULL-entry */ 5861 if (FcbTable->TableEntryForNull != NULL) 5862 { 5863 Fcb = CONTAINING_RECORD(FcbTable->TableEntryForNull, FCB, FcbTableEntry.HashLinks); 5864 ASSERT(NodeTypeIsFcb(Fcb)); 5865 RxOrphanSrvOpensForThisFcb(Fcb, ThisVNetRoot, FALSE); 5866 } 5867 } 5868 _SEH2_FINALLY 5869 { 5870 RxReleaseFcbTableLock(FcbTable); 5871 } 5872 _SEH2_END; 5873 } 5874 5875 VOID 5876 RxOrphanSrvOpensForThisFcb( 5877 IN PFCB Fcb, 5878 IN PV_NET_ROOT ThisVNetRoot, 5879 IN BOOLEAN OrphanAll) 5880 { 5881 UNIMPLEMENTED; 5882 } 5883 5884 /* 5885 * @implemented 5886 */ 5887 BOOLEAN 5888 RxpAcquirePrefixTableLockShared( 5889 PRX_PREFIX_TABLE pTable, 5890 BOOLEAN Wait, 5891 BOOLEAN ProcessBufferingStateChangeRequests) 5892 { 5893 PAGED_CODE(); 5894 5895 DPRINT("RxpAcquirePrefixTableLockShared(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests, 5896 pTable->TableLock.ActiveEntries); 5897 5898 return ExAcquireResourceSharedLite(&pTable->TableLock, Wait); 5899 } 5900 5901 /* 5902 * @implemented 5903 */ 5904 BOOLEAN 5905 RxpAcquirePrefixTableLockExclusive( 5906 PRX_PREFIX_TABLE pTable, 5907 BOOLEAN Wait, 5908 BOOLEAN ProcessBufferingStateChangeRequests) 5909 { 5910 PAGED_CODE(); 5911 5912 DPRINT("RxpAcquirePrefixTableLockExclusive(%p, %d, %d) -> %d\n", pTable, Wait, ProcessBufferingStateChangeRequests, 5913 pTable->TableLock.ActiveEntries); 5914 5915 return ExAcquireResourceExclusiveLite(&pTable->TableLock, Wait); 5916 } 5917 5918 /* 5919 * @implemented 5920 */ 5921 BOOLEAN 5922 RxpDereferenceAndFinalizeNetFcb( 5923 OUT PFCB ThisFcb, 5924 IN PRX_CONTEXT RxContext, 5925 IN BOOLEAN RecursiveFinalize, 5926 IN BOOLEAN ForceFinalize) 5927 { 5928 NTSTATUS Status; 5929 ULONG References; 5930 PNET_ROOT NetRoot; 5931 BOOLEAN ResourceAcquired, NetRootReferenced, Freed; 5932 5933 PAGED_CODE(); 5934 5935 ASSERT(!ForceFinalize); 5936 ASSERT(NodeTypeIsFcb(ThisFcb)); 5937 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb)); 5938 5939 /* Unless we're recursively finalizing, or forcing, if FCB is still in use, quit */ 5940 References = InterlockedDecrement((volatile long *)&ThisFcb->NodeReferenceCount); 5941 if (!ForceFinalize && !RecursiveFinalize && (ThisFcb->OpenCount != 0 || ThisFcb->UncleanCount != 0 || References > 1)) 5942 { 5943 return FALSE; 5944 } 5945 5946 Freed = FALSE; 5947 Status = STATUS_SUCCESS; 5948 NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot; 5949 ResourceAcquired = FALSE; 5950 NetRootReferenced = FALSE; 5951 /* If FCB isn't orphaned, it still have context attached */ 5952 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_ORPHANED)) 5953 { 5954 /* Don't let NetRoot go away before we're done */ 5955 RxReferenceNetRoot(NetRoot); 5956 NetRootReferenced = TRUE; 5957 5958 /* Try to acquire the table lock exclusively */ 5959 if (!RxIsFcbTableLockExclusive(&NetRoot->FcbTable)) 5960 { 5961 RxReferenceNetFcb(ThisFcb); 5962 5963 if (!RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, FALSE)) 5964 { 5965 if (RxContext != NULL && RxContext != CHANGE_BUFFERING_STATE_CONTEXT && 5966 RxContext != CHANGE_BUFFERING_STATE_CONTEXT_WAIT) 5967 { 5968 RxContext->Flags |= RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK; 5969 } 5970 5971 RxReleaseFcb(RxContext, ThisFcb); 5972 5973 RxAcquireFcbTableLockExclusive(&NetRoot->FcbTable, TRUE); 5974 5975 Status = RxAcquireExclusiveFcb(RxContext, ThisFcb); 5976 } 5977 5978 References = RxDereferenceNetFcb(ThisFcb); 5979 5980 ResourceAcquired = TRUE; 5981 } 5982 } 5983 5984 /* If locking was OK (or not needed!), attempt finalization */ 5985 if (Status == STATUS_SUCCESS) 5986 { 5987 Freed = RxFinalizeNetFcb(ThisFcb, RecursiveFinalize, ForceFinalize, References); 5988 } 5989 5990 /* Release table lock if acquired */ 5991 if (ResourceAcquired) 5992 { 5993 RxReleaseFcbTableLock(&NetRoot->FcbTable); 5994 } 5995 5996 /* We don't need the NetRoot anylonger */ 5997 if (NetRootReferenced) 5998 { 5999 RxDereferenceNetRoot(NetRoot, LHS_LockNotHeld); 6000 } 6001 6002 return Freed; 6003 } 6004 6005 /* 6006 * @implemented 6007 */ 6008 LONG 6009 RxpDereferenceNetFcb( 6010 PFCB Fcb) 6011 { 6012 LONG NewCount; 6013 6014 PAGED_CODE(); 6015 6016 ASSERT(NodeTypeIsFcb(Fcb)); 6017 6018 NewCount = InterlockedDecrement((volatile long *)&Fcb->NodeReferenceCount); 6019 ASSERT(NewCount >= 0); 6020 6021 PRINT_REF_COUNT(NETFCB, NewCount); 6022 6023 return NewCount; 6024 } 6025 6026 /* 6027 * @implemented 6028 */ 6029 VOID 6030 NTAPI 6031 RxpDestroySrvCall( 6032 IN PVOID Context) 6033 { 6034 NTSTATUS Status; 6035 PSRV_CALL SrvCall; 6036 BOOLEAN ForceFinalize; 6037 PRX_PREFIX_TABLE PrefixTable; 6038 6039 SrvCall = (PSRV_CALL)Context; 6040 /* At this step, RxFinalizeSrvCall already cleaned some fields */ 6041 ASSERT(SrvCall->UpperFinalizationDone); 6042 6043 PrefixTable = SrvCall->RxDeviceObject->pRxNetNameTable; 6044 /* Were we called with ForceFinalize? */ 6045 ForceFinalize = BooleanFlagOn(SrvCall->Flags, SRVCALL_FLAG_FORCE_FINALIZED); 6046 6047 /* Notify mini-rdr */ 6048 MINIRDR_CALL_THROUGH(Status, SrvCall->RxDeviceObject->Dispatch, 6049 MRxFinalizeSrvCall, ((PMRX_SRV_CALL)SrvCall, 6050 ForceFinalize)); 6051 (void)Status; 6052 6053 /* Dereference our extra reference (set before queueing) */ 6054 RxAcquirePrefixTableLockExclusive(PrefixTable, TRUE); 6055 InterlockedDecrement((volatile long *)&SrvCall->NodeReferenceCount); 6056 /* And finalize for real, with the right context */ 6057 RxFinalizeSrvCall(SrvCall, FALSE, ForceFinalize); 6058 RxReleasePrefixTableLock(PrefixTable); 6059 } 6060 6061 /* 6062 * @implemented 6063 */ 6064 VOID 6065 RxpDiscardChangeBufferingStateRequests( 6066 _Inout_ PLIST_ENTRY DiscardedRequests) 6067 { 6068 PLIST_ENTRY Entry; 6069 6070 PAGED_CODE(); 6071 6072 /* No requests to discard */ 6073 if (IsListEmpty(DiscardedRequests)) 6074 { 6075 return; 6076 } 6077 6078 /* Free all the discarded requests */ 6079 Entry = DiscardedRequests->Flink; 6080 while (Entry != DiscardedRequests) 6081 { 6082 PCHANGE_BUFFERING_STATE_REQUEST Request; 6083 6084 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry); 6085 Entry = Entry->Flink; 6086 6087 DPRINT("Req %p for %p (%p) discarded\n", Request, Request->SrvOpenKey, Request->SrvOpen); 6088 6089 RxPrepareRequestForReuse(Request); 6090 RxFreePool(Request); 6091 } 6092 } 6093 6094 /* 6095 * @implemented 6096 */ 6097 VOID 6098 RxpDispatchChangeBufferingStateRequests( 6099 PSRV_CALL SrvCall, 6100 PSRV_OPEN SrvOpen, 6101 PLIST_ENTRY DiscardedRequests) 6102 { 6103 KIRQL OldIrql; 6104 NTSTATUS Status; 6105 BOOLEAN StartDispatcher; 6106 LIST_ENTRY AcceptedReqs; 6107 LIST_ENTRY DispatcherList; 6108 PRX_BUFFERING_MANAGER BufferingManager; 6109 6110 /* Initialize our lists */ 6111 InitializeListHead(&AcceptedReqs); 6112 InitializeListHead(DiscardedRequests); 6113 6114 /* Transfer the requests to dispatch locally */ 6115 BufferingManager = &SrvCall->BufferingManager; 6116 KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql); 6117 RxTransferList(&DispatcherList, &BufferingManager->DispatcherList); 6118 KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql); 6119 6120 /* If there were requests */ 6121 if (!IsListEmpty(&DispatcherList)) 6122 { 6123 PLIST_ENTRY Entry; 6124 6125 /* For each of the entries... */ 6126 Entry = DispatcherList.Flink; 6127 while (Entry != &DispatcherList) 6128 { 6129 PCHANGE_BUFFERING_STATE_REQUEST Request; 6130 6131 Request = CONTAINING_RECORD(Entry, CHANGE_BUFFERING_STATE_REQUEST, ListEntry); 6132 Entry = Entry->Flink; 6133 6134 /* If we have been provided a SRV_OPEN, see whether it matches */ 6135 if (SrvOpen != NULL) 6136 { 6137 /* Match, the request is accepted */ 6138 if (Request->SrvOpenKey == SrvOpen->Key) 6139 { 6140 Request->SrvOpen = SrvOpen; 6141 RxReferenceSrvOpen(SrvOpen); 6142 6143 RemoveEntryList(&Request->ListEntry); 6144 InsertTailList(&AcceptedReqs, &Request->ListEntry); 6145 6146 /* Move to the next entry */ 6147 continue; 6148 } 6149 else 6150 { 6151 Status = STATUS_PENDING; 6152 } 6153 } 6154 else 6155 { 6156 /* No SRV_OPEN provided, try to find one */ 6157 Status = RxpLookupSrvOpenForRequestLite(SrvCall, Request); 6158 } 6159 6160 /* We found a matching SRV_OPEN, accept the request */ 6161 if (Status == STATUS_SUCCESS) 6162 { 6163 RemoveEntryList(&Request->ListEntry); 6164 InsertTailList(&AcceptedReqs, &Request->ListEntry); 6165 } 6166 /* Another run might help handling it, don't discard it */ 6167 else if (Status == STATUS_PENDING) 6168 { 6169 continue; 6170 } 6171 /* Otherwise, discard the request */ 6172 else 6173 { 6174 ASSERT(Status == STATUS_NOT_FOUND); 6175 6176 RemoveEntryList(&Request->ListEntry); 6177 InsertTailList(DiscardedRequests, &Request->ListEntry); 6178 } 6179 } 6180 } 6181 6182 KeAcquireSpinLock(&BufferingManager->SpinLock, &OldIrql); 6183 /* Nothing to dispatch, no need to start dispatcher */ 6184 if (IsListEmpty(&DispatcherList)) 6185 { 6186 StartDispatcher = FALSE; 6187 } 6188 else 6189 { 6190 /* Transfer back the list of the not treated entries to the buffering manager */ 6191 RxTransferList(&BufferingManager->DispatcherList, &DispatcherList); 6192 StartDispatcher = (BufferingManager->DispatcherActive == FALSE); 6193 /* If the dispatcher isn't active, start it */ 6194 if (StartDispatcher) 6195 { 6196 BufferingManager->DispatcherActive = TRUE; 6197 } 6198 } 6199 6200 /* If there were accepted requests, move them to the buffering manager */ 6201 if (!IsListEmpty(&AcceptedReqs)) 6202 { 6203 RxTransferList(&BufferingManager->HandlerList, &AcceptedReqs); 6204 } 6205 KeReleaseSpinLock(&BufferingManager->SpinLock, OldIrql); 6206 6207 /* If we're to start the dispatcher, do it */ 6208 if (StartDispatcher) 6209 { 6210 RxReferenceSrvCall(SrvCall); 6211 DPRINT("Starting dispatcher\n"); 6212 RxPostToWorkerThread(RxFileSystemDeviceObject, HyperCriticalWorkQueue, 6213 &BufferingManager->DispatcherWorkItem, 6214 RxDispatchChangeBufferingStateRequests, SrvCall); 6215 } 6216 } 6217 6218 /* 6219 * @implemented 6220 */ 6221 NTSTATUS 6222 RxpLookupSrvOpenForRequestLite( 6223 IN PSRV_CALL SrvCall, 6224 IN OUT PCHANGE_BUFFERING_STATE_REQUEST Request) 6225 { 6226 NTSTATUS Status; 6227 PLIST_ENTRY Entry; 6228 PSRV_OPEN SrvOpen; 6229 6230 PAGED_CODE(); 6231 6232 Status = STATUS_SUCCESS; 6233 /* Browse all our associated SRV_OPENs to find the one! */ 6234 for (Entry = SrvCall->BufferingManager.SrvOpenLists[0].Flink; 6235 Entry != &SrvCall->BufferingManager.SrvOpenLists[0]; 6236 Entry = Entry->Flink) 6237 { 6238 /* Same key, not orphaned, this is ours */ 6239 SrvOpen = CONTAINING_RECORD(Entry, SRV_OPEN, SrvOpenKeyList); 6240 if (SrvOpen->Key == Request->SrvOpenKey) 6241 { 6242 if (!BooleanFlagOn(SrvOpen->pFcb->FcbState, FCB_STATE_ORPHANED)) 6243 { 6244 RxReferenceSrvOpen(SrvOpen); 6245 break; 6246 } 6247 } 6248 } 6249 6250 /* We didn't manage to find a SRV_OPEN */ 6251 if (Entry == &SrvCall->BufferingManager.SrvOpenLists[0]) 6252 { 6253 SrvOpen = NULL; 6254 6255 /* The coming open might help, mark as pending for later retry */ 6256 if (SrvCall->BufferingManager.NumberOfOutstandingOpens != 0) 6257 { 6258 Status = STATUS_PENDING; 6259 } 6260 /* Else, it's a complete failure */ 6261 else 6262 { 6263 Status = STATUS_NOT_FOUND; 6264 } 6265 } 6266 6267 /* Return the (not) found SRV_OPEN */ 6268 Request->SrvOpen = SrvOpen; 6269 6270 return Status; 6271 } 6272 6273 /* 6274 * @implemented 6275 */ 6276 VOID 6277 RxpMarkInstanceForScavengedFinalization( 6278 PVOID Instance) 6279 { 6280 NODE_TYPE_CODE NodeType; 6281 PNODE_TYPE_AND_SIZE Node; 6282 PRDBSS_SCAVENGER Scavenger; 6283 PRDBSS_DEVICE_OBJECT DeviceObject; 6284 PLIST_ENTRY ScavengerHead, InstEntry; 6285 6286 PAGED_CODE(); 6287 6288 /* If still referenced, don't mark it (broken caller) */ 6289 Node = (PNODE_TYPE_AND_SIZE)Instance; 6290 if (Node->NodeReferenceCount > 1) 6291 { 6292 return; 6293 } 6294 6295 DeviceObject = RxGetDeviceObjectOfInstance(Instance); 6296 Scavenger = DeviceObject->pRdbssScavenger; 6297 6298 /* Mark the node */ 6299 NodeType = NodeType(Instance); 6300 SetFlag(NodeType(Node), RX_SCAVENGER_MASK); 6301 DPRINT("Node %p has now the scavenger mark!\n", Instance); 6302 6303 /* Increase the count in the scavenger, and queue it */ 6304 ScavengerHead = NULL; 6305 switch (NodeType) 6306 { 6307 case RDBSS_NTC_FOBX: 6308 ++Scavenger->FobxsToBeFinalized; 6309 ScavengerHead = &Scavenger->FobxFinalizationList; 6310 InstEntry = &((PFOBX)Instance)->ScavengerFinalizationList; 6311 break; 6312 6313 case RDBSS_NTC_SRVCALL: 6314 ++Scavenger->SrvCallsToBeFinalized; 6315 ScavengerHead = &Scavenger->SrvCallFinalizationList; 6316 InstEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList; 6317 break; 6318 6319 case RDBSS_NTC_NETROOT: 6320 ++Scavenger->NetRootsToBeFinalized; 6321 ScavengerHead = &Scavenger->NetRootFinalizationList; 6322 InstEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList; 6323 break; 6324 6325 case RDBSS_NTC_V_NETROOT: 6326 ++Scavenger->VNetRootsToBeFinalized; 6327 ScavengerHead = &Scavenger->VNetRootFinalizationList; 6328 InstEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList; 6329 break; 6330 6331 case RDBSS_NTC_SRVOPEN: 6332 ++Scavenger->SrvOpensToBeFinalized; 6333 ScavengerHead = &Scavenger->SrvOpenFinalizationList; 6334 InstEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList; 6335 break; 6336 } 6337 6338 /* Extra ref for scavenger */ 6339 InterlockedIncrement((volatile long *)&Node->NodeReferenceCount); 6340 6341 /* If matching type */ 6342 if (ScavengerHead != NULL) 6343 { 6344 /* Insert in the scavenger list */ 6345 InsertTailList(ScavengerHead, InstEntry); 6346 6347 /* And if it wasn't started, start it */ 6348 if (Scavenger->State == RDBSS_SCAVENGER_INACTIVE) 6349 { 6350 Scavenger->State = RDBSS_SCAVENGER_DORMANT; 6351 RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem, 6352 RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit); 6353 } 6354 } 6355 } 6356 6357 /* 6358 * @implemented 6359 */ 6360 NTSTATUS 6361 NTAPI 6362 RxPostOneShotTimerRequest( 6363 IN PRDBSS_DEVICE_OBJECT pDeviceObject, 6364 IN PRX_WORK_ITEM pWorkItem, 6365 IN PRX_WORKERTHREAD_ROUTINE Routine, 6366 IN PVOID pContext, 6367 IN LARGE_INTEGER TimeInterval) 6368 { 6369 KIRQL OldIrql; 6370 6371 ASSERT(pWorkItem != NULL); 6372 6373 /* Prepare the work item */ 6374 ExInitializeWorkItem(&pWorkItem->WorkQueueItem, Routine, pContext); 6375 pWorkItem->WorkQueueItem.pDeviceObject = pDeviceObject; 6376 6377 /* Last tick can be computed with the number of times it was caller (timertickcount) 6378 * and the interval between calls 6379 */ 6380 KeAcquireSpinLock(&RxTimerLock, &OldIrql); 6381 pWorkItem->LastTick = (TimeInterval.QuadPart / 550000) + RxTimerTickCount + 1; 6382 /* Insert in work queue */ 6383 InsertTailList(&RxTimerQueueHead, &pWorkItem->WorkQueueItem.List); 6384 KeReleaseSpinLock(&RxTimerLock, OldIrql); 6385 6386 /* If there are queued events, queue an execution */ 6387 if (IsListEmpty(&RxTimerQueueHead)) 6388 { 6389 KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc); 6390 } 6391 6392 return STATUS_SUCCESS; 6393 } 6394 6395 /* 6396 * @implemented 6397 */ 6398 NTSTATUS 6399 NTAPI 6400 RxPostToWorkerThread( 6401 _In_ PRDBSS_DEVICE_OBJECT pMRxDeviceObject, 6402 _In_ WORK_QUEUE_TYPE WorkQueueType, 6403 _In_ PRX_WORK_QUEUE_ITEM pWorkQueueItem, 6404 _In_ PRX_WORKERTHREAD_ROUTINE Routine, 6405 _In_ PVOID pContext) 6406 { 6407 /* Initialize work queue item */ 6408 pWorkQueueItem->List.Flink = NULL; 6409 pWorkQueueItem->WorkerRoutine = Routine; 6410 pWorkQueueItem->Parameter = pContext; 6411 6412 /* And insert it in the work queue */ 6413 return RxInsertWorkQueueItem(pMRxDeviceObject, WorkQueueType, pWorkQueueItem); 6414 } 6415 6416 VOID 6417 RxpProcessChangeBufferingStateRequests( 6418 PSRV_CALL SrvCall, 6419 BOOLEAN UpdateHandlerState) 6420 { 6421 UNIMPLEMENTED; 6422 } 6423 6424 /* 6425 * @implemented 6426 */ 6427 PRX_PREFIX_ENTRY 6428 RxPrefixTableInsertName( 6429 IN OUT PRX_PREFIX_TABLE ThisTable, 6430 IN OUT PRX_PREFIX_ENTRY ThisEntry, 6431 IN PVOID Container, 6432 IN PULONG ContainerRefCount, 6433 IN USHORT CaseInsensitiveLength, 6434 IN PRX_CONNECTION_ID ConnectionId 6435 ) 6436 { 6437 PAGED_CODE(); 6438 6439 DPRINT("Insert: %wZ\n", &ThisEntry->Prefix); 6440 6441 ASSERT(RxIsPrefixTableLockExclusive(ThisTable)); 6442 ASSERT(CaseInsensitiveLength <= ThisEntry->Prefix.Length); 6443 6444 /* Copy parameters and compute hash */ 6445 ThisEntry->CaseInsensitiveLength = CaseInsensitiveLength; 6446 ThisEntry->ContainingRecord = Container; 6447 ThisEntry->ContainerRefCount = ContainerRefCount; 6448 InterlockedIncrement((volatile long *)ContainerRefCount); 6449 ThisEntry->SavedHashValue = RxTableComputeHashValue(&ThisEntry->Prefix); 6450 DPRINT("Associated hash: %x\n", ThisEntry->SavedHashValue); 6451 6452 /* If no path length: this is entry for null path */ 6453 if (ThisEntry->Prefix.Length == 0) 6454 { 6455 ThisTable->TableEntryForNull = ThisEntry; 6456 } 6457 /* Otherwise, insert in the appropriate bucket */ 6458 else 6459 { 6460 InsertTailList(HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue), &ThisEntry->HashLinks); 6461 } 6462 6463 /* If we had a connection ID, keep track of it */ 6464 if (ConnectionId != NULL) 6465 { 6466 ThisEntry->ConnectionId.Luid = ConnectionId->Luid; 6467 } 6468 else 6469 { 6470 ThisEntry->ConnectionId.Luid.LowPart = 0; 6471 ThisEntry->ConnectionId.Luid.HighPart = 0; 6472 } 6473 6474 InsertTailList(&ThisTable->MemberQueue, &ThisEntry->MemberQLinks); 6475 /* Reflect the changes */ 6476 ++ThisTable->Version; 6477 6478 DPRINT("Inserted in bucket: %p\n", HASH_BUCKET(ThisTable, ThisEntry->SavedHashValue)); 6479 6480 return ThisEntry; 6481 } 6482 6483 /* 6484 * @implemented 6485 */ 6486 PVOID 6487 RxPrefixTableLookupName( 6488 IN PRX_PREFIX_TABLE ThisTable, 6489 IN PUNICODE_STRING CanonicalName, 6490 OUT PUNICODE_STRING RemainingName, 6491 IN PRX_CONNECTION_ID ConnectionId) 6492 { 6493 PVOID Container; 6494 6495 PAGED_CODE(); 6496 6497 ASSERT(RxIsPrefixTableLockAcquired(ThisTable)); 6498 ASSERT(CanonicalName->Length > 0); 6499 6500 /* Call the internal helper */ 6501 Container = RxTableLookupName(ThisTable, CanonicalName, RemainingName, ConnectionId); 6502 if (Container == NULL) 6503 { 6504 return NULL; 6505 } 6506 6507 /* Reference our container before returning it */ 6508 if (RdbssReferenceTracingValue != 0) 6509 { 6510 NODE_TYPE_CODE Type; 6511 6512 Type = (NodeType(Container) & ~RX_SCAVENGER_MASK); 6513 switch (Type) 6514 { 6515 case RDBSS_NTC_SRVCALL: 6516 RxReferenceSrvCall(Container); 6517 break; 6518 6519 case RDBSS_NTC_NETROOT: 6520 RxReferenceNetRoot(Container); 6521 break; 6522 6523 case RDBSS_NTC_V_NETROOT: 6524 RxReferenceVNetRoot(Container); 6525 break; 6526 6527 default: 6528 DPRINT1("Invalid node type: %x\n", Type); 6529 ASSERT(FALSE); 6530 RxReference(Container); 6531 break; 6532 } 6533 } 6534 else 6535 { 6536 RxReference(Container); 6537 } 6538 6539 return Container; 6540 } 6541 6542 /* 6543 * @implemented 6544 */ 6545 LONG 6546 RxpReferenceNetFcb( 6547 PFCB Fcb) 6548 { 6549 LONG NewCount; 6550 6551 PAGED_CODE(); 6552 6553 ASSERT(NodeTypeIsFcb(Fcb)); 6554 6555 NewCount = InterlockedIncrement((volatile long *)&Fcb->NodeReferenceCount); 6556 6557 PRINT_REF_COUNT(NETFCB, Fcb->NodeReferenceCount); 6558 6559 return NewCount; 6560 } 6561 6562 /* 6563 * @implemented 6564 */ 6565 VOID 6566 RxpReleasePrefixTableLock( 6567 PRX_PREFIX_TABLE pTable, 6568 BOOLEAN ProcessBufferingStateChangeRequests) 6569 { 6570 PAGED_CODE(); 6571 6572 DPRINT("RxpReleasePrefixTableLock(%p, %d) -> %d\n", pTable, ProcessBufferingStateChangeRequests, 6573 pTable->TableLock.ActiveEntries); 6574 6575 ExReleaseResourceLite(&pTable->TableLock); 6576 } 6577 6578 /* 6579 * @implemented 6580 */ 6581 VOID 6582 NTAPI 6583 RxPrepareContextForReuse( 6584 IN OUT PRX_CONTEXT RxContext) 6585 { 6586 PAGED_CODE(); 6587 6588 /* When we reach that point, make sure mandatory parts are null-ed */ 6589 if (RxContext->MajorFunction == IRP_MJ_CREATE) 6590 { 6591 ASSERT(RxContext->Create.CanonicalNameBuffer == NULL); 6592 RxContext->Create.RdrFlags = 0; 6593 } 6594 else if (RxContext->MajorFunction == IRP_MJ_READ || RxContext->MajorFunction == IRP_MJ_WRITE) 6595 { 6596 ASSERT(RxContext->RxContextSerializationQLinks.Flink == NULL); 6597 ASSERT(RxContext->RxContextSerializationQLinks.Blink == NULL); 6598 } 6599 6600 RxContext->ReferenceCount = 0; 6601 } 6602 6603 /* 6604 * @implemented 6605 */ 6606 VOID 6607 RxPrepareRequestForReuse( 6608 PCHANGE_BUFFERING_STATE_REQUEST Request) 6609 { 6610 PSRV_OPEN SrvOpen; 6611 6612 PAGED_CODE(); 6613 6614 SrvOpen = Request->SrvOpen; 6615 6616 /* If the request was already prepared for service */ 6617 if (BooleanFlagOn(Request->Flags, RX_REQUEST_PREPARED_FOR_HANDLING)) 6618 { 6619 /* We have to dereference the associated SRV_OPEN depending on the lock */ 6620 if (RxIsFcbAcquiredExclusive(SrvOpen->pFcb)) 6621 { 6622 RxDereferenceSrvOpen(SrvOpen, LHS_ExclusiveLockHeld); 6623 } 6624 else 6625 { 6626 RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld); 6627 } 6628 } 6629 /* Otherwise, just dereference */ 6630 else if (SrvOpen != NULL) 6631 { 6632 RxDereferenceSrvOpen(SrvOpen, LHS_LockNotHeld); 6633 } 6634 6635 Request->SrvOpen = NULL; 6636 } 6637 6638 /* 6639 * @implemented 6640 */ 6641 VOID 6642 NTAPI 6643 RxProcessChangeBufferingStateRequests( 6644 _In_ PVOID SrvCall) 6645 { 6646 /* Call internal routine */ 6647 RxUndoScavengerFinalizationMarking(SrvCall); 6648 RxpProcessChangeBufferingStateRequests(SrvCall, TRUE); 6649 } 6650 6651 /* 6652 * @implemented 6653 */ 6654 VOID 6655 RxProcessChangeBufferingStateRequestsForSrvOpen( 6656 PSRV_OPEN SrvOpen) 6657 { 6658 LONG NumberOfBufferingChangeRequests, LockedOldBufferingToken, OldBufferingToken; 6659 6660 /* Get the current number of change requests */ 6661 NumberOfBufferingChangeRequests = ((PSRV_CALL)SrvOpen->pVNetRoot->pNetRoot->pSrvCall)->BufferingManager.CumulativeNumberOfBufferingChangeRequests; 6662 /* Get our old token */ 6663 OldBufferingToken = SrvOpen->BufferingToken; 6664 LockedOldBufferingToken = InterlockedCompareExchange(&SrvOpen->BufferingToken, 6665 NumberOfBufferingChangeRequests, 6666 NumberOfBufferingChangeRequests); 6667 /* If buffering state changed in between, process changes */ 6668 if (OldBufferingToken != LockedOldBufferingToken) 6669 { 6670 PFCB Fcb; 6671 NTSTATUS Status; 6672 6673 /* Acquire the FCB and start processing */ 6674 Fcb = (PFCB)SrvOpen->pFcb; 6675 Status = RxAcquireExclusiveFcb(NULL, Fcb); 6676 if (Status == STATUS_SUCCESS) 6677 { 6678 RxProcessFcbChangeBufferingStateRequest(Fcb); 6679 RxReleaseFcb(NULL, Fcb); 6680 } 6681 } 6682 } 6683 6684 VOID 6685 RxProcessFcbChangeBufferingStateRequest( 6686 PFCB Fcb) 6687 { 6688 UNIMPLEMENTED; 6689 } 6690 6691 /* 6692 * @implemented 6693 */ 6694 VOID 6695 RxpScavengeFobxs( 6696 PRDBSS_SCAVENGER Scavenger, 6697 PLIST_ENTRY FobxToScavenge) 6698 { 6699 /* Explore the whole list of FOBX to scavenge */ 6700 while (!IsListEmpty(FobxToScavenge)) 6701 { 6702 PFCB Fcb; 6703 PFOBX Fobx; 6704 PLIST_ENTRY Entry; 6705 6706 Entry = RemoveHeadList(FobxToScavenge); 6707 Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList); 6708 Fcb = (PFCB)Fobx->SrvOpen->pFcb; 6709 6710 /* Try to acquire the lock exclusively to perform finalization */ 6711 if (RxAcquireExclusiveFcb(NULL, Fcb) != STATUS_SUCCESS) 6712 { 6713 RxDereferenceNetRoot(Fobx, LHS_LockNotHeld); 6714 } 6715 else 6716 { 6717 RxReferenceNetFcb(Fcb); 6718 RxDereferenceNetRoot(Fobx, LHS_ExclusiveLockHeld); 6719 6720 if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE)) 6721 { 6722 RxReleaseFcb(NULL, Fcb); 6723 } 6724 } 6725 } 6726 } 6727 6728 BOOLEAN 6729 RxpTrackDereference( 6730 _In_ ULONG TraceType, 6731 _In_ PCSTR FileName, 6732 _In_ ULONG Line, 6733 _In_ PVOID Instance) 6734 { 6735 PCSTR InstanceType; 6736 ULONG ReferenceCount; 6737 6738 PAGED_CODE(); 6739 6740 if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType)) 6741 { 6742 return TRUE; 6743 } 6744 6745 switch (TraceType) 6746 { 6747 case RDBSS_REF_TRACK_SRVCALL: 6748 InstanceType = "SrvCall"; 6749 ReferenceCount = ((PSRV_CALL)Instance)->NodeReferenceCount; 6750 break; 6751 6752 case RDBSS_REF_TRACK_NETROOT: 6753 InstanceType = "NetRoot"; 6754 ReferenceCount = ((PNET_ROOT)Instance)->NodeReferenceCount; 6755 break; 6756 6757 case RDBSS_REF_TRACK_VNETROOT: 6758 InstanceType = "VNetRoot"; 6759 ReferenceCount = ((PV_NET_ROOT)Instance)->NodeReferenceCount; 6760 break; 6761 6762 case RDBSS_REF_TRACK_NETFOBX: 6763 InstanceType = "NetFobx"; 6764 ReferenceCount = ((PFOBX)Instance)->NodeReferenceCount; 6765 break; 6766 6767 case RDBSS_REF_TRACK_NETFCB: 6768 InstanceType = "NetFcb"; 6769 ReferenceCount = ((PFCB)Instance)->NodeReferenceCount; 6770 break; 6771 6772 case RDBSS_REF_TRACK_SRVOPEN: 6773 InstanceType = "SrvOpen"; 6774 ReferenceCount = ((PSRV_OPEN)Instance)->NodeReferenceCount; 6775 break; 6776 6777 default: 6778 DPRINT1("Invalid node type!\n"); 6779 return TRUE; 6780 } 6781 6782 if (BooleanFlagOn(RdbssReferenceTracingValue, RX_LOG_REF_TRACKING)) 6783 { 6784 UNIMPLEMENTED; 6785 } 6786 6787 if (BooleanFlagOn(RdbssReferenceTracingValue, RX_PRINT_REF_TRACKING)) 6788 { 6789 DbgPrint("(%s:%d) %p (%s) dereferenced from %d\n", FileName, Line, Instance, InstanceType, ReferenceCount); 6790 } 6791 6792 return TRUE; 6793 } 6794 6795 VOID 6796 RxpTrackReference( 6797 _In_ ULONG TraceType, 6798 _In_ PCSTR FileName, 6799 _In_ ULONG Line, 6800 _In_ PVOID Instance) 6801 { 6802 PCSTR InstanceType; 6803 ULONG ReferenceCount; 6804 6805 if (!BooleanFlagOn(RdbssReferenceTracingValue, TraceType)) 6806 { 6807 return; 6808 } 6809 6810 switch (TraceType) 6811 { 6812 case RDBSS_REF_TRACK_SRVCALL: 6813 InstanceType = "SrvCall"; 6814 ReferenceCount = ((PSRV_CALL)Instance)->NodeReferenceCount; 6815 break; 6816 6817 case RDBSS_REF_TRACK_NETROOT: 6818 InstanceType = "NetRoot"; 6819 ReferenceCount = ((PNET_ROOT)Instance)->NodeReferenceCount; 6820 break; 6821 6822 case RDBSS_REF_TRACK_VNETROOT: 6823 InstanceType = "VNetRoot"; 6824 ReferenceCount = ((PV_NET_ROOT)Instance)->NodeReferenceCount; 6825 break; 6826 6827 case RDBSS_REF_TRACK_NETFOBX: 6828 InstanceType = "NetFobx"; 6829 ReferenceCount = ((PFOBX)Instance)->NodeReferenceCount; 6830 break; 6831 6832 case RDBSS_REF_TRACK_NETFCB: 6833 InstanceType = "NetFcb"; 6834 ReferenceCount = ((PFCB)Instance)->NodeReferenceCount; 6835 break; 6836 6837 case RDBSS_REF_TRACK_SRVOPEN: 6838 InstanceType = "SrvOpen"; 6839 ReferenceCount = ((PSRV_OPEN)Instance)->NodeReferenceCount; 6840 break; 6841 6842 default: 6843 DPRINT1("Invalid node type!\n"); 6844 return; 6845 } 6846 6847 if (BooleanFlagOn(RdbssReferenceTracingValue, RX_LOG_REF_TRACKING)) 6848 { 6849 UNIMPLEMENTED; 6850 } 6851 6852 if (BooleanFlagOn(RdbssReferenceTracingValue, RX_PRINT_REF_TRACKING)) 6853 { 6854 DbgPrint("(%s:%d) %p (%s) referenced from %d\n", FileName, Line, Instance, InstanceType, ReferenceCount); 6855 } 6856 } 6857 6858 /* 6859 * @implemented 6860 */ 6861 VOID 6862 RxpUndoScavengerFinalizationMarking( 6863 PVOID Instance) 6864 { 6865 PLIST_ENTRY ListEntry; 6866 PNODE_TYPE_AND_SIZE Node; 6867 PRDBSS_SCAVENGER Scavenger; 6868 6869 PAGED_CODE(); 6870 6871 Node = (PNODE_TYPE_AND_SIZE)Instance; 6872 /* There's no marking - nothing to do */ 6873 if (!BooleanFlagOn(NodeType(Node), RX_SCAVENGER_MASK)) 6874 { 6875 return; 6876 } 6877 6878 /* First of all, remove the mark */ 6879 ClearFlag(NodeType(Node), RX_SCAVENGER_MASK); 6880 DPRINT("Node %p no longer has the scavenger mark\n"); 6881 6882 /* And now, remove from the scavenger */ 6883 Scavenger = RxGetDeviceObjectOfInstance(Instance)->pRdbssScavenger; 6884 switch (NodeType(Node)) 6885 { 6886 case RDBSS_NTC_FOBX: 6887 --Scavenger->FobxsToBeFinalized; 6888 ListEntry = &((PFOBX)Instance)->ScavengerFinalizationList; 6889 break; 6890 6891 case RDBSS_NTC_SRVCALL: 6892 --Scavenger->SrvCallsToBeFinalized; 6893 ListEntry = &((PSRV_CALL)Instance)->ScavengerFinalizationList; 6894 break; 6895 6896 case RDBSS_NTC_NETROOT: 6897 --Scavenger->NetRootsToBeFinalized; 6898 ListEntry = &((PNET_ROOT)Instance)->ScavengerFinalizationList; 6899 break; 6900 6901 case RDBSS_NTC_V_NETROOT: 6902 --Scavenger->VNetRootsToBeFinalized; 6903 ListEntry = &((PV_NET_ROOT)Instance)->ScavengerFinalizationList; 6904 break; 6905 6906 case RDBSS_NTC_SRVOPEN: 6907 --Scavenger->SrvOpensToBeFinalized; 6908 ListEntry = &((PSRV_OPEN)Instance)->ScavengerFinalizationList; 6909 break; 6910 6911 default: 6912 return; 6913 } 6914 6915 /* Also, remove the extra ref from the scavenger */ 6916 RemoveEntryList(ListEntry); 6917 InterlockedDecrement((volatile long *)&Node->NodeReferenceCount); 6918 } 6919 6920 /* 6921 * @implemented 6922 */ 6923 VOID 6924 RxPurgeChangeBufferingStateRequestsForSrvOpen( 6925 PSRV_OPEN SrvOpen) 6926 { 6927 PSRV_CALL SrvCall; 6928 LIST_ENTRY Discarded; 6929 6930 PAGED_CODE(); 6931 6932 ASSERT(RxIsFcbAcquiredExclusive(SrvOpen->Fcb)); 6933 6934 /* Initialize our discarded list */ 6935 InitializeListHead(&Discarded); 6936 6937 SrvCall = (PSRV_CALL)SrvOpen->Fcb->VNetRoot->pNetRoot->pSrvCall; 6938 RxAcquireBufferingManagerMutex(&SrvCall->BufferingManager); 6939 6940 /* Set the flag, and get the requests */ 6941 InitializeListHead(&SrvOpen->SrvOpenKeyList); 6942 SetFlag(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_REQUESTS_PURGED); 6943 RxGatherRequestsForSrvOpen(SrvCall, SrvOpen, &Discarded); 6944 6945 RxReleaseBufferingManagerMutex(&SrvCall->BufferingManager); 6946 6947 /* If there were discarded requests */ 6948 if (!IsListEmpty(&Discarded)) 6949 { 6950 /* And a pending buffering state change */ 6951 if (BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_BUFFERING_STATE_CHANGE_PENDING)) 6952 { 6953 /* Clear the flag, and set the associated event - job done */ 6954 RxAcquireSerializationMutex(); 6955 ClearFlag(SrvOpen->Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING); 6956 if (SrvOpen->Fcb->pBufferingStateChangeCompletedEvent != NULL) 6957 { 6958 KeSetEvent(SrvOpen->Fcb->pBufferingStateChangeCompletedEvent, IO_NETWORK_INCREMENT, FALSE); 6959 } 6960 RxReleaseSerializationMutex(); 6961 } 6962 6963 /* Drop the discarded requests */ 6964 RxpDiscardChangeBufferingStateRequests(&Discarded); 6965 } 6966 } 6967 6968 /* 6969 * @implemented 6970 */ 6971 VOID 6972 RxPurgeFcb( 6973 IN PFCB Fcb) 6974 { 6975 PAGED_CODE(); 6976 6977 ASSERT(RxIsFcbAcquiredExclusive(Fcb)); 6978 6979 /* Reference our FCB so that it doesn't disappear */ 6980 RxReferenceNetFcb(Fcb); 6981 /* Purge Cc if required */ 6982 if (Fcb->OpenCount != 0) 6983 { 6984 RxPurgeFcbInSystemCache(Fcb, NULL, 0, TRUE, TRUE); 6985 } 6986 6987 /* If it wasn't freed, release the lock */ 6988 if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE)) 6989 { 6990 RxReleaseFcb(NULL, Fcb); 6991 } 6992 } 6993 6994 /* 6995 * @implemented 6996 */ 6997 NTSTATUS 6998 RxPurgeFcbInSystemCache( 6999 IN PFCB Fcb, 7000 IN PLARGE_INTEGER FileOffset OPTIONAL, 7001 IN ULONG Length, 7002 IN BOOLEAN UninitializeCacheMaps, 7003 IN BOOLEAN FlushFile) 7004 { 7005 BOOLEAN Purged; 7006 NTSTATUS Status; 7007 7008 PAGED_CODE(); 7009 7010 ASSERT(RxIsFcbAcquiredExclusive(Fcb)); 7011 7012 /* Try to flush first, if asked */ 7013 if (FlushFile) 7014 { 7015 /* If flushing failed, just make some noise */ 7016 Status = RxFlushFcbInSystemCache(Fcb, TRUE); 7017 if (!NT_SUCCESS(Status)) 7018 { 7019 PVOID CallersAddress, CallersCaller; 7020 7021 RtlGetCallersAddress(&CallersAddress, &CallersCaller); 7022 DPRINT1("Flush failed with status %lx for FCB %p\n", Status, Fcb); 7023 DPRINT1("Caller was %p %p\n", CallersAddress, CallersCaller); 7024 } 7025 } 7026 7027 /* Deal with Cc for purge */ 7028 Purged = CcPurgeCacheSection(&Fcb->NonPaged->SectionObjectPointers, FileOffset, 7029 Length, UninitializeCacheMaps); 7030 /* If purge failed, force section closing */ 7031 if (!Purged) 7032 { 7033 MmFlushImageSection(&Fcb->NonPaged->SectionObjectPointers, MmFlushForWrite); 7034 7035 RxReleaseFcb(NULL, Fcb); 7036 Purged = MmForceSectionClosed(&Fcb->NonPaged->SectionObjectPointers, TRUE); 7037 RxAcquireExclusiveFcb(NULL, Fcb); 7038 } 7039 7040 /* Return appropriate status */ 7041 Status = (Purged ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); 7042 DPRINT("Purge for FCB %p returns %lx\n", Fcb, Status); 7043 7044 return Status; 7045 } 7046 7047 /* 7048 * @implemented 7049 */ 7050 BOOLEAN 7051 RxPurgeFobx( 7052 PFOBX pFobx) 7053 { 7054 NTSTATUS Status; 7055 PFCB FcbToBePurged; 7056 7057 PAGED_CODE(); 7058 7059 /* Get the associated FCB */ 7060 FcbToBePurged = (PFCB)pFobx->pSrvOpen->pFcb; 7061 Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged); 7062 ASSERT(Status == STATUS_SUCCESS); 7063 7064 /* Purge it */ 7065 Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE); 7066 if (Status != STATUS_SUCCESS) 7067 { 7068 DPRINT1("Purge failed for %p (%p)\n", FcbToBePurged, pFobx); 7069 return FALSE; 7070 } 7071 7072 /* And flush */ 7073 if (!MmFlushImageSection(&FcbToBePurged->NonPaged->SectionObjectPointers, MmFlushForWrite)) 7074 { 7075 DPRINT1("Image section flush failed for %p (%p)\n", FcbToBePurged, pFobx); 7076 return FALSE; 7077 } 7078 7079 DPRINT("Purge OK for %p (%p)\n", FcbToBePurged, pFobx); 7080 return TRUE; 7081 } 7082 7083 /* 7084 * @implemented 7085 */ 7086 NTSTATUS 7087 RxPurgeFobxFromCache( 7088 PFOBX FobxToBePurged) 7089 { 7090 NTSTATUS Status; 7091 PFCB FcbToBePurged; 7092 7093 PAGED_CODE(); 7094 7095 FcbToBePurged = (PFCB)FobxToBePurged->pSrvOpen->pFcb; 7096 ASSERT(FcbToBePurged != NULL); 7097 7098 /* If we cannot have our FCB exclusively, give up */ 7099 Status = RxAcquireExclusiveFcb(NULL, FcbToBePurged); 7100 if (Status != STATUS_SUCCESS) 7101 { 7102 RxDereferenceNetFobx(FobxToBePurged, LHS_LockNotHeld); 7103 return Status; 7104 } 7105 7106 /* Don't let the FCB disappear */ 7107 RxReferenceNetFcb(FcbToBePurged); 7108 7109 /* If the SRV_OPEN was already closed, or if there are unclean FOBX, give up */ 7110 if (BooleanFlagOn(FobxToBePurged->Flags, FOBX_FLAG_SRVOPEN_CLOSED) || FobxToBePurged->pSrvOpen->UncleanFobxCount != 0) 7111 { 7112 DPRINT("FCB purge skipped\n"); 7113 } 7114 else 7115 { 7116 Status = RxPurgeFcbInSystemCache(FcbToBePurged, NULL, 0, FALSE, TRUE); 7117 } 7118 7119 RxDereferenceNetFobx(FobxToBePurged, LHS_ExclusiveLockHeld); 7120 /* Drop our extra reference */ 7121 if (!RxDereferenceAndFinalizeNetFcb(FcbToBePurged, NULL, FALSE, FALSE)) 7122 { 7123 RxReleaseFcb(NULL, FcbToBePurged); 7124 } 7125 7126 return Status; 7127 } 7128 7129 /* 7130 * @implemented 7131 */ 7132 NTSTATUS 7133 RxPurgeRelatedFobxs( 7134 PNET_ROOT NetRoot, 7135 PRX_CONTEXT RxContext, 7136 BOOLEAN AttemptFinalization, 7137 PFCB PurgingFcb) 7138 { 7139 PLIST_ENTRY Entry; 7140 ULONG SuccessfullPurge; 7141 PRDBSS_SCAVENGER Scavenger; 7142 PRDBSS_DEVICE_OBJECT RxDeviceObject; 7143 PPURGE_SYNCHRONIZATION_CONTEXT PurgeSyncCtx; 7144 7145 PAGED_CODE(); 7146 7147 RxDeviceObject = RxContext->RxDeviceObject; 7148 Scavenger = RxDeviceObject->pRdbssScavenger; 7149 PurgeSyncCtx = &NetRoot->PurgeSyncronizationContext; 7150 7151 RxAcquireScavengerMutex(); 7152 7153 /* If there's already a purge in progress */ 7154 if (PurgeSyncCtx->PurgeInProgress) 7155 { 7156 /* Add our RX_CONTEXT to the current run */ 7157 InsertTailList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion, 7158 &RxContext->RxContextSerializationQLinks); 7159 7160 /* And wait until it's done */ 7161 RxReleaseScavengerMutex(); 7162 RxWaitSync(RxContext); 7163 RxAcquireScavengerMutex(); 7164 } 7165 7166 /* Start the purge */ 7167 PurgeSyncCtx->PurgeInProgress = TRUE; 7168 7169 /* While the purge is still handling our NET_ROOT, do nothing but wait */ 7170 while (Scavenger->CurrentNetRootForClosePendingProcessing == NetRoot) 7171 { 7172 RxReleaseScavengerMutex(); 7173 KeWaitForSingleObject(&Scavenger->ClosePendingProcessingSyncEvent, Executive, 7174 KernelMode, TRUE, NULL); 7175 RxAcquireScavengerMutex(); 7176 } 7177 7178 /* Now, for all the entries */ 7179 SuccessfullPurge = 0; 7180 Entry = Scavenger->ClosePendingFobxsList.Flink; 7181 while (Entry != &Scavenger->ClosePendingFobxsList) 7182 { 7183 PFCB Fcb; 7184 PFOBX Fobx; 7185 BOOLEAN Success; 7186 7187 Fobx = CONTAINING_RECORD(Entry, FOBX, ClosePendingList); 7188 DPRINT("Dealing with FOBX: %p\n", Fobx); 7189 7190 Entry = Entry->Flink; 7191 7192 /* If it's not matching our NET_ROOT, ignore */ 7193 if (Fobx->pSrvOpen == NULL || 7194 Fobx->pSrvOpen->pFcb == NULL || 7195 ((PFCB)Fobx->pSrvOpen->pFcb)->VNetRoot == NULL || 7196 (PNET_ROOT)((PFCB)Fobx->pSrvOpen->pFcb)->VNetRoot->pNetRoot != NetRoot) 7197 { 7198 continue; 7199 } 7200 7201 /* Determine if it matches our FCB */ 7202 Fcb = (PFCB)Fobx->pSrvOpen->pFcb; 7203 if (PurgingFcb != NULL && NodeType(PurgingFcb) != RDBSS_NTC_STORAGE_TYPE_DIRECTORY && 7204 PurgingFcb != Fcb) 7205 { 7206 NTSTATUS Status; 7207 7208 MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb)); 7209 if (Status == STATUS_SUCCESS) 7210 { 7211 continue; 7212 } 7213 } 7214 7215 /* Matching, we'll purge it */ 7216 RemoveEntryList(&Fobx->ClosePendingList); 7217 7218 /* Reference it so that it doesn't disappear */ 7219 RxReferenceNetFobx(Fobx); 7220 7221 RxReleaseScavengerMutex(); 7222 7223 /* And purge */ 7224 Success = RxPurgeFobx(Fobx); 7225 if (Success) 7226 { 7227 ++SuccessfullPurge; 7228 } 7229 7230 /* If we don't have to finalize it (or if we cannot acquire lock exclusively 7231 * Just normally dereference 7232 */ 7233 if ((AttemptFinalization == DONT_ATTEMPT_FINALIZE_ON_PURGE) || 7234 RxAcquireExclusiveFcb(NULL, Fcb) != STATUS_SUCCESS) 7235 { 7236 RxDereferenceNetFobx(Fobx, LHS_LockNotHeld); 7237 } 7238 /* Otherwise, finalize */ 7239 else 7240 { 7241 RxReferenceNetFcb(Fcb); 7242 RxDereferenceNetFobx(Fobx, LHS_ExclusiveLockHeld); 7243 if (!RxDereferenceAndFinalizeNetFcb(Fcb, NULL, FALSE, FALSE)) 7244 { 7245 RxReleaseFcb(NULL, Fcb); 7246 } 7247 } 7248 7249 if (!Success) 7250 { 7251 DPRINT1("Failed purging %p (%p)\n", Fcb, Fobx); 7252 } 7253 7254 RxAcquireScavengerMutex(); 7255 } 7256 7257 /* If no contexts left, purge is not running */ 7258 if (IsListEmpty(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion)) 7259 { 7260 PurgeSyncCtx->PurgeInProgress = FALSE; 7261 } 7262 /* Otherwise, notify a waiter it can start */ 7263 else 7264 { 7265 PRX_CONTEXT Context; 7266 7267 Entry = RemoveHeadList(&PurgeSyncCtx->ContextsAwaitingPurgeCompletion); 7268 Context = CONTAINING_RECORD(Entry, RX_CONTEXT, RxContextSerializationQLinks); 7269 7270 RxSignalSynchronousWaiter(Context); 7271 } 7272 7273 RxReleaseScavengerMutex(); 7274 7275 return (SuccessfullPurge > 0 ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL); 7276 } 7277 7278 /* 7279 * @implemented 7280 */ 7281 VOID 7282 RxpWorkerThreadDispatcher( 7283 IN PRX_WORK_QUEUE WorkQueue, 7284 IN PLARGE_INTEGER WaitInterval) 7285 { 7286 NTSTATUS Status; 7287 PVOID Parameter; 7288 PETHREAD CurrentThread; 7289 BOOLEAN KillThread, Dereference; 7290 PRX_WORK_QUEUE_ITEM WorkQueueItem; 7291 PWORKER_THREAD_ROUTINE WorkerRoutine; 7292 7293 InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads); 7294 7295 /* Reference ourselves */ 7296 CurrentThread = PsGetCurrentThread(); 7297 Status = ObReferenceObjectByPointer(CurrentThread, THREAD_ALL_ACCESS, *PsThreadType, KernelMode); 7298 ASSERT(NT_SUCCESS(Status)); 7299 7300 /* Infinite loop for worker */ 7301 KillThread = FALSE; 7302 Dereference = FALSE; 7303 do 7304 { 7305 KIRQL OldIrql; 7306 PLIST_ENTRY ListEntry; 7307 7308 /* Remove an entry from the work queue */ 7309 ListEntry = KeRemoveQueue(&WorkQueue->Queue, KernelMode, WaitInterval); 7310 if ((ULONG_PTR)ListEntry != STATUS_TIMEOUT) 7311 { 7312 PRDBSS_DEVICE_OBJECT DeviceObject; 7313 7314 WorkQueueItem = CONTAINING_RECORD(ListEntry, RX_WORK_QUEUE_ITEM, List); 7315 7316 InterlockedIncrement(&WorkQueue->NumberOfWorkItemsDispatched); 7317 InterlockedDecrement(&WorkQueue->NumberOfWorkItemsToBeDispatched); 7318 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads); 7319 7320 /* Get the parameters, and null-them in the struct */ 7321 WorkerRoutine = WorkQueueItem->WorkerRoutine; 7322 Parameter = WorkQueueItem->Parameter; 7323 DeviceObject = WorkQueueItem->pDeviceObject; 7324 7325 WorkQueueItem->List.Flink = NULL; 7326 WorkQueueItem->WorkerRoutine = NULL; 7327 WorkQueueItem->Parameter = NULL; 7328 WorkQueueItem->pDeviceObject = NULL; 7329 7330 /* Call the routine */ 7331 DPRINT("Calling: %p(%p)\n", WorkerRoutine, Parameter); 7332 WorkerRoutine(Parameter); 7333 7334 /* Are we going down now? */ 7335 if (InterlockedDecrement(&DeviceObject->DispatcherContext.NumberOfWorkerThreads) == 0) 7336 { 7337 PKEVENT TearDownEvent; 7338 7339 TearDownEvent = InterlockedExchangePointer((void * volatile*)&DeviceObject->DispatcherContext.pTearDownEvent, NULL); 7340 if (TearDownEvent != NULL) 7341 { 7342 KeSetEvent(TearDownEvent, IO_NO_INCREMENT, FALSE); 7343 } 7344 } 7345 7346 InterlockedIncrement(&WorkQueue->NumberOfIdleWorkerThreads); 7347 } 7348 7349 /* Shall we shutdown... */ 7350 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql); 7351 switch (WorkQueue->State) 7352 { 7353 /* Our queue is active, kill it if we have no more items to dispatch 7354 * and more threads than the required minimum 7355 */ 7356 case RxWorkQueueActive: 7357 if (WorkQueue->NumberOfWorkItemsToBeDispatched <= 0) 7358 { 7359 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0); 7360 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads) 7361 { 7362 KillThread = TRUE; 7363 Dereference = TRUE; 7364 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads); 7365 } 7366 7367 if (KillThread) 7368 { 7369 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads); 7370 } 7371 } 7372 break; 7373 7374 /* The queue is inactive: kill it we have more threads than the required minimum */ 7375 case RxWorkQueueInactive: 7376 ASSERT(WorkQueue->NumberOfActiveWorkerThreads > 0); 7377 if (WorkQueue->NumberOfActiveWorkerThreads > WorkQueue->MinimumNumberOfWorkerThreads) 7378 { 7379 KillThread = TRUE; 7380 Dereference = TRUE; 7381 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads); 7382 } 7383 7384 if (KillThread) 7385 { 7386 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads); 7387 } 7388 break; 7389 7390 /* Rundown in progress..., kill it for sure! */ 7391 case RxWorkQueueRundownInProgress: 7392 { 7393 PRX_WORK_QUEUE_RUNDOWN_CONTEXT RundownContext; 7394 7395 ASSERT(WorkQueue->pRundownContext != NULL); 7396 7397 RundownContext = WorkQueue->pRundownContext; 7398 RundownContext->ThreadPointers[RundownContext->NumberOfThreadsSpunDown++] = CurrentThread; 7399 7400 InterlockedDecrement(&WorkQueue->NumberOfActiveWorkerThreads); 7401 KillThread = TRUE; 7402 Dereference = FALSE; 7403 7404 if (WorkQueue->NumberOfActiveWorkerThreads == 0) 7405 { 7406 KeSetEvent(&RundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE); 7407 } 7408 7409 InterlockedDecrement(&WorkQueue->NumberOfIdleWorkerThreads); 7410 } 7411 break; 7412 7413 default: 7414 break; 7415 } 7416 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql); 7417 } while (!KillThread); 7418 7419 DPRINT("Killed worker thread\n"); 7420 7421 /* Do we have to dereference ourselves? */ 7422 if (Dereference) 7423 { 7424 ObDereferenceObject(CurrentThread); 7425 } 7426 7427 /* Dump last executed routine */ 7428 if (DumpDispatchRoutine) 7429 { 7430 DPRINT("Dispatch routine %p(%p) taken from %p\n", WorkerRoutine, Parameter, WorkQueueItem); 7431 } 7432 7433 PsTerminateSystemThread(STATUS_SUCCESS); 7434 } 7435 7436 VOID 7437 RxReference( 7438 IN OUT PVOID Instance) 7439 { 7440 NODE_TYPE_CODE NodeType; 7441 PNODE_TYPE_AND_SIZE Node; 7442 7443 PAGED_CODE(); 7444 7445 RxAcquireScavengerMutex(); 7446 7447 /* We can only reference a few structs */ 7448 NodeType = NodeType(Instance) & ~RX_SCAVENGER_MASK; 7449 ASSERT((NodeType == RDBSS_NTC_SRVCALL) || (NodeType == RDBSS_NTC_NETROOT) || 7450 (NodeType == RDBSS_NTC_V_NETROOT) || (NodeType == RDBSS_NTC_SRVOPEN) || 7451 (NodeType == RDBSS_NTC_FOBX)); 7452 7453 Node = (PNODE_TYPE_AND_SIZE)Instance; 7454 InterlockedIncrement((volatile long *)&Node->NodeReferenceCount); 7455 7456 /* Trace refcount if asked */ 7457 switch (NodeType) 7458 { 7459 case RDBSS_NTC_SRVCALL: 7460 PRINT_REF_COUNT(SRVCALL, Node->NodeReferenceCount); 7461 break; 7462 7463 case RDBSS_NTC_NETROOT: 7464 PRINT_REF_COUNT(NETROOT, Node->NodeReferenceCount); 7465 break; 7466 7467 case RDBSS_NTC_V_NETROOT: 7468 PRINT_REF_COUNT(VNETROOT, Node->NodeReferenceCount); 7469 break; 7470 7471 case RDBSS_NTC_SRVOPEN: 7472 PRINT_REF_COUNT(SRVOPEN, Node->NodeReferenceCount); 7473 break; 7474 7475 case RDBSS_NTC_FOBX: 7476 PRINT_REF_COUNT(NETFOBX, Node->NodeReferenceCount); 7477 break; 7478 7479 default: 7480 ASSERT(FALSE); 7481 break; 7482 } 7483 7484 RxpUndoScavengerFinalizationMarking(Instance); 7485 RxReleaseScavengerMutex(); 7486 } 7487 7488 /* 7489 * @implemented 7490 */ 7491 VOID 7492 NTAPI 7493 RxReinitializeContext( 7494 IN OUT PRX_CONTEXT RxContext) 7495 { 7496 PIRP Irp; 7497 PRDBSS_DEVICE_OBJECT RxDeviceObject; 7498 ULONG InitialContextFlags, SavedFlags; 7499 7500 PAGED_CODE(); 7501 7502 /* Backup a few flags */ 7503 Irp = RxContext->CurrentIrp; 7504 RxDeviceObject = RxContext->RxDeviceObject; 7505 SavedFlags = RxContext->Flags & RX_CONTEXT_PRESERVED_FLAGS; 7506 InitialContextFlags = RxContext->Flags & RX_CONTEXT_INITIALIZATION_FLAGS; 7507 7508 /* Reset our context */ 7509 RxPrepareContextForReuse(RxContext); 7510 7511 /* Zero everything */ 7512 RtlZeroMemory(&RxContext->MajorFunction, sizeof(RX_CONTEXT) - FIELD_OFFSET(RX_CONTEXT, MajorFunction)); 7513 7514 /* Restore saved flags */ 7515 RxContext->Flags = SavedFlags; 7516 /* And reinit the context */ 7517 RxInitializeContext(Irp, RxDeviceObject, InitialContextFlags, RxContext); 7518 } 7519 7520 /* 7521 * @implemented 7522 */ 7523 VOID 7524 NTAPI 7525 RxReleaseFcbFromLazyWrite( 7526 PVOID Context) 7527 { 7528 PFCB Fcb; 7529 7530 PAGED_CODE(); 7531 7532 Fcb = Context; 7533 /* The received context is a FCB */ 7534 ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB); 7535 ASSERT_CORRECT_FCB_STRUCTURE(Fcb); 7536 7537 /* Lazy writer is releasing lock, so forget about it */ 7538 Fcb->Specific.Fcb.LazyWriteThread = NULL; 7539 7540 /* If we were top level IRP, unwind */ 7541 if (RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) 7542 { 7543 RxUnwindTopLevelIrp(NULL); 7544 } 7545 7546 /* And finally, release the lock */ 7547 Fcb->PagingIoResourceFile = NULL; 7548 Fcb->PagingIoResourceLine = 0; 7549 ExReleaseResourceLite(Fcb->Header.PagingIoResource); 7550 } 7551 7552 /* 7553 * @implemented 7554 */ 7555 VOID 7556 NTAPI 7557 RxReleaseFcbFromReadAhead( 7558 PVOID Context) 7559 { 7560 PFCB Fcb; 7561 7562 PAGED_CODE(); 7563 7564 Fcb = Context; 7565 /* The received context is a FCB */ 7566 ASSERT(NodeType(Fcb) == RDBSS_NTC_FCB); 7567 ASSERT_CORRECT_FCB_STRUCTURE(Fcb); 7568 7569 /* Top Level IRP is CC */ 7570 ASSERT(RxGetTopIrpIfRdbssIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); 7571 RxUnwindTopLevelIrp(NULL); 7572 7573 ExReleaseResourceLite(Fcb->Header.Resource); 7574 } 7575 7576 VOID 7577 NTAPI 7578 RxReleaseFileForNtCreateSection( 7579 PFILE_OBJECT FileObject) 7580 { 7581 UNIMPLEMENTED; 7582 } 7583 7584 NTSTATUS 7585 NTAPI 7586 RxReleaseForCcFlush( 7587 PFILE_OBJECT FileObject, 7588 PDEVICE_OBJECT DeviceObject) 7589 { 7590 UNIMPLEMENTED; 7591 return STATUS_NOT_IMPLEMENTED; 7592 } 7593 7594 /* 7595 * @implemented 7596 */ 7597 VOID 7598 RxRemoveNameNetFcb( 7599 OUT PFCB ThisFcb) 7600 { 7601 PNET_ROOT NetRoot; 7602 7603 PAGED_CODE(); 7604 7605 ASSERT(NodeTypeIsFcb(ThisFcb)); 7606 7607 /* Just remove the entry from the FCB_TABLE */ 7608 NetRoot = (PNET_ROOT)ThisFcb->VNetRoot->pNetRoot; 7609 ASSERT(RxIsFcbTableLockExclusive(&NetRoot->FcbTable)); 7610 ASSERT(RxIsFcbAcquiredExclusive(ThisFcb)); 7611 7612 #ifdef __REACTOS__ 7613 if (!BooleanFlagOn(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED)) 7614 { 7615 #endif 7616 RxFcbTableRemoveFcb(&NetRoot->FcbTable, ThisFcb); 7617 DPRINT("FCB (%p) %wZ removed\n", ThisFcb, &ThisFcb->FcbTableEntry.Path); 7618 /* Mark, so that we don't try to do it twice */ 7619 SetFlag(ThisFcb->FcbState, FCB_STATE_NAME_ALREADY_REMOVED); 7620 #ifdef __REACTOS__ 7621 } 7622 #endif 7623 } 7624 7625 /* 7626 * @implemented 7627 */ 7628 VOID 7629 RxRemoveOperationFromBlockingQueue( 7630 IN OUT PRX_CONTEXT RxContext) 7631 { 7632 /* Acquire the pipe mutex */ 7633 ExAcquireFastMutex(&RxContextPerFileSerializationMutex); 7634 7635 /* Is that a blocking serial operation? */ 7636 if (BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) 7637 { 7638 /* Clear it! */ 7639 ClearFlag(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION); 7640 7641 /* Drop it off the list */ 7642 RemoveEntryList(&RxContext->RxContextSerializationQLinks); 7643 RxContext->RxContextSerializationQLinks.Flink = NULL; 7644 RxContext->RxContextSerializationQLinks.Blink = NULL; 7645 } 7646 7647 /* Done */ 7648 ExReleaseFastMutex(&RxContextPerFileSerializationMutex); 7649 } 7650 7651 /* 7652 * @implemented 7653 */ 7654 VOID 7655 RxRemovePrefixTableEntry( 7656 IN OUT PRX_PREFIX_TABLE ThisTable, 7657 IN OUT PRX_PREFIX_ENTRY Entry) 7658 { 7659 PAGED_CODE(); 7660 7661 ASSERT(NodeType(Entry) == RDBSS_NTC_PREFIX_ENTRY); 7662 ASSERT(RxIsPrefixTableLockExclusive(ThisTable)); 7663 7664 /* Check whether we're asked to remove null entry */ 7665 if (Entry->Prefix.Length == 0) 7666 { 7667 ThisTable->TableEntryForNull = NULL; 7668 } 7669 else 7670 { 7671 RemoveEntryList(&Entry->HashLinks); 7672 } 7673 7674 Entry->ContainingRecord = NULL; 7675 7676 /* Also remove it from global list */ 7677 RemoveEntryList(&Entry->MemberQLinks); 7678 7679 ++ThisTable->Version; 7680 } 7681 7682 /* 7683 * @implemented 7684 */ 7685 VOID 7686 RxRemoveVirtualNetRootFromNetRoot( 7687 PNET_ROOT NetRoot, 7688 PV_NET_ROOT VNetRoot) 7689 { 7690 PRX_PREFIX_TABLE PrefixTable; 7691 7692 PAGED_CODE(); 7693 7694 PrefixTable = NetRoot->pSrvCall->RxDeviceObject->pRxNetNameTable; 7695 ASSERT(RxIsPrefixTableLockAcquired(PrefixTable)); 7696 7697 /* Remove the VNetRoot from the list in the NetRoot */ 7698 --NetRoot->NumberOfVirtualNetRoots; 7699 RemoveEntryList(&VNetRoot->NetRootListEntry); 7700 7701 /* Fix the NetRoot if we were the default VNetRoot */ 7702 if (NetRoot->DefaultVNetRoot == VNetRoot) 7703 { 7704 /* Put the first one available */ 7705 if (!IsListEmpty(&NetRoot->VirtualNetRoots)) 7706 { 7707 NetRoot->DefaultVNetRoot = CONTAINING_RECORD(NetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry); 7708 } 7709 /* Otherwise, none */ 7710 else 7711 { 7712 NetRoot->DefaultVNetRoot = NULL; 7713 } 7714 } 7715 7716 /* If there are still other VNetRoot available, we're done */ 7717 if (!IsListEmpty(&NetRoot->VirtualNetRoots)) 7718 { 7719 return; 7720 } 7721 7722 /* Otherwise, initiate NetRoot finalization */ 7723 if (!BooleanFlagOn(NetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED)) 7724 { 7725 RxRemovePrefixTableEntry(PrefixTable, &NetRoot->PrefixEntry); 7726 SetFlag(NetRoot->Flags, NETROOT_FLAG_NAME_ALREADY_REMOVED); 7727 } 7728 7729 /* Notify mini-rdr */ 7730 if (NetRoot->pSrvCall != NULL && NetRoot->pSrvCall->RxDeviceObject != NULL) 7731 { 7732 NTSTATUS Status; 7733 7734 MINIRDR_CALL_THROUGH(Status, NetRoot->pSrvCall->RxDeviceObject->Dispatch, 7735 MRxFinalizeNetRoot, ((PMRX_NET_ROOT)NetRoot, FALSE)); 7736 (void)Status; 7737 } 7738 } 7739 7740 VOID 7741 RxResumeBlockedOperations_ALL( 7742 IN OUT PRX_CONTEXT RxContext) 7743 { 7744 LIST_ENTRY BlockedOps; 7745 7746 PAGED_CODE(); 7747 7748 /* Get the blocked operations */ 7749 RxTransferListWithMutex(&BlockedOps, &RxContext->BlockedOperations, RxContext->BlockedOpsMutex); 7750 7751 if (!IsListEmpty(&BlockedOps)) 7752 { 7753 UNIMPLEMENTED; 7754 } 7755 } 7756 7757 VOID 7758 NTAPI 7759 RxResumeBlockedOperations_Serially( 7760 IN OUT PRX_CONTEXT RxContext, 7761 IN OUT PLIST_ENTRY BlockingIoQ) 7762 { 7763 PAGED_CODE(); 7764 7765 RxAcquireSerializationMutex(); 7766 7767 /* This can only happen on pipes */ 7768 if (!BooleanFlagOn(RxContext->FlagsForLowIo, RXCONTEXT_FLAG4LOWIO_PIPE_SYNC_OPERATION)) 7769 { 7770 RxReleaseSerializationMutex(); 7771 return; 7772 } 7773 7774 UNIMPLEMENTED; 7775 7776 RxReleaseSerializationMutex(); 7777 } 7778 7779 /* 7780 * @implemented 7781 */ 7782 VOID 7783 RxSetFileSizeWithLock( 7784 IN OUT PFCB Fcb, 7785 IN PLONGLONG FileSize) 7786 { 7787 PAGED_CODE(); 7788 7789 /* Set attribute and increase version */ 7790 Fcb->Header.FileSize.QuadPart = *FileSize; 7791 ++Fcb->ulFileSizeVersion; 7792 } 7793 7794 /* 7795 * @implemented 7796 */ 7797 VOID 7798 RxScavengeFobxsForNetRoot( 7799 PNET_ROOT NetRoot, 7800 PFCB PurgingFcb, 7801 BOOLEAN SynchronizeWithScavenger) 7802 { 7803 PRDBSS_SCAVENGER Scavenger; 7804 PRDBSS_DEVICE_OBJECT RxDeviceObject; 7805 7806 PAGED_CODE(); 7807 7808 RxDeviceObject = NetRoot->pSrvCall->RxDeviceObject; 7809 Scavenger = RxDeviceObject->pRdbssScavenger; 7810 7811 /* Wait for the scavenger, if asked to */ 7812 if (SynchronizeWithScavenger) 7813 { 7814 KeWaitForSingleObject(&Scavenger->ScavengeEvent, Executive, KernelMode, FALSE, NULL); 7815 } 7816 7817 RxAcquireScavengerMutex(); 7818 7819 /* If there's nothing left to do... */ 7820 if (Scavenger->FobxsToBeFinalized <= 0) 7821 { 7822 RxReleaseScavengerMutex(); 7823 } 7824 else 7825 { 7826 PLIST_ENTRY Entry; 7827 LIST_ENTRY FobxToScavenge; 7828 7829 InitializeListHead(&FobxToScavenge); 7830 7831 /* Browse all the FOBXs to finalize */ 7832 Entry = Scavenger->FobxFinalizationList.Flink; 7833 while (Entry != &Scavenger->FobxFinalizationList) 7834 { 7835 PFOBX Fobx; 7836 7837 Fobx = CONTAINING_RECORD(Entry, FOBX, ScavengerFinalizationList); 7838 Entry = Entry->Flink; 7839 7840 if (Fobx->SrvOpen != NULL) 7841 { 7842 PFCB Fcb; 7843 7844 Fcb = (PFCB)Fobx->SrvOpen->pFcb; 7845 7846 /* If it matches our NET_ROOT */ 7847 if ((PNET_ROOT)Fcb->pNetRoot == NetRoot) 7848 { 7849 NTSTATUS Status; 7850 7851 /* Check whether it matches our FCB */ 7852 Status = STATUS_MORE_PROCESSING_REQUIRED; 7853 if (PurgingFcb != NULL && PurgingFcb != Fcb) 7854 { 7855 MINIRDR_CALL_THROUGH(Status, RxDeviceObject->Dispatch, MRxAreFilesAliased, (Fcb, PurgingFcb)); 7856 } 7857 7858 /* If so, add it to the list of the FOBXs to scavenge */ 7859 if (Status != STATUS_SUCCESS) 7860 { 7861 RxReferenceNetFobx(Fobx); 7862 ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX); 7863 7864 RemoveEntryList(&Fobx->ScavengerFinalizationList); 7865 InsertTailList(&FobxToScavenge, &Fobx->ScavengerFinalizationList); 7866 } 7867 } 7868 } 7869 } 7870 7871 RxReleaseScavengerMutex(); 7872 7873 /* Now, scavenge all the extracted FOBX */ 7874 RxpScavengeFobxs(Scavenger, &FobxToScavenge); 7875 } 7876 7877 if (SynchronizeWithScavenger) 7878 { 7879 KeSetEvent(&Scavenger->ScavengeEvent, IO_NO_INCREMENT, FALSE); 7880 } 7881 } 7882 7883 /* 7884 * @implemented 7885 */ 7886 BOOLEAN 7887 RxScavengeRelatedFobxs( 7888 PFCB Fcb) 7889 { 7890 PFOBX Fobx; 7891 LIST_ENTRY LocalList; 7892 PLIST_ENTRY NextEntry; 7893 PRDBSS_SCAVENGER Scavenger; 7894 7895 PAGED_CODE(); 7896 7897 /* First of all, check whether there are FOBX to scavenge */ 7898 Scavenger = Fcb->RxDeviceObject->pRdbssScavenger; 7899 RxAcquireScavengerMutex(); 7900 if (Scavenger->FobxsToBeFinalized <= 0) 7901 { 7902 RxReleaseScavengerMutex(); 7903 return FALSE; 7904 } 7905 7906 /* Initialize our local list which will hold all the FOBX to scavenge so 7907 * that we don't acquire the scavenger mutex too long 7908 */ 7909 InitializeListHead(&LocalList); 7910 7911 /* Technically, that condition should all be true... */ 7912 if (!IsListEmpty(&Scavenger->FobxFinalizationList)) 7913 { 7914 PLIST_ENTRY NextEntry, LastEntry; 7915 7916 /* Browse all the FCBs to find the matching ones */ 7917 NextEntry = Scavenger->FobxFinalizationList.Flink; 7918 LastEntry = &Scavenger->FobxFinalizationList; 7919 while (NextEntry != LastEntry) 7920 { 7921 Fobx = CONTAINING_RECORD(NextEntry, FOBX, ScavengerFinalizationList); 7922 NextEntry = NextEntry->Flink; 7923 /* Matching our FCB? Let's finalize it */ 7924 if (Fobx->pSrvOpen != NULL && Fobx->pSrvOpen->pFcb == RX_GET_MRX_FCB(Fcb)) 7925 { 7926 RxpUndoScavengerFinalizationMarking(Fobx); 7927 ASSERT(NodeType(Fobx) == RDBSS_NTC_FOBX); 7928 InsertTailList(&LocalList, &Fobx->ScavengerFinalizationList); 7929 } 7930 } 7931 } 7932 7933 RxReleaseScavengerMutex(); 7934 7935 /* Nothing to scavenge? Quit */ 7936 if (IsListEmpty(&LocalList)) 7937 { 7938 return FALSE; 7939 } 7940 7941 /* Now, finalize all the extracted FOBX */ 7942 while (!IsListEmpty(&LocalList)) 7943 { 7944 NextEntry = RemoveHeadList(&LocalList); 7945 Fobx = CONTAINING_RECORD(NextEntry, FOBX, ScavengerFinalizationList); 7946 RxFinalizeNetFobx(Fobx, TRUE, TRUE); 7947 } 7948 7949 return TRUE; 7950 } 7951 7952 VOID 7953 RxScavengerFinalizeEntries( 7954 PRDBSS_DEVICE_OBJECT DeviceObject) 7955 { 7956 UNIMPLEMENTED; 7957 } 7958 7959 /* 7960 * @implemented 7961 */ 7962 VOID 7963 NTAPI 7964 RxScavengerTimerRoutine( 7965 PVOID Context) 7966 { 7967 BOOLEAN Requeue; 7968 PRDBSS_DEVICE_OBJECT DeviceObject; 7969 PRDBSS_SCAVENGER Scavenger; 7970 7971 PAGED_CODE(); 7972 7973 DeviceObject = Context; 7974 Scavenger = DeviceObject->pRdbssScavenger; 7975 7976 Requeue = FALSE; 7977 RxAcquireScavengerMutex(); 7978 /* If the scavenger was dormant, wake it up! */ 7979 if (Scavenger->State == RDBSS_SCAVENGER_DORMANT) 7980 { 7981 /* Done */ 7982 Scavenger->State = RDBSS_SCAVENGER_ACTIVE; 7983 KeClearEvent(&Scavenger->ScavengeEvent); 7984 7985 /* Scavenger the entries */ 7986 RxReleaseScavengerMutex(); 7987 RxScavengerFinalizeEntries(DeviceObject); 7988 RxAcquireScavengerMutex(); 7989 7990 /* If we're still active (race) */ 7991 if (Scavenger->State == RDBSS_SCAVENGER_ACTIVE) 7992 { 7993 /* If there are new entries to scavenge, stay dormant and requeue a run */ 7994 if (Scavenger->NumberOfDormantFiles + Scavenger->SrvCallsToBeFinalized + 7995 Scavenger->NetRootsToBeFinalized + Scavenger->VNetRootsToBeFinalized + 7996 Scavenger->FcbsToBeFinalized + Scavenger->SrvOpensToBeFinalized + 7997 Scavenger->FobxsToBeFinalized != 0) 7998 { 7999 Requeue = TRUE; 8000 Scavenger->State = RDBSS_SCAVENGER_DORMANT; 8001 } 8002 /* Otherwise, we're inactive again */ 8003 else 8004 { 8005 Scavenger->State = RDBSS_SCAVENGER_INACTIVE; 8006 } 8007 } 8008 8009 RxReleaseScavengerMutex(); 8010 8011 /* Requeue an execution */ 8012 if (Requeue) 8013 { 8014 RxPostOneShotTimerRequest(RxFileSystemDeviceObject, &Scavenger->WorkItem, 8015 RxScavengerTimerRoutine, DeviceObject, Scavenger->TimeLimit); 8016 } 8017 } 8018 else 8019 { 8020 RxReleaseScavengerMutex(); 8021 } 8022 8023 KeSetEvent(&Scavenger->ScavengeEvent, IO_NO_INCREMENT, FALSE); 8024 } 8025 8026 BOOLEAN 8027 RxScavengeVNetRoots( 8028 PRDBSS_DEVICE_OBJECT RxDeviceObject) 8029 { 8030 UNIMPLEMENTED; 8031 return FALSE; 8032 } 8033 8034 /* 8035 * @implemented 8036 */ 8037 VOID 8038 NTAPI 8039 RxSpinUpRequestsDispatcher( 8040 PVOID Dispatcher) 8041 { 8042 NTSTATUS Status; 8043 PRX_DISPATCHER RxDispatcher; 8044 8045 Status = ObReferenceObjectByPointer(PsGetCurrentThread(), THREAD_ALL_ACCESS, *PsThreadType, KernelMode); 8046 if (!NT_SUCCESS(Status)) 8047 { 8048 PsTerminateSystemThread(STATUS_SUCCESS); 8049 } 8050 8051 RxDispatcher = Dispatcher; 8052 8053 do 8054 { 8055 KIRQL OldIrql; 8056 PLIST_ENTRY ListEntry; 8057 8058 Status = KeWaitForSingleObject(&RxDispatcher->SpinUpRequestsEvent, Executive, 8059 KernelMode, FALSE, &RxSpinUpDispatcherWaitInterval); 8060 ASSERT((Status == STATUS_SUCCESS) || (Status == STATUS_TIMEOUT)); 8061 8062 KeAcquireSpinLock(&RxDispatcher->SpinUpRequestsLock, &OldIrql); 8063 if (!IsListEmpty(&RxDispatcher->SpinUpRequests)) 8064 { 8065 ListEntry = RemoveHeadList(&RxDispatcher->SpinUpRequests); 8066 } 8067 else 8068 { 8069 ListEntry = &RxDispatcher->SpinUpRequests; 8070 } 8071 KeClearEvent(&RxDispatcher->SpinUpRequestsEvent); 8072 KeReleaseSpinLock(&RxDispatcher->SpinUpRequestsLock, OldIrql); 8073 8074 while (ListEntry != &RxDispatcher->SpinUpRequests) 8075 { 8076 PWORK_QUEUE_ITEM WorkItem; 8077 PRX_WORK_QUEUE WorkQueue; 8078 8079 WorkItem = CONTAINING_RECORD(ListEntry, WORK_QUEUE_ITEM, List); 8080 WorkQueue = WorkItem->Parameter; 8081 8082 InterlockedDecrement(&WorkQueue->WorkQueueItemForSpinUpWorkerThreadInUse); 8083 8084 DPRINT("Workqueue: calling %p(%p)\n", WorkItem->WorkerRoutine, WorkItem->Parameter); 8085 WorkItem->WorkerRoutine(WorkItem->Parameter); 8086 } 8087 } while (RxDispatcher->State == RxDispatcherActive); 8088 8089 KeSetEvent(&RxDispatcher->SpinUpRequestsTearDownEvent, IO_NO_INCREMENT, FALSE); 8090 PsTerminateSystemThread(STATUS_SUCCESS); 8091 } 8092 8093 /* 8094 * @implemented 8095 */ 8096 NTSTATUS 8097 RxSpinUpWorkerThread( 8098 PRX_WORK_QUEUE WorkQueue, 8099 PRX_WORKERTHREAD_ROUTINE Routine, 8100 PVOID Parameter) 8101 { 8102 KIRQL OldIrql; 8103 NTSTATUS Status; 8104 HANDLE ThreadHandle; 8105 8106 PAGED_CODE(); 8107 8108 /* If work queue is inactive, that cannot work */ 8109 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql); 8110 if (WorkQueue->State != RxWorkQueueActive) 8111 { 8112 Status = STATUS_UNSUCCESSFUL; 8113 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads); 8114 } 8115 else 8116 { 8117 ++WorkQueue->NumberOfActiveWorkerThreads; 8118 Status = STATUS_SUCCESS; 8119 } 8120 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql); 8121 8122 /* Quit on failure */ 8123 if (!NT_SUCCESS(Status)) 8124 { 8125 return Status; 8126 } 8127 8128 /* Spin up the worker thread */ 8129 Status = PsCreateSystemThread(&ThreadHandle, PROCESS_ALL_ACCESS, NULL, NULL, NULL, Routine, Parameter); 8130 if (NT_SUCCESS(Status)) 8131 { 8132 ZwClose(ThreadHandle); 8133 return Status; 8134 } 8135 /* Read well: we reached that point because it failed! */ 8136 DPRINT("WorkQ: %p, Status: %lx\n", WorkQueue, Status); 8137 8138 KeAcquireSpinLock(&WorkQueue->SpinLock, &OldIrql); 8139 --WorkQueue->NumberOfActiveWorkerThreads; 8140 ++WorkQueue->NumberOfFailedSpinUpRequests; 8141 8142 /* Rundown, no more active threads, set the event! */ 8143 if (WorkQueue->NumberOfActiveWorkerThreads == 0 && 8144 WorkQueue->State == RxWorkQueueRundownInProgress) 8145 { 8146 KeSetEvent(&WorkQueue->pRundownContext->RundownCompletionEvent, IO_NO_INCREMENT, FALSE); 8147 } 8148 8149 DPRINT("Workqueue not active! WorkQ: %p, State: %d, Active: %d\n", WorkQueue, WorkQueue->State, WorkQueue->NumberOfActiveWorkerThreads); 8150 8151 KeReleaseSpinLock(&WorkQueue->SpinLock, OldIrql); 8152 8153 return Status; 8154 } 8155 8156 VOID 8157 RxSpinUpWorkerThreads( 8158 PRX_WORK_QUEUE WorkQueue) 8159 { 8160 UNIMPLEMENTED; 8161 } 8162 8163 VOID 8164 RxSynchronizeWithScavenger( 8165 IN PRX_CONTEXT RxContext) 8166 { 8167 UNIMPLEMENTED; 8168 } 8169 8170 /* 8171 * @implemented 8172 */ 8173 ULONG 8174 RxTableComputeHashValue( 8175 IN PUNICODE_STRING Name) 8176 { 8177 ULONG Hash; 8178 SHORT Loops[8]; 8179 USHORT MaxChar, i; 8180 8181 PAGED_CODE(); 8182 8183 MaxChar = Name->Length / sizeof(WCHAR); 8184 8185 Loops[0] = 1; 8186 Loops[1] = MaxChar - 1; 8187 Loops[2] = MaxChar - 2; 8188 Loops[3] = MaxChar - 3; 8189 Loops[4] = MaxChar - 4; 8190 Loops[5] = MaxChar / 4; 8191 Loops[6] = 2 * MaxChar / 4; 8192 Loops[7] = 3 * MaxChar / 4; 8193 8194 Hash = 0; 8195 for (i = 0; i < 8; ++i) 8196 { 8197 SHORT Idx; 8198 8199 Idx = Loops[i]; 8200 if (Idx >= 0 && Idx < MaxChar) 8201 { 8202 Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash; 8203 } 8204 } 8205 8206 return Hash; 8207 } 8208 8209 /* 8210 * @implemented 8211 */ 8212 ULONG 8213 RxTableComputePathHashValue( 8214 IN PUNICODE_STRING Name) 8215 { 8216 ULONG Hash; 8217 SHORT Loops[8]; 8218 USHORT MaxChar, i; 8219 8220 PAGED_CODE(); 8221 8222 MaxChar = Name->Length / sizeof(WCHAR); 8223 8224 Loops[0] = 1; 8225 Loops[1] = MaxChar - 1; 8226 Loops[2] = MaxChar - 2; 8227 Loops[3] = MaxChar - 3; 8228 Loops[4] = MaxChar - 4; 8229 Loops[5] = MaxChar / 4; 8230 Loops[6] = 2 * MaxChar / 4; 8231 Loops[7] = 3 * MaxChar / 4; 8232 8233 Hash = 0; 8234 for (i = 0; i < 8; ++i) 8235 { 8236 SHORT Idx; 8237 8238 Idx = Loops[i]; 8239 if (Idx >= 0 && Idx < MaxChar) 8240 { 8241 Hash = RtlUpcaseUnicodeChar(Name->Buffer[Idx]) + 8 * Hash; 8242 } 8243 } 8244 8245 return Hash; 8246 } 8247 8248 /* 8249 * @implemented 8250 */ 8251 PVOID 8252 RxTableLookupName( 8253 IN PRX_PREFIX_TABLE ThisTable, 8254 IN PUNICODE_STRING Name, 8255 OUT PUNICODE_STRING RemainingName, 8256 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId) 8257 { 8258 PVOID Container; 8259 USHORT i, MaxChar; 8260 PRX_PREFIX_ENTRY Entry; 8261 RX_CONNECTION_ID NullId; 8262 UNICODE_STRING LookupString; 8263 8264 PAGED_CODE(); 8265 8266 /* If caller didn't provide a connection ID, setup one */ 8267 if (ThisTable->IsNetNameTable && RxConnectionId == NULL) 8268 { 8269 NullId.Luid.LowPart = 0; 8270 NullId.Luid.HighPart = 0; 8271 RxConnectionId = &NullId; 8272 } 8273 8274 /* Validate name */ 8275 ASSERT(Name->Buffer[0] == OBJ_NAME_PATH_SEPARATOR); 8276 8277 Entry = NULL; 8278 Container = NULL; 8279 LookupString.Buffer = Name->Buffer; 8280 MaxChar = Name->Length / sizeof(WCHAR); 8281 /* We'll perform the lookup, path component after another */ 8282 for (i = 1; i < MaxChar; ++i) 8283 { 8284 ULONG Hash; 8285 PRX_PREFIX_ENTRY CurEntry; 8286 8287 /* Don't cut in the middle of a path element */ 8288 if (Name->Buffer[i] != OBJ_NAME_PATH_SEPARATOR && Name->Buffer[i] != ':') 8289 { 8290 continue; 8291 } 8292 8293 /* Perform lookup in the table */ 8294 LookupString.Length = i * sizeof(WCHAR); 8295 Hash = RxTableComputeHashValue(&LookupString); 8296 CurEntry = RxTableLookupName_ExactLengthMatch(ThisTable, &LookupString, Hash, RxConnectionId); 8297 #if DBG 8298 ++ThisTable->Lookups; 8299 #endif 8300 /* Entry not found, move to the next component */ 8301 if (CurEntry == NULL) 8302 { 8303 #if DBG 8304 ++ThisTable->FailedLookups; 8305 #endif 8306 continue; 8307 } 8308 8309 Entry = CurEntry; 8310 ASSERT(Entry->ContainingRecord != NULL); 8311 Container = Entry->ContainingRecord; 8312 8313 /* If we have a NET_ROOT, let's return a V_NET_ROOT */ 8314 if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_NETROOT) 8315 { 8316 PNET_ROOT NetRoot; 8317 8318 NetRoot = (PNET_ROOT)Entry->ContainingRecord; 8319 /* If there's a default one, perfect, that's a match */ 8320 if (NetRoot->DefaultVNetRoot != NULL) 8321 { 8322 Container = NetRoot->DefaultVNetRoot; 8323 } 8324 /* If none (that shouldn't happen!), try to find one */ 8325 else 8326 { 8327 /* Use the first one in the list */ 8328 if (!IsListEmpty(&NetRoot->VirtualNetRoots)) 8329 { 8330 Container = CONTAINING_RECORD(NetRoot->VirtualNetRoots.Flink, V_NET_ROOT, NetRootListEntry); 8331 } 8332 /* Really, really, shouldn't happen */ 8333 else 8334 { 8335 ASSERT(FALSE); 8336 Entry = NULL; 8337 Container = NULL; 8338 } 8339 } 8340 8341 break; 8342 } 8343 else if ((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_V_NETROOT) 8344 { 8345 break; 8346 } 8347 else 8348 { 8349 ASSERT((NodeType(Entry->ContainingRecord) & ~RX_SCAVENGER_MASK) == RDBSS_NTC_SRVCALL); 8350 } 8351 } 8352 8353 /* Entry was found */ 8354 if (Entry != NULL) 8355 { 8356 DPRINT("Found\n"); 8357 8358 ASSERT(Name->Length >= Entry->Prefix.Length); 8359 8360 /* Setup remaining name */ 8361 RemainingName->Buffer = Add2Ptr(Name->Buffer, Entry->Prefix.Length); 8362 RemainingName->Length = Name->Length - Entry->Prefix.Length; 8363 RemainingName->MaximumLength = Name->Length - Entry->Prefix.Length; 8364 } 8365 else 8366 { 8367 /* Otherwise, that's the whole name */ 8368 RemainingName = Name; 8369 } 8370 8371 return Container; 8372 } 8373 8374 /* 8375 * @implemented 8376 */ 8377 PRX_PREFIX_ENTRY 8378 RxTableLookupName_ExactLengthMatch( 8379 IN PRX_PREFIX_TABLE ThisTable, 8380 IN PUNICODE_STRING Name, 8381 IN ULONG HashValue, 8382 IN PRX_CONNECTION_ID OPTIONAL RxConnectionId) 8383 { 8384 PLIST_ENTRY ListEntry, HashBucket; 8385 8386 PAGED_CODE(); 8387 8388 ASSERT(RxConnectionId != NULL); 8389 8390 /* Select the right bucket */ 8391 HashBucket = HASH_BUCKET(ThisTable, HashValue); 8392 DPRINT("Looking in bucket: %p for %x\n", HashBucket, HashValue); 8393 /* If bucket is empty, no match */ 8394 if (IsListEmpty(HashBucket)) 8395 { 8396 return NULL; 8397 } 8398 8399 /* Browse all the entries in the bucket */ 8400 for (ListEntry = HashBucket->Flink; 8401 ListEntry != HashBucket; 8402 ListEntry = ListEntry->Flink) 8403 { 8404 PVOID Container; 8405 PRX_PREFIX_ENTRY Entry; 8406 BOOLEAN CaseInsensitive; 8407 PUNICODE_STRING CmpName, CmpPrefix; 8408 UNICODE_STRING InsensitiveName, InsensitivePrefix; 8409 8410 Entry = CONTAINING_RECORD(ListEntry, RX_PREFIX_ENTRY, HashLinks); 8411 #if DBG 8412 ++ThisTable->Considers; 8413 #endif 8414 ASSERT(HashBucket == HASH_BUCKET(ThisTable, Entry->SavedHashValue)); 8415 8416 Container = Entry->ContainingRecord; 8417 ASSERT(Container != NULL); 8418 8419 /* Not the same hash, not the same length, move on */ 8420 if (Entry->SavedHashValue != HashValue || Entry->Prefix.Length != Name->Length) 8421 { 8422 continue; 8423 } 8424 8425 #if DBG 8426 ++ThisTable->Compares; 8427 #endif 8428 /* If we have to perform a case insensitive compare on a portion... */ 8429 if (Entry->CaseInsensitiveLength != 0) 8430 { 8431 ASSERT(Entry->CaseInsensitiveLength <= Name->Length); 8432 8433 /* Perform the case insensitive check on the asked length */ 8434 InsensitiveName.Buffer = Name->Buffer; 8435 InsensitivePrefix.Buffer = Entry->Prefix.Buffer; 8436 InsensitiveName.Length = Entry->CaseInsensitiveLength; 8437 InsensitivePrefix.Length = Entry->CaseInsensitiveLength; 8438 /* No match, move to the next entry */ 8439 if (!RtlEqualUnicodeString(&InsensitiveName, &InsensitivePrefix, TRUE)) 8440 { 8441 continue; 8442 } 8443 8444 /* Was the case insensitive covering the whole name? */ 8445 if (Name->Length == Entry->CaseInsensitiveLength) 8446 { 8447 /* If connection ID also matches, that a complete match! */ 8448 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId)) 8449 { 8450 return Entry; 8451 } 8452 } 8453 8454 /* Otherwise, we have to continue with the sensitive match.... */ 8455 InsensitiveName.Buffer = Add2Ptr(InsensitiveName.Buffer, Entry->CaseInsensitiveLength); 8456 InsensitivePrefix.Buffer = Add2Ptr(InsensitivePrefix.Buffer, Entry->CaseInsensitiveLength); 8457 InsensitiveName.Length = Name->Length - Entry->CaseInsensitiveLength; 8458 InsensitivePrefix.Length = Entry->Prefix.Length - Entry->CaseInsensitiveLength; 8459 8460 CmpName = &InsensitiveName; 8461 CmpPrefix = &InsensitivePrefix; 8462 CaseInsensitive = FALSE; 8463 } 8464 else 8465 { 8466 CmpName = Name; 8467 CmpPrefix = &Entry->Prefix; 8468 CaseInsensitive = ThisTable->CaseInsensitiveMatch; 8469 } 8470 8471 /* Perform the compare, if there's a match, also check for connection ID */ 8472 if (RtlEqualUnicodeString(CmpName, CmpPrefix, CaseInsensitive)) 8473 { 8474 if (!ThisTable->IsNetNameTable || RxEqualConnectionId(RxConnectionId, &Entry->ConnectionId)) 8475 { 8476 return Entry; 8477 } 8478 } 8479 } 8480 8481 return NULL; 8482 } 8483 8484 /* 8485 * @implemented 8486 */ 8487 NTSTATUS 8488 RxTearDownBufferingManager( 8489 PSRV_CALL SrvCall) 8490 { 8491 PAGED_CODE(); 8492 8493 /* Nothing to do */ 8494 return STATUS_SUCCESS; 8495 } 8496 8497 /* 8498 * @implemented 8499 */ 8500 VOID 8501 NTAPI 8502 RxTimerDispatch( 8503 _In_ struct _KDPC *Dpc, 8504 _In_opt_ PVOID DeferredContext, 8505 _In_opt_ PVOID SystemArgument1, 8506 _In_opt_ PVOID SystemArgument2) 8507 { 8508 BOOLEAN Set; 8509 LIST_ENTRY LocalList; 8510 PLIST_ENTRY ListEntry; 8511 PRX_WORK_ITEM WorkItem; 8512 8513 InitializeListHead(&LocalList); 8514 8515 KeAcquireSpinLockAtDpcLevel(&RxTimerLock); 8516 ++RxTimerTickCount; 8517 8518 /* Find any entry matching */ 8519 if (!IsListEmpty(&RxTimerQueueHead)) 8520 { 8521 ListEntry = RxTimerQueueHead.Flink; 8522 do 8523 { 8524 WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List); 8525 if (WorkItem->LastTick == RxTimerTickCount) 8526 { 8527 ListEntry = ListEntry->Flink; 8528 8529 RemoveEntryList(&WorkItem->WorkQueueItem.List); 8530 InsertTailList(&LocalList, &WorkItem->WorkQueueItem.List); 8531 } 8532 else 8533 { 8534 ListEntry = ListEntry->Flink; 8535 } 8536 } while (ListEntry != &RxTimerQueueHead); 8537 } 8538 /* Do we have to requeue a later execution? */ 8539 Set = !IsListEmpty(&RxTimerQueueHead); 8540 8541 KeReleaseSpinLockFromDpcLevel(&RxTimerLock); 8542 8543 /* Requeue if list wasn't empty */ 8544 if (Set) 8545 { 8546 KeSetTimer(&RxTimer, RxTimerInterval, &RxTimerDpc); 8547 } 8548 8549 /* If we had matching entries */ 8550 if (!IsListEmpty(&LocalList)) 8551 { 8552 /* Post them, one after another */ 8553 ListEntry = LocalList.Flink; 8554 do 8555 { 8556 WorkItem = CONTAINING_RECORD(ListEntry, RX_WORK_ITEM, WorkQueueItem.List); 8557 ListEntry = ListEntry->Flink; 8558 8559 WorkItem->WorkQueueItem.List.Flink = NULL; 8560 WorkItem->WorkQueueItem.List.Blink = NULL; 8561 RxPostToWorkerThread(WorkItem->WorkQueueItem.pDeviceObject, CriticalWorkQueue, 8562 &WorkItem->WorkQueueItem, WorkItem->WorkQueueItem.WorkerRoutine, 8563 WorkItem->WorkQueueItem.Parameter); 8564 } 8565 while (ListEntry != &LocalList); 8566 } 8567 } 8568 8569 #ifdef RDBSS_TRACKER 8570 /* 8571 * @implemented 8572 */ 8573 VOID 8574 RxTrackerUpdateHistory( 8575 _Inout_opt_ PRX_CONTEXT RxContext, 8576 _Inout_ PMRX_FCB MrxFcb, 8577 _In_ ULONG Operation, 8578 _In_ ULONG LineNumber, 8579 _In_ PCSTR FileName, 8580 _In_ ULONG SerialNumber) 8581 { 8582 PFCB Fcb; 8583 RX_FCBTRACKER_CASES Case; 8584 8585 /* Check for null or special context */ 8586 if (RxContext == NULL) 8587 { 8588 Case = RX_FCBTRACKER_CASE_NULLCONTEXT; 8589 } 8590 else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT) 8591 { 8592 Case = RX_FCBTRACKER_CASE_CBS_CONTEXT; 8593 } 8594 else if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT) 8595 { 8596 Case = RX_FCBTRACKER_CASE_CBS_WAIT_CONTEXT; 8597 } 8598 else 8599 { 8600 ASSERT(NodeType(RxContext) == RDBSS_NTC_RX_CONTEXT); 8601 Case = RX_FCBTRACKER_CASE_NORMAL; 8602 } 8603 8604 /* If caller provided a FCB, update its history */ 8605 if (MrxFcb != NULL) 8606 { 8607 Fcb = (PFCB)MrxFcb; 8608 ASSERT(NodeTypeIsFcb(Fcb)); 8609 8610 /* Only one acquire operation, so many release operations... */ 8611 if (Operation == TRACKER_ACQUIRE_FCB) 8612 { 8613 ++Fcb->FcbAcquires[Case]; 8614 } 8615 else 8616 { 8617 ++Fcb->FcbReleases[Case]; 8618 } 8619 } 8620 8621 /* If we have a normal context, update its history about this function calls */ 8622 if (Case == RX_FCBTRACKER_CASE_NORMAL) 8623 { 8624 ULONG TrackerHistoryPointer; 8625 8626 /* Only one acquire operation, so many release operations... */ 8627 if (Operation == TRACKER_ACQUIRE_FCB) 8628 { 8629 InterlockedIncrement(&RxContext->AcquireReleaseFcbTrackerX); 8630 } 8631 else 8632 { 8633 InterlockedDecrement(&RxContext->AcquireReleaseFcbTrackerX); 8634 } 8635 8636 /* We only keep track of the 32 first calls */ 8637 TrackerHistoryPointer = InterlockedExchangeAdd((volatile long *)&RxContext->TrackerHistoryPointer, 1); 8638 if (TrackerHistoryPointer < RDBSS_TRACKER_HISTORY_SIZE) 8639 { 8640 RxContext->TrackerHistory[TrackerHistoryPointer].AcquireRelease = Operation; 8641 RxContext->TrackerHistory[TrackerHistoryPointer].LineNumber = LineNumber; 8642 RxContext->TrackerHistory[TrackerHistoryPointer].FileName = (PSZ)FileName; 8643 RxContext->TrackerHistory[TrackerHistoryPointer].SavedTrackerValue = RxContext->AcquireReleaseFcbTrackerX; 8644 RxContext->TrackerHistory[TrackerHistoryPointer].Flags = RxContext->Flags; 8645 } 8646 8647 /* If it's negative, then we released once more than we acquired it?! */ 8648 ASSERT(RxContext->AcquireReleaseFcbTrackerX >= 0); 8649 } 8650 } 8651 #endif 8652 8653 VOID 8654 RxTrackPagingIoResource( 8655 _Inout_ PVOID Instance, 8656 _In_ ULONG Type, 8657 _In_ ULONG Line, 8658 _In_ PCSTR File) 8659 { 8660 UNIMPLEMENTED; 8661 } 8662 8663 /* 8664 * @implemented 8665 */ 8666 VOID 8667 RxUndoScavengerFinalizationMarking( 8668 PVOID Instance) 8669 { 8670 /* Just call internal routine with mutex held */ 8671 RxAcquireScavengerMutex(); 8672 RxpUndoScavengerFinalizationMarking(Instance); 8673 RxReleaseScavengerMutex(); 8674 } 8675 8676 /* 8677 * @implemented 8678 */ 8679 VOID 8680 RxUninitializeVNetRootParameters( 8681 IN PUNICODE_STRING UserName, 8682 IN PUNICODE_STRING UserDomainName, 8683 IN PUNICODE_STRING Password, 8684 OUT PULONG Flags) 8685 { 8686 PAGED_CODE(); 8687 8688 /* Only free what could have been allocated */ 8689 if (UserName != NULL) 8690 { 8691 RxFreePool(UserName); 8692 } 8693 8694 if (UserDomainName != NULL) 8695 { 8696 RxFreePool(UserDomainName); 8697 } 8698 8699 if (Password != NULL) 8700 { 8701 RxFreePool(Password); 8702 } 8703 8704 /* And remove the possibly set CSC agent flag */ 8705 if (Flags != NULL) 8706 { 8707 (*Flags) &= ~VNETROOT_FLAG_CSCAGENT_INSTANCE; 8708 } 8709 } 8710 8711 /* 8712 * @implemented 8713 */ 8714 VOID 8715 RxUpdateCondition( 8716 IN RX_BLOCK_CONDITION NewConditionValue, 8717 OUT PRX_BLOCK_CONDITION Condition, 8718 IN OUT PLIST_ENTRY TransitionWaitList) 8719 { 8720 PRX_CONTEXT Context; 8721 LIST_ENTRY SerializationQueue; 8722 8723 PAGED_CODE(); 8724 8725 DPRINT("RxUpdateCondition(%d, %p, %p)\n", NewConditionValue, Condition, TransitionWaitList); 8726 8727 /* Set the new condition */ 8728 RxAcquireSerializationMutex(); 8729 ASSERT(NewConditionValue != Condition_InTransition); 8730 *Condition = NewConditionValue; 8731 /* And get the serialization queue for treatment */ 8732 RxTransferList(&SerializationQueue, TransitionWaitList); 8733 RxReleaseSerializationMutex(); 8734 8735 /* Handle the serialization queue */ 8736 Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue); 8737 while (Context != NULL) 8738 { 8739 /* If the caller asked for post, post the request */ 8740 if (BooleanFlagOn(Context->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION)) 8741 { 8742 Context->Flags &= ~RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION; 8743 RxFsdPostRequest(Context); 8744 } 8745 /* Otherwise, wake up sleeping waiters */ 8746 else 8747 { 8748 RxSignalSynchronousWaiter(Context); 8749 } 8750 8751 Context = RxRemoveFirstContextFromSerializationQueue(&SerializationQueue); 8752 } 8753 } 8754 8755 /* 8756 * @implemented 8757 */ 8758 VOID 8759 RxVerifyOperationIsLegal( 8760 IN PRX_CONTEXT RxContext) 8761 { 8762 PIRP Irp; 8763 PMRX_FOBX Fobx; 8764 BOOLEAN FlagSet; 8765 PFILE_OBJECT FileObject; 8766 PIO_STACK_LOCATION Stack; 8767 8768 PAGED_CODE(); 8769 8770 Irp = RxContext->CurrentIrp; 8771 Stack = RxContext->CurrentIrpSp; 8772 FileObject = Stack->FileObject; 8773 8774 /* We'll only check stuff on opened files, this requires an IRP and a FO */ 8775 if (Irp == NULL || FileObject == NULL) 8776 { 8777 return; 8778 } 8779 8780 /* Set no exception for breakpoint - remember whether is was already set */ 8781 FlagSet = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT); 8782 SetFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT); 8783 8784 /* If we have a CCB, perform a few checks on opened file */ 8785 Fobx = RxContext->pFobx; 8786 if (Fobx != NULL) 8787 { 8788 PMRX_SRV_OPEN SrvOpen; 8789 8790 SrvOpen = Fobx->pSrvOpen; 8791 if (SrvOpen != NULL) 8792 { 8793 UCHAR MajorFunction; 8794 8795 MajorFunction = RxContext->MajorFunction; 8796 /* Only allow closing/cleanup operations on renamed files */ 8797 if (MajorFunction != IRP_MJ_CLEANUP && MajorFunction != IRP_MJ_CLOSE && 8798 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_RENAMED)) 8799 { 8800 RxContext->IoStatusBlock.Status = STATUS_FILE_RENAMED; 8801 ExRaiseStatus(STATUS_FILE_RENAMED); 8802 } 8803 8804 /* Only allow closing/cleanup operations on deleted files */ 8805 if (MajorFunction != IRP_MJ_CLEANUP && MajorFunction != IRP_MJ_CLOSE && 8806 BooleanFlagOn(SrvOpen->Flags, SRVOPEN_FLAG_FILE_DELETED)) 8807 { 8808 RxContext->IoStatusBlock.Status = STATUS_FILE_DELETED; 8809 ExRaiseStatus(STATUS_FILE_DELETED); 8810 } 8811 } 8812 } 8813 8814 /* If that's an open operation */ 8815 if (RxContext->MajorFunction == IRP_MJ_CREATE) 8816 { 8817 PFILE_OBJECT RelatedFileObject; 8818 8819 /* We won't allow an open operation relative to a file to be deleted */ 8820 RelatedFileObject = FileObject->RelatedFileObject; 8821 if (RelatedFileObject != NULL) 8822 { 8823 PMRX_FCB Fcb; 8824 8825 Fcb = RelatedFileObject->FsContext; 8826 if (BooleanFlagOn(Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE)) 8827 { 8828 RxContext->IoStatusBlock.Status = STATUS_DELETE_PENDING; 8829 ExRaiseStatus(STATUS_DELETE_PENDING); 8830 } 8831 } 8832 } 8833 8834 /* If cleanup was completed */ 8835 if (BooleanFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) 8836 { 8837 if (!BooleanFlagOn(Irp->Flags, IRP_PAGING_IO)) 8838 { 8839 UCHAR MajorFunction; 8840 8841 /* We only allow a subset of operations (see FatVerifyOperationIsLegal for instance) */ 8842 MajorFunction = Stack->MajorFunction; 8843 if (MajorFunction != IRP_MJ_CLOSE && MajorFunction != IRP_MJ_QUERY_INFORMATION && 8844 MajorFunction != IRP_MJ_SET_INFORMATION) 8845 { 8846 if ((MajorFunction != IRP_MJ_READ && MajorFunction != IRP_MJ_WRITE) || 8847 !BooleanFlagOn(Stack->MinorFunction, IRP_MN_COMPLETE)) 8848 { 8849 RxContext->IoStatusBlock.Status = STATUS_FILE_CLOSED; 8850 ExRaiseStatus(STATUS_FILE_CLOSED); 8851 } 8852 } 8853 } 8854 } 8855 8856 /* If flag was already set, don't clear it */ 8857 if (!FlagSet) 8858 { 8859 ClearFlag(RxContext->Flags, RX_CONTEXT_FLAG_NO_EXCEPTION_BREAKPOINT); 8860 } 8861 } 8862 8863 /* 8864 * @implemented 8865 */ 8866 VOID 8867 RxWaitForStableCondition( 8868 IN PRX_BLOCK_CONDITION Condition, 8869 IN OUT PLIST_ENTRY TransitionWaitList, 8870 IN OUT PRX_CONTEXT RxContext, 8871 OUT NTSTATUS *AsyncStatus OPTIONAL) 8872 { 8873 BOOLEAN Wait; 8874 NTSTATUS LocalStatus; 8875 8876 PAGED_CODE(); 8877 8878 /* Make sure to always get status */ 8879 if (AsyncStatus == NULL) 8880 { 8881 AsyncStatus = &LocalStatus; 8882 } 8883 8884 /* By default, it's a success */ 8885 *AsyncStatus = STATUS_SUCCESS; 8886 8887 Wait = FALSE; 8888 /* If it's not stable, we've to wait */ 8889 if (!StableCondition(*Condition)) 8890 { 8891 /* Lock the mutex */ 8892 RxAcquireSerializationMutex(); 8893 /* Still not stable? */ 8894 if (!StableCondition(*Condition)) 8895 { 8896 /* Insert us in the wait list for processing on stable condition */ 8897 RxInsertContextInSerializationQueue(TransitionWaitList, RxContext); 8898 8899 /* If we're asked to post on stable, don't wait, and just return pending */ 8900 if (BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_POST_ON_STABLE_CONDITION)) 8901 { 8902 *AsyncStatus = STATUS_PENDING; 8903 } 8904 else 8905 { 8906 Wait = TRUE; 8907 } 8908 } 8909 RxReleaseSerializationMutex(); 8910 8911 /* We don't post on stable, so, just wait... */ 8912 if (Wait) 8913 { 8914 RxWaitSync(RxContext); 8915 } 8916 } 8917 } 8918 8919 /* 8920 * @implemented 8921 */ 8922 VOID 8923 NTAPI 8924 RxWorkItemDispatcher( 8925 PVOID Context) 8926 { 8927 PRX_WORK_DISPATCH_ITEM DispatchItem = Context; 8928 8929 DPRINT("Calling: %p, %p\n", DispatchItem->DispatchRoutine, DispatchItem->DispatchRoutineParameter); 8930 8931 DispatchItem->DispatchRoutine(DispatchItem->DispatchRoutineParameter); 8932 8933 RxFreePoolWithTag(DispatchItem, RX_WORKQ_POOLTAG); 8934 } 8935 8936 /* 8937 * @implemented 8938 */ 8939 PVOID 8940 NTAPI 8941 _RxAllocatePoolWithTag( 8942 _In_ POOL_TYPE PoolType, 8943 _In_ SIZE_T NumberOfBytes, 8944 _In_ ULONG Tag) 8945 { 8946 return ExAllocatePoolWithTagPriority(PoolType, NumberOfBytes, Tag, LowPoolPriority); 8947 } 8948 8949 /* 8950 * @implemented 8951 */ 8952 VOID 8953 NTAPI 8954 _RxFreePool( 8955 _In_ PVOID Buffer) 8956 { 8957 ExFreePoolWithTag(Buffer, 0); 8958 } 8959 8960 /* 8961 * @implemented 8962 */ 8963 VOID 8964 NTAPI 8965 _RxFreePoolWithTag( 8966 _In_ PVOID Buffer, 8967 _In_ ULONG Tag) 8968 { 8969 ExFreePoolWithTag(Buffer, Tag); 8970 } 8971 8972 NTSTATUS 8973 __RxAcquireFcb( 8974 _Inout_ PFCB Fcb, 8975 _Inout_opt_ PRX_CONTEXT RxContext OPTIONAL, 8976 _In_ ULONG Mode 8977 #ifdef RDBSS_TRACKER 8978 , 8979 _In_ ULONG LineNumber, 8980 _In_ PCSTR FileName, 8981 _In_ ULONG SerialNumber 8982 #endif 8983 ) 8984 { 8985 NTSTATUS Status; 8986 BOOLEAN SpecialContext, CanWait, Acquired, ContextIsPresent; 8987 8988 PAGED_CODE(); 8989 8990 DPRINT("__RxAcquireFcb(%p, %p, %d, %d, %s, %d)\n", Fcb, RxContext, Mode, LineNumber, FileName, SerialNumber); 8991 8992 SpecialContext = FALSE; 8993 ContextIsPresent = FALSE; 8994 /* Check for special context */ 8995 if (RxContext == CHANGE_BUFFERING_STATE_CONTEXT || RxContext == CHANGE_BUFFERING_STATE_CONTEXT_WAIT) 8996 { 8997 SpecialContext = TRUE; 8998 } 8999 9000 /* We don't handle buffering state change yet... */ 9001 if (!RxIsFcbAcquired(Fcb) && !SpecialContext && 9002 BooleanFlagOn(Fcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING)) 9003 { 9004 UNIMPLEMENTED; 9005 } 9006 9007 /* Nor special contexts */ 9008 if (SpecialContext) 9009 { 9010 UNIMPLEMENTED; 9011 } 9012 9013 /* If we don't have a context, assume we can wait! */ 9014 if (RxContext == NULL) 9015 { 9016 CanWait = TRUE; 9017 } 9018 else 9019 { 9020 /* That said: we have a real context! */ 9021 ContextIsPresent = TRUE; 9022 9023 /* If we've been cancelled in between, give up */ 9024 Status = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_CANCELLED) ? STATUS_CANCELLED : STATUS_SUCCESS; 9025 if (!NT_SUCCESS(Status)) 9026 { 9027 return Status; 9028 } 9029 9030 /* Can we wait? */ 9031 CanWait = BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT); 9032 } 9033 9034 while (TRUE) 9035 { 9036 /* Assume we cannot lock */ 9037 Status = STATUS_LOCK_NOT_GRANTED; 9038 9039 /* Lock according to what the caller asked */ 9040 switch (Mode) 9041 { 9042 case FCB_MODE_EXCLUSIVE: 9043 Acquired = ExAcquireResourceExclusiveLite(Fcb->Header.Resource, CanWait); 9044 break; 9045 9046 case FCB_MODE_SHARED: 9047 Acquired = ExAcquireResourceSharedLite(Fcb->Header.Resource, CanWait); 9048 break; 9049 9050 case FCB_MODE_SHARED_WAIT_FOR_EXCLUSIVE: 9051 Acquired = ExAcquireSharedWaitForExclusive(Fcb->Header.Resource, CanWait); 9052 break; 9053 9054 default: 9055 ASSERT(Mode == FCB_MODE_SHARED_STARVE_EXCLUSIVE); 9056 Acquired = ExAcquireSharedStarveExclusive(Fcb->Header.Resource, CanWait); 9057 break; 9058 } 9059 9060 /* Lock granted! */ 9061 if (Acquired) 9062 { 9063 Status = STATUS_SUCCESS; 9064 ASSERT_CORRECT_FCB_STRUCTURE(Fcb); 9065 9066 /* Handle paging write - not implemented */ 9067 if (Fcb->NonPaged->OutstandingAsyncWrites != 0) 9068 { 9069 UNIMPLEMENTED; 9070 } 9071 } 9072 9073 /* And break, that cool! */ 9074 if (Acquired) 9075 { 9076 break; 9077 } 9078 9079 /* If it failed, return immediately */ 9080 if (!NT_SUCCESS(Status)) 9081 { 9082 return Status; 9083 } 9084 } 9085 9086 /* If we don't have to check for valid operation, job done, nothing more to do */ 9087 if (!ContextIsPresent || BooleanFlagOn(RxContext->Flags, RX_CONTEXT_FLAG_BYPASS_VALIDOP_CHECK)) 9088 { 9089 if (NT_SUCCESS(Status)) 9090 { 9091 RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber); 9092 } 9093 9094 return Status; 9095 } 9096 9097 /* Verify operation */ 9098 _SEH2_TRY 9099 { 9100 RxVerifyOperationIsLegal(RxContext); 9101 } 9102 _SEH2_FINALLY 9103 { 9104 /* If it failed, release lock and fail */ 9105 if (_SEH2_AbnormalTermination()) 9106 { 9107 ExReleaseResourceLite(Fcb->Header.Resource); 9108 Status = STATUS_LOCK_NOT_GRANTED; 9109 } 9110 } 9111 _SEH2_END; 9112 9113 if (NT_SUCCESS(Status)) 9114 { 9115 RxTrackerUpdateHistory(RxContext, RX_GET_MRX_FCB(Fcb), TRACKER_ACQUIRE_FCB, LineNumber, FileName, SerialNumber); 9116 } 9117 9118 DPRINT("Status: %x\n", Status); 9119 return Status; 9120 } 9121 9122 /* 9123 * @implemented 9124 */ 9125 VOID 9126 __RxItsTheSameContext( 9127 _In_ PRX_CONTEXT RxContext, 9128 _In_ ULONG CapturedRxContextSerialNumber, 9129 _In_ ULONG Line, 9130 _In_ PCSTR File) 9131 { 9132 /* Check we have a context with the same serial number */ 9133 if (NodeType(RxContext) != RDBSS_NTC_RX_CONTEXT || 9134 RxContext->SerialNumber != CapturedRxContextSerialNumber) 9135 { 9136 /* Just be noisy */ 9137 DPRINT1("Context %p has changed at line %d in file %s\n", RxContext, Line, File); 9138 } 9139 } 9140 9141 VOID 9142 __RxReleaseFcb( 9143 _Inout_opt_ PRX_CONTEXT RxContext, 9144 _Inout_ PMRX_FCB MrxFcb 9145 #ifdef RDBSS_TRACKER 9146 , 9147 _In_ ULONG LineNumber, 9148 _In_ PCSTR FileName, 9149 _In_ ULONG SerialNumber 9150 #endif 9151 ) 9152 { 9153 BOOLEAN IsExclusive, BufferingPending; 9154 9155 RxAcquireSerializationMutex(); 9156 9157 BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING); 9158 IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource); 9159 9160 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock), 9161 * then just release the FCB 9162 */ 9163 if (!BufferingPending || !IsExclusive) 9164 { 9165 RxTrackerUpdateHistory(RxContext, MrxFcb, (!BufferingPending ? TRACKER_RELEASE_FCB_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_BUFF_PENDING), 9166 LineNumber, FileName, SerialNumber); 9167 ExReleaseResourceLite(MrxFcb->Header.Resource); 9168 } 9169 9170 RxReleaseSerializationMutex(); 9171 9172 /* And finally leave */ 9173 if (!BufferingPending || !IsExclusive) 9174 { 9175 return; 9176 } 9177 9178 ASSERT(RxIsFcbAcquiredExclusive(MrxFcb)); 9179 9180 /* Otherwise, handle buffering state and release */ 9181 RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb); 9182 9183 RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_BUFF_PENDING, LineNumber, FileName, SerialNumber); 9184 ExReleaseResourceLite(MrxFcb->Header.Resource); 9185 } 9186 9187 VOID 9188 __RxReleaseFcbForThread( 9189 _Inout_opt_ PRX_CONTEXT RxContext, 9190 _Inout_ PMRX_FCB MrxFcb, 9191 _In_ ERESOURCE_THREAD ResourceThreadId 9192 #ifdef RDBSS_TRACKER 9193 , 9194 _In_ ULONG LineNumber, 9195 _In_ PCSTR FileName, 9196 _In_ ULONG SerialNumber 9197 #endif 9198 ) 9199 { 9200 BOOLEAN IsExclusive, BufferingPending; 9201 9202 RxAcquireSerializationMutex(); 9203 9204 BufferingPending = BooleanFlagOn(MrxFcb->FcbState, FCB_STATE_BUFFERING_STATE_CHANGE_PENDING); 9205 IsExclusive = !!RxIsResourceOwnershipStateExclusive(MrxFcb->Header.Resource); 9206 9207 /* If no buffering pending, or no exclusive lock (we can only handle with an exclusive lock), 9208 * then just release the FCB 9209 */ 9210 if (!BufferingPending || !IsExclusive) 9211 { 9212 RxTrackerUpdateHistory(RxContext, MrxFcb, 9213 (!BufferingPending ? TRACKER_RELEASE_FCB_FOR_THRD_NO_BUFF_PENDING : TRACKER_RELEASE_NON_EXCL_FCB_FOR_THRD_BUFF_PENDING), 9214 LineNumber, FileName, SerialNumber); 9215 ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId); 9216 } 9217 9218 RxReleaseSerializationMutex(); 9219 9220 /* And finally leave */ 9221 if (!BufferingPending || !IsExclusive) 9222 { 9223 return; 9224 } 9225 9226 /* Otherwise, handle buffering state and release */ 9227 RxTrackerUpdateHistory(RxContext, MrxFcb, TRACKER_RELEASE_EXCL_FCB_FOR_THRD_BUFF_PENDING, LineNumber, FileName, SerialNumber); 9228 RxProcessFcbChangeBufferingStateRequest((PFCB)MrxFcb); 9229 ExReleaseResourceForThreadLite(MrxFcb->Header.Resource, ResourceThreadId); 9230 } 9231