📄 flush.c
字号:
return Status;
}
NTSTATUS
FatFlushDirectory (
IN PIRP_CONTEXT IrpContext,
IN PDCB Dcb,
IN FAT_FLUSH_TYPE FlushType
)
/*++
Routine Description:
This routine non-recursively flushes a dcb tree.
Arguments:
Dcb - Supplies the Dcb being flushed
FlushType - Specifies the kind of flushing to perform
Return Value:
VOID
--*/
{
PFCB Fcb;
PVCB Vcb;
PFCB NextFcb;
PDIRENT Dirent;
PBCB DirentBcb = NULL;
NTSTATUS Status;
NTSTATUS ReturnStatus = STATUS_SUCCESS;
BOOLEAN ClearWriteThroughOnExit = FALSE;
BOOLEAN ClearWaitOnExit = FALSE;
PAGED_CODE();
ASSERT( FatVcbAcquiredExclusive(IrpContext, Dcb->Vcb) );
DebugTrace(+1, Dbg, "FatFlushDirectory, Dcb = %08lx\n", Dcb);
//
// First flush all the files, then the directories, to make sure all the
// file sizes and times get sets correctly on disk.
//
// We also have to check here if the "Ea Data. Sf" fcb really
// corressponds to an existing file.
//
if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH)) {
ClearWriteThroughOnExit = TRUE;
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
}
if (!FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)) {
ClearWaitOnExit = TRUE;
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
}
Vcb = Dcb->Vcb;
Fcb = Dcb;
while (Fcb != NULL) {
NextFcb = FatGetNextFcbTopDown(IrpContext, Fcb, Dcb);
if ( (NodeType( Fcb ) == FAT_NTC_FCB) &&
(Vcb->EaFcb != Fcb) &&
!IsFileDeleted(IrpContext, Fcb)) {
(VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
//
// Exception handler to catch and commute errors encountered
// doing the flush dance. We may encounter corruption, and
// should continue flushing the volume as much as possible.
//
try {
//
// Standard handler to release resources, etc.
//
try {
//
// Make sure the Fcb is OK.
//
try {
FatVerifyFcb( IrpContext, Fcb );
} except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
FatResetExceptionState( IrpContext );
}
//
// If this Fcb is not good skip it. Note that a 'continue'
// here would be very expensive as we inside a try{} body.
//
if (Fcb->FcbCondition != FcbGood) {
try_leave( NOTHING);
}
//
// In case a handle was never closed and the FS and AS are more
// than a cluster different, do this truncate.
//
if ( FlagOn(Fcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE) ) {
FatTruncateFileAllocation( IrpContext,
Fcb,
Fcb->Header.FileSize.LowPart );
}
//
// Also compare the file's dirent in the parent directory
// with the size information in the Fcb and update
// it if neccessary. Note that we don't mark the Bcb dirty
// because we will be flushing the file object presently, and
// Mm knows what's really dirty.
//
FatGetDirentFromFcbOrDcb( IrpContext,
Fcb,
FALSE,
&Dirent,
&DirentBcb );
if (Dirent->FileSize != Fcb->Header.FileSize.LowPart) {
Dirent->FileSize = Fcb->Header.FileSize.LowPart;
}
//
// We must unpin the Bcb before the flush since we recursively tear up
// the tree if Mm decides that the data section is no longer referenced
// and the final close comes in for this file. If this parent has no
// more children as a result, we will try to initiate teardown on it
// and Cc will deadlock against the active count of this Bcb.
//
FatUnpinBcb( IrpContext, DirentBcb );
//
// Now flush the file. Note that this may make the Fcb
// go away if Mm dereferences its file object.
//
Status = FatFlushFile( IrpContext, Fcb, FlushType );
if (!NT_SUCCESS(Status)) {
ReturnStatus = Status;
}
} finally {
FatUnpinBcb( IrpContext, DirentBcb );
//
// Since we have the Vcb exclusive we know that if any closes
// come in it is because the CcPurgeCacheSection caused the
// Fcb to go away.
//
if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB) ) {
FatReleaseFcb( (IRPCONTEXT), Fcb );
}
}
} except( (ReturnStatus = FsRtlIsNtstatusExpected(GetExceptionCode())) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
FatResetExceptionState( IrpContext );
}
}
Fcb = NextFcb;
}
//
// OK, now flush the directories.
//
Fcb = Dcb;
while (Fcb != NULL) {
NextFcb = FatGetNextFcbTopDown(IrpContext, Fcb, Dcb);
if ( (NodeType( Fcb ) != FAT_NTC_FCB) &&
!IsFileDeleted(IrpContext, Fcb) ) {
//
// Make sure the Fcb is OK.
//
try {
FatVerifyFcb( IrpContext, Fcb );
} except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
FatResetExceptionState( IrpContext );
}
if (Fcb->FcbCondition == FcbGood) {
Status = FatFlushFile( IrpContext, Fcb, FlushType );
if (!NT_SUCCESS(Status)) {
ReturnStatus = Status;
}
}
}
Fcb = NextFcb;
}
try {
FatUnpinRepinnedBcbs( IrpContext );
} except(FatExceptionFilter( IrpContext, GetExceptionInformation() )) {
ReturnStatus = IrpContext->ExceptionStatus;
}
if (ClearWriteThroughOnExit) {
ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
}
if (ClearWaitOnExit) {
ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
}
DebugTrace(-1, Dbg, "FatFlushDirectory -> 0x%08lx\n", ReturnStatus);
return ReturnStatus;
}
NTSTATUS
FatFlushFat (
IN PIRP_CONTEXT IrpContext,
IN PVCB Vcb
)
/*++
Routine Description:
The function carefully flushes the entire FAT for a volume. It is
nessecary to dance around a bit because of complicated synchronization
reasons.
Arguments:
Vcb - Supplies the Vcb whose FAT is being flushed
Return Value:
VOID
--*/
{
PBCB Bcb;
PVOID DontCare;
IO_STATUS_BLOCK Iosb;
LARGE_INTEGER Offset;
NTSTATUS ReturnStatus = STATUS_SUCCESS;
PAGED_CODE();
//
// If this volume is write protected, no need to flush.
//
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
return STATUS_SUCCESS;
}
//
// Make sure the Vcb is OK.
//
try {
FatVerifyVcb( IrpContext, Vcb );
} except( FsRtlIsNtstatusExpected(GetExceptionCode()) ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
FatResetExceptionState( IrpContext );
}
if (Vcb->VcbCondition != VcbGood) {
return STATUS_FILE_INVALID;
}
//
// The only way we have to correctly synchronize things is to
// repin stuff, and then unpin repin it.
//
// With NT 5.0, we can use some new cache manager support to make
// this a lot more efficient (important for FAT32). Since we're
// only worried about ranges that are dirty - and since we're a
// modified-no-write stream - we can assume that if there is no
// BCB, there is no work to do in the range. I.e., the lazy writer
// beat us to it.
//
// This is much better than reading the entire FAT in and trying
// to punch it out (see the test in the write path to blow
// off writes that don't correspond to dirty ranges of the FAT).
// For FAT32, this would be a *lot* of reading.
//
if (Vcb->AllocationSupport.FatIndexBitSize != 12) {
//
// Walk through the Fat, one page at a time.
//
ULONG NumberOfPages;
ULONG Page;
NumberOfPages = ( FatReservedBytes(&Vcb->Bpb) +
FatBytesPerFat(&Vcb->Bpb) +
(PAGE_SIZE - 1) ) / PAGE_SIZE;
for ( Page = 0, Offset.QuadPart = 0;
Page < NumberOfPages;
Page++, Offset.LowPart += PAGE_SIZE ) {
try {
if (CcPinRead( Vcb->VirtualVolumeFile,
&Offset,
PAGE_SIZE,
PIN_WAIT | PIN_IF_BCB,
&Bcb,
&DontCare )) {
CcSetDirtyPinnedData( Bcb, NULL );
CcRepinBcb( Bcb );
CcUnpinData( Bcb );
CcUnpinRepinnedBcb( Bcb, TRUE, &Iosb );
if (!NT_SUCCESS(Iosb.Status)) {
ReturnStatus = Iosb.Status;
}
}
} except(FatExceptionFilter(IrpContext, GetExceptionInformation())) {
ReturnStatus = IrpContext->ExceptionStatus;
continue;
}
}
} else {
//
// We read in the entire fat in the 12 bit case.
//
Offset.QuadPart = FatReservedBytes( &Vcb->Bpb );
try {
if (CcPinRead( Vcb->VirtualVolumeFile,
&Offset,
FatBytesPerFat( &Vcb->Bpb ),
PIN_WAIT | PIN_IF_BCB,
&Bcb,
&DontCare )) {
CcSetDirtyPinnedData( Bcb, NULL );
CcRepinBcb( Bcb );
CcUnpinData( Bcb );
CcUnpinRepinnedBcb( Bcb, TRUE, &Iosb );
if (!NT_SUCCESS(Iosb.Status)) {
ReturnStatus = Iosb.Status;
}
}
} except(FatExceptionFilter(IrpContext, GetExceptionInformation())) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -