1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 ////////////////////////////////////////////////////////////////////
5 /*************************************************************************
9 * Module: UDF File System Driver (Kernel mode execution only)
12 * Contains code to handle the "Close" dispatch entry point.
14 *************************************************************************/
18 // define the file specific bug-check id
19 #define UDF_BUG_CHECK_ID UDF_FILE_CLOSE
21 typedef BOOLEAN (*PCHECK_TREE_ITEM
) (IN PUDF_FILE_INFO FileInfo
);
22 #define TREE_ITEM_LIST_GRAN 32
25 UDFBuildTreeItemsList(
27 IN PUDF_FILE_INFO FileInfo
,
28 IN PCHECK_TREE_ITEM CheckItemProc
,
29 IN PUDF_DATALOC_INFO
** PassedList
,
30 IN PULONG PassedListSize
,
31 IN PUDF_DATALOC_INFO
** FoundList
,
32 IN PULONG FoundListSize
);
34 // callbacks, can't be __fastcall
36 UDFIsInDelayedCloseQueue(
37 PUDF_FILE_INFO FileInfo
);
41 PUDF_FILE_INFO FileInfo
);
43 /*************************************************************************
45 * Function: UDFClose()
48 * The I/O Manager will invoke this routine to handle a close
51 * Expected Interrupt Level (for execution) :
53 * IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
54 * to be deferred to a worker thread context)
56 * Return Value: STATUS_SUCCESS
58 *************************************************************************/
62 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
63 PIRP Irp
// I/O Request Packet
66 NTSTATUS RC
= STATUS_SUCCESS
;
67 PtrUDFIrpContext PtrIrpContext
= NULL
;
68 BOOLEAN AreWeTopLevel
= FALSE
;
70 AdPrint(("UDFClose: \n"));
72 FsRtlEnterFileSystem();
76 // If we were called with our file system device object instead of a
77 // volume device object, just complete this request with STATUS_SUCCESS
78 if (UDFIsFSDevObj(DeviceObject
)) {
79 // this is a close of the FSD itself
80 Irp
->IoStatus
.Status
= RC
;
81 Irp
->IoStatus
.Information
= 0;
83 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
84 FsRtlExitFileSystem();
88 // set the top level context
89 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
93 // get an IRP context structure and issue the request
94 PtrIrpContext
= UDFAllocateIrpContext(Irp
, DeviceObject
);
95 ASSERT(PtrIrpContext
);
97 RC
= UDFCommonClose(PtrIrpContext
, Irp
);
99 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
101 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
103 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
107 IoSetTopLevelIrp(NULL
);
110 FsRtlExitFileSystem();
118 /*************************************************************************
120 * Function: UDFCommonClose()
123 * The actual work is performed here. This routine may be invoked in one'
124 * of the two possible contexts:
125 * (a) in the context of a system worker thread
126 * (b) in the context of the original caller
128 * Expected Interrupt Level (for execution) :
132 * Return Value: must be STATUS_SUCCESS
134 *************************************************************************/
137 PtrUDFIrpContext PtrIrpContext
,
141 NTSTATUS RC
= STATUS_SUCCESS
;
142 PIO_STACK_LOCATION IrpSp
= NULL
;
143 PFILE_OBJECT FileObject
= NULL
;
144 PtrUDFFCB Fcb
= NULL
;
145 PtrUDFCCB Ccb
= NULL
;
147 // PERESOURCE PtrResourceAcquired = NULL;
148 BOOLEAN AcquiredVcb
= FALSE
;
149 BOOLEAN AcquiredGD
= FALSE
;
152 ULONG clean_stat
= 0;
154 // BOOLEAN CompleteIrp = TRUE;
155 BOOLEAN PostRequest
= FALSE
;
158 UNICODE_STRING CurName
;
159 PDIR_INDEX_HDR DirNdx
;
162 AdPrint(("UDFCommonClose: \n"));
167 // If this is the first (IOManager) request
168 // First, get a pointer to the current I/O stack location
169 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
172 FileObject
= IrpSp
->FileObject
;
175 // Get the FCB and CCB pointers
176 Ccb
= (PtrUDFCCB
)(FileObject
->FsContext2
);
178 if(Ccb
->CCBFlags
& UDF_CCB_READ_ONLY
) {
179 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_READ_ONLY
;
183 // If this is a queued call (for our dispatch)
184 // Get saved Fcb address
185 Fcb
= PtrIrpContext
->Fcb
;
186 i
= PtrIrpContext
->TreeLength
;
190 Vcb
= (PVCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
192 ASSERT(Vcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
193 // Vcb->VCBFlags |= UDF_VCB_SKIP_EJECT_CHECK;
195 // Steps we shall take at this point are:
196 // (a) Acquire the VCB shared
197 // (b) Acquire the FCB's CCB list exclusively
198 // (c) Delete the CCB structure (free memory)
199 // (d) If this is the last close, release the FCB structure
200 // (unless we keep these around for "delayed close" functionality.
201 // Note that it is often the case that the close dispatch entry point is invoked
202 // in the most inconvenient of situations (when it is not possible, for example,
203 // to safely acquire certain required resources without deadlocking or waiting).
204 // Therefore, be extremely careful in implementing this close dispatch entry point.
205 // Also note that we do not have the option of returning a failure code from the
206 // close dispatch entry point; the system expects that the close will always succeed.
208 UDFAcquireResourceShared(&(Vcb
->VCBResource
), TRUE
);
211 // Is this is the first (IOManager) request ?
213 PtrIrpContext
->TreeLength
=
215 // remember the number of incomplete Close requests
216 InterlockedIncrement((PLONG
)&(Fcb
->CcbCount
));
217 // we can release CCB in any case
219 FileObject
->FsContext2
= NULL
;
222 ASSERT(Fcb->NTRequiredFCB);
223 if(Fcb->NTRequiredFCB) {
224 ASSERT(Fcb->NTRequiredFCB->FileObject);
225 if(Fcb->NTRequiredFCB->FileObject) {
226 ASSERT(!Fcb->NTRequiredFCB->FileObject->FsContext2);
232 #ifdef UDF_DELAYED_CLOSE
233 // check if this is the last Close (no more Handles)
234 // and try to Delay it....
235 if((Fcb
->FCBFlags
& UDF_FCB_DELAY_CLOSE
) &&
236 (Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
) &&
237 !(Vcb
->VCBFlags
& UDF_VCB_FLAGS_NO_DELAYED_CLOSE
) &&
238 !(Fcb
->OpenHandleCount
)) {
239 UDFReleaseResource(&(Vcb
->VCBResource
));
241 if((RC
= UDFQueueDelayedClose(PtrIrpContext
,Fcb
)) == STATUS_SUCCESS
)
242 try_return(RC
= STATUS_SUCCESS
);
243 // do standard Close if we can't Delay this opeartion
244 AdPrint((" Cant queue Close Irp, status=%x\n", RC
));
246 #endif //UDF_DELAYED_CLOSE
249 // We should post actual procesing if this is a recursive call
250 if((PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_NOT_TOP_LEVEL
) ||
251 (Fcb
->NTRequiredFCB
->AcqFlushCount
)) {
252 AdPrint((" post NOT_TOP_LEVEL Irp\n"));
254 try_return(RC
= STATUS_SUCCESS
);
258 // Close request is near completion, Vcb is acquired.
259 // Now we can safely decrease CcbCount, because no Rename
260 // operation can run until Vcb release.
261 InterlockedDecrement((PLONG
)&(Fcb
->CcbCount
));
263 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
264 if(PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_READ_ONLY
)
265 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCountRO
));
267 if(!i
|| (Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
)) {
269 AdPrint(("UDF: Closing volume\n"));
270 AdPrint(("UDF: ReferenceCount: %x\n",Fcb
->ReferenceCount
));
272 if (Vcb
->VCBOpenCount
> UDF_RESIDUAL_REFERENCE
) {
273 ASSERT(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
274 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
275 ASSERT(Fcb
->NTRequiredFCB
);
276 UDFInterlockedDecrement((PLONG
)&(Fcb
->NTRequiredFCB
->CommonRefCount
));
278 try_return(RC
= STATUS_SUCCESS
);
281 UDFInterlockedIncrement((PLONG
)&(Vcb
->VCBOpenCount
));
284 UDFReleaseResource(&(Vcb
->VCBResource
));
289 // Acquire GlobalDataResource
290 UDFAcquireResourceExclusive(&(UDFGlobalData
.GlobalDataResource
), TRUE
);
293 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
296 UDFInterlockedDecrement((PLONG
)&(Vcb
->VCBOpenCount
));
299 ASSERT(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_VCB
);
300 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
301 ASSERT(Fcb
->NTRequiredFCB
);
302 UDFInterlockedDecrement((PLONG
)&(Fcb
->NTRequiredFCB
->CommonRefCount
));
304 //AdPrint(("UDF: Closing volume, reset driver (e.g. stop BGF)\n"));
305 //UDFResetDeviceDriver(Vcb, Vcb->TargetDeviceObject, FALSE);
307 AdPrint(("UDF: Closing volume, reset write status\n"));
308 RC
= UDFPhSendIOCTL(IOCTL_CDRW_RESET_WRITE_STATUS
, Vcb
->TargetDeviceObject
,
309 NULL
, 0, NULL
, 0, TRUE
, NULL
);
311 if((Vcb
->VCBFlags
& UDF_VCB_FLAGS_BEING_DISMOUNTED
) ||
312 ((!(Vcb
->VCBFlags
& UDF_VCB_FLAGS_VOLUME_MOUNTED
)) && (Vcb
->VCBOpenCount
<= UDF_RESIDUAL_REFERENCE
))) {
313 // Try to KILL dismounted volume....
314 // w2k requires this, NT4 - recomends
315 AcquiredVcb
= UDFCheckForDismount(PtrIrpContext
, Vcb
, TRUE
);
318 try_return(RC
= STATUS_SUCCESS
);
327 DirNdx
= UDFGetDirIndexByFileInfo(fi
);
329 CurName
.Buffer
= UDFDirIndex(DirNdx
,fi
->Index
)->FName
.Buffer
;
331 AdPrint(("Closing file: %ws %8.8x\n", CurName
.Buffer
, FileObject
));
333 AdPrint(("Closing file: ??? \n"));
336 AdPrint(("UDF: ReferenceCount: %x\n",Fcb
->ReferenceCount
));
338 // try to clean up as long chain as it is possible
339 clean_stat
= UDFCleanUpFcbChain(Vcb
, fi
, i
, TRUE
);
346 UDFReleaseResource(&(Vcb
->VCBResource
));
349 UDFReleaseResource(&(UDFGlobalData
.GlobalDataResource
));
352 // Post IRP if required
355 // Perform the post operation & complete the IRP
356 // if this is first call of UDFCommonClose
357 // and will return STATUS_SUCCESS back to us
358 PtrIrpContext
->Irp
= NULL
;
359 PtrIrpContext
->Fcb
= Fcb
;
360 UDFPostRequest(PtrIrpContext
, NULL
);
363 if (!_SEH2_AbnormalTermination()) {
364 // If this is not async close complete the IRP
366 /* if( FileObject ) {
367 if(clean_stat & UDF_CLOSE_NTREQFCB_DELETED) {
368 // ASSERT(!FileObject->FsContext2);
369 FileObject->FsContext = NULL;
372 UDFNTRequiredFCB* NtReqFcb = ((UDFNTRequiredFCB*)(FileObject->FsContext));
373 if(NtReqFcb->FileObject == FileObject) {
374 NtReqFcb->FileObject = NULL;
379 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
380 Irp
->IoStatus
.Information
= 0;
381 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
383 // Free up the Irp Context
385 UDFReleaseIrpContext(PtrIrpContext
);
388 } _SEH2_END
; // end of "__finally" processing
390 return STATUS_SUCCESS
;
391 } // end UDFCommonClose()
394 This routine walks through the tree to RootDir & kills all unreferenced
401 IN PUDF_FILE_INFO fi
,
403 IN BOOLEAN VcbAcquired
406 PtrUDFFCB Fcb
= NULL
;
407 PtrUDFFCB ParentFcb
= NULL
;
408 PUDF_FILE_INFO ParentFI
;
409 UDFNTRequiredFCB
* NtReqFcb
;
411 LONG RefCount
, ComRefCount
;
412 BOOLEAN Delete
= FALSE
;
415 ValidateFileInfo(fi
);
416 AdPrint(("UDFCleanUpFcbChain\n"));
420 // we can't process Tree until we can acquire Vcb
422 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
424 // cleanup parent chain (if any & unused)
428 if(ParentFI
= fi
->ParentFile
) {
430 ParentFcb
= fi
->Fcb
->ParentFcb
;
432 ASSERT(ParentFcb
->NTRequiredFCB
);
433 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
434 UDFAcquireResourceExclusive(&(ParentFcb
->NTRequiredFCB
->MainResource
),TRUE
);
436 // we get to RootDir, it has no parent
438 UDFAcquireResourceShared(&(Vcb
->VCBResource
),TRUE
);
441 ASSERT(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_FCB
);
443 NtReqFcb
= Fcb
->NTRequiredFCB
;
444 ASSERT(NtReqFcb
->CommonFCBHeader
.NodeTypeCode
== UDF_NODE_TYPE_NT_REQ_FCB
);
446 // acquire current file/dir
447 // we must assure that no more threads try to re-use this object
451 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
452 UDFAcquireResourceExclusive(&(NtReqFcb
->MainResource
),TRUE
);
454 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
457 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
458 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
461 UDFReleaseResource(&(Vcb
->VCBResource
));
466 ASSERT_REF((Fcb
->ReferenceCount
> fi
->RefCount
) || !TreeLength
);
467 // If we haven't pass through all files opened
468 // in UDFCommonCreate before target file (TreeLength specfies
469 // the number of such files) dereference them.
470 // Otherwise we'll just check if the file has no references.
474 ASSERT(Fcb
->ReferenceCount
);
475 ASSERT(NtReqFcb
->CommonRefCount
);
476 RefCount
= UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
477 ComRefCount
= UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
484 ASSERT(Fcb
->OpenHandleCount
<= Fcb
->ReferenceCount
);
487 RefCount
= UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
488 ComRefCount
= UDFInterlockedDecrement((PLONG
)&(NtReqFcb
->CommonRefCount
));
493 /* if(Fcb && Fcb->FCBName && Fcb->FCBName->ObjectName.Buffer) {
494 AdPrint((" %ws (%x)\n",
495 Fcb->FCBName->ObjectName.Buffer,Fcb->ReferenceCount));
497 AdPrint((" ??? (%x)\n",Fcb->ReferenceCount));
499 AdPrint((" ??? (??)\n"));
501 // ...and delete if it has gone
503 if(!RefCount
&& !Fcb
->OpenHandleCount
) {
504 // no more references... current file/dir MUST DIE!!!
505 BOOLEAN AutoInherited
= UDFIsAStreamDir(fi
) || UDFIsAStream(fi
);
507 if(Vcb
->VCBFlags
& UDF_VCB_FLAGS_RAW_DISK
) {
510 #ifndef UDF_READ_ONLY_BUILD
512 /* if(!(Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
513 // set file size to zero (for UdfInfo package)
514 // we should not do this for directories
515 UDFResizeFile__(Vcb, fi, 0);
517 UDFReferenceFile__(fi
);
518 ASSERT(Fcb
->ReferenceCount
< fi
->RefCount
);
519 UDFFlushFile__(Vcb
, fi
);
520 UDFUnlinkFile__(Vcb
, fi
, TRUE
);
521 UDFCloseFile__(Vcb
, fi
);
522 ASSERT(Fcb
->ReferenceCount
== fi
->RefCount
);
523 Fcb
->FCBFlags
|= UDF_FCB_DELETED
;
526 #endif //UDF_READ_ONLY_BUILD
527 if(!(Fcb
->FCBFlags
& UDF_FCB_DELETED
)) {
528 UDFFlushFile__(Vcb
, fi
);
532 #ifndef UDF_READ_ONLY_BUILD
533 // check if we should try to delete Parent for the next time
534 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_PARENT
)
536 #endif //UDF_READ_ONLY_BUILD
538 // remove references to OS-specific structures
539 // to let UDF_INFO release FI & Co
542 // CommonFcb is also completly dereferenced
544 fi
->Dloc
->CommonFcb
= NULL
;
547 if(CleanCode
= UDFCleanUpFile__(Vcb
, fi
)) {
548 // Check, if we can uninitialize & deallocate CommonFcb part
549 // kill some cross links
550 Fcb
->FileInfo
= NULL
;
551 // release allocated resources
552 if(CleanCode
& UDF_FREE_DLOC
) {
553 // Obviously, it is a good time & place to release
554 // CommonFcb structure
556 // NtReqFcb->NtReqFCBFlags &= ~UDF_NTREQ_FCB_VALID;
557 // Unitialize byte-range locks support structure
558 FsRtlUninitializeFileLock(&(NtReqFcb
->FileLock
));
560 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
561 UDFReleaseResource(&(NtReqFcb
->MainResource
));
562 if(NtReqFcb
->CommonFCBHeader
.Resource
) {
563 UDFDeleteResource(&(NtReqFcb
->MainResource
));
564 UDFDeleteResource(&(NtReqFcb
->PagingIoResource
));
566 NtReqFcb
->CommonFCBHeader
.Resource
=
567 NtReqFcb
->CommonFCBHeader
.PagingIoResource
= NULL
;
568 UDFDeassignAcl(NtReqFcb
, AutoInherited
);
569 KdPrint(("UDFReleaseNtReqFCB: %x\n", NtReqFcb
));
571 // NtReqFcb->FileObject->FsContext2 = NULL;
572 // ASSERT(NtReqFcb->FileObject);
573 /* if(NtReqFcb->FileObject) {
574 ASSERT(!NtReqFcb->FileObject->FsContext2);
575 NtReqFcb->FileObject->FsContext = NULL;
576 NtReqFcb->FileObject->SectionObjectPointer = NULL;
579 MyFreePool__(NtReqFcb
);
580 ret_val
|= UDF_CLOSE_NTREQFCB_DELETED
;
582 // we usually get here when the file has some opened links
583 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
584 UDFReleaseResource(&(NtReqFcb
->MainResource
));
586 // remove some references & free Fcb structure
587 Fcb
->NTRequiredFCB
= NULL
;
588 Fcb
->ParentFcb
= NULL
;
591 ret_val
|= UDF_CLOSE_FCB_DELETED
;
592 // get pointer to parent FCB
594 // free old parent's resource...
596 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
597 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
600 UDFReleaseResource(&(Vcb
->VCBResource
));
607 fi
->Dloc
->CommonFcb
= NtReqFcb
;
608 // free all acquired resources
609 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
610 UDFReleaseResource(&(NtReqFcb
->MainResource
));
613 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
614 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
617 UDFReleaseResource(&(Vcb
->VCBResource
));
619 // If we have dereferenced all parents 'associated'
620 // with input file & current file is still in use
621 // then it isn't worth walking down the tree
622 // 'cause in this case all the rest files are also used
625 // AdPrint(("Stop on referenced File/Dir\n"));
628 // we get to referenced file/dir. Stop search & release resource
629 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb
);
630 UDFReleaseResource(&(NtReqFcb
->MainResource
));
632 UDF_CHECK_PAGING_IO_RESOURCE(ParentFcb
->NTRequiredFCB
);
633 UDFReleaseResource(&(ParentFcb
->NTRequiredFCB
->MainResource
));
636 UDFReleaseResource(&(Vcb
->VCBResource
));
646 for(;TreeLength
&& fi
;TreeLength
--) {
648 ParentFcb
= Fcb
->ParentFcb
;
649 ASSERT(Fcb
->ReferenceCount
);
650 ASSERT(Fcb
->NTRequiredFCB
->CommonRefCount
);
651 ASSERT_REF(Fcb
->ReferenceCount
> fi
->RefCount
);
652 UDFInterlockedDecrement((PLONG
)&(Fcb
->ReferenceCount
));
653 UDFInterlockedDecrement((PLONG
)&(Fcb
->NTRequiredFCB
->CommonRefCount
));
663 UDFReleaseResource(&(Vcb
->VCBResource
));
666 } // end UDFCleanUpFcbChain()
670 IN PtrUDFIrpContextLite NextIrpContextLite
673 PtrUDFIrpContext IrpContext
;
675 AdPrint((" UDFDoDelayedClose\n"));
676 UDFInitializeIrpContextFromLite(&IrpContext
,NextIrpContextLite
);
677 IrpContext
->Fcb
->IrpContextLite
= NULL
;
678 MyFreePool__(NextIrpContextLite
);
679 IrpContext
->Fcb
->FCBFlags
&= ~UDF_FCB_DELAY_CLOSE
;
680 UDFCommonClose(IrpContext
,NULL
);
681 } // end UDFDoDelayedClose()
684 This routine removes request from Delayed Close queue.
685 It operates until reach lower threshold
693 PtrUDFIrpContextLite NextIrpContextLite
;
695 AdPrint((" UDFDelayedClose\n"));
696 // Acquire DelayedCloseResource
697 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
699 while (UDFGlobalData
.ReduceDelayedClose
&&
700 (UDFGlobalData
.DelayedCloseCount
> UDFGlobalData
.MinDelayedCloseCount
)) {
702 Entry
= UDFGlobalData
.DelayedCloseQueue
.Flink
;
704 if (!IsListEmpty(Entry
)) {
705 // Extract the IrpContext.
706 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
710 RemoveEntryList( Entry
);
711 UDFGlobalData
.DelayedCloseCount
--;
712 UDFDoDelayedClose(NextIrpContextLite
);
718 while (UDFGlobalData
.ReduceDirDelayedClose
&&
719 (UDFGlobalData
.DirDelayedCloseCount
> UDFGlobalData
.MinDirDelayedCloseCount
)) {
721 Entry
= UDFGlobalData
.DirDelayedCloseQueue
.Flink
;
723 if (!IsListEmpty(Entry
)) {
724 // Extract the IrpContext.
725 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
729 RemoveEntryList( Entry
);
730 UDFGlobalData
.DirDelayedCloseCount
--;
731 UDFDoDelayedClose(NextIrpContextLite
);
737 UDFGlobalData
.FspCloseActive
= FALSE
;
738 UDFGlobalData
.ReduceDelayedClose
= FALSE
;
739 UDFGlobalData
.ReduceDirDelayedClose
= FALSE
;
741 // Release DelayedCloseResource
742 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
745 } // end UDFDelayedClose()
748 This routine performs Close operation for all files from
757 PtrUDFIrpContextLite NextIrpContextLite
;
758 BOOLEAN GlobalDataAcquired
= FALSE
;
760 AdPrint((" UDFCloseAllDelayed\n"));
761 // Acquire DelayedCloseResource
762 if (!ExIsResourceAcquiredExclusive(&UDFGlobalData
.GlobalDataResource
)) {
763 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
764 GlobalDataAcquired
= TRUE
;
767 Entry
= UDFGlobalData
.DelayedCloseQueue
.Flink
;
769 while (Entry
!= &UDFGlobalData
.DelayedCloseQueue
) {
770 // Extract the IrpContext.
771 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
774 Entry
= Entry
->Flink
;
775 if (NextIrpContextLite
->Fcb
->Vcb
== Vcb
) {
776 RemoveEntryList( &(NextIrpContextLite
->DelayedCloseLinks
) );
777 UDFGlobalData
.DelayedCloseCount
--;
778 UDFDoDelayedClose(NextIrpContextLite
);
782 Entry
= UDFGlobalData
.DirDelayedCloseQueue
.Flink
;
784 while (Entry
!= &UDFGlobalData
.DirDelayedCloseQueue
) {
785 // Extract the IrpContext.
786 NextIrpContextLite
= CONTAINING_RECORD( Entry
,
789 Entry
= Entry
->Flink
;
790 if (NextIrpContextLite
->Fcb
->Vcb
== Vcb
) {
791 RemoveEntryList( &(NextIrpContextLite
->DelayedCloseLinks
) );
792 UDFGlobalData
.DirDelayedCloseCount
--;
793 UDFDoDelayedClose(NextIrpContextLite
);
797 // Release DelayedCloseResource
798 if(GlobalDataAcquired
)
799 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
801 } // end UDFCloseAllDelayed()
804 UDFBuildTreeItemsList(
806 IN PUDF_FILE_INFO FileInfo
,
807 IN PCHECK_TREE_ITEM CheckItemProc
,
808 IN PUDF_FILE_INFO
** PassedList
,
809 IN PULONG PassedListSize
,
810 IN PUDF_FILE_INFO
** FoundList
,
811 IN PULONG FoundListSize
814 PDIR_INDEX_HDR hDirNdx
;
815 PUDF_FILE_INFO SDirInfo
;
818 KdPrint((" UDFBuildTreeItemsList():\n"));
819 if(!(*PassedList
) || !(*FoundList
)) {
821 (*PassedList
) = (PUDF_FILE_INFO
*)
822 MyAllocatePool__(NonPagedPool
, sizeof(PUDF_FILE_INFO
)*TREE_ITEM_LIST_GRAN
);
824 return STATUS_INSUFFICIENT_RESOURCES
;
825 (*PassedListSize
) = 0;
827 (*FoundList
) = (PUDF_FILE_INFO
*)
828 MyAllocatePool__(NonPagedPool
, sizeof(PUDF_FILE_INFO
)*TREE_ITEM_LIST_GRAN
);
830 MyFreePool__(*PassedList
);
832 return STATUS_INSUFFICIENT_RESOURCES
;
834 (*FoundListSize
) = 0;
837 // check if already passed
838 for(i
=0;i
<(*PassedListSize
);i
++) {
839 if( ((*PassedList
)[i
]) == FileInfo
)
840 return STATUS_SUCCESS
;
842 // remember passed object
843 // we should not proceed linked objects twice
845 if( !((*PassedListSize
) & (TREE_ITEM_LIST_GRAN
- 1)) ) {
846 if(!MyReallocPool__((PCHAR
)(*PassedList
), (*PassedListSize
)*sizeof(PUDF_FILE_INFO
),
847 (PCHAR
*)PassedList
, ((*PassedListSize
)+TREE_ITEM_LIST_GRAN
)*sizeof(PUDF_FILE_INFO
))) {
848 return STATUS_INSUFFICIENT_RESOURCES
;
851 (*PassedList
)[(*PassedListSize
)-1] = FileInfo
;
853 // check if this object matches our conditions
854 if(CheckItemProc(FileInfo
)) {
855 // remember matched object
857 if( !((*FoundListSize
) & (TREE_ITEM_LIST_GRAN
- 1)) ) {
858 if(!MyReallocPool__((PCHAR
)(*FoundList
), (*FoundListSize
)*sizeof(PUDF_DATALOC_INFO
),
859 (PCHAR
*)FoundList
, ((*FoundListSize
)+TREE_ITEM_LIST_GRAN
)*sizeof(PUDF_DATALOC_INFO
))) {
860 return STATUS_INSUFFICIENT_RESOURCES
;
863 (*FoundList
)[(*FoundListSize
)-1] = FileInfo
;
866 // walk through SDir (if any)
867 if(SDirInfo
= FileInfo
->Dloc
->SDirInfo
)
868 UDFBuildTreeItemsList(Vcb
, SDirInfo
, CheckItemProc
,
869 PassedList
, PassedListSize
, FoundList
, FoundListSize
);
871 // walk through subsequent objects (if any)
872 if(hDirNdx
= FileInfo
->Dloc
->DirIndex
) {
875 UDF_DIR_SCAN_CONTEXT ScanContext
;
876 PDIR_INDEX_ITEM DirNdx
;
877 PUDF_FILE_INFO CurFileInfo
;
879 if(UDFDirIndexInitScan(FileInfo
, &ScanContext
, 2)) {
880 while(DirNdx
= UDFDirIndexScan(&ScanContext
, &CurFileInfo
)) {
883 UDFBuildTreeItemsList(Vcb
, CurFileInfo
, CheckItemProc
,
884 PassedList
, PassedListSize
, FoundList
, FoundListSize
);
889 return STATUS_SUCCESS
;
890 } // end UDFBuildTreeItemsList()
893 UDFIsInDelayedCloseQueue(
894 PUDF_FILE_INFO FileInfo
)
897 return (FileInfo
->Fcb
&& FileInfo
->Fcb
->IrpContextLite
);
898 } // end UDFIsInDelayedCloseQueue()
902 PUDF_FILE_INFO FileInfo
)
905 PtrUDFFCB Fcb
= FileInfo
->Fcb
;
907 !Fcb
->OpenHandleCount
&&
908 Fcb
->ReferenceCount
&&
909 Fcb
->NTRequiredFCB
->SectionObject
.DataSectionObject
) {
913 } // UDFIsLastClose()
916 UDFCloseAllXXXDelayedInDir(
918 IN PUDF_FILE_INFO FileInfo
,
922 PUDF_FILE_INFO
* PassedList
= NULL
;
923 ULONG PassedListSize
= 0;
924 PUDF_FILE_INFO
* FoundList
= NULL
;
925 ULONG FoundListSize
= 0;
928 BOOLEAN ResAcq
= FALSE
;
929 BOOLEAN AcquiredVcb
= FALSE
;
930 UDFNTRequiredFCB
* NtReqFcb
;
931 PUDF_FILE_INFO CurFileInfo
;
932 PFE_LIST_ENTRY CurListPtr
;
933 PFE_LIST_ENTRY
* ListPtrArray
= NULL
;
937 KdPrint((" UDFCloseAllXXXDelayedInDir(): Acquire DelayedCloseResource\n"));
938 // Acquire DelayedCloseResource
939 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
942 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
945 RC
= UDFBuildTreeItemsList(Vcb
, FileInfo
,
946 System
? UDFIsLastClose
: UDFIsInDelayedCloseQueue
,
947 &PassedList
, &PassedListSize
, &FoundList
, &FoundListSize
);
949 if(!NT_SUCCESS(RC
)) {
950 KdPrint((" UDFBuildTreeItemsList(): error %x\n", RC
));
954 if(!FoundList
|| !FoundListSize
) {
955 try_return(RC
= STATUS_SUCCESS
);
958 // build array of referenced pointers
959 ListPtrArray
= (PFE_LIST_ENTRY
*)(MyAllocatePool__(NonPagedPool
, FoundListSize
*sizeof(PFE_LIST_ENTRY
)));
961 KdPrint((" Can't alloc ListPtrArray for %x items\n", FoundListSize
));
962 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
965 for(i
=0;i
<FoundListSize
;i
++) {
969 CurFileInfo
= FoundList
[i
];
970 if(!CurFileInfo
->ListPtr
) {
971 CurFileInfo
->ListPtr
= (PFE_LIST_ENTRY
)(MyAllocatePool__(NonPagedPool
, sizeof(FE_LIST_ENTRY
)));
972 if(!CurFileInfo
->ListPtr
) {
973 KdPrint((" Can't alloc ListPtrEntry for items %x\n", i
));
974 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
976 CurFileInfo
->ListPtr
->FileInfo
= CurFileInfo
;
977 CurFileInfo
->ListPtr
->EntryRefCount
= 0;
979 CurFileInfo
->ListPtr
->EntryRefCount
++;
980 ListPtrArray
[i
] = CurFileInfo
->ListPtr
;
982 } _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER
) {
987 UDFReleaseResource(&(Vcb
->VCBResource
));
991 // Remove from system queue
993 IO_STATUS_BLOCK IoStatus
;
994 BOOLEAN NoDelayed
= (Vcb
->VCBFlags
& UDF_VCB_FLAGS_NO_DELAYED_CLOSE
) ?
997 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_NO_DELAYED_CLOSE
;
998 for(i
=FoundListSize
;i
>0;i
--) {
999 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
1003 CurListPtr
= ListPtrArray
[i
-1];
1004 CurFileInfo
= CurListPtr
->FileInfo
;
1006 (Fcb
= CurFileInfo
->Fcb
)) {
1007 NtReqFcb
= Fcb
->NTRequiredFCB
;
1008 ASSERT((ULONG
)NtReqFcb
> 0x1000);
1009 // ASSERT((ULONG)(NtReqFcb->SectionObject) > 0x1000);
1010 if(!(NtReqFcb
->NtReqFCBFlags
& UDF_NTREQ_FCB_DELETED
) &&
1011 (NtReqFcb
->NtReqFCBFlags
& UDF_NTREQ_FCB_MODIFIED
)) {
1012 MmPrint((" CcFlushCache()\n"));
1013 CcFlushCache(&(NtReqFcb
->SectionObject
), NULL
, 0, &IoStatus
);
1015 if(NtReqFcb
->SectionObject
.ImageSectionObject
) {
1016 MmPrint((" MmFlushImageSection()\n"));
1017 MmFlushImageSection(&(NtReqFcb
->SectionObject
), MmFlushForWrite
);
1019 if(NtReqFcb
->SectionObject
.DataSectionObject
) {
1020 MmPrint((" CcPurgeCacheSection()\n"));
1021 CcPurgeCacheSection( &(NtReqFcb
->SectionObject
), NULL
, 0, FALSE
);
1024 MmPrint((" Skip item: deleted\n"));
1026 CurListPtr
->EntryRefCount
--;
1027 if(!CurListPtr
->EntryRefCount
) {
1028 if(CurListPtr
->FileInfo
)
1029 CurListPtr
->FileInfo
->ListPtr
= NULL
;
1030 MyFreePool__(CurListPtr
);
1032 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
1035 UDFReleaseResource(&(Vcb
->VCBResource
));
1036 AcquiredVcb
= FALSE
;
1039 Vcb
->VCBFlags
&= ~UDF_VCB_FLAGS_NO_DELAYED_CLOSE
;
1041 // Remove from internal queue
1042 PtrUDFIrpContextLite NextIrpContextLite
;
1044 for(i
=FoundListSize
;i
>0;i
--) {
1046 UDFAcquireResourceExclusive(&(Vcb
->VCBResource
), TRUE
);
1049 CurListPtr
= ListPtrArray
[i
-1];
1050 CurFileInfo
= CurListPtr
->FileInfo
;
1054 (NextIrpContextLite
= CurFileInfo
->Fcb
->IrpContextLite
)) {
1055 RemoveEntryList( &(NextIrpContextLite
->DelayedCloseLinks
) );
1056 if (NextIrpContextLite
->Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
1058 UDFGlobalData
.DirDelayedCloseCount
--;
1060 UDFGlobalData
.DelayedCloseCount
--;
1062 UDFDoDelayedClose(NextIrpContextLite
);
1064 CurListPtr
->EntryRefCount
--;
1065 if(!CurListPtr
->EntryRefCount
) {
1066 if(CurListPtr
->FileInfo
)
1067 CurListPtr
->FileInfo
->ListPtr
= NULL
;
1068 MyFreePool__(CurListPtr
);
1070 UDFReleaseResource(&(Vcb
->VCBResource
));
1071 AcquiredVcb
= FALSE
;
1074 RC
= STATUS_SUCCESS
;
1081 UDFReleaseResource(&(Vcb
->VCBResource
));
1082 // Release DelayedCloseResource
1084 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
1087 MyFreePool__(ListPtrArray
);
1089 MyFreePool__(PassedList
);
1091 MyFreePool__(FoundList
);
1095 } // end UDFCloseAllXXXDelayedInDir(
1099 This routine adds request to Delayed Close queue.
1100 If number of queued requests exceeds higher threshold it fires
1104 UDFQueueDelayedClose(
1105 PtrUDFIrpContext IrpContext
,
1109 PtrUDFIrpContextLite IrpContextLite
;
1110 BOOLEAN StartWorker
= FALSE
;
1111 BOOLEAN AcquiredVcb
= FALSE
;
1114 AdPrint((" UDFQueueDelayedClose\n"));
1117 // Acquire DelayedCloseResource
1118 UDFAcquireResourceExclusive(&(UDFGlobalData
.DelayedCloseResource
), TRUE
);
1120 UDFAcquireResourceShared(&(Fcb
->Vcb
->VCBResource
), TRUE
);
1123 if(Fcb
->FCBFlags
& UDF_FCB_DELETE_ON_CLOSE
) {
1124 try_return(RC
= STATUS_DELETE_PENDING
);
1127 if(Fcb
->IrpContextLite
||
1128 Fcb
->FCBFlags
& UDF_FCB_POSTED_RENAME
) {
1130 try_return(RC
= STATUS_UNSUCCESSFUL
);
1133 if(!NT_SUCCESS(RC
= UDFInitializeIrpContextLite(&IrpContextLite
,IrpContext
,Fcb
))) {
1137 if(Fcb
->FCBFlags
& UDF_FCB_DIRECTORY
) {
1138 InsertTailList( &UDFGlobalData
.DirDelayedCloseQueue
,
1139 &IrpContextLite
->DelayedCloseLinks
);
1140 UDFGlobalData
.DirDelayedCloseCount
++;
1142 InsertTailList( &UDFGlobalData
.DelayedCloseQueue
,
1143 &IrpContextLite
->DelayedCloseLinks
);
1144 UDFGlobalData
.DelayedCloseCount
++;
1146 Fcb
->IrpContextLite
= IrpContextLite
;
1148 // If we are above our threshold then start the delayed
1150 if(UDFGlobalData
.DelayedCloseCount
> UDFGlobalData
.MaxDelayedCloseCount
) {
1152 UDFGlobalData
.ReduceDelayedClose
= TRUE
;
1154 if(!UDFGlobalData
.FspCloseActive
) {
1156 UDFGlobalData
.FspCloseActive
= TRUE
;
1160 // If we are above our threshold then start the delayed
1162 if(UDFGlobalData
.DirDelayedCloseCount
> UDFGlobalData
.MaxDirDelayedCloseCount
) {
1164 UDFGlobalData
.ReduceDirDelayedClose
= TRUE
;
1166 if(!UDFGlobalData
.FspCloseActive
) {
1168 UDFGlobalData
.FspCloseActive
= TRUE
;
1172 // Start the FspClose thread if we need to.
1174 ExQueueWorkItem( &UDFGlobalData
.CloseItem
, CriticalWorkQueue
);
1176 RC
= STATUS_SUCCESS
;
1182 if(!NT_SUCCESS(RC
)) {
1183 Fcb
->FCBFlags
&= ~UDF_FCB_DELAY_CLOSE
;
1186 UDFReleaseResource(&(Fcb
->Vcb
->VCBResource
));
1188 // Release DelayedCloseResource
1189 UDFReleaseResource(&(UDFGlobalData
.DelayedCloseResource
));
1192 } // end UDFQueueDelayedClose()