📄 write.c
字号:
for (Fat = 0; Fat < (ULONG)Vcb->Bpb.Fats; Fat++) {
IoRuns[Fat].Vbo = StartingDirtyVbo;
IoRuns[Fat].Lbo = Fat * BytesPerFat + StartingDirtyVbo;
IoRuns[Fat].Offset = StartingDirtyVbo - StartingVbo;
IoRuns[Fat].ByteCount = WriteLength;
}
//
// Keep track of meta-data disk ios.
//
Vcb->Statistics[KeGetCurrentProcessorNumber()].Common.MetaDataDiskWrites += Vcb->Bpb.Fats;
try {
FatMultipleAsync( IrpContext,
Vcb,
Irp,
(ULONG)Vcb->Bpb.Fats,
IoRuns );
} finally {
if (IoRuns != StackIoRuns) {
ExFreePool( IoRuns );
}
}
//
// Wait for all the writes to finish
//
FatWaitSync( IrpContext );
//
// If we got an error, or verify required, remember it.
//
if (!NT_SUCCESS( Irp->IoStatus.Status )) {
DebugTrace( 0,
Dbg,
"Error %X while writing volume file.\n",
Irp->IoStatus.Status );
RaiseIosb = Irp->IoStatus;
}
}
//
// If the writes were a success, set the sectors clean, else
// raise the error status and mark the volume as needing
// verification. This will automatically reset the volume
// structures.
//
// If not, then mark this volume as needing verification to
// automatically cause everything to get cleaned up.
//
Irp->IoStatus = RaiseIosb;
if ( NT_SUCCESS( Status = Irp->IoStatus.Status )) {
FatRemoveMcbEntry( Vcb, &Vcb->DirtyFatMcb,
StartingDirtyVbo,
WriteLength );
} else {
FatNormalizeAndRaiseStatus( IrpContext, Status );
}
DebugTrace(-1, Dbg, "CommonRead -> %08lx\n", Status );
FatCompleteRequest( IrpContext, Irp, Status );
return Status;
}
//
// This case corresponds to a general opened volume (DASD), ie.
// open ("a:").
//
if (TypeOfOpen == UserVolumeOpen) {
LBO StartingLbo;
LBO VolumeSize;
//
// Precalculate the volume size since we're nearly always going
// to be wanting to use it.
//
VolumeSize = (LBO) Int32x32To64( Vcb->Bpb.BytesPerSector,
(Vcb->Bpb.Sectors != 0 ? Vcb->Bpb.Sectors :
Vcb->Bpb.LargeSectors));
StartingLbo = StartingByte.QuadPart;
DebugTrace(0, Dbg, "Type of write is User Volume.\n", 0);
//
// Verify that the volume for this handle is still valid, permitting
// operations to proceed on dismounted volumes via the handle which
// performed the dismount.
//
if (!FlagOn( Ccb->Flags, CCB_FLAG_COMPLETE_DISMOUNT )) {
FatQuickVerifyVcb( IrpContext, Vcb );
}
if (!FlagOn( Ccb->Flags, CCB_FLAG_DASD_PURGE_DONE )) {
BOOLEAN PreviousWait = BooleanFlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
//
// Grab the entire volume so that even the normally unsafe action
// of writing to an unlocked volume won't open us to a race between
// the flush and purge of the FAT below.
//
// I really don't think this is particularly important to worry about,
// but a repro case for another bug happens to dance into this race
// condition pretty easily. Eh.
//
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
FatAcquireExclusiveVolume( IrpContext, Vcb );
try {
//
// If the volume isn't locked, flush and purge it.
//
if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
FatFlushFat( IrpContext, Vcb );
CcPurgeCacheSection( &Vcb->SectionObjectPointers,
NULL,
0,
FALSE );
FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
}
} finally {
FatReleaseVolume( IrpContext, Vcb );
if (!PreviousWait) {
ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT );
}
}
SetFlag( Ccb->Flags, CCB_FLAG_DASD_PURGE_DONE |
CCB_FLAG_DASD_FLUSH_DONE );
}
if (!FlagOn( Ccb->Flags, CCB_FLAG_ALLOW_EXTENDED_DASD_IO )) {
//
// Make sure we don't try to write past end of volume,
// reducing the requested byte count if necessary.
//
if (WriteToEof || StartingLbo >= VolumeSize) {
FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
return STATUS_SUCCESS;
}
if (ByteCount > VolumeSize - StartingLbo) {
ByteCount = (ULONG) (VolumeSize - StartingLbo);
//
// For async writes we had set the byte count in the FatIoContext
// above, so fix that here.
//
if (!Wait) {
IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
ByteCount;
}
}
} else {
//
// This has a peculiar interpretation, but just adjust the starting
// byte to the end of the visible volume.
//
if (WriteToEof) {
StartingLbo = VolumeSize;
}
}
//
// For DASD we have to probe and lock the user's buffer
//
FatLockUserBuffer( IrpContext, Irp, IoReadAccess, ByteCount );
//
// Set the FO_MODIFIED flag here to trigger a verify when this
// handle is closed. Note that we can err on the conservative
// side with no problem, i.e. if we accidently do an extra
// verify there is no problem.
//
SetFlag( FileObject->Flags, FO_FILE_MODIFIED );
//
// Write the data and wait for the results
//
FatSingleAsync( IrpContext,
Vcb,
StartingLbo,
ByteCount,
Irp );
if (!Wait) {
//
// We, nor anybody else, need the IrpContext any more.
//
IrpContext->FatIoContext = NULL;
FatDeleteIrpContext( IrpContext );
DebugTrace(-1, Dbg, "FatNonCachedIo -> STATUS_PENDING\n", 0);
return STATUS_PENDING;
}
FatWaitSync( IrpContext );
//
// If the call didn't succeed, raise the error status
//
// Also mark this volume as needing verification to automatically
// cause everything to get cleaned up.
//
if (!NT_SUCCESS( Status = Irp->IoStatus.Status )) {
FatNormalizeAndRaiseStatus( IrpContext, Status );
}
//
// Update the current file position. We assume that
// open/create zeros out the CurrentByteOffset field.
//
if (SynchronousIo && !PagingIo) {
FileObject->CurrentByteOffset.QuadPart =
StartingLbo + Irp->IoStatus.Information;
}
DebugTrace(-1, Dbg, "FatCommonWrite -> %08lx\n", Status );
FatCompleteRequest( IrpContext, Irp, Status );
return Status;
}
//
// At this point we know there is an Fcb/Dcb.
//
ASSERT( FcbOrDcb != NULL );
//
// Use a try-finally to free Fcb/Dcb and buffers on the way out.
//
try {
//
// This case corresponds to a normal user write file.
//
if ( TypeOfOpen == UserFileOpen ) {
ULONG ValidDataLength;
ULONG ValidDataToDisk;
ULONG ValidDataToCheck;
DebugTrace(0, Dbg, "Type of write is user file open\n", 0);
//
// If this is a noncached transfer and is not a paging I/O, and
// the file has been opened cached, then we will do a flush here
// to avoid stale data problems. Note that we must flush before
// acquiring the Fcb shared since the write may try to acquire
// it exclusive.
//
// The Purge following the flush will garentee cache coherency.
//
if (NonCachedIo && !PagingIo &&
(FileObject->SectionObjectPointer->DataSectionObject != NULL)) {
//
// We need the Fcb exclsuive to do the CcPurgeCache
//
if (!FatAcquireExclusiveFcb( IrpContext, FcbOrDcb )) {
DebugTrace( 0, Dbg, "Cannot acquire FcbOrDcb = %08lx shared without waiting\n", FcbOrDcb );
try_return( PostIrp = TRUE );
}
FcbOrDcbAcquired = TRUE;
FcbAcquiredExclusive = TRUE;
//
// Preacquire pagingio for the flush.
//
ExAcquireResourceExclusiveLite( FcbOrDcb->Header.PagingIoResource, TRUE );
CcFlushCache( FileObject->SectionObjectPointer,
WriteToEof ? &FcbOrDcb->Header.FileSize : &StartingByte,
ByteCount,
&Irp->IoStatus );
if (!NT_SUCCESS( Irp->IoStatus.Status )) {
ExReleaseResourceLite( FcbOrDcb->Header.PagingIoResource );
try_return( Irp->IoStatus.Status );
}
//
// Remember that we are holding the paging I/O resource.
//
PagingIoResourceAcquired = TRUE;
//
// We hold so that we will prevent a pagefault from occuring and seeing
// soon-to-be stale data from the disk. We used to believe this was
// something to be left to the app to synchronize; we now realize that
// noncached IO on a fileserver is doomed without the filesystem forcing
// the coherency issue. By only penalizing noncached coherency when
// needed, this is about the best we can do.
//
CcPurgeCacheSection( FileObject->SectionObjectPointer,
WriteToEof ? &FcbOrDcb->Header.FileSize : &StartingByte,
ByteCount,
FALSE );
//
// Indicate we're OK with the fcb being demoted to shared access
// if that turns out to be possible later on after VDL extension
// is checked for.
//
// PagingIo must be held all the way through.
//
FcbCanDemoteToShared = TRUE;
}
//
// We assert that Paging Io writes will never WriteToEof.
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -