3 Copyright (c) 1990-2000 Microsoft Corporation
11 This module implements the cache management routines for the Cdfs
12 FSD and FSP, by calling the Common Cache Manager.
20 // The Bug check file id for this module
23 #define BugCheckFileId (CDFS_BUG_CHECK_CACHESUP)
26 // Local debug trace level
30 #pragma alloc_text(PAGE, CdCompleteMdl)
31 #pragma alloc_text(PAGE, CdCreateInternalStream)
32 #pragma alloc_text(PAGE, CdDeleteInternalStream)
33 #pragma alloc_text(PAGE, CdPurgeVolume)
38 CdCreateInternalStream (
39 _In_ PIRP_CONTEXT IrpContext
,
42 _In_ PUNICODE_STRING Name
49 This function creates an internal stream file for interaction
50 with the cache manager. The Fcb here can be for either a
51 directory stream or for a path table stream.
55 Vcb - Vcb for this volume.
57 Fcb - Points to the Fcb for this file. It is either an Index or
67 PFILE_OBJECT StreamFile
= NULL
;
68 BOOLEAN DecrementReference
= FALSE
;
70 BOOLEAN CleanupDirContext
= FALSE
;
71 BOOLEAN UpdateFcbSizes
= FALSE
;
74 DIRENT_ENUM_CONTEXT DirContext
= {0};
78 ASSERT_IRP_CONTEXT( IrpContext
);
82 // We may only have the Fcb shared. Lock the Fcb and do a
83 // safe test to see if we need to really create the file object.
86 CdLockFcb( IrpContext
, Fcb
);
88 if (Fcb
->FileObject
!= NULL
) {
90 CdUnlockFcb( IrpContext
, Fcb
);
95 // Use a try-finally to facilitate cleanup.
101 // Create the internal stream. The Vpb should be pointing at our volume
102 // device object at this point.
105 StreamFile
= IoCreateStreamFileObjectLite( NULL
, Vcb
->Vpb
->RealDevice
);
107 if (StreamFile
== NULL
) {
109 CdRaiseStatus( IrpContext
, STATUS_INSUFFICIENT_RESOURCES
);
113 // Initialize the fields of the file object.
116 StreamFile
->ReadAccess
= TRUE
;
117 StreamFile
->WriteAccess
= FALSE
;
118 StreamFile
->DeleteAccess
= FALSE
;
120 StreamFile
->SectionObjectPointer
= &Fcb
->FcbNonpaged
->SegmentObject
;
123 // Set the file object type and increment the Vcb counts.
126 CdSetFileObject( IrpContext
,
133 // We'll give stream file objects a name to aid IO profiling etc. We
134 // NULL this in CdDeleteInternalStream before OB deletes the file object,
135 // and before CdRemovePrefix is called (which frees Fcb names).
138 StreamFile
->FileName
= *Name
;
141 // We will reference the current Fcb twice to keep it from going
142 // away in the error path. Otherwise if we dereference it
143 // below in the finally clause a close could cause the Fcb to
147 CdLockVcb( IrpContext
, Vcb
);
148 CdIncrementReferenceCounts( IrpContext
, Fcb
, 2, 0 );
149 CdUnlockVcb( IrpContext
, Vcb
);
150 DecrementReference
= TRUE
;
153 // Initialize the cache map for the file.
156 CcInitializeCacheMap( StreamFile
,
157 (PCC_FILE_SIZES
)&Fcb
->AllocationSize
,
159 &CdData
.CacheManagerCallbacks
,
163 // Go ahead and store the stream file into the Fcb.
166 Fcb
->FileObject
= StreamFile
;
170 // If this is the first file object for a directory then we need to
171 // read the self entry for this directory and update the sizes
172 // in the Fcb. We know that the Fcb has been initialized so
173 // that we have a least one sector available to read.
176 if (!FlagOn( Fcb
->FcbState
, FCB_STATE_INITIALIZED
)) {
181 // Initialize the search structures.
184 CdInitializeDirContext( IrpContext
, &DirContext
);
185 CdInitializeDirent( IrpContext
, &Dirent
);
186 CleanupDirContext
= TRUE
;
189 // Read the dirent from disk and transfer the data to the
193 CdLookupDirent( IrpContext
,
198 CdUpdateDirentFromRawDirent( IrpContext
, Fcb
, &DirContext
, &Dirent
);
201 // Verify that this really for the self entry. We do this by
202 // updating the name in the dirent and then checking that it matches
203 // one of the hard coded names.
206 CdUpdateDirentName( IrpContext
, &Dirent
, FALSE
);
208 if (Dirent
.CdFileName
.FileName
.Buffer
!= CdUnicodeSelfArray
) {
210 CdRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
214 // If the data sizes are different then update the header
215 // and Mcb for this Fcb.
218 NewDataLength
= BlockAlign( Vcb
, Dirent
.DataLength
+ Fcb
->StreamOffset
);
220 if (NewDataLength
== 0) {
222 CdRaiseStatus( IrpContext
, STATUS_FILE_CORRUPT_ERROR
);
225 if (NewDataLength
!= Fcb
->FileSize
.QuadPart
) {
227 Fcb
->AllocationSize
.QuadPart
=
228 Fcb
->FileSize
.QuadPart
=
229 Fcb
->ValidDataLength
.QuadPart
= NewDataLength
;
231 CcSetFileSizes( Fcb
->FileObject
, (PCC_FILE_SIZES
) &Fcb
->AllocationSize
);
233 CdTruncateAllocation( IrpContext
, Fcb
, 0 );
234 CdAddInitialAllocation( IrpContext
,
236 Dirent
.StartingOffset
,
239 UpdateFcbSizes
= TRUE
;
243 // Check for the existence flag and transform to hidden.
246 if (FlagOn( Dirent
.DirentFlags
, CD_ATTRIBUTE_HIDDEN
)) {
248 SetFlag( Fcb
->FileAttributes
, FILE_ATTRIBUTE_HIDDEN
);
252 // Convert the time to NT time.
255 CdConvertCdTimeToNtTime( IrpContext
,
257 (PLARGE_INTEGER
) &Fcb
->CreationTime
);
260 // Update the Fcb flags to indicate we have read the
264 SetFlag( Fcb
->FcbState
, FCB_STATE_INITIALIZED
);
267 // If we updated the sizes then we want to purge the file. Go
268 // ahead and unpin and then purge the first page.
271 CdCleanupDirContext( IrpContext
, &DirContext
);
272 CdCleanupDirent( IrpContext
, &Dirent
);
273 CleanupDirContext
= FALSE
;
275 if (UpdateFcbSizes
) {
277 CcPurgeCacheSection( &Fcb
->FcbNonpaged
->SegmentObject
,
287 // Cleanup any dirent structures we may have used.
290 if (CleanupDirContext
) {
292 CdCleanupDirContext( IrpContext
, &DirContext
);
293 CdCleanupDirent( IrpContext
, &Dirent
);
297 // If we raised then we need to dereference the file object.
300 if (StreamFile
!= NULL
) {
303 // Null the name pointer, since the stream file object never actually
304 // 'owns' the names, we just point it to existing ones.
307 StreamFile
->FileName
.Buffer
= NULL
;
308 StreamFile
->FileName
.MaximumLength
= StreamFile
->FileName
.Length
= 0;
310 ObDereferenceObject( StreamFile
);
311 Fcb
->FileObject
= NULL
;
315 // Dereference and unlock the Fcb.
318 if (DecrementReference
) {
320 CdLockVcb( IrpContext
, Vcb
);
321 CdDecrementReferenceCounts( IrpContext
, Fcb
, 1, 0 );
322 CdUnlockVcb( IrpContext
, Vcb
);
325 CdUnlockFcb( IrpContext
, Fcb
);
333 CdDeleteInternalStream (
334 _In_ PIRP_CONTEXT IrpContext
,
342 This function creates an internal stream file for interaction
343 with the cache manager. The Fcb here can be for either a
344 directory stream or for a path table stream.
348 Fcb - Points to the Fcb for this file. It is either an Index or
358 PFILE_OBJECT FileObject
;
362 UNREFERENCED_PARAMETER( IrpContext
);
364 ASSERT_IRP_CONTEXT( IrpContext
);
371 CdLockFcb( IrpContext
, Fcb
);
374 // Capture the file object.
377 FileObject
= Fcb
->FileObject
;
378 Fcb
->FileObject
= NULL
;
381 // It is now safe to unlock the Fcb.
384 CdUnlockFcb( IrpContext
, Fcb
);
387 // Dereference the file object if present.
390 if (FileObject
!= NULL
) {
392 if (FileObject
->PrivateCacheMap
!= NULL
) {
394 CcUninitializeCacheMap( FileObject
, NULL
, NULL
);
398 // Null the name pointer, since the stream file object never actually
399 // 'owns' the names, we just point it to existing ones.
402 FileObject
->FileName
.Buffer
= NULL
;
403 FileObject
->FileName
.MaximumLength
= FileObject
->FileName
.Length
= 0;
405 ObDereferenceObject( FileObject
);
412 _In_ PIRP_CONTEXT IrpContext
,
420 This routine performs the function of completing Mdl reads.
421 It should be called only from CdFsdRead.
425 Irp - Supplies the originating Irp.
429 NTSTATUS - Will always be STATUS_SUCCESS.
434 PFILE_OBJECT FileObject
;
439 // Do completion processing.
442 FileObject
= IoGetCurrentIrpStackLocation( Irp
)->FileObject
;
444 CcMdlReadComplete( FileObject
, Irp
->MdlAddress
);
447 // Mdl is now deallocated.
450 Irp
->MdlAddress
= NULL
;
453 // Complete the request and exit right away.
456 CdCompleteRequest( IrpContext
, Irp
, STATUS_SUCCESS
);
458 return STATUS_SUCCESS
;
463 _Requires_lock_held_(_Global_critical_region_
)
466 _In_ PIRP_CONTEXT IrpContext
,
468 _In_ BOOLEAN DismountUnderway
475 This routine is called to purge the volume. The purpose is to make all the stale file
476 objects in the system go away in order to lock the volume.
478 The Vcb is already acquired exclusively. We will lock out all file operations by
479 acquiring the global file resource. Then we will walk through all of the Fcb's and
484 Vcb - Vcb for the volume to purge.
486 DismountUnderway - Indicates that we are trying to delete all of the objects.
487 We will purge the Path Table and VolumeDasd and dereference all
492 NTSTATUS - The first failure of the purge operation.
497 NTSTATUS Status
= STATUS_SUCCESS
;
499 PVOID RestartKey
= NULL
;
507 ASSERT_EXCLUSIVE_VCB( Vcb
);
510 // Force any remaining Fcb's in the delayed close queue to be closed.
516 // Acquire the global file resource.
519 CdAcquireAllFiles( IrpContext
, Vcb
);
522 // Loop through each Fcb in the Fcb Table and perform the flush.
528 // Lock the Vcb to lookup the next Fcb.
531 CdLockVcb( IrpContext
, Vcb
);
532 NextFcb
= CdGetNextFcb( IrpContext
, Vcb
, &RestartKey
);
535 // Reference the NextFcb if present.
538 if (NextFcb
!= NULL
) {
540 NextFcb
->FcbReference
+= 1;
544 // If the last Fcb is present then decrement reference count and call teardown
545 // to see if it should be removed.
548 if (ThisFcb
!= NULL
) {
550 ThisFcb
->FcbReference
-= 1;
552 CdUnlockVcb( IrpContext
, Vcb
);
554 CdTeardownStructures( IrpContext
, ThisFcb
, &RemovedFcb
);
558 CdUnlockVcb( IrpContext
, Vcb
);
562 // Break out of the loop if no more Fcb's.
565 if (NextFcb
== NULL
) {
571 // Move to the next Fcb.
577 // If there is a image section then see if that can be closed.
580 if (ThisFcb
->FcbNonpaged
->SegmentObject
.ImageSectionObject
!= NULL
) {
582 MmFlushImageSection( &ThisFcb
->FcbNonpaged
->SegmentObject
, MmFlushForWrite
);
586 // If there is a data section then purge this. If there is an image
587 // section then we won't be able to. Remember this if it is our first
591 if ((ThisFcb
->FcbNonpaged
->SegmentObject
.DataSectionObject
!= NULL
) &&
592 !CcPurgeCacheSection( &ThisFcb
->FcbNonpaged
->SegmentObject
,
596 (Status
== STATUS_SUCCESS
)) {
598 Status
= STATUS_UNABLE_TO_DELETE_SECTION
;
602 // Dereference the internal stream if dismounting.
605 if (DismountUnderway
&&
606 (SafeNodeType( ThisFcb
) != CDFS_NTC_FCB_DATA
) &&
607 (ThisFcb
->FileObject
!= NULL
)) {
609 CdDeleteInternalStream( IrpContext
, ThisFcb
);
614 // Now look at the path table and volume Dasd Fcb's.
617 if (DismountUnderway
) {
619 if (Vcb
->PathTableFcb
!= NULL
) {
621 ThisFcb
= Vcb
->PathTableFcb
;
622 InterlockedIncrement( (LONG
*)&Vcb
->PathTableFcb
->FcbReference
);
624 if ((ThisFcb
->FcbNonpaged
->SegmentObject
.DataSectionObject
!= NULL
) &&
625 !CcPurgeCacheSection( &ThisFcb
->FcbNonpaged
->SegmentObject
,
629 (Status
== STATUS_SUCCESS
)) {
631 Status
= STATUS_UNABLE_TO_DELETE_SECTION
;
634 CdDeleteInternalStream( IrpContext
, ThisFcb
);
636 InterlockedDecrement( (LONG
*)&ThisFcb
->FcbReference
);
638 CdTeardownStructures( IrpContext
, ThisFcb
, &RemovedFcb
);
641 if (Vcb
->VolumeDasdFcb
!= NULL
) {
643 ThisFcb
= Vcb
->VolumeDasdFcb
;
644 InterlockedIncrement( (LONG
*)&ThisFcb
->FcbReference
);
646 if ((ThisFcb
->FcbNonpaged
->SegmentObject
.DataSectionObject
!= NULL
) &&
647 !CcPurgeCacheSection( &ThisFcb
->FcbNonpaged
->SegmentObject
,
651 (Status
== STATUS_SUCCESS
)) {
653 Status
= STATUS_UNABLE_TO_DELETE_SECTION
;
656 InterlockedDecrement( (LONG
*)&ThisFcb
->FcbReference
);
658 CdTeardownStructures( IrpContext
, ThisFcb
, &RemovedFcb
);
663 // Release all of the files.
666 CdReleaseAllFiles( IrpContext
, Vcb
);