[UDFS] Fix 64 bit issues
[reactos.git] / 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 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