📄 write.c
字号:
UnwindOutstandingAsync = TRUE;
IrpContext->FatIoContext->Wait.Async.NonPagedFcb = FcbOrDcb->NonPaged;
}
}
//
// Now that we have the Fcb exclusive, get a new batch of
// filesize and ValidDataLength.
//
ValidDataToDisk = FcbOrDcb->ValidDataToDisk;
ValidDataLength = FcbOrDcb->Header.ValidDataLength.LowPart;
FileSize = FcbOrDcb->Header.FileSize.LowPart;
//
// If this is PagingIo check again if any pruning is
// required. It is important to start from basic
// princples in case the file was *grown* ...
//
if ( PagingIo ) {
if (StartingVbo >= FileSize) {
Irp->IoStatus.Information = 0;
try_return( Status = STATUS_SUCCESS );
}
ByteCount = IrpSp->Parameters.Write.Length;
if (ByteCount > FileSize - StartingVbo) {
ByteCount = FileSize - StartingVbo;
}
}
}
//
// Remember the final requested byte count
//
if (NonCachedIo && !Wait) {
IrpContext->FatIoContext->Wait.Async.RequestedByteCount =
ByteCount;
}
//
// Remember the initial file size and valid data length,
// just in case .....
//
InitialFileSize = FileSize;
InitialValidDataLength = ValidDataLength;
//
// Make sure the FcbOrDcb is still good
//
FatVerifyFcb( IrpContext, FcbOrDcb );
//
// Check for writing to end of File. If we are, then we have to
// recalculate a number of fields.
//
if ( WriteToEof ) {
StartingVbo = FileSize;
StartingByte = FcbOrDcb->Header.FileSize;
//
// Since we couldn't know this information until now, perform the
// necessary bounds checking that we ommited at the top because
// this is a WriteToEof operation.
//
if (!FatIsIoRangeValid( Vcb, StartingByte, ByteCount )) {
Irp->IoStatus.Information = 0;
try_return( Status = STATUS_DISK_FULL );
}
}
//
// If this is a non paging write to a data stream object we have to
// check for access according to the current state op/filelocks.
//
// Note that after this point, operations will be performed on the file.
// No modifying activity can occur prior to this point in the write
// path.
//
if (!PagingIo && TypeOfOpen == UserFileOpen) {
Status = FsRtlCheckOplock( &FcbOrDcb->Specific.Fcb.Oplock,
Irp,
IrpContext,
FatOplockComplete,
FatPrePostIrp );
if (Status != STATUS_SUCCESS) {
OplockPostIrp = TRUE;
PostIrp = TRUE;
try_return( NOTHING );
}
//
// This oplock call can affect whether fast IO is possible.
// We may have broken an oplock to no oplock held. If the
// current state of the file is FastIoIsNotPossible then
// recheck the fast IO state.
//
if (FcbOrDcb->Header.IsFastIoPossible == FastIoIsNotPossible) {
FcbOrDcb->Header.IsFastIoPossible = FatIsFastIoPossible( FcbOrDcb );
}
//
// And finally check the regular file locks.
//
if (!FsRtlCheckLockForWriteAccess( &FcbOrDcb->Specific.Fcb.FileLock, Irp )) {
try_return( Status = STATUS_FILE_LOCK_CONFLICT );
}
}
//
// Determine if we will deal with extending the file. Note that
// this implies extending valid data, and so we already have all
// of the required synchronization done.
//
if (!PagingIo && (StartingVbo + ByteCount > FileSize)) {
ExtendingFile = TRUE;
}
if ( ExtendingFile ) {
//
// EXTENDING THE FILE
//
// Update our local copy of FileSize
//
FileSize = StartingVbo + ByteCount;
if (FcbOrDcb->Header.AllocationSize.QuadPart == FCB_LOOKUP_ALLOCATIONSIZE_HINT) {
FatLookupFileAllocationSize( IrpContext, FcbOrDcb );
}
//
// If the write goes beyond the allocation size, add some
// file allocation.
//
if ( FileSize > FcbOrDcb->Header.AllocationSize.LowPart ) {
BOOLEAN AllocateMinimumSize = TRUE;
//
// Only do allocation chuncking on writes if this is
// not the first allocation added to the file.
//
if (FcbOrDcb->Header.AllocationSize.LowPart != 0 ) {
ULONG ApproximateClusterCount;
ULONG TargetAllocation;
ULONG Multiplier;
ULONG BytesPerCluster;
ULONG ClusterAlignedFileSize;
//
// We are going to try and allocate a bigger chunk than
// we actually need in order to maximize FastIo usage.
//
// The multiplier is computed as follows:
//
//
// (FreeDiskSpace )
// Mult = ( (-------------------------) / 32 ) + 1
// (FileSize - AllocationSize)
//
// and max out at 32.
//
// With this formula we start winding down chunking
// as we get near the disk space wall.
//
// For instance on an empty 1 MEG floppy doing an 8K
// write, the multiplier is 6, or 48K to allocate.
// When this disk is half full, the multipler is 3,
// and when it is 3/4 full, the mupltiplier is only 1.
//
// On a larger disk, the multiplier for a 8K read will
// reach its maximum of 32 when there is at least ~8 Megs
// available.
//
//
// Small write performance note, use cluster aligned
// file size in above equation.
//
//
// We need to carefully consider what happens when we approach
// a 2^32 byte filesize. Overflows will cause problems.
//
BytesPerCluster = 1 << Vcb->AllocationSupport.LogOfBytesPerCluster;
//
// This can overflow if the target filesize is in the last cluster.
// In this case, we can obviously skip over all of this fancy
// logic and just max out the file right now.
//
ClusterAlignedFileSize = (FileSize + (BytesPerCluster - 1)) &
~(BytesPerCluster - 1);
if (ClusterAlignedFileSize != 0) {
//
// This actually has a chance but the possibility of overflowing
// the numerator is pretty unlikely, made more unlikely by moving
// the divide by 32 up to scale the BytesPerCluster. However, even if it does the
// effect is completely benign.
//
// FAT32 with a 64k cluster and over 2^21 clusters would do it (and
// so forth - 2^(16 - 5 + 21) == 2^32). Since this implies a partition
// of 32gb and a number of clusters (and cluster size) we plan to
// disallow in format for FAT32, the odds of this happening are pretty
// low anyway.
//
Multiplier = ((Vcb->AllocationSupport.NumberOfFreeClusters *
(BytesPerCluster >> 5)) /
(ClusterAlignedFileSize -
FcbOrDcb->Header.AllocationSize.LowPart)) + 1;
if (Multiplier > 32) { Multiplier = 32; }
Multiplier *= (ClusterAlignedFileSize - FcbOrDcb->Header.AllocationSize.LowPart);
TargetAllocation = FcbOrDcb->Header.AllocationSize.LowPart + Multiplier;
//
// We know that TargetAllocation is in whole clusters, so simply
// checking if it wrapped is correct. If it did, we fall back
// to allocating up to the maximum legal size.
//
if (TargetAllocation < FcbOrDcb->Header.AllocationSize.LowPart) {
TargetAllocation = ~BytesPerCluster + 1;
Multiplier = TargetAllocation - FcbOrDcb->Header.AllocationSize.LowPart;
}
//
// Now do an unsafe check here to see if we should even
// try to allocate this much. If not, just allocate
// the minimum size we need, if so so try it, but if it
// fails, just allocate the minimum size we need.
//
ApproximateClusterCount = (Multiplier / BytesPerCluster);
if (ApproximateClusterCount <= Vcb->AllocationSupport.NumberOfFreeClusters) {
try {
FatAddFileAllocation( IrpContext,
FcbOrDcb,
FileObject,
TargetAllocation );
AllocateMinimumSize = FALSE;
SetFlag( FcbOrDcb->FcbState, FCB_STATE_TRUNCATE_ON_CLOSE );
} except( GetExceptionCode() == STATUS_DISK_FULL ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) {
FatResetExceptionState( IrpContext );
}
}
}
}
if ( AllocateMinimumSize ) {
FatAddFileAllocation( IrpContext,
FcbOrDcb,
FileObject,
FileSize );
}
//
// Assert that the allocation worked
//
ASSERT( FcbOrDcb->Header.AllocationSize.LowPart >= FileSize );
}
//
// Set the new file size in the Fcb
//
ASSERT( FileSize <= FcbOrDcb->Header.AllocationSize.LowPart );
FcbOrDcb->Header.FileSize.LowPart = FileSize;
//
// Extend the cache map, letting mm knows the new file size.
// We only have to do this if the file is cached.
//
if (CcIsFileCached(FileObject)) {
CcSetFileSizes( FileObject, (PCC_FILE_SIZES)&FcbOrDcb->Header.AllocationSize );
}
}
//
// Determine if we will deal with extending valid data.
//
if ( !CalledByLazyWriter &&
!RecursiveWriteThrough &&
(StartingVbo + ByteCount > ValidDataLength) ) {
ExtendingValidData = TRUE;
} else {
//
// If not extending valid data, and we otherwise believe we
// could demote from exclusive to shared, do so. This will
// occur when we synchronize tight for noncached coherency
// but must defer the demotion until after we decide about
// valid data length, which requires it exclusive. Since we
// can't drop/re-pick the resources without letting a pagefault
// squirt through, the resource decision was kept up in the air
// until now.
//
// Note that we've still got PagingIo exclusive in these cases.
//
if (FcbCanDemoteToShared) {
ASSERT( FcbAcquiredExclusive && ExIsResourceAcquiredExclusiveLite( FcbOrDcb->Header.Resource ));
ExConvertExclusiveToSharedLite( FcbOrDcb->Header.Resource );
FcbAcquiredExclusive = FALSE;
}
}
if (ValidDataToDisk > ValidDataLength) {
ValidDataToCheck = ValidDataToDisk;
} else {
ValidDataToCheck = ValidDataLength;
}
//
// HANDLE THE NON-CACHED CASE
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -