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