📄 write.c
字号:
ASSERT( Vcb != NULL );
//
// Save callers who try to do cached IO to the raw volume from themselves.
//
if (TypeOfOpen == UserVolumeOpen) {
NonCachedIo = TRUE;
}
ASSERT(!(NonCachedIo == FALSE && TypeOfOpen == VirtualVolumeFile));
//
// Collect interesting statistics. The FLAG_USER_IO bit will indicate
// what type of io we're doing in the FatNonCachedIo function.
//
if (PagingIo) {
CollectWriteStats(Vcb, TypeOfOpen, ByteCount);
if (TypeOfOpen == UserFileOpen) {
SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
} else {
ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_USER_IO);
}
}
//
// We must disallow writes to regular objects that would require us
// to maintain an AllocationSize of greater than 32 significant bits.
//
// If this is paging IO, this is simply a case where we need to trim.
// This will occur in due course.
//
if (!PagingIo && !WriteToEof && (TypeOfOpen != UserVolumeOpen)) {
if (!FatIsIoRangeValid( Vcb, StartingByte, ByteCount )) {
Irp->IoStatus.Information = 0;
FatCompleteRequest( IrpContext, Irp, STATUS_DISK_FULL );
return STATUS_DISK_FULL;
}
}
//
// Allocate if necessary and initialize a FAT_IO_CONTEXT block for
// all non cached Io. For synchronous Io
// we use stack storage, otherwise we allocate pool.
//
if (NonCachedIo) {
if (IrpContext->FatIoContext == NULL) {
if (!Wait) {
IrpContext->FatIoContext =
FsRtlAllocatePoolWithTag( NonPagedPool,
sizeof(FAT_IO_CONTEXT),
TAG_FAT_IO_CONTEXT );
} else {
IrpContext->FatIoContext = &StackFatIoContext;
SetFlag( IrpContext->Flags, IRP_CONTEXT_STACK_IO_CONTEXT );
}
}
RtlZeroMemory( IrpContext->FatIoContext, sizeof(FAT_IO_CONTEXT) );
if (Wait) {
KeInitializeEvent( &IrpContext->FatIoContext->Wait.SyncEvent,
NotificationEvent,
FALSE );
} else {
IrpContext->FatIoContext->Wait.Async.ResourceThreadId =
ExGetCurrentResourceThread();
IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
ByteCount;
IrpContext->FatIoContext->Wait.Async.FileObject = FileObject;
}
}
//
// Check if this volume has already been shut down. If it has, fail
// this write request.
//
if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_SHUTDOWN) ) {
Irp->IoStatus.Information = 0;
FatCompleteRequest( IrpContext, Irp, STATUS_TOO_LATE );
return STATUS_TOO_LATE;
}
//
// This case corresponds to a write of the volume file (only the first
// fat allowed, the other fats are written automatically in parallel).
//
// We use an Mcb keep track of dirty sectors. Actual entries are Vbos
// and Lbos (ie. bytes), though they are all added in sector chunks.
// Since Vbo == Lbo for the volume file, the Mcb entries
// alternate between runs of Vbo == Lbo, and holes (Lbo == 0). We use
// the prior to represent runs of dirty fat sectors, and the latter
// for runs of clean fat. Note that since the first part of the volume
// file (boot sector) is always clean (a hole), and an Mcb never ends in
// a hole, there must always be an even number of runs(entries) in the Mcb.
//
// The strategy is to find the first and last dirty run in the desired
// write range (which will always be a set of pages), and write from the
// former to the later. The may result in writing some clean data, but
// will generally be more efficient than writing each runs seperately.
//
if (TypeOfOpen == VirtualVolumeFile) {
LBO DirtyLbo;
LBO CleanLbo;
VBO DirtyVbo;
VBO StartingDirtyVbo;
ULONG DirtyByteCount;
ULONG CleanByteCount;
ULONG WriteLength;
BOOLEAN MoreDirtyRuns = TRUE;
IO_STATUS_BLOCK RaiseIosb;
DebugTrace(0, Dbg, "Type of write is Virtual Volume File\n", 0);
//
// If we can't wait we have to post this.
//
if (!Wait) {
DebugTrace( 0, Dbg, "Passing request to Fsp\n", 0 );
Status = FatFsdPostRequest(IrpContext, Irp);
return Status;
}
//
// If we weren't called by the Lazy Writer, then this write
// must be the result of a write-through or flush operation.
// Setting the IrpContext flag, will cause DevIoSup.c to
// write-through the data to the disk.
//
if (!FlagOn((ULONG_PTR)IoGetTopLevelIrp(), FSRTL_CACHE_TOP_LEVEL_IRP)) {
SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH );
}
//
// Assert an even number of entries in the Mcb, an odd number would
// mean that the Mcb is corrupt.
//
ASSERT( (FsRtlNumberOfRunsInLargeMcb( &Vcb->DirtyFatMcb ) & 1) == 0);
//
// We need to skip over any clean sectors at the start of the write.
//
// Also check the two cases where there are no dirty fats in the
// desired write range, and complete them with success.
//
// 1) There is no Mcb entry corresponding to StartingVbo, meaning
// we are beyond the end of the Mcb, and thus dirty fats.
//
// 2) The run at StartingVbo is clean and continues beyond the
// desired write range.
//
if (!FatLookupMcbEntry( Vcb, &Vcb->DirtyFatMcb,
StartingVbo,
&DirtyLbo,
&DirtyByteCount,
NULL )
|| ( (DirtyLbo == 0) && (DirtyByteCount >= ByteCount) ) ) {
DebugTrace(0, DEBUG_TRACE_DEBUG_HOOKS,
"No dirty fat sectors in the write range.\n", 0);
FatCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
return STATUS_SUCCESS;
}
DirtyVbo = (VBO)DirtyLbo;
//
// If the last run was a hole (clean), up DirtyVbo to the next
// run, which must be dirty.
//
if (DirtyVbo == 0) {
DirtyVbo = StartingVbo + DirtyByteCount;
}
//
// This is where the write will start.
//
StartingDirtyVbo = DirtyVbo;
//
//
// Now start enumerating the dirty fat sectors spanning the desired
// write range, this first one of which is now DirtyVbo.
//
while ( MoreDirtyRuns ) {
//
// Find the next dirty run, if it is not there, the Mcb ended
// in a hole, or there is some other corruption of the Mcb.
//
if (!FatLookupMcbEntry( Vcb, &Vcb->DirtyFatMcb,
DirtyVbo,
&DirtyLbo,
&DirtyByteCount,
NULL )) {
DirtyVbo = (VBO)DirtyLbo;
DebugTrace(0, Dbg, "Last dirty fat Mcb entry was a hole: corrupt.\n", 0);
FatBugCheck( 0, 0, 0 );
} else {
DirtyVbo = (VBO)DirtyLbo;
//
// This has to correspond to a dirty run, and must start
// within the write range since we check it at entry to,
// and at the bottom of this loop.
//
ASSERT((DirtyVbo != 0) && (DirtyVbo < StartingVbo + ByteCount));
//
// There are three ways we can know that this was the
// last dirty run we want to write.
//
// 1) The current dirty run extends beyond or to the
// desired write range.
//
// 2) On trying to find the following clean run, we
// discover that this is the last run in the Mcb.
//
// 3) The following clean run extend beyond the
// desired write range.
//
// In any of these cases we set MoreDirtyRuns = FALSE.
//
//
// If the run is larger than we are writing, we also
// must truncate the WriteLength. This is benign in
// the equals case.
//
if (DirtyVbo + DirtyByteCount >= StartingVbo + ByteCount) {
DirtyByteCount = StartingVbo + ByteCount - DirtyVbo;
MoreDirtyRuns = FALSE;
} else {
//
// Scan the clean hole after this dirty run. If this
// run was the last, prepare to exit the loop
//
if (!FatLookupMcbEntry( Vcb, &Vcb->DirtyFatMcb,
DirtyVbo + DirtyByteCount,
&CleanLbo,
&CleanByteCount,
NULL )) {
MoreDirtyRuns = FALSE;
} else {
//
// Assert that we actually found a clean run.
// and compute the start of the next dirty run.
//
ASSERT (CleanLbo == 0);
//
// If the next dirty run starts beyond the desired
// write, we have found all the runs we need, so
// prepare to exit.
//
if (DirtyVbo + DirtyByteCount + CleanByteCount >=
StartingVbo + ByteCount) {
MoreDirtyRuns = FALSE;
} else {
//
// Compute the start of the next dirty run.
//
DirtyVbo += DirtyByteCount + CleanByteCount;
}
}
}
}
} // while ( MoreDirtyRuns )
//
// At this point DirtyVbo and DirtyByteCount correctly reflect the
// final dirty run, constrained to the desired write range.
//
// Now compute the length we finally must write.
//
WriteLength = (DirtyVbo + DirtyByteCount) - StartingDirtyVbo;
//
// We must now assume that the write will complete with success,
// and initialize our expected status in RaiseIosb. It will be
// modified below if an error occurs.
//
RaiseIosb.Status = STATUS_SUCCESS;
RaiseIosb.Information = ByteCount;
//
// Loop through all the fats, setting up a multiple async to
// write them all. If there are more than FAT_MAX_PARALLEL_IOS
// then we do several muilple asyncs.
//
{
ULONG Fat;
ULONG BytesPerFat;
IO_RUN StackIoRuns[2];
PIO_RUN IoRuns;
BytesPerFat = FatBytesPerFat( &Vcb->Bpb );
if ((ULONG)Vcb->Bpb.Fats > 2) {
IoRuns = FsRtlAllocatePoolWithTag( PagedPool,
(ULONG)Vcb->Bpb.Fats,
TAG_IO_RUNS );
} else {
IoRuns = StackIoRuns;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -