[UDFS]
[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 // 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 KdPrint(("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 UDFDelayedClose(
690 PVOID unused
691 )
692 {
693 PLIST_ENTRY Entry;
694 PtrUDFIrpContextLite NextIrpContextLite;
695
696 AdPrint((" UDFDelayedClose\n"));
697 // Acquire DelayedCloseResource
698 UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE);
699
700 while (UDFGlobalData.ReduceDelayedClose &&
701 (UDFGlobalData.DelayedCloseCount > UDFGlobalData.MinDelayedCloseCount)) {
702
703 Entry = UDFGlobalData.DelayedCloseQueue.Flink;
704
705 if (!IsListEmpty(Entry)) {
706 // Extract the IrpContext.
707 NextIrpContextLite = CONTAINING_RECORD( Entry,
708 UDFIrpContextLite,
709 DelayedCloseLinks );
710
711 RemoveEntryList( Entry );
712 UDFGlobalData.DelayedCloseCount--;
713 UDFDoDelayedClose(NextIrpContextLite);
714 } else {
715 BrutePoint();
716 }
717 }
718
719 while (UDFGlobalData.ReduceDirDelayedClose &&
720 (UDFGlobalData.DirDelayedCloseCount > UDFGlobalData.MinDirDelayedCloseCount)) {
721
722 Entry = UDFGlobalData.DirDelayedCloseQueue.Flink;
723
724 if (!IsListEmpty(Entry)) {
725 // Extract the IrpContext.
726 NextIrpContextLite = CONTAINING_RECORD( Entry,
727 UDFIrpContextLite,
728 DelayedCloseLinks );
729
730 RemoveEntryList( Entry );
731 UDFGlobalData.DirDelayedCloseCount--;
732 UDFDoDelayedClose(NextIrpContextLite);
733 } else {
734 BrutePoint();
735 }
736 }
737
738 UDFGlobalData.FspCloseActive = FALSE;
739 UDFGlobalData.ReduceDelayedClose = FALSE;
740 UDFGlobalData.ReduceDirDelayedClose = FALSE;
741
742 // Release DelayedCloseResource
743 UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
744
745 return;
746 } // end UDFDelayedClose()
747
748 /*
749 This routine performs Close operation for all files from
750 Delayed Close queue.
751 */
752 VOID
753 UDFCloseAllDelayed(
754 IN PVCB Vcb
755 )
756 {
757 PLIST_ENTRY Entry;
758 PtrUDFIrpContextLite NextIrpContextLite;
759 BOOLEAN GlobalDataAcquired = FALSE;
760
761 AdPrint((" UDFCloseAllDelayed\n"));
762 // Acquire DelayedCloseResource
763 if (!ExIsResourceAcquiredExclusive(&UDFGlobalData.GlobalDataResource)) {
764 UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE);
765 GlobalDataAcquired = TRUE;
766 }
767
768 Entry = UDFGlobalData.DelayedCloseQueue.Flink;
769
770 while (Entry != &UDFGlobalData.DelayedCloseQueue) {
771 // Extract the IrpContext.
772 NextIrpContextLite = CONTAINING_RECORD( Entry,
773 UDFIrpContextLite,
774 DelayedCloseLinks );
775 Entry = Entry->Flink;
776 if (NextIrpContextLite->Fcb->Vcb == Vcb) {
777 RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) );
778 UDFGlobalData.DelayedCloseCount--;
779 UDFDoDelayedClose(NextIrpContextLite);
780 }
781 }
782
783 Entry = UDFGlobalData.DirDelayedCloseQueue.Flink;
784
785 while (Entry != &UDFGlobalData.DirDelayedCloseQueue) {
786 // Extract the IrpContext.
787 NextIrpContextLite = CONTAINING_RECORD( Entry,
788 UDFIrpContextLite,
789 DelayedCloseLinks );
790 Entry = Entry->Flink;
791 if (NextIrpContextLite->Fcb->Vcb == Vcb) {
792 RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) );
793 UDFGlobalData.DirDelayedCloseCount--;
794 UDFDoDelayedClose(NextIrpContextLite);
795 }
796 }
797
798 // Release DelayedCloseResource
799 if(GlobalDataAcquired)
800 UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
801
802 } // end UDFCloseAllDelayed()
803
804 NTSTATUS
805 UDFBuildTreeItemsList(
806 IN PVCB Vcb,
807 IN PUDF_FILE_INFO FileInfo,
808 IN PCHECK_TREE_ITEM CheckItemProc,
809 IN PUDF_FILE_INFO** PassedList,
810 IN PULONG PassedListSize,
811 IN PUDF_FILE_INFO** FoundList,
812 IN PULONG FoundListSize
813 )
814 {
815 PDIR_INDEX_HDR hDirNdx;
816 PUDF_FILE_INFO SDirInfo;
817 ULONG i;
818
819 KdPrint((" UDFBuildTreeItemsList():\n"));
820 if(!(*PassedList) || !(*FoundList)) {
821
822 (*PassedList) = (PUDF_FILE_INFO*)
823 MyAllocatePool__(NonPagedPool, sizeof(PUDF_FILE_INFO)*TREE_ITEM_LIST_GRAN);
824 if(!(*PassedList))
825 return STATUS_INSUFFICIENT_RESOURCES;
826 (*PassedListSize) = 0;
827
828 (*FoundList) = (PUDF_FILE_INFO*)
829 MyAllocatePool__(NonPagedPool, sizeof(PUDF_FILE_INFO)*TREE_ITEM_LIST_GRAN);
830 if(!(*FoundList)) {
831 MyFreePool__(*PassedList);
832 *PassedList = NULL;
833 return STATUS_INSUFFICIENT_RESOURCES;
834 }
835 (*FoundListSize) = 0;
836 }
837
838 // check if already passed
839 for(i=0;i<(*PassedListSize);i++) {
840 if( ((*PassedList)[i]) == FileInfo )
841 return STATUS_SUCCESS;
842 }
843 // remember passed object
844 // we should not proceed linked objects twice
845 (*PassedListSize)++;
846 if( !((*PassedListSize) & (TREE_ITEM_LIST_GRAN - 1)) ) {
847 if(!MyReallocPool__((PCHAR)(*PassedList), (*PassedListSize)*sizeof(PUDF_FILE_INFO),
848 (PCHAR*)PassedList, ((*PassedListSize)+TREE_ITEM_LIST_GRAN)*sizeof(PUDF_FILE_INFO))) {
849 return STATUS_INSUFFICIENT_RESOURCES;
850 }
851 }
852 (*PassedList)[(*PassedListSize)-1] = FileInfo;
853
854 // check if this object matches our conditions
855 if(CheckItemProc(FileInfo)) {
856 // remember matched object
857 (*FoundListSize)++;
858 if( !((*FoundListSize) & (TREE_ITEM_LIST_GRAN - 1)) ) {
859 if(!MyReallocPool__((PCHAR)(*FoundList), (*FoundListSize)*sizeof(PUDF_DATALOC_INFO),
860 (PCHAR*)FoundList, ((*FoundListSize)+TREE_ITEM_LIST_GRAN)*sizeof(PUDF_DATALOC_INFO))) {
861 return STATUS_INSUFFICIENT_RESOURCES;
862 }
863 }
864 (*FoundList)[(*FoundListSize)-1] = FileInfo;
865 }
866
867 // walk through SDir (if any)
868 if((SDirInfo = FileInfo->Dloc->SDirInfo))
869 UDFBuildTreeItemsList(Vcb, SDirInfo, CheckItemProc,
870 PassedList, PassedListSize, FoundList, FoundListSize);
871
872 // walk through subsequent objects (if any)
873 if((hDirNdx = FileInfo->Dloc->DirIndex)) {
874
875 // scan DirIndex
876 UDF_DIR_SCAN_CONTEXT ScanContext;
877 PDIR_INDEX_ITEM DirNdx;
878 PUDF_FILE_INFO CurFileInfo;
879
880 if(UDFDirIndexInitScan(FileInfo, &ScanContext, 2)) {
881 while((DirNdx = UDFDirIndexScan(&ScanContext, &CurFileInfo))) {
882 if(!CurFileInfo)
883 continue;
884 UDFBuildTreeItemsList(Vcb, CurFileInfo, CheckItemProc,
885 PassedList, PassedListSize, FoundList, FoundListSize);
886 }
887 }
888
889 }
890 return STATUS_SUCCESS;
891 } // end UDFBuildTreeItemsList()
892
893 BOOLEAN
894 UDFIsInDelayedCloseQueue(
895 PUDF_FILE_INFO FileInfo)
896 {
897 ASSERT(FileInfo);
898 return (FileInfo->Fcb && FileInfo->Fcb->IrpContextLite);
899 } // end UDFIsInDelayedCloseQueue()
900
901 BOOLEAN
902 UDFIsLastClose(
903 PUDF_FILE_INFO FileInfo)
904 {
905 ASSERT(FileInfo);
906 PtrUDFFCB Fcb = FileInfo->Fcb;
907 if( Fcb &&
908 !Fcb->OpenHandleCount &&
909 Fcb->ReferenceCount &&
910 Fcb->NTRequiredFCB->SectionObject.DataSectionObject) {
911 return TRUE;
912 }
913 return FALSE;
914 } // UDFIsLastClose()
915
916 NTSTATUS
917 UDFCloseAllXXXDelayedInDir(
918 IN PVCB Vcb,
919 IN PUDF_FILE_INFO FileInfo,
920 IN BOOLEAN System
921 )
922 {
923 PUDF_FILE_INFO* PassedList = NULL;
924 ULONG PassedListSize = 0;
925 PUDF_FILE_INFO* FoundList = NULL;
926 ULONG FoundListSize = 0;
927 NTSTATUS RC;
928 ULONG i;
929 BOOLEAN ResAcq = FALSE;
930 BOOLEAN AcquiredVcb = FALSE;
931 UDFNTRequiredFCB* NtReqFcb;
932 PUDF_FILE_INFO CurFileInfo;
933 PFE_LIST_ENTRY CurListPtr;
934 PFE_LIST_ENTRY* ListPtrArray = NULL;
935
936 _SEH2_TRY {
937
938 KdPrint((" UDFCloseAllXXXDelayedInDir(): Acquire DelayedCloseResource\n"));
939 // Acquire DelayedCloseResource
940 UDFAcquireResourceExclusive(&(UDFGlobalData.DelayedCloseResource), TRUE);
941 ResAcq = TRUE;
942
943 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
944 AcquiredVcb = TRUE;
945
946 RC = UDFBuildTreeItemsList(Vcb, FileInfo,
947 System ? UDFIsLastClose : UDFIsInDelayedCloseQueue,
948 &PassedList, &PassedListSize, &FoundList, &FoundListSize);
949
950 if(!NT_SUCCESS(RC)) {
951 KdPrint((" UDFBuildTreeItemsList(): error %x\n", RC));
952 try_return(RC);
953 }
954
955 if(!FoundList || !FoundListSize) {
956 try_return(RC = STATUS_SUCCESS);
957 }
958
959 // build array of referenced pointers
960 ListPtrArray = (PFE_LIST_ENTRY*)(MyAllocatePool__(NonPagedPool, FoundListSize*sizeof(PFE_LIST_ENTRY)));
961 if(!ListPtrArray) {
962 KdPrint((" Can't alloc ListPtrArray for %x items\n", FoundListSize));
963 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
964 }
965
966 for(i=0;i<FoundListSize;i++) {
967
968 _SEH2_TRY {
969
970 CurFileInfo = FoundList[i];
971 if(!CurFileInfo->ListPtr) {
972 CurFileInfo->ListPtr = (PFE_LIST_ENTRY)(MyAllocatePool__(NonPagedPool, sizeof(FE_LIST_ENTRY)));
973 if(!CurFileInfo->ListPtr) {
974 KdPrint((" Can't alloc ListPtrEntry for items %x\n", i));
975 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
976 }
977 CurFileInfo->ListPtr->FileInfo = CurFileInfo;
978 CurFileInfo->ListPtr->EntryRefCount = 0;
979 }
980 CurFileInfo->ListPtr->EntryRefCount++;
981 ListPtrArray[i] = CurFileInfo->ListPtr;
982
983 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER) {
984 BrutePoint();
985 } _SEH2_END;
986 }
987
988 UDFReleaseResource(&(Vcb->VCBResource));
989 AcquiredVcb = FALSE;
990
991 if(System) {
992 // Remove from system queue
993 PtrUDFFCB Fcb;
994 IO_STATUS_BLOCK IoStatus;
995 BOOLEAN NoDelayed = (Vcb->VCBFlags & UDF_VCB_FLAGS_NO_DELAYED_CLOSE) ?
996 TRUE : FALSE;
997
998 Vcb->VCBFlags |= UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
999 for(i=FoundListSize;i>0;i--) {
1000 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
1001 AcquiredVcb = TRUE;
1002 _SEH2_TRY {
1003
1004 CurListPtr = ListPtrArray[i-1];
1005 CurFileInfo = CurListPtr->FileInfo;
1006 if(CurFileInfo &&
1007 (Fcb = CurFileInfo->Fcb)) {
1008 NtReqFcb = Fcb->NTRequiredFCB;
1009 ASSERT((ULONG)NtReqFcb > 0x1000);
1010 // ASSERT((ULONG)(NtReqFcb->SectionObject) > 0x1000);
1011 if(!(NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_DELETED) &&
1012 (NtReqFcb->NtReqFCBFlags & UDF_NTREQ_FCB_MODIFIED)) {
1013 MmPrint((" CcFlushCache()\n"));
1014 CcFlushCache(&(NtReqFcb->SectionObject), NULL, 0, &IoStatus);
1015 }
1016 if(NtReqFcb->SectionObject.ImageSectionObject) {
1017 MmPrint((" MmFlushImageSection()\n"));
1018 MmFlushImageSection(&(NtReqFcb->SectionObject), MmFlushForWrite);
1019 }
1020 if(NtReqFcb->SectionObject.DataSectionObject) {
1021 MmPrint((" CcPurgeCacheSection()\n"));
1022 CcPurgeCacheSection( &(NtReqFcb->SectionObject), NULL, 0, FALSE );
1023 }
1024 } else {
1025 MmPrint((" Skip item: deleted\n"));
1026 }
1027 CurListPtr->EntryRefCount--;
1028 if(!CurListPtr->EntryRefCount) {
1029 if(CurListPtr->FileInfo)
1030 CurListPtr->FileInfo->ListPtr = NULL;
1031 MyFreePool__(CurListPtr);
1032 }
1033 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
1034 BrutePoint();
1035 } _SEH2_END;
1036 UDFReleaseResource(&(Vcb->VCBResource));
1037 AcquiredVcb = FALSE;
1038 }
1039 if(!NoDelayed)
1040 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_NO_DELAYED_CLOSE;
1041 } else {
1042 // Remove from internal queue
1043 PtrUDFIrpContextLite NextIrpContextLite;
1044
1045 for(i=FoundListSize;i>0;i--) {
1046
1047 UDFAcquireResourceExclusive(&(Vcb->VCBResource), TRUE);
1048 AcquiredVcb = TRUE;
1049
1050 CurListPtr = ListPtrArray[i-1];
1051 CurFileInfo = CurListPtr->FileInfo;
1052
1053 if(CurFileInfo &&
1054 CurFileInfo->Fcb &&
1055 (NextIrpContextLite = CurFileInfo->Fcb->IrpContextLite)) {
1056 RemoveEntryList( &(NextIrpContextLite->DelayedCloseLinks) );
1057 if (NextIrpContextLite->Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
1058 // BrutePoint();
1059 UDFGlobalData.DirDelayedCloseCount--;
1060 } else {
1061 UDFGlobalData.DelayedCloseCount--;
1062 }
1063 UDFDoDelayedClose(NextIrpContextLite);
1064 }
1065 CurListPtr->EntryRefCount--;
1066 if(!CurListPtr->EntryRefCount) {
1067 if(CurListPtr->FileInfo)
1068 CurListPtr->FileInfo->ListPtr = NULL;
1069 MyFreePool__(CurListPtr);
1070 }
1071 UDFReleaseResource(&(Vcb->VCBResource));
1072 AcquiredVcb = FALSE;
1073 }
1074 }
1075 RC = STATUS_SUCCESS;
1076
1077 try_exit: NOTHING;
1078
1079 } _SEH2_FINALLY {
1080 // release Vcb
1081 if(AcquiredVcb)
1082 UDFReleaseResource(&(Vcb->VCBResource));
1083 // Release DelayedCloseResource
1084 if(ResAcq)
1085 UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
1086
1087 if(ListPtrArray)
1088 MyFreePool__(ListPtrArray);
1089 if(PassedList)
1090 MyFreePool__(PassedList);
1091 if(FoundList)
1092 MyFreePool__(FoundList);
1093 } _SEH2_END;
1094
1095 return RC;
1096 } // end UDFCloseAllXXXDelayedInDir(
1097
1098
1099 /*
1100 This routine adds request to Delayed Close queue.
1101 If number of queued requests exceeds higher threshold it fires
1102 UDFDelayedClose()
1103 */
1104 NTSTATUS
1105 UDFQueueDelayedClose(
1106 PtrUDFIrpContext IrpContext,
1107 PtrUDFFCB Fcb
1108 )
1109 {
1110 PtrUDFIrpContextLite IrpContextLite;
1111 BOOLEAN StartWorker = 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
1122 if(Fcb->FCBFlags & UDF_FCB_DELETE_ON_CLOSE) {
1123 try_return(RC = STATUS_DELETE_PENDING);
1124 }
1125
1126 if(Fcb->IrpContextLite ||
1127 Fcb->FCBFlags & UDF_FCB_POSTED_RENAME) {
1128 // BrutePoint();
1129 try_return(RC = STATUS_UNSUCCESSFUL);
1130 }
1131
1132 if(!NT_SUCCESS(RC = UDFInitializeIrpContextLite(&IrpContextLite,IrpContext,Fcb))) {
1133 try_return(RC);
1134 }
1135
1136 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
1137 InsertTailList( &UDFGlobalData.DirDelayedCloseQueue,
1138 &IrpContextLite->DelayedCloseLinks );
1139 UDFGlobalData.DirDelayedCloseCount++;
1140 } else {
1141 InsertTailList( &UDFGlobalData.DelayedCloseQueue,
1142 &IrpContextLite->DelayedCloseLinks );
1143 UDFGlobalData.DelayedCloseCount++;
1144 }
1145 Fcb->IrpContextLite = IrpContextLite;
1146
1147 // If we are above our threshold then start the delayed
1148 // close operation.
1149 if(UDFGlobalData.DelayedCloseCount > UDFGlobalData.MaxDelayedCloseCount) {
1150
1151 UDFGlobalData.ReduceDelayedClose = TRUE;
1152
1153 if(!UDFGlobalData.FspCloseActive) {
1154
1155 UDFGlobalData.FspCloseActive = TRUE;
1156 StartWorker = TRUE;
1157 }
1158 }
1159 // If we are above our threshold then start the delayed
1160 // close operation.
1161 if(UDFGlobalData.DirDelayedCloseCount > UDFGlobalData.MaxDirDelayedCloseCount) {
1162
1163 UDFGlobalData.ReduceDirDelayedClose = TRUE;
1164
1165 if(!UDFGlobalData.FspCloseActive) {
1166
1167 UDFGlobalData.FspCloseActive = TRUE;
1168 StartWorker = TRUE;
1169 }
1170 }
1171 // Start the FspClose thread if we need to.
1172 if(StartWorker) {
1173 ExQueueWorkItem( &UDFGlobalData.CloseItem, CriticalWorkQueue );
1174 }
1175 RC = STATUS_SUCCESS;
1176
1177 try_exit: NOTHING;
1178
1179 } _SEH2_FINALLY {
1180
1181 if(!NT_SUCCESS(RC)) {
1182 Fcb->FCBFlags &= ~UDF_FCB_DELAY_CLOSE;
1183 }
1184 UDFReleaseResource(&(Fcb->Vcb->VCBResource));
1185 // Release DelayedCloseResource
1186 UDFReleaseResource(&(UDFGlobalData.DelayedCloseResource));
1187 } _SEH2_END;
1188 return RC;
1189 } // end UDFQueueDelayedClose()
1190