1 //////////////////////////////////////////////////////////////////// 2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine 3 // All rights reserved 4 // This file was released under the GPLv2 on June 2015. 5 //////////////////////////////////////////////////////////////////// 6 /************************************************************************* 7 * 8 * File: Close.cpp 9 * 10 * Module: UDF File System Driver (Kernel mode execution only) 11 * 12 * Description: 13 * Contains code to handle the "Close" dispatch entry point. 14 * 15 *************************************************************************/ 16 17 #include "udffs.h" 18 19 // define the file specific bug-check id 20 #define UDF_BUG_CHECK_ID UDF_FILE_CLOSE 21 22 typedef BOOLEAN (*PCHECK_TREE_ITEM) (IN PUDF_FILE_INFO FileInfo); 23 #define TREE_ITEM_LIST_GRAN 32 24 25 NTSTATUS 26 UDFBuildTreeItemsList( 27 IN PVCB Vcb, 28 IN PUDF_FILE_INFO FileInfo, 29 IN PCHECK_TREE_ITEM CheckItemProc, 30 IN PUDF_DATALOC_INFO** PassedList, 31 IN PULONG PassedListSize, 32 IN PUDF_DATALOC_INFO** FoundList, 33 IN PULONG FoundListSize); 34 35 // callbacks, can't be __fastcall 36 BOOLEAN 37 UDFIsInDelayedCloseQueue( 38 PUDF_FILE_INFO FileInfo); 39 40 BOOLEAN 41 UDFIsLastClose( 42 PUDF_FILE_INFO FileInfo); 43 44 /************************************************************************* 45 * 46 * Function: UDFClose() 47 * 48 * Description: 49 * The I/O Manager will invoke this routine to handle a close 50 * request 51 * 52 * Expected Interrupt Level (for execution) : 53 * 54 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution 55 * to be deferred to a worker thread context) 56 * 57 * Return Value: STATUS_SUCCESS 58 * 59 *************************************************************************/ 60 NTSTATUS 61 NTAPI 62 UDFClose( 63 PDEVICE_OBJECT DeviceObject, // the logical volume device object 64 PIRP Irp // I/O Request Packet 65 ) 66 { 67 NTSTATUS RC = STATUS_SUCCESS; 68 PtrUDFIrpContext PtrIrpContext = NULL; 69 BOOLEAN AreWeTopLevel = FALSE; 70 71 AdPrint(("UDFClose: \n")); 72 73 FsRtlEnterFileSystem(); 74 ASSERT(DeviceObject); 75 ASSERT(Irp); 76 77 // If we were called with our file system device object instead of a 78 // volume device object, just complete this request with STATUS_SUCCESS 79 if (UDFIsFSDevObj(DeviceObject)) { 80 // this is a close of the FSD itself 81 Irp->IoStatus.Status = RC; 82 Irp->IoStatus.Information = 0; 83 84 IoCompleteRequest(Irp, IO_NO_INCREMENT); 85 FsRtlExitFileSystem(); 86 return(RC); 87 } 88 89 // set the top level context 90 AreWeTopLevel = UDFIsIrpTopLevel(Irp); 91 92 _SEH2_TRY { 93 94 // get an IRP context structure and issue the request 95 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject); 96 ASSERT(PtrIrpContext); 97 98 RC = UDFCommonClose(PtrIrpContext, Irp); 99 100 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) { 101 102 RC = UDFExceptionHandler(PtrIrpContext, Irp); 103 104 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC); 105 } _SEH2_END; 106 107 if (AreWeTopLevel) { 108 IoSetTopLevelIrp(NULL); 109 } 110 111 FsRtlExitFileSystem(); 112 113 return(RC); 114 } 115 116 117 118 119 /************************************************************************* 120 * 121 * Function: UDFCommonClose() 122 * 123 * Description: 124 * The actual work is performed here. This routine may be invoked in one' 125 * of the two possible contexts: 126 * (a) in the context of a system worker thread 127 * (b) in the context of the original caller 128 * 129 * Expected Interrupt Level (for execution) : 130 * 131 * IRQL_PASSIVE_LEVEL 132 * 133 * Return Value: must be STATUS_SUCCESS 134 * 135 *************************************************************************/ 136 NTSTATUS 137 UDFCommonClose( 138 PtrUDFIrpContext PtrIrpContext, 139 PIRP Irp 140 ) 141 { 142 NTSTATUS RC = STATUS_SUCCESS; 143 PIO_STACK_LOCATION IrpSp = NULL; 144 PFILE_OBJECT FileObject = NULL; 145 PtrUDFFCB Fcb = NULL; 146 PtrUDFCCB Ccb = NULL; 147 PVCB Vcb = NULL; 148 // PERESOURCE PtrResourceAcquired = NULL; 149 BOOLEAN AcquiredVcb = FALSE; 150 BOOLEAN AcquiredGD = FALSE; 151 PUDF_FILE_INFO fi; 152 ULONG i = 0; 153 // ULONG clean_stat = 0; 154 155 // BOOLEAN CompleteIrp = TRUE; 156 BOOLEAN PostRequest = FALSE; 157 158 #ifdef UDF_DBG 159 UNICODE_STRING CurName; 160 PDIR_INDEX_HDR DirNdx; 161 #endif 162 163 AdPrint(("UDFCommonClose: \n")); 164 165 _SEH2_TRY { 166 if (Irp) { 167 168 // If this is the first (IOManager) request 169 // First, get a pointer to the current I/O stack location 170 IrpSp = IoGetCurrentIrpStackLocation(Irp); 171 ASSERT(IrpSp); 172 173 FileObject = IrpSp->FileObject; 174 ASSERT(FileObject); 175 176 // Get the FCB and CCB pointers 177 Ccb = (PtrUDFCCB)(FileObject->FsContext2); 178 ASSERT(Ccb); 179 if(Ccb->CCBFlags & UDF_CCB_READ_ONLY) { 180 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_READ_ONLY; 181 } 182 Fcb = Ccb->Fcb; 183 } else { 184 // If this is a queued call (for our dispatch) 185 // Get saved Fcb address 186 Fcb = PtrIrpContext->Fcb; 187 i = PtrIrpContext->TreeLength; 188 } 189 190 ASSERT(Fcb); 191 Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension); 192 ASSERT(Vcb); 193 ASSERT(Vcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); 194 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK; 195 196 // Steps we shall take at this point are: 197 // (a) Acquire the VCB shared 198 // (b) Acquire the FCB's CCB list exclusively 199 // (c) Delete the CCB structure (free memory) 200 // (d) If this is the last close, release the FCB structure 201 // (unless we keep these around for "delayed close" functionality. 202 // Note that it is often the case that the close dispatch entry point is invoked 203 // in the most inconvenient of situations (when it is not possible, for example, 204 // to safely acquire certain required resources without deadlocking or waiting). 205 // Therefore, be extremely careful in implementing this close dispatch entry point. 206 // Also note that we do not have the option of returning a failure code from the 207 // close dispatch entry point; the system expects that the close will always succeed. 208 209 UDFAcquireResourceShared(&(Vcb->VCBResource), TRUE); 210 AcquiredVcb = TRUE; 211 212 // Is this is the first (IOManager) request ? 213 if (Irp) { 214 PtrIrpContext->TreeLength = 215 i = Ccb->TreeLength; 216 // remember the number of incomplete Close requests 217 InterlockedIncrement((PLONG)&(Fcb->CcbCount)); 218 // we can release CCB in any case 219 UDFCleanUpCCB(Ccb); 220 FileObject->FsContext2 = NULL; 221 #ifdef DBG 222 /* } else { 223 ASSERT(Fcb->NTRequiredFCB); 224 if(Fcb->NTRequiredFCB) { 225 ASSERT(Fcb->NTRequiredFCB->FileObject); 226 if(Fcb->NTRequiredFCB->FileObject) { 227 ASSERT(!Fcb->NTRequiredFCB->FileObject->FsContext2); 228 } 229 }*/ 230 #endif //DBG 231 } 232 233 #ifdef UDF_DELAYED_CLOSE 234 // check if this is the last Close (no more Handles) 235 // and try to Delay it.... 236 if((Fcb->FCBFlags & UDF_FCB_DELAY_CLOSE) && 237 (Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED) && 238 !(Vcb->VCBFlags & UDF_VCB_FLAGS_NO_DELAYED_CLOSE) && 239 !(Fcb->OpenHandleCount)) { 240 UDFReleaseResource(&(Vcb->VCBResource)); 241 AcquiredVcb = FALSE; 242 if((RC = UDFQueueDelayedClose(PtrIrpContext,Fcb)) == STATUS_SUCCESS) 243 try_return(RC = STATUS_SUCCESS); 244 // do standard Close if we can't Delay this opeartion 245 AdPrint((" Cant queue Close Irp, status=%x\n", RC)); 246 } 247 #endif //UDF_DELAYED_CLOSE 248 249 if(Irp) { 250 // We should post actual procesing if this is a recursive call 251 if((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_TOP_LEVEL) || 252 (Fcb->NTRequiredFCB->AcqFlushCount)) { 253 AdPrint((" post NOT_TOP_LEVEL Irp\n")); 254 PostRequest = TRUE; 255 try_return(RC = STATUS_SUCCESS); 256 } 257 } 258 259 // Close request is near completion, Vcb is acquired. 260 // Now we can safely decrease CcbCount, because no Rename 261 // operation can run until Vcb release. 262 InterlockedDecrement((PLONG)&(Fcb->CcbCount)); 263 264 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); 265 if(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_READ_ONLY) 266 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCountRO)); 267 268 if(!i || (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB)) { 269 270 AdPrint(("UDF: Closing volume\n")); 271 AdPrint(("UDF: ReferenceCount: %x\n",Fcb->ReferenceCount)); 272 273 if (Vcb->VCBOpenCount > UDF_RESIDUAL_REFERENCE) { 274 ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); 275 UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); 276 ASSERT(Fcb->NTRequiredFCB); 277 UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount)); 278 279 try_return(RC = STATUS_SUCCESS); 280 } 281 282 UDFInterlockedIncrement((PLONG)&(Vcb->VCBOpenCount)); 283 284 if(AcquiredVcb) { 285 UDFReleaseResource(&(Vcb->VCBResource)); 286 AcquiredVcb = FALSE; 287 } else { 288 BrutePoint(); 289 } 290 // Acquire GlobalDataResource 291 UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE); 292 AcquiredGD = TRUE; 293 // // Acquire Vcb 294 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 295 AcquiredVcb = TRUE; 296 297 UDFInterlockedDecrement((PLONG)&(Vcb->VCBOpenCount)); 298 299 300 ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB); 301 UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); 302 ASSERT(Fcb->NTRequiredFCB); 303 UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount)); 304 305 //AdPrint(("UDF: Closing volume, reset driver (e.g. stop BGF)\n")); 306 //UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE); 307 308 AdPrint(("UDF: Closing volume, reset write status\n")); 309 RC = UDFPhSendIOCTL(IOCTL_CDRW_RESET_WRITE_STATUS, Vcb->TargetDeviceObject, 310 NULL, 0, NULL, 0, TRUE, NULL); 311 312 if((Vcb->VCBFlags & UDF_VCB_FLAGS_BEING_DISMOUNTED) || 313 ((!(Vcb->VCBFlags & UDF_VCB_FLAGS_VOLUME_MOUNTED)) && (Vcb->VCBOpenCount <= UDF_RESIDUAL_REFERENCE))) { 314 // Try to KILL dismounted volume.... 315 // w2k requires this, NT4 - recomends 316 AcquiredVcb = UDFCheckForDismount(PtrIrpContext, Vcb, TRUE); 317 } 318 319 try_return(RC = STATUS_SUCCESS); 320 } 321 322 fi = Fcb->FileInfo; 323 #ifdef UDF_DBG 324 if(!fi) { 325 BrutePoint(); 326 } 327 328 DirNdx = UDFGetDirIndexByFileInfo(fi); 329 if(DirNdx) { 330 CurName.Buffer = UDFDirIndex(DirNdx,fi->Index)->FName.Buffer; 331 if(CurName.Buffer) { 332 AdPrint(("Closing file: %ws %8.8x\n", CurName.Buffer, FileObject)); 333 } else { 334 AdPrint(("Closing file: ??? \n")); 335 } 336 } 337 AdPrint(("UDF: ReferenceCount: %x\n",Fcb->ReferenceCount)); 338 #endif // UDF_DBG 339 // try to clean up as long chain as it is possible 340 UDFCleanUpFcbChain(Vcb, fi, i, TRUE); 341 342 try_exit: NOTHING; 343 344 } _SEH2_FINALLY { 345 346 if(AcquiredVcb) { 347 UDFReleaseResource(&(Vcb->VCBResource)); 348 } 349 if(AcquiredGD) { 350 UDFReleaseResource(&(UDFGlobalData.GlobalDataResource)); 351 } 352 353 // Post IRP if required 354 if (PostRequest) { 355 356 // Perform the post operation & complete the IRP 357 // if this is first call of UDFCommonClose 358 // and will return STATUS_SUCCESS back to us 359 PtrIrpContext->Irp = NULL; 360 PtrIrpContext->Fcb = Fcb; 361 UDFPostRequest(PtrIrpContext, NULL); 362 } 363 364 if (!_SEH2_AbnormalTermination()) { 365 // If this is not async close complete the IRP 366 if (Irp) { 367 /* if( FileObject ) { 368 if(clean_stat & UDF_CLOSE_NTREQFCB_DELETED) { 369 // ASSERT(!FileObject->FsContext2); 370 FileObject->FsContext = NULL; 371 #ifdef DBG 372 } else { 373 UDFNTRequiredFCB* NtReqFcb = ((UDFNTRequiredFCB*)(FileObject->FsContext)); 374 if(NtReqFcb->FileObject == FileObject) { 375 NtReqFcb->FileObject = NULL; 376 } 377 #endif //DBG 378 } 379 }*/ 380 Irp->IoStatus.Status = STATUS_SUCCESS; 381 Irp->IoStatus.Information = 0; 382 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 383 } 384 // Free up the Irp Context 385 if(!PostRequest) 386 UDFReleaseIrpContext(PtrIrpContext); 387 } 388 389 } _SEH2_END; // end of "__finally" processing 390 391 return STATUS_SUCCESS ; 392 } // end UDFCommonClose() 393 394 /* 395 This routine walks through the tree to RootDir & kills all unreferenced 396 structures.... 397 imho, Useful feature 398 */ 399 ULONG 400 UDFCleanUpFcbChain( 401 IN PVCB Vcb, 402 IN PUDF_FILE_INFO fi, 403 IN ULONG TreeLength, 404 IN BOOLEAN VcbAcquired 405 ) 406 { 407 PtrUDFFCB Fcb = NULL; 408 PtrUDFFCB ParentFcb = NULL; 409 PUDF_FILE_INFO ParentFI; 410 UDFNTRequiredFCB* NtReqFcb; 411 ULONG CleanCode; 412 LONG RefCount, ComRefCount; 413 BOOLEAN Delete = FALSE; 414 ULONG ret_val = 0; 415 416 ValidateFileInfo(fi); 417 AdPrint(("UDFCleanUpFcbChain\n")); 418 419 ASSERT(TreeLength); 420 421 // we can't process Tree until we can acquire Vcb 422 if(!VcbAcquired) 423 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); 424 425 // cleanup parent chain (if any & unused) 426 while(fi) { 427 428 // acquire parent 429 if((ParentFI = fi->ParentFile)) { 430 ASSERT(fi->Fcb); 431 ParentFcb = fi->Fcb->ParentFcb; 432 ASSERT(ParentFcb); 433 ASSERT(ParentFcb->NTRequiredFCB); 434 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); 435 UDFAcquireResourceExclusive(&(ParentFcb->NTRequiredFCB->MainResource),TRUE); 436 } else { 437 // we get to RootDir, it has no parent 438 if(!VcbAcquired) 439 UDFAcquireResourceShared(&(Vcb->VCBResource),TRUE); 440 } 441 Fcb = fi->Fcb; 442 ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB); 443 444 NtReqFcb = Fcb->NTRequiredFCB; 445 ASSERT(NtReqFcb->CommonFCBHeader.NodeTypeCode == UDF_NODE_TYPE_NT_REQ_FCB); 446 447 // acquire current file/dir 448 // we must assure that no more threads try to re-use this object 449 #ifdef UDF_DBG 450 _SEH2_TRY { 451 #endif // UDF_DBG 452 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 453 UDFAcquireResourceExclusive(&(NtReqFcb->MainResource),TRUE); 454 #ifdef UDF_DBG 455 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 456 BrutePoint(); 457 if(ParentFI) { 458 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); 459 UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource)); 460 } else { 461 if(!VcbAcquired) 462 UDFReleaseResource(&(Vcb->VCBResource)); 463 } 464 break; 465 } _SEH2_END; 466 #endif // UDF_DBG 467 ASSERT_REF((Fcb->ReferenceCount > fi->RefCount) || !TreeLength); 468 // If we haven't pass through all files opened 469 // in UDFCommonCreate before target file (TreeLength specfies 470 // the number of such files) dereference them. 471 // Otherwise we'll just check if the file has no references. 472 #ifdef UDF_DBG 473 if(Fcb) { 474 if(TreeLength) { 475 ASSERT(Fcb->ReferenceCount); 476 ASSERT(NtReqFcb->CommonRefCount); 477 RefCount = UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); 478 ComRefCount = UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount)); 479 } 480 } else { 481 BrutePoint(); 482 } 483 if(TreeLength) 484 TreeLength--; 485 ASSERT(Fcb->OpenHandleCount <= Fcb->ReferenceCount); 486 #else 487 if(TreeLength) { 488 RefCount = UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); 489 ComRefCount = UDFInterlockedDecrement((PLONG)&(NtReqFcb->CommonRefCount)); 490 TreeLength--; 491 } 492 #endif 493 494 /* if(Fcb && Fcb->FCBName && Fcb->FCBName->ObjectName.Buffer) { 495 AdPrint((" %ws (%x)\n", 496 Fcb->FCBName->ObjectName.Buffer,Fcb->ReferenceCount)); 497 } else if (Fcb) { 498 AdPrint((" ??? (%x)\n",Fcb->ReferenceCount)); 499 } else { 500 AdPrint((" ??? (??)\n")); 501 }*/ 502 // ...and delete if it has gone 503 504 if(!RefCount && !Fcb->OpenHandleCount) { 505 // no more references... current file/dir MUST DIE!!! 506 BOOLEAN AutoInherited = UDFIsAStreamDir(fi) || UDFIsAStream(fi); 507 508 if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) { 509 // do nothing 510 } else 511 #ifndef UDF_READ_ONLY_BUILD 512 if(Delete) { 513 /* if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) { 514 // set file size to zero (for UdfInfo package) 515 // we should not do this for directories 516 UDFResizeFile__(Vcb, fi, 0); 517 }*/ 518 UDFReferenceFile__(fi); 519 ASSERT(Fcb->ReferenceCount < fi->RefCount); 520 UDFFlushFile__(Vcb, fi); 521 UDFUnlinkFile__(Vcb, fi, TRUE); 522 UDFCloseFile__(Vcb, fi); 523 ASSERT(Fcb->ReferenceCount == fi->RefCount); 524 Fcb->FCBFlags |= UDF_FCB_DELETED; 525 Delete = FALSE; 526 } else 527 #endif //UDF_READ_ONLY_BUILD 528 if(!(Fcb->FCBFlags & UDF_FCB_DELETED)) { 529 UDFFlushFile__(Vcb, fi); 530 } else { 531 // BrutePoint(); 532 } 533 #ifndef UDF_READ_ONLY_BUILD 534 // check if we should try to delete Parent for the next time 535 if(Fcb->FCBFlags & UDF_FCB_DELETE_PARENT) 536 Delete = TRUE; 537 #endif //UDF_READ_ONLY_BUILD 538 539 // remove references to OS-specific structures 540 // to let UDF_INFO release FI & Co 541 fi->Fcb = NULL; 542 if(!ComRefCount) { 543 // CommonFcb is also completly dereferenced 544 // Kill it! 545 fi->Dloc->CommonFcb = NULL; 546 } 547 548 if((CleanCode = UDFCleanUpFile__(Vcb, fi))) { 549 // Check, if we can uninitialize & deallocate CommonFcb part 550 // kill some cross links 551 Fcb->FileInfo = NULL; 552 // release allocated resources 553 if(CleanCode & UDF_FREE_DLOC) { 554 // Obviously, it is a good time & place to release 555 // CommonFcb structure 556 557 // NtReqFcb->NtReqFCBFlags &= ~UDF_NTREQ_FCB_VALID; 558 // Unitialize byte-range locks support structure 559 FsRtlUninitializeFileLock(&(NtReqFcb->FileLock)); 560 // Remove resources 561 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 562 UDFReleaseResource(&(NtReqFcb->MainResource)); 563 if(NtReqFcb->CommonFCBHeader.Resource) { 564 UDFDeleteResource(&(NtReqFcb->MainResource)); 565 UDFDeleteResource(&(NtReqFcb->PagingIoResource)); 566 } 567 NtReqFcb->CommonFCBHeader.Resource = 568 NtReqFcb->CommonFCBHeader.PagingIoResource = NULL; 569 UDFDeassignAcl(NtReqFcb, AutoInherited); 570 UDFPrint(("UDFReleaseNtReqFCB: %x\n", NtReqFcb)); 571 #ifdef DBG 572 // NtReqFcb->FileObject->FsContext2 = NULL; 573 // ASSERT(NtReqFcb->FileObject); 574 /* if(NtReqFcb->FileObject) { 575 ASSERT(!NtReqFcb->FileObject->FsContext2); 576 NtReqFcb->FileObject->FsContext = NULL; 577 NtReqFcb->FileObject->SectionObjectPointer = NULL; 578 }*/ 579 #endif //DBG 580 MyFreePool__(NtReqFcb); 581 ret_val |= UDF_CLOSE_NTREQFCB_DELETED; 582 } else { 583 // we usually get here when the file has some opened links 584 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 585 UDFReleaseResource(&(NtReqFcb->MainResource)); 586 } 587 // remove some references & free Fcb structure 588 Fcb->NTRequiredFCB = NULL; 589 Fcb->ParentFcb = NULL; 590 UDFCleanUpFCB(Fcb); 591 MyFreePool__(fi); 592 ret_val |= UDF_CLOSE_FCB_DELETED; 593 // get pointer to parent FCB 594 fi = ParentFI; 595 // free old parent's resource... 596 if(fi) { 597 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); 598 UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource)); 599 } else { 600 if(!VcbAcquired) 601 UDFReleaseResource(&(Vcb->VCBResource)); 602 } 603 } else { 604 // Stop cleaning up 605 606 // Restore pointers 607 fi->Fcb = Fcb; 608 fi->Dloc->CommonFcb = NtReqFcb; 609 // free all acquired resources 610 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 611 UDFReleaseResource(&(NtReqFcb->MainResource)); 612 fi = ParentFI; 613 if(fi) { 614 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); 615 UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource)); 616 } else { 617 if(!VcbAcquired) 618 UDFReleaseResource(&(Vcb->VCBResource)); 619 } 620 // If we have dereferenced all parents 'associated' 621 // with input file & current file is still in use 622 // then it isn't worth walking down the tree 623 // 'cause in this case all the rest files are also used 624 if(!TreeLength) 625 break; 626 // AdPrint(("Stop on referenced File/Dir\n")); 627 } 628 } else { 629 // we get to referenced file/dir. Stop search & release resource 630 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb); 631 UDFReleaseResource(&(NtReqFcb->MainResource)); 632 if(ParentFI) { 633 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb->NTRequiredFCB); 634 UDFReleaseResource(&(ParentFcb->NTRequiredFCB->MainResource)); 635 } else { 636 if(!VcbAcquired) 637 UDFReleaseResource(&(Vcb->VCBResource)); 638 } 639 Delete = FALSE; 640 if(!TreeLength) 641 break; 642 fi = ParentFI; 643 } 644 } 645 if(fi) { 646 Fcb = fi->Fcb; 647 for(;TreeLength && fi;TreeLength--) { 648 if(Fcb) { 649 ParentFcb = Fcb->ParentFcb; 650 ASSERT(Fcb->ReferenceCount); 651 ASSERT(Fcb->NTRequiredFCB->CommonRefCount); 652 ASSERT_REF(Fcb->ReferenceCount > fi->RefCount); 653 UDFInterlockedDecrement((PLONG)&(Fcb->ReferenceCount)); 654 UDFInterlockedDecrement((PLONG)&(Fcb->NTRequiredFCB->CommonRefCount)); 655 #ifdef UDF_DBG 656 } else { 657 BrutePoint(); 658 #endif 659 } 660 Fcb = ParentFcb; 661 } 662 } 663 if(!VcbAcquired) 664 UDFReleaseResource(&(Vcb->VCBResource)); 665 return ret_val; 666 667 } // end UDFCleanUpFcbChain() 668 669 VOID 670 UDFDoDelayedClose( 671 IN PtrUDFIrpContextLite NextIrpContextLite 672 ) 673 { 674 PtrUDFIrpContext IrpContext; 675 676 AdPrint((" UDFDoDelayedClose\n")); 677 UDFInitializeIrpContextFromLite(&IrpContext,NextIrpContextLite); 678 IrpContext->Fcb->IrpContextLite = NULL; 679 MyFreePool__(NextIrpContextLite); 680 IrpContext->Fcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE; 681 UDFCommonClose(IrpContext,NULL); 682 } // end UDFDoDelayedClose() 683 684 /* 685 This routine removes request from Delayed Close queue. 686 It operates until reach lower threshold 687 */ 688 VOID 689 NTAPI 690 UDFDelayedClose( 691 PVOID unused 692 ) 693 { 694 PLIST_ENTRY Entry; 695 PtrUDFIrpContextLite NextIrpContextLite; 696 697 AdPrint((" UDFDelayedClose\n")); 698 // Acquire DelayedCloseResource 699 UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE); 700 701 while (UDFGlobalData.ReduceDelayedClose && 702 (UDFGlobalData.DelayedCloseCount > UDFGlobalData.MinDelayedCloseCount)) { 703 704 Entry = UDFGlobalData.DelayedCloseQueue.Flink; 705 706 if (!IsListEmpty(Entry)) { 707 // Extract the IrpContext. 708 NextIrpContextLite = CONTAINING_RECORD( Entry, 709 UDFIrpContextLite, 710 DelayedCloseLinks ); 711 712 RemoveEntryList( Entry ); 713 UDFGlobalData.DelayedCloseCount--; 714 UDFDoDelayedClose(NextIrpContextLite); 715 } else { 716 BrutePoint(); 717 } 718 } 719 720 while (UDFGlobalData.ReduceDirDelayedClose && 721 (UDFGlobalData.DirDelayedCloseCount > UDFGlobalData.MinDirDelayedCloseCount)) { 722 723 Entry = UDFGlobalData.DirDelayedCloseQueue.Flink; 724 725 if (!IsListEmpty(Entry)) { 726 // Extract the IrpContext. 727 NextIrpContextLite = CONTAINING_RECORD( Entry, 728 UDFIrpContextLite, 729 DelayedCloseLinks ); 730 731 RemoveEntryList( Entry ); 732 UDFGlobalData.DirDelayedCloseCount--; 733 UDFDoDelayedClose(NextIrpContextLite); 734 } else { 735 BrutePoint(); 736 } 737 } 738 739 UDFGlobalData.FspCloseActive = FALSE; 740 UDFGlobalData.ReduceDelayedClose = FALSE; 741 UDFGlobalData.ReduceDirDelayedClose = FALSE; 742 743 // Release DelayedCloseResource 744 UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource)); 745 746 return; 747 } // end UDFDelayedClose() 748 749 /* 750 This routine performs Close operation for all files from 751 Delayed Close queue. 752 */ 753 VOID 754 UDFCloseAllDelayed( 755 IN PVCB Vcb 756 ) 757 { 758 PLIST_ENTRY Entry; 759 PtrUDFIrpContextLite NextIrpContextLite; 760 BOOLEAN GlobalDataAcquired = FALSE; 761 762 AdPrint((" UDFCloseAllDelayed\n")); 763 // Acquire DelayedCloseResource 764 if (!ExIsResourceAcquiredExclusive(&UDFGlobalData.GlobalDataResource)) { 765 UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE); 766 GlobalDataAcquired = TRUE; 767 } 768 769 Entry = UDFGlobalData.DelayedCloseQueue.Flink; 770 771 while (Entry != &UDFGlobalData.DelayedCloseQueue) { 772 // Extract the IrpContext. 773 NextIrpContextLite = CONTAINING_RECORD( Entry, 774 UDFIrpContextLite, 775 DelayedCloseLinks ); 776 Entry = Entry->Flink; 777 if (NextIrpContextLite->Fcb->Vcb == Vcb) { 778 RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) ); 779 UDFGlobalData.DelayedCloseCount--; 780 UDFDoDelayedClose(NextIrpContextLite); 781 } 782 } 783 784 Entry = UDFGlobalData.DirDelayedCloseQueue.Flink; 785 786 while (Entry != &UDFGlobalData.DirDelayedCloseQueue) { 787 // Extract the IrpContext. 788 NextIrpContextLite = CONTAINING_RECORD( Entry, 789 UDFIrpContextLite, 790 DelayedCloseLinks ); 791 Entry = Entry->Flink; 792 if (NextIrpContextLite->Fcb->Vcb == Vcb) { 793 RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) ); 794 UDFGlobalData.DirDelayedCloseCount--; 795 UDFDoDelayedClose(NextIrpContextLite); 796 } 797 } 798 799 // Release DelayedCloseResource 800 if(GlobalDataAcquired) 801 UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource)); 802 803 } // end UDFCloseAllDelayed() 804 805 NTSTATUS 806 UDFBuildTreeItemsList( 807 IN PVCB Vcb, 808 IN PUDF_FILE_INFO FileInfo, 809 IN PCHECK_TREE_ITEM CheckItemProc, 810 IN PUDF_FILE_INFO** PassedList, 811 IN PULONG PassedListSize, 812 IN PUDF_FILE_INFO** FoundList, 813 IN PULONG FoundListSize 814 ) 815 { 816 PDIR_INDEX_HDR hDirNdx; 817 PUDF_FILE_INFO SDirInfo; 818 ULONG i; 819 820 UDFPrint((" UDFBuildTreeItemsList():\n")); 821 if(!(*PassedList) || !(*FoundList)) { 822 823 (*PassedList) = (PUDF_FILE_INFO*) 824 MyAllocatePool__(NonPagedPool, sizeof(PUDF_FILE_INFO)*TREE_ITEM_LIST_GRAN); 825 if(!(*PassedList)) 826 return STATUS_INSUFFICIENT_RESOURCES; 827 (*PassedListSize) = 0; 828 829 (*FoundList) = (PUDF_FILE_INFO*) 830 MyAllocatePool__(NonPagedPool, sizeof(PUDF_FILE_INFO)*TREE_ITEM_LIST_GRAN); 831 if(!(*FoundList)) { 832 MyFreePool__(*PassedList); 833 *PassedList = NULL; 834 return STATUS_INSUFFICIENT_RESOURCES; 835 } 836 (*FoundListSize) = 0; 837 } 838 839 // check if already passed 840 for(i=0;i<(*PassedListSize);i++) { 841 if( ((*PassedList)[i]) == FileInfo ) 842 return STATUS_SUCCESS; 843 } 844 // remember passed object 845 // we should not proceed linked objects twice 846 (*PassedListSize)++; 847 if( !((*PassedListSize) & (TREE_ITEM_LIST_GRAN - 1)) ) { 848 if(!MyReallocPool__((PCHAR)(*PassedList), (*PassedListSize)*sizeof(PUDF_FILE_INFO), 849 (PCHAR*)PassedList, ((*PassedListSize)+TREE_ITEM_LIST_GRAN)*sizeof(PUDF_FILE_INFO))) { 850 return STATUS_INSUFFICIENT_RESOURCES; 851 } 852 } 853 (*PassedList)[(*PassedListSize)-1] = FileInfo; 854 855 // check if this object matches our conditions 856 if(CheckItemProc(FileInfo)) { 857 // remember matched object 858 (*FoundListSize)++; 859 if( !((*FoundListSize) & (TREE_ITEM_LIST_GRAN - 1)) ) { 860 if(!MyReallocPool__((PCHAR)(*FoundList), (*FoundListSize)*sizeof(PUDF_DATALOC_INFO), 861 (PCHAR*)FoundList, ((*FoundListSize)+TREE_ITEM_LIST_GRAN)*sizeof(PUDF_DATALOC_INFO))) { 862 return STATUS_INSUFFICIENT_RESOURCES; 863 } 864 } 865 (*FoundList)[(*FoundListSize)-1] = FileInfo; 866 } 867 868 // walk through SDir (if any) 869 if((SDirInfo = FileInfo->Dloc->SDirInfo)) 870 UDFBuildTreeItemsList(Vcb, SDirInfo, CheckItemProc, 871 PassedList, PassedListSize, FoundList, FoundListSize); 872 873 // walk through subsequent objects (if any) 874 if((hDirNdx = FileInfo->Dloc->DirIndex)) { 875 876 // scan DirIndex 877 UDF_DIR_SCAN_CONTEXT ScanContext; 878 PDIR_INDEX_ITEM DirNdx; 879 PUDF_FILE_INFO CurFileInfo; 880 881 if(UDFDirIndexInitScan(FileInfo, &ScanContext, 2)) { 882 while((DirNdx = UDFDirIndexScan(&ScanContext, &CurFileInfo))) { 883 if(!CurFileInfo) 884 continue; 885 UDFBuildTreeItemsList(Vcb, CurFileInfo, CheckItemProc, 886 PassedList, PassedListSize, FoundList, FoundListSize); 887 } 888 } 889 890 } 891 return STATUS_SUCCESS; 892 } // end UDFBuildTreeItemsList() 893 894 BOOLEAN 895 UDFIsInDelayedCloseQueue( 896 PUDF_FILE_INFO FileInfo) 897 { 898 ASSERT(FileInfo); 899 return (FileInfo->Fcb && FileInfo->Fcb->IrpContextLite); 900 } // end UDFIsInDelayedCloseQueue() 901 902 BOOLEAN 903 UDFIsLastClose( 904 PUDF_FILE_INFO FileInfo) 905 { 906 ASSERT(FileInfo); 907 PtrUDFFCB Fcb = FileInfo->Fcb; 908 if( Fcb && 909 !Fcb->OpenHandleCount && 910 Fcb->ReferenceCount && 911 Fcb->NTRequiredFCB->SectionObject.DataSectionObject) { 912 return TRUE; 913 } 914 return FALSE; 915 } // UDFIsLastClose() 916 917 NTSTATUS 918 UDFCloseAllXXXDelayedInDir( 919 IN PVCB Vcb, 920 IN PUDF_FILE_INFO FileInfo, 921 IN BOOLEAN System 922 ) 923 { 924 PUDF_FILE_INFO* PassedList = NULL; 925 ULONG PassedListSize = 0; 926 PUDF_FILE_INFO* FoundList = NULL; 927 ULONG FoundListSize = 0; 928 NTSTATUS RC; 929 ULONG i; 930 BOOLEAN ResAcq = FALSE; 931 BOOLEAN AcquiredVcb = FALSE; 932 UDFNTRequiredFCB* NtReqFcb; 933 PUDF_FILE_INFO CurFileInfo; 934 PFE_LIST_ENTRY CurListPtr; 935 PFE_LIST_ENTRY* ListPtrArray = NULL; 936 937 _SEH2_TRY { 938 939 UDFPrint((" UDFCloseAllXXXDelayedInDir(): Acquire DelayedCloseResource\n")); 940 // Acquire DelayedCloseResource 941 UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE); 942 ResAcq = TRUE; 943 944 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 945 AcquiredVcb = TRUE; 946 947 RC = UDFBuildTreeItemsList(Vcb, FileInfo, 948 System ? UDFIsLastClose : UDFIsInDelayedCloseQueue, 949 &PassedList, &PassedListSize, &FoundList, &FoundListSize); 950 951 if(!NT_SUCCESS(RC)) { 952 UDFPrint((" UDFBuildTreeItemsList(): error %x\n", RC)); 953 try_return(RC); 954 } 955 956 if(!FoundList || !FoundListSize) { 957 try_return(RC = STATUS_SUCCESS); 958 } 959 960 // build array of referenced pointers 961 ListPtrArray = (PFE_LIST_ENTRY*)(MyAllocatePool__(NonPagedPool, FoundListSize*sizeof(PFE_LIST_ENTRY))); 962 if(!ListPtrArray) { 963 UDFPrint((" Can't alloc ListPtrArray for %x items\n", FoundListSize)); 964 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 965 } 966 967 for(i=0;i<FoundListSize;i++) { 968 969 _SEH2_TRY { 970 971 CurFileInfo = FoundList[i]; 972 if(!CurFileInfo->ListPtr) { 973 CurFileInfo->ListPtr = (PFE_LIST_ENTRY)(MyAllocatePool__(NonPagedPool, sizeof(FE_LIST_ENTRY))); 974 if(!CurFileInfo->ListPtr) { 975 UDFPrint((" Can't alloc ListPtrEntry for items %x\n", i)); 976 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 977 } 978 CurFileInfo->ListPtr->FileInfo = CurFileInfo; 979 CurFileInfo->ListPtr->EntryRefCount = 0; 980 } 981 CurFileInfo->ListPtr->EntryRefCount++; 982 ListPtrArray[i] = CurFileInfo->ListPtr; 983 984 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) { 985 BrutePoint(); 986 } _SEH2_END; 987 } 988 989 UDFReleaseResource(&(Vcb->VCBResource)); 990 AcquiredVcb = FALSE; 991 992 if(System) { 993 // Remove from system queue 994 PtrUDFFCB Fcb; 995 IO_STATUS_BLOCK IoStatus; 996 BOOLEAN NoDelayed = (Vcb->VCBFlags & UDF_VCB_FLAGS_NO_DELAYED_CLOSE) ? 997 TRUE : FALSE; 998 999 Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE; 1000 for(i=FoundListSize;i>0;i--) { 1001 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 1002 AcquiredVcb = TRUE; 1003 _SEH2_TRY { 1004 1005 CurListPtr = ListPtrArray[i-1]; 1006 CurFileInfo = CurListPtr->FileInfo; 1007 if(CurFileInfo && 1008 (Fcb = CurFileInfo->Fcb)) { 1009 NtReqFcb = Fcb->NTRequiredFCB; 1010 ASSERT((ULONG_PTR)NtReqFcb > 0x1000); 1011 // ASSERT((ULONG)(NtReqFcb->SectionObject) > 0x1000); 1012 if(!(NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED) && 1013 (NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED)) { 1014 MmPrint((" CcFlushCache()\n")); 1015 CcFlushCache(&(NtReqFcb->SectionObject), NULL, 0, &IoStatus); 1016 } 1017 if(NtReqFcb->SectionObject.ImageSectionObject) { 1018 MmPrint((" MmFlushImageSection()\n")); 1019 MmFlushImageSection(&(NtReqFcb->SectionObject), MmFlushForWrite); 1020 } 1021 if(NtReqFcb->SectionObject.DataSectionObject) { 1022 MmPrint((" CcPurgeCacheSection()\n")); 1023 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE ); 1024 } 1025 } else { 1026 MmPrint((" Skip item: deleted\n")); 1027 } 1028 CurListPtr->EntryRefCount--; 1029 if(!CurListPtr->EntryRefCount) { 1030 if(CurListPtr->FileInfo) 1031 CurListPtr->FileInfo->ListPtr = NULL; 1032 MyFreePool__(CurListPtr); 1033 } 1034 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 1035 BrutePoint(); 1036 } _SEH2_END; 1037 UDFReleaseResource(&(Vcb->VCBResource)); 1038 AcquiredVcb = FALSE; 1039 } 1040 if(!NoDelayed) 1041 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_NO_DELAYED_CLOSE; 1042 } else { 1043 // Remove from internal queue 1044 PtrUDFIrpContextLite NextIrpContextLite; 1045 1046 for(i=FoundListSize;i>0;i--) { 1047 1048 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE); 1049 AcquiredVcb = TRUE; 1050 1051 CurListPtr = ListPtrArray[i-1]; 1052 CurFileInfo = CurListPtr->FileInfo; 1053 1054 if(CurFileInfo && 1055 CurFileInfo->Fcb && 1056 (NextIrpContextLite = CurFileInfo->Fcb->IrpContextLite)) { 1057 RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) ); 1058 if (NextIrpContextLite->Fcb->FCBFlags & UDF_FCB_DIRECTORY) { 1059 // BrutePoint(); 1060 UDFGlobalData.DirDelayedCloseCount--; 1061 } else { 1062 UDFGlobalData.DelayedCloseCount--; 1063 } 1064 UDFDoDelayedClose(NextIrpContextLite); 1065 } 1066 CurListPtr->EntryRefCount--; 1067 if(!CurListPtr->EntryRefCount) { 1068 if(CurListPtr->FileInfo) 1069 CurListPtr->FileInfo->ListPtr = NULL; 1070 MyFreePool__(CurListPtr); 1071 } 1072 UDFReleaseResource(&(Vcb->VCBResource)); 1073 AcquiredVcb = FALSE; 1074 } 1075 } 1076 RC = STATUS_SUCCESS; 1077 1078 try_exit: NOTHING; 1079 1080 } _SEH2_FINALLY { 1081 // release Vcb 1082 if(AcquiredVcb) 1083 UDFReleaseResource(&(Vcb->VCBResource)); 1084 // Release DelayedCloseResource 1085 if(ResAcq) 1086 UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource)); 1087 1088 if(ListPtrArray) 1089 MyFreePool__(ListPtrArray); 1090 if(PassedList) 1091 MyFreePool__(PassedList); 1092 if(FoundList) 1093 MyFreePool__(FoundList); 1094 } _SEH2_END; 1095 1096 return RC; 1097 } // end UDFCloseAllXXXDelayedInDir( 1098 1099 1100 /* 1101 This routine adds request to Delayed Close queue. 1102 If number of queued requests exceeds higher threshold it fires 1103 UDFDelayedClose() 1104 */ 1105 NTSTATUS 1106 UDFQueueDelayedClose( 1107 PtrUDFIrpContext IrpContext, 1108 PtrUDFFCB Fcb 1109 ) 1110 { 1111 PtrUDFIrpContextLite IrpContextLite; 1112 BOOLEAN StartWorker = FALSE; 1113 _SEH2_VOLATILE BOOLEAN AcquiredVcb = FALSE; 1114 NTSTATUS RC; 1115 1116 AdPrint((" UDFQueueDelayedClose\n")); 1117 1118 _SEH2_TRY { 1119 // Acquire DelayedCloseResource 1120 UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE); 1121 1122 UDFAcquireResourceShared(&(Fcb->Vcb->VCBResource), TRUE); 1123 AcquiredVcb = TRUE; 1124 1125 if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) { 1126 try_return(RC = STATUS_DELETE_PENDING); 1127 } 1128 1129 if(Fcb->IrpContextLite || 1130 Fcb->FCBFlags & UDF_FCB_POSTED_RENAME) { 1131 // BrutePoint(); 1132 try_return(RC = STATUS_UNSUCCESSFUL); 1133 } 1134 1135 if(!NT_SUCCESS(RC = UDFInitializeIrpContextLite(&IrpContextLite,IrpContext,Fcb))) { 1136 try_return(RC); 1137 } 1138 1139 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) { 1140 InsertTailList( &UDFGlobalData.DirDelayedCloseQueue, 1141 &IrpContextLite->DelayedCloseLinks ); 1142 UDFGlobalData.DirDelayedCloseCount++; 1143 } else { 1144 InsertTailList( &UDFGlobalData.DelayedCloseQueue, 1145 &IrpContextLite->DelayedCloseLinks ); 1146 UDFGlobalData.DelayedCloseCount++; 1147 } 1148 Fcb->IrpContextLite = IrpContextLite; 1149 1150 // If we are above our threshold then start the delayed 1151 // close operation. 1152 if(UDFGlobalData.DelayedCloseCount > UDFGlobalData.MaxDelayedCloseCount) { 1153 1154 UDFGlobalData.ReduceDelayedClose = TRUE; 1155 1156 if(!UDFGlobalData.FspCloseActive) { 1157 1158 UDFGlobalData.FspCloseActive = TRUE; 1159 StartWorker = TRUE; 1160 } 1161 } 1162 // If we are above our threshold then start the delayed 1163 // close operation. 1164 if(UDFGlobalData.DirDelayedCloseCount > UDFGlobalData.MaxDirDelayedCloseCount) { 1165 1166 UDFGlobalData.ReduceDirDelayedClose = TRUE; 1167 1168 if(!UDFGlobalData.FspCloseActive) { 1169 1170 UDFGlobalData.FspCloseActive = TRUE; 1171 StartWorker = TRUE; 1172 } 1173 } 1174 // Start the FspClose thread if we need to. 1175 if(StartWorker) { 1176 ExQueueWorkItem( &UDFGlobalData.CloseItem, CriticalWorkQueue ); 1177 } 1178 RC = STATUS_SUCCESS; 1179 1180 try_exit: NOTHING; 1181 1182 } _SEH2_FINALLY { 1183 1184 if(!NT_SUCCESS(RC)) { 1185 Fcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE; 1186 } 1187 if(AcquiredVcb) { 1188 UDFReleaseResource(&(Fcb->Vcb->VCBResource)); 1189 } 1190 // Release DelayedCloseResource 1191 UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource)); 1192 } _SEH2_END; 1193 return RC; 1194 } // end UDFQueueDelayedClose() 1195 1196