1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
10 * Module: UDF File System Driver (Kernel mode execution only)
13 * Contains code to handle the "Close" dispatch entry point.
15 *************************************************************************/
19 // define the file specific bug-check id
20 #define UDF_BUG_CHECK_ID UDF_FILE_CLOSE
22 typedef BOOLEAN (*PCHECK_TREE_ITEM
) (IN PUDF_FILE_INFO FileInfo
);
23 #define TREE_ITEM_LIST_GRAN 32
26 UDFBuildTreeItemsList(
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
);
35 // callbacks, can't be __fastcall
37 UDFIsInDelayedCloseQueue(
38 PUDF_FILE_INFO FileInfo
);
42 PUDF_FILE_INFO FileInfo
);
44 /*************************************************************************
46 * Function: UDFClose()
49 * The I/O Manager will invoke this routine to handle a close
52 * Expected Interrupt Level (for execution) :
54 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
55 * to be deferred to a worker thread context)
57 * Return Value: STATUS_SUCCESS
59 *************************************************************************/
63 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
64 PIRP Irp
// I/O Request Packet
67 NTSTATUS RC
= STATUS_SUCCESS
;
68 PtrUDFIrpContext PtrIrpContext
= NULL
;
69 BOOLEAN AreWeTopLevel
= FALSE
;
71 AdPrint(("UDFClose: \n"));
73 FsRtlEnterFileSystem();
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;
84 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
85 FsRtlExitFileSystem();
89 // set the top level context
90 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
94 // get an IRP context structure and issue the request
95 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
96 ASSERT(PtrIrpContext
);
98 RC
= UDFCommonClose(PtrIrpContext
, Irp
);
100 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
102 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
104 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
108 IoSetTopLevelIrp(NULL
);
111 FsRtlExitFileSystem();
119 /*************************************************************************
121 * Function: UDFCommonClose()
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
129 * Expected Interrupt Level (for execution) :
133 * Return Value: must be STATUS_SUCCESS
135 *************************************************************************/
138 PtrUDFIrpContext PtrIrpContext
,
142 NTSTATUS RC
= STATUS_SUCCESS
;
143 PIO_STACK_LOCATION IrpSp
= NULL
;
144 PFILE_OBJECT FileObject
= NULL
;
145 PtrUDFFCB Fcb
= NULL
;
146 PtrUDFCCB Ccb
= NULL
;
148 // PERESOURCE PtrResourceAcquired = NULL;
149 BOOLEAN AcquiredVcb
= FALSE
;
150 BOOLEAN AcquiredGD
= FALSE
;
153 // ULONG clean_stat = 0;
155 // BOOLEAN CompleteIrp = TRUE;
156 BOOLEAN PostRequest
= FALSE
;
159 UNICODE_STRING CurName
;
160 PDIR_INDEX_HDR DirNdx
;
163 AdPrint(("UDFCommonClose: \n"));
168 // If this is the first (IOManager) request
169 // First, get a pointer to the current I/O stack location
170 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
173 FileObject
= IrpSp
->FileObject
;
176 // Get the FCB and CCB pointers
177 Ccb
= (PtrUDFCCB
)(FileObject
->FsContext2
);
179 if(Ccb
->CCBFlags
& UDF_CCB_READ_ONLY
) {
180 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_READ_ONLY
;
184 // If this is a queued call (for our dispatch)
185 // Get saved Fcb address
186 Fcb
= PtrIrpContext
->Fcb
;
187 i
= PtrIrpContext
->TreeLength
;
191 Vcb
= (PVCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
193 ASSERT(Vcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
194 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
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.
209 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
212 // Is this is the first (IOManager) request ?
214 PtrIrpContext
->TreeLength
=
216 // remember the number of incomplete Close requests
217 InterlockedIncrement((PLONG
)&(Fcb
->CcbCount
));
218 // we can release CCB in any case
220 FileObject
->FsContext2
= NULL
;
223 ASSERT(Fcb->NTRequiredFCB);
224 if(Fcb->NTRequiredFCB) {
225 ASSERT(Fcb->NTRequiredFCB->FileObject);
226 if(Fcb->NTRequiredFCB->FileObject) {
227 ASSERT(!Fcb->NTRequiredFCB->FileObject->FsContext2);
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
));
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
));
247 #endif //UDF_DELAYED_CLOSE
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"));
255 try_return(RC
= STATUS_SUCCESS
);
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
));
264 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
265 if(PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_READ_ONLY
)
266 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCountRO
));
268 if(!i
|| (Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
)) {
270 AdPrint(("UDF: Closing volume\n"));
271 AdPrint(("UDF: ReferenceCount: %x\n",Fcb
->ReferenceCount
));
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
));
279 try_return(RC
= STATUS_SUCCESS
);
282 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCount
));
285 UDFReleaseResource(&(Vcb
->VCBResource
));
290 // Acquire GlobalDataResource
291 UDFAcquireResourceExclusive(&(UDFGlobalData
.GlobalDataResource
), TRUE
);
294 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
297 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
300 ASSERT(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
301 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
302 ASSERT(Fcb
->NTRequiredFCB
);
303 UDFInterlockedDecrement((PLONG
)&(Fcb
->NTRequiredFCB
->CommonRefCount
));
305 //AdPrint(("UDF: Closing volume, reset driver (e.g. stop BGF)\n"));
306 //UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE);
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
);
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
);
319 try_return(RC
= STATUS_SUCCESS
);
328 DirNdx
= UDFGetDirIndexByFileInfo(fi
);
330 CurName
.Buffer
= UDFDirIndex(DirNdx
,fi
->Index
)->FName
.Buffer
;
332 AdPrint(("Closing file: %ws %8.8x\n", CurName
.Buffer
, FileObject
));
334 AdPrint(("Closing file: ??? \n"));
337 AdPrint(("UDF: ReferenceCount: %x\n",Fcb
->ReferenceCount
));
339 // try to clean up as long chain as it is possible
340 UDFCleanUpFcbChain(Vcb
, fi
, i
, TRUE
);
347 UDFReleaseResource(&(Vcb
->VCBResource
));
350 UDFReleaseResource(&(UDFGlobalData
.GlobalDataResource
));
353 // Post IRP if required
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
);
364 if (!_SEH2_AbnormalTermination()) {
365 // If this is not async close complete the IRP
367 /* if( FileObject ) {
368 if(clean_stat & UDF_CLOSE_NTREQFCB_DELETED) {
369 // ASSERT(!FileObject->FsContext2);
370 FileObject->FsContext = NULL;
373 UDFNTRequiredFCB* NtReqFcb = ((UDFNTRequiredFCB*)(FileObject->FsContext));
374 if(NtReqFcb->FileObject == FileObject) {
375 NtReqFcb->FileObject = NULL;
380 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
381 Irp
->IoStatus
.Information
= 0;
382 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
384 // Free up the Irp Context
386 UDFReleaseIrpContext(PtrIrpContext
);
389 } _SEH2_END
; // end of "__finally" processing
391 return STATUS_SUCCESS
;
392 } // end UDFCommonClose()
395 This routine walks through the tree to RootDir & kills all unreferenced
402 IN PUDF_FILE_INFO fi
,
404 IN BOOLEAN VcbAcquired
407 PtrUDFFCB Fcb
= NULL
;
408 PtrUDFFCB ParentFcb
= NULL
;
409 PUDF_FILE_INFO ParentFI
;
410 UDFNTRequiredFCB
* NtReqFcb
;
412 LONG RefCount
, ComRefCount
;
413 BOOLEAN Delete
= FALSE
;
416 ValidateFileInfo(fi
);
417 AdPrint(("UDFCleanUpFcbChain\n"));
421 // we can't process Tree until we can acquire Vcb
423 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
425 // cleanup parent chain (if any & unused)
429 if((ParentFI
= fi
->ParentFile
)) {
431 ParentFcb
= fi
->Fcb
->ParentFcb
;
433 ASSERT(ParentFcb
->NTRequiredFCB
);
434 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
435 UDFAcquireResourceExclusive(&(ParentFcb
->NTRequiredFCB
->MainResource
),TRUE
);
437 // we get to RootDir, it has no parent
439 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
442 ASSERT(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_FCB
);
444 NtReqFcb
= Fcb
->NTRequiredFCB
;
445 ASSERT(NtReqFcb
->CommonFCBHeader
.NodeTypeCode
== UDF_NODE_TYPE_NT_REQ_FCB
);
447 // acquire current file/dir
448 // we must assure that no more threads try to re-use this object
452 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
453 UDFAcquireResourceExclusive(&(NtReqFcb
->MainResource
),TRUE
);
455 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
458 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
459 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
462 UDFReleaseResource(&(Vcb
->VCBResource
));
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.
475 ASSERT(Fcb
->ReferenceCount
);
476 ASSERT(NtReqFcb
->CommonRefCount
);
477 RefCount
= UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
478 ComRefCount
= UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
485 ASSERT(Fcb
->OpenHandleCount
<= Fcb
->ReferenceCount
);
488 RefCount
= UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
489 ComRefCount
= UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
494 /* if(Fcb && Fcb->FCBName && Fcb->FCBName->ObjectName.Buffer) {
495 AdPrint((" %ws (%x)\n",
496 Fcb->FCBName->ObjectName.Buffer,Fcb->ReferenceCount));
498 AdPrint((" ??? (%x)\n",Fcb->ReferenceCount));
500 AdPrint((" ??? (??)\n"));
502 // ...and delete if it has gone
504 if(!RefCount
&& !Fcb
->OpenHandleCount
) {
505 // no more references... current file/dir MUST DIE!!!
506 BOOLEAN AutoInherited
= UDFIsAStreamDir(fi
) || UDFIsAStream(fi
);
508 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) {
511 #ifndef UDF_READ_ONLY_BUILD
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);
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
;
527 #endif //UDF_READ_ONLY_BUILD
528 if(!(Fcb
->FCBFlags
& UDF_FCB_DELETED
)) {
529 UDFFlushFile__(Vcb
, fi
);
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
)
537 #endif //UDF_READ_ONLY_BUILD
539 // remove references to OS-specific structures
540 // to let UDF_INFO release FI & Co
543 // CommonFcb is also completly dereferenced
545 fi
->Dloc
->CommonFcb
= NULL
;
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
557 // NtReqFcb->NtReqFCBFlags &= ~UDF_NTREQ_FCB_VALID;
558 // Unitialize byte-range locks support structure
559 FsRtlUninitializeFileLock(&(NtReqFcb
->FileLock
));
561 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
562 UDFReleaseResource(&(NtReqFcb
->MainResource
));
563 if(NtReqFcb
->CommonFCBHeader
.Resource
) {
564 UDFDeleteResource(&(NtReqFcb
->MainResource
));
565 UDFDeleteResource(&(NtReqFcb
->PagingIoResource
));
567 NtReqFcb
->CommonFCBHeader
.Resource
=
568 NtReqFcb
->CommonFCBHeader
.PagingIoResource
= NULL
;
569 UDFDeassignAcl(NtReqFcb
, AutoInherited
);
570 UDFPrint(("UDFReleaseNtReqFCB: %x\n", NtReqFcb
));
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;
580 MyFreePool__(NtReqFcb
);
581 ret_val
|= UDF_CLOSE_NTREQFCB_DELETED
;
583 // we usually get here when the file has some opened links
584 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
585 UDFReleaseResource(&(NtReqFcb
->MainResource
));
587 // remove some references & free Fcb structure
588 Fcb
->NTRequiredFCB
= NULL
;
589 Fcb
->ParentFcb
= NULL
;
592 ret_val
|= UDF_CLOSE_FCB_DELETED
;
593 // get pointer to parent FCB
595 // free old parent's resource...
597 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
598 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
601 UDFReleaseResource(&(Vcb
->VCBResource
));
608 fi
->Dloc
->CommonFcb
= NtReqFcb
;
609 // free all acquired resources
610 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
611 UDFReleaseResource(&(NtReqFcb
->MainResource
));
614 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
615 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
618 UDFReleaseResource(&(Vcb
->VCBResource
));
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
626 // AdPrint(("Stop on referenced File/Dir\n"));
629 // we get to referenced file/dir. Stop search & release resource
630 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
631 UDFReleaseResource(&(NtReqFcb
->MainResource
));
633 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
634 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
637 UDFReleaseResource(&(Vcb
->VCBResource
));
647 for(;TreeLength
&& fi
;TreeLength
--) {
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
));
664 UDFReleaseResource(&(Vcb
->VCBResource
));
667 } // end UDFCleanUpFcbChain()
671 IN PtrUDFIrpContextLite NextIrpContextLite
674 PtrUDFIrpContext IrpContext
;
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()
685 This routine removes request from Delayed Close queue.
686 It operates until reach lower threshold
695 PtrUDFIrpContextLite NextIrpContextLite
;
697 AdPrint((" UDFDelayedClose\n"));
698 // Acquire DelayedCloseResource
699 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
701 while (UDFGlobalData
.ReduceDelayedClose
&&
702 (UDFGlobalData
.DelayedCloseCount
> UDFGlobalData
.MinDelayedCloseCount
)) {
704 Entry
= UDFGlobalData
.DelayedCloseQueue
.Flink
;
706 if (!IsListEmpty(Entry
)) {
707 // Extract the IrpContext.
708 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
712 RemoveEntryList( Entry
);
713 UDFGlobalData
.DelayedCloseCount
--;
714 UDFDoDelayedClose(NextIrpContextLite
);
720 while (UDFGlobalData
.ReduceDirDelayedClose
&&
721 (UDFGlobalData
.DirDelayedCloseCount
> UDFGlobalData
.MinDirDelayedCloseCount
)) {
723 Entry
= UDFGlobalData
.DirDelayedCloseQueue
.Flink
;
725 if (!IsListEmpty(Entry
)) {
726 // Extract the IrpContext.
727 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
731 RemoveEntryList( Entry
);
732 UDFGlobalData
.DirDelayedCloseCount
--;
733 UDFDoDelayedClose(NextIrpContextLite
);
739 UDFGlobalData
.FspCloseActive
= FALSE
;
740 UDFGlobalData
.ReduceDelayedClose
= FALSE
;
741 UDFGlobalData
.ReduceDirDelayedClose
= FALSE
;
743 // Release DelayedCloseResource
744 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
747 } // end UDFDelayedClose()
750 This routine performs Close operation for all files from
759 PtrUDFIrpContextLite NextIrpContextLite
;
760 BOOLEAN GlobalDataAcquired
= FALSE
;
762 AdPrint((" UDFCloseAllDelayed\n"));
763 // Acquire DelayedCloseResource
764 if (!ExIsResourceAcquiredExclusive(&UDFGlobalData
.GlobalDataResource
)) {
765 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
766 GlobalDataAcquired
= TRUE
;
769 Entry
= UDFGlobalData
.DelayedCloseQueue
.Flink
;
771 while (Entry
!= &UDFGlobalData
.DelayedCloseQueue
) {
772 // Extract the IrpContext.
773 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
776 Entry
= Entry
->Flink
;
777 if (NextIrpContextLite
->Fcb
->Vcb
== Vcb
) {
778 RemoveEntryList( &(NextIrpContextLite
->DelayedCloseLinks
) );
779 UDFGlobalData
.DelayedCloseCount
--;
780 UDFDoDelayedClose(NextIrpContextLite
);
784 Entry
= UDFGlobalData
.DirDelayedCloseQueue
.Flink
;
786 while (Entry
!= &UDFGlobalData
.DirDelayedCloseQueue
) {
787 // Extract the IrpContext.
788 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
791 Entry
= Entry
->Flink
;
792 if (NextIrpContextLite
->Fcb
->Vcb
== Vcb
) {
793 RemoveEntryList( &(NextIrpContextLite
->DelayedCloseLinks
) );
794 UDFGlobalData
.DirDelayedCloseCount
--;
795 UDFDoDelayedClose(NextIrpContextLite
);
799 // Release DelayedCloseResource
800 if(GlobalDataAcquired
)
801 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
803 } // end UDFCloseAllDelayed()
806 UDFBuildTreeItemsList(
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
816 PDIR_INDEX_HDR hDirNdx
;
817 PUDF_FILE_INFO SDirInfo
;
820 UDFPrint((" UDFBuildTreeItemsList():\n"));
821 if(!(*PassedList
) || !(*FoundList
)) {
823 (*PassedList
) = (PUDF_FILE_INFO
*)
824 MyAllocatePool__(NonPagedPool
, sizeof(PUDF_FILE_INFO
)*TREE_ITEM_LIST_GRAN
);
826 return STATUS_INSUFFICIENT_RESOURCES
;
827 (*PassedListSize
) = 0;
829 (*FoundList
) = (PUDF_FILE_INFO
*)
830 MyAllocatePool__(NonPagedPool
, sizeof(PUDF_FILE_INFO
)*TREE_ITEM_LIST_GRAN
);
832 MyFreePool__(*PassedList
);
834 return STATUS_INSUFFICIENT_RESOURCES
;
836 (*FoundListSize
) = 0;
839 // check if already passed
840 for(i
=0;i
<(*PassedListSize
);i
++) {
841 if( ((*PassedList
)[i
]) == FileInfo
)
842 return STATUS_SUCCESS
;
844 // remember passed object
845 // we should not proceed linked objects twice
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
;
853 (*PassedList
)[(*PassedListSize
)-1] = FileInfo
;
855 // check if this object matches our conditions
856 if(CheckItemProc(FileInfo
)) {
857 // remember matched object
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
;
865 (*FoundList
)[(*FoundListSize
)-1] = FileInfo
;
868 // walk through SDir (if any)
869 if((SDirInfo
= FileInfo
->Dloc
->SDirInfo
))
870 UDFBuildTreeItemsList(Vcb
, SDirInfo
, CheckItemProc
,
871 PassedList
, PassedListSize
, FoundList
, FoundListSize
);
873 // walk through subsequent objects (if any)
874 if((hDirNdx
= FileInfo
->Dloc
->DirIndex
)) {
877 UDF_DIR_SCAN_CONTEXT ScanContext
;
878 PDIR_INDEX_ITEM DirNdx
;
879 PUDF_FILE_INFO CurFileInfo
;
881 if(UDFDirIndexInitScan(FileInfo
, &ScanContext
, 2)) {
882 while((DirNdx
= UDFDirIndexScan(&ScanContext
, &CurFileInfo
))) {
885 UDFBuildTreeItemsList(Vcb
, CurFileInfo
, CheckItemProc
,
886 PassedList
, PassedListSize
, FoundList
, FoundListSize
);
891 return STATUS_SUCCESS
;
892 } // end UDFBuildTreeItemsList()
895 UDFIsInDelayedCloseQueue(
896 PUDF_FILE_INFO FileInfo
)
899 return (FileInfo
->Fcb
&& FileInfo
->Fcb
->IrpContextLite
);
900 } // end UDFIsInDelayedCloseQueue()
904 PUDF_FILE_INFO FileInfo
)
907 PtrUDFFCB Fcb
= FileInfo
->Fcb
;
909 !Fcb
->OpenHandleCount
&&
910 Fcb
->ReferenceCount
&&
911 Fcb
->NTRequiredFCB
->SectionObject
.DataSectionObject
) {
915 } // UDFIsLastClose()
918 UDFCloseAllXXXDelayedInDir(
920 IN PUDF_FILE_INFO FileInfo
,
924 PUDF_FILE_INFO
* PassedList
= NULL
;
925 ULONG PassedListSize
= 0;
926 PUDF_FILE_INFO
* FoundList
= NULL
;
927 ULONG FoundListSize
= 0;
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
;
939 UDFPrint((" UDFCloseAllXXXDelayedInDir(): Acquire DelayedCloseResource\n"));
940 // Acquire DelayedCloseResource
941 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
944 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
947 RC
= UDFBuildTreeItemsList(Vcb
, FileInfo
,
948 System
? UDFIsLastClose
: UDFIsInDelayedCloseQueue
,
949 &PassedList
, &PassedListSize
, &FoundList
, &FoundListSize
);
951 if(!NT_SUCCESS(RC
)) {
952 UDFPrint((" UDFBuildTreeItemsList(): error %x\n", RC
));
956 if(!FoundList
|| !FoundListSize
) {
957 try_return(RC
= STATUS_SUCCESS
);
960 // build array of referenced pointers
961 ListPtrArray
= (PFE_LIST_ENTRY
*)(MyAllocatePool__(NonPagedPool
, FoundListSize
*sizeof(PFE_LIST_ENTRY
)));
963 UDFPrint((" Can't alloc ListPtrArray for %x items\n", FoundListSize
));
964 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
967 for(i
=0;i
<FoundListSize
;i
++) {
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
);
978 CurFileInfo
->ListPtr
->FileInfo
= CurFileInfo
;
979 CurFileInfo
->ListPtr
->EntryRefCount
= 0;
981 CurFileInfo
->ListPtr
->EntryRefCount
++;
982 ListPtrArray
[i
] = CurFileInfo
->ListPtr
;
984 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
989 UDFReleaseResource(&(Vcb
->VCBResource
));
993 // Remove from system queue
995 IO_STATUS_BLOCK IoStatus
;
996 BOOLEAN NoDelayed
= (Vcb
->VCBFlags
& UDF_VCB_FLAGS_NO_DELAYED_CLOSE
) ?
999 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_NO_DELAYED_CLOSE
;
1000 for(i
=FoundListSize
;i
>0;i
--) {
1001 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
1005 CurListPtr
= ListPtrArray
[i
-1];
1006 CurFileInfo
= CurListPtr
->FileInfo
;
1008 (Fcb
= CurFileInfo
->Fcb
)) {
1009 NtReqFcb
= Fcb
->NTRequiredFCB
;
1010 ASSERT((ULONG
)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
);
1017 if(NtReqFcb
->SectionObject
.ImageSectionObject
) {
1018 MmPrint((" MmFlushImageSection()\n"));
1019 MmFlushImageSection(&(NtReqFcb
->SectionObject
), MmFlushForWrite
);
1021 if(NtReqFcb
->SectionObject
.DataSectionObject
) {
1022 MmPrint((" CcPurgeCacheSection()\n"));
1023 CcPurgeCacheSection( &(NtReqFcb
->SectionObject
), NULL
, 0, FALSE
);
1026 MmPrint((" Skip item: deleted\n"));
1028 CurListPtr
->EntryRefCount
--;
1029 if(!CurListPtr
->EntryRefCount
) {
1030 if(CurListPtr
->FileInfo
)
1031 CurListPtr
->FileInfo
->ListPtr
= NULL
;
1032 MyFreePool__(CurListPtr
);
1034 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1037 UDFReleaseResource(&(Vcb
->VCBResource
));
1038 AcquiredVcb
= FALSE
;
1041 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_NO_DELAYED_CLOSE
;
1043 // Remove from internal queue
1044 PtrUDFIrpContextLite NextIrpContextLite
;
1046 for(i
=FoundListSize
;i
>0;i
--) {
1048 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
1051 CurListPtr
= ListPtrArray
[i
-1];
1052 CurFileInfo
= CurListPtr
->FileInfo
;
1056 (NextIrpContextLite
= CurFileInfo
->Fcb
->IrpContextLite
)) {
1057 RemoveEntryList( &(NextIrpContextLite
->DelayedCloseLinks
) );
1058 if (NextIrpContextLite
->Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
1060 UDFGlobalData
.DirDelayedCloseCount
--;
1062 UDFGlobalData
.DelayedCloseCount
--;
1064 UDFDoDelayedClose(NextIrpContextLite
);
1066 CurListPtr
->EntryRefCount
--;
1067 if(!CurListPtr
->EntryRefCount
) {
1068 if(CurListPtr
->FileInfo
)
1069 CurListPtr
->FileInfo
->ListPtr
= NULL
;
1070 MyFreePool__(CurListPtr
);
1072 UDFReleaseResource(&(Vcb
->VCBResource
));
1073 AcquiredVcb
= FALSE
;
1076 RC
= STATUS_SUCCESS
;
1083 UDFReleaseResource(&(Vcb
->VCBResource
));
1084 // Release DelayedCloseResource
1086 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
1089 MyFreePool__(ListPtrArray
);
1091 MyFreePool__(PassedList
);
1093 MyFreePool__(FoundList
);
1097 } // end UDFCloseAllXXXDelayedInDir(
1101 This routine adds request to Delayed Close queue.
1102 If number of queued requests exceeds higher threshold it fires
1106 UDFQueueDelayedClose(
1107 PtrUDFIrpContext IrpContext
,
1111 PtrUDFIrpContextLite IrpContextLite
;
1112 BOOLEAN StartWorker
= FALSE
;
1113 _SEH2_VOLATILE BOOLEAN AcquiredVcb
= FALSE
;
1116 AdPrint((" UDFQueueDelayedClose\n"));
1119 // Acquire DelayedCloseResource
1120 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
1122 UDFAcquireResourceShared(&(Fcb
->Vcb
->VCBResource
), TRUE
);
1125 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) {
1126 try_return(RC
= STATUS_DELETE_PENDING
);
1129 if(Fcb
->IrpContextLite
||
1130 Fcb
->FCBFlags
& UDF_FCB_POSTED_RENAME
) {
1132 try_return(RC
= STATUS_UNSUCCESSFUL
);
1135 if(!NT_SUCCESS(RC
= UDFInitializeIrpContextLite(&IrpContextLite
,IrpContext
,Fcb
))) {
1139 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
1140 InsertTailList( &UDFGlobalData
.DirDelayedCloseQueue
,
1141 &IrpContextLite
->DelayedCloseLinks
);
1142 UDFGlobalData
.DirDelayedCloseCount
++;
1144 InsertTailList( &UDFGlobalData
.DelayedCloseQueue
,
1145 &IrpContextLite
->DelayedCloseLinks
);
1146 UDFGlobalData
.DelayedCloseCount
++;
1148 Fcb
->IrpContextLite
= IrpContextLite
;
1150 // If we are above our threshold then start the delayed
1152 if(UDFGlobalData
.DelayedCloseCount
> UDFGlobalData
.MaxDelayedCloseCount
) {
1154 UDFGlobalData
.ReduceDelayedClose
= TRUE
;
1156 if(!UDFGlobalData
.FspCloseActive
) {
1158 UDFGlobalData
.FspCloseActive
= TRUE
;
1162 // If we are above our threshold then start the delayed
1164 if(UDFGlobalData
.DirDelayedCloseCount
> UDFGlobalData
.MaxDirDelayedCloseCount
) {
1166 UDFGlobalData
.ReduceDirDelayedClose
= TRUE
;
1168 if(!UDFGlobalData
.FspCloseActive
) {
1170 UDFGlobalData
.FspCloseActive
= TRUE
;
1174 // Start the FspClose thread if we need to.
1176 ExQueueWorkItem( &UDFGlobalData
.CloseItem
, CriticalWorkQueue
);
1178 RC
= STATUS_SUCCESS
;
1184 if(!NT_SUCCESS(RC
)) {
1185 Fcb
->FCBFlags
&= ~UDF_FCB_DELAY_CLOSE
;
1188 UDFReleaseResource(&(Fcb
->Vcb
->VCBResource
));
1190 // Release DelayedCloseResource
1191 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
1194 } // end UDFQueueDelayedClose()