xref: /reactos/drivers/filesystems/udfs/close.cpp (revision 53221834)
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