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