diff options
Diffstat (limited to 'private/ntos/cntfs/resrcsup.c')
-rw-r--r-- | private/ntos/cntfs/resrcsup.c | 2114 |
1 files changed, 2114 insertions, 0 deletions
diff --git a/private/ntos/cntfs/resrcsup.c b/private/ntos/cntfs/resrcsup.c new file mode 100644 index 000000000..e6d186118 --- /dev/null +++ b/private/ntos/cntfs/resrcsup.c @@ -0,0 +1,2114 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + ResrcSup.c + +Abstract: + + This module implements the Ntfs Resource acquisition routines + +Author: + + Gary Kimura [GaryKi] 21-May-1991 + +Revision History: + +--*/ + +#include "NtfsProc.h" + +#ifdef ALLOC_PRAGMA +#pragma alloc_text(PAGE, NtfsAcquireAllFiles) +#pragma alloc_text(PAGE, NtfsAcquireExclusiveFcb) +#pragma alloc_text(PAGE, NtfsAcquireExclusiveScb) +#pragma alloc_text(PAGE, NtfsAcquireSharedScbForTransaction) +#pragma alloc_text(PAGE, NtfsAcquireExclusiveGlobal) +#pragma alloc_text(PAGE, NtfsAcquireExclusiveVcb) +#pragma alloc_text(PAGE, NtfsAcquireFcbWithPaging) +#pragma alloc_text(PAGE, NtfsAcquireForCreateSection) +#pragma alloc_text(PAGE, NtfsAcquireScbForLazyWrite) +#pragma alloc_text(PAGE, NtfsAcquireSharedGlobal) +#pragma alloc_text(PAGE, NtfsAcquireFileForCcFlush) +#pragma alloc_text(PAGE, NtfsAcquireFileForModWrite) +#pragma alloc_text(PAGE, NtfsAcquireSharedVcb) +#pragma alloc_text(PAGE, NtfsAcquireVolumeFileForClose) +#pragma alloc_text(PAGE, NtfsAcquireVolumeFileForLazyWrite) +#pragma alloc_text(PAGE, NtfsAcquireVolumeForClose) +#pragma alloc_text(PAGE, NtfsReleaseAllFiles) +#pragma alloc_text(PAGE, NtfsReleaseFcbWithPaging) +#pragma alloc_text(PAGE, NtfsReleaseFileForCcFlush) +#pragma alloc_text(PAGE, NtfsReleaseForCreateSection) +#pragma alloc_text(PAGE, NtfsReleaseScbFromLazyWrite) +#pragma alloc_text(PAGE, NtfsReleaseScbWithPaging) +#pragma alloc_text(PAGE, NtfsReleaseSharedResources) +#pragma alloc_text(PAGE, NtfsReleaseVolumeFileFromClose) +#pragma alloc_text(PAGE, NtfsReleaseVolumeFileFromLazyWrite) +#pragma alloc_text(PAGE, NtfsReleaseVolumeFromClose) +#endif + + +VOID +NtfsAcquireExclusiveGlobal ( + IN PIRP_CONTEXT IrpContext + ) + +/*++ + +Routine Description: + + This routine acquires exclusive access to the global resource. + + This routine will raise if it cannot acquire the resource and wait + in the IrpContext is false. + +Arguments: + +Return Value: + + None. + +--*/ + +{ + ASSERT_IRP_CONTEXT(IrpContext); + + PAGED_CODE(); + + if (!ExAcquireResourceExclusive( &NtfsData.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { + + NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL ); + } + + return; +} + + +VOID +NtfsAcquireSharedGlobal ( + IN PIRP_CONTEXT IrpContext + ) + +/*++ + +Routine Description: + + This routine acquires shared access to the global resource. + + This routine will raise if it cannot acquire the resource and wait + in the IrpContext is false. + +Arguments: + +Return Value: + + None. + +--*/ + +{ + ASSERT_IRP_CONTEXT(IrpContext); + + PAGED_CODE(); + + if (!ExAcquireResourceShared( &NtfsData.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { + + NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL ); + } + + return; +} + + +VOID +NtfsAcquireAllFiles ( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN BOOLEAN Exclusive, + IN BOOLEAN AcquirePagingIo + ) + +/*++ + +Routine Description: + + This routine non-recursively requires all files on a volume. + +Arguments: + + Vcb - Supplies the volume + + Exclusive - Indicates if we should be acquiring all the files exclusively. + If FALSE then we acquire all the files shared except for files with + streams which could be part of transactions. + + AcquirePagingIo - Indicates if we need to acquire the paging io resource + exclusively. Only needed if a future call will flush the volume + (i.e. shutdown) + +Return Value: + + None + +--*/ + +{ + PFCB Fcb; + PSCB *Scb; + PSCB NextScb; + PVOID RestartKey; + + PAGED_CODE(); + + SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT ); + + NtfsAcquireExclusiveVcb( IrpContext, Vcb, TRUE ); + + RestartKey = NULL; + while (TRUE) { + + NtfsAcquireFcbTable( IrpContext, Vcb ); + Fcb = NtfsGetNextFcbTableEntry(Vcb, &RestartKey); + NtfsReleaseFcbTable( IrpContext, Vcb ); + + if (Fcb == NULL) { + + break; + } + + ASSERT_FCB( Fcb ); + + // + // We can skip over the Fcb's for any of the Scb's in the Vcb. + // We delay acquiring those to avoid deadlocks. + // + + if (NtfsSegmentNumber( &Fcb->FileReference ) >= FIRST_USER_FILE_NUMBER) { + + // + // If there is a paging Io resource then acquire this if required. + // + + if (AcquirePagingIo && (Fcb->PagingIoResource != NULL)) { + + ExAcquireResourceExclusive( Fcb->PagingIoResource, TRUE ); + } + + // + // Acquire this Fcb whether or not the underlying file has been deleted. + // + + if (Exclusive || + IsDirectory( &Fcb->Info )) { + + NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, TRUE, FALSE ); + + } else { + + // + // Assume that we only need this file shared. We will then + // look for Lsn related streams. + // + + NtfsAcquireSharedFcb( IrpContext, Fcb, NULL, TRUE ); + + // + // Walk through all of the Scb's for the file and look for + // an Lsn protected stream. + // + + NtfsLockFcb( IrpContext, Fcb ); + + NextScb = NULL; + + while (NextScb = NtfsGetNextChildScb( Fcb, NextScb )) { + + if (!(NextScb->AttributeTypeCode == $DATA || + NextScb->AttributeTypeCode == $EA)) { + + break; + } + } + + NtfsUnlockFcb( IrpContext, Fcb ); + + // + // If we found a protected Scb then release and reacquire the Fcb + // exclusively. + // + + if (NextScb != NULL) { + + NtfsReleaseFcb( IrpContext, Fcb ); + NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, TRUE, FALSE ); + } + } + } + } + + // + // Now acquire the Fcb's in the Vcb. + // + + Scb = &Vcb->QuotaTableScb; + + while (TRUE) { + + if ((*Scb != NULL) + && (*Scb != Vcb->BitmapScb)) { + + if (AcquirePagingIo && ((*Scb)->Fcb->PagingIoResource != NULL)) { + + ExAcquireResourceExclusive( (*Scb)->Fcb->PagingIoResource, TRUE ); + } + + NtfsAcquireExclusiveFcb( IrpContext, (*Scb)->Fcb, NULL, TRUE, FALSE ); + } + + if (Scb == &Vcb->MftScb) { + + break; + } + + Scb -= 1; + } + + // + // Treat the bitmap as an end resource and acquire it last. + // + + if (Vcb->BitmapScb != NULL) { + + if (AcquirePagingIo && (Vcb->BitmapScb->Fcb->PagingIoResource != NULL)) { + + ExAcquireResourceExclusive( Vcb->BitmapScb->Fcb->PagingIoResource, TRUE ); + } + + NtfsAcquireExclusiveFcb( IrpContext, Vcb->BitmapScb->Fcb, NULL, TRUE, FALSE ); + } + + return; +} + + +VOID +NtfsReleaseAllFiles ( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN BOOLEAN ReleasePagingIo + ) + +/*++ + +Routine Description: + + This routine non-recursively requires all files on a volume. + +Arguments: + + Vcb - Supplies the volume + + ReleasePagingIo - Indicates whether we should release the paging io resources + as well. + +Return Value: + + None + +--*/ + +{ + PFCB Fcb; + PSCB *Scb; + PVOID RestartKey; + + PAGED_CODE(); + + // + // Loop to flush all of the prerestart streams, to do the loop + // we cycle through the Fcb Table and for each fcb we acquire it. + // + + RestartKey = NULL; + while (TRUE) { + + NtfsAcquireFcbTable( IrpContext, Vcb ); + Fcb = NtfsGetNextFcbTableEntry(Vcb, &RestartKey); + NtfsReleaseFcbTable( IrpContext, Vcb ); + + if (Fcb == NULL) { + + break; + } + + ASSERT_FCB( Fcb ); + + if (NtfsSegmentNumber( &Fcb->FileReference ) >= FIRST_USER_FILE_NUMBER) { + + // + // Release the file. + // + + if (ReleasePagingIo && (Fcb->PagingIoResource != NULL)) { + + ExReleaseResource( Fcb->PagingIoResource ); + } + + NtfsReleaseFcb( IrpContext, Fcb ); + } + } + + // + // Now release the Fcb's in the Vcb. + // + + Scb = &Vcb->QuotaTableScb; + + while (TRUE) { + + if (*Scb != NULL) { + + if (ReleasePagingIo && ((*Scb)->Fcb->PagingIoResource != NULL)) { + + ExReleaseResource( (*Scb)->Fcb->PagingIoResource ); + } + + NtfsReleaseFcb( IrpContext, (*Scb)->Fcb ); + } + + if (Scb == &Vcb->MftScb) { + + break; + } + + Scb -= 1; + } + + NtfsReleaseVcb( IrpContext, Vcb ); + + return; +} + + +BOOLEAN +NtfsAcquireExclusiveVcb ( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN BOOLEAN RaiseOnCantWait + ) + +/*++ + +Routine Description: + + This routine acquires exclusive access to the Vcb. + + This routine will raise if it cannot acquire the resource and wait + in the IrpContext is false. + +Arguments: + + Vcb - Supplies the Vcb to acquire + + RaiseOnCantWait - Indicates if we should raise on an acquisition error + or simply return a BOOLEAN indicating that we couldn't get the + resource. + +Return Value: + + BOOLEAN - Indicates if we were able to acquire the resource. This is really + only meaningful if the RaiseOnCantWait value is FALSE. + +--*/ + +{ + ASSERT_IRP_CONTEXT(IrpContext); + ASSERT_VCB(Vcb); + + PAGED_CODE(); + + if (ExAcquireResourceExclusive( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { + + return TRUE; + } + + if (RaiseOnCantWait) { + + NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL ); + } + + return FALSE; +} + + +BOOLEAN +NtfsAcquireSharedVcb ( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN BOOLEAN RaiseOnCantWait + ) + +/*++ + +Routine Description: + + This routine acquires shared access to the Vcb. + + This routine will raise if it cannot acquire the resource and wait + in the IrpContext is false. + +Arguments: + + Vcb - Supplies the Vcb to acquire + + RaiseOnCantWait - Indicates if we should raise on an acquisition error + or simply return a BOOLEAN indicating that we couldn't get the + resource. + +Return Value: + + None. + +--*/ + +{ + ASSERT_IRP_CONTEXT(IrpContext); + ASSERT_VCB(Vcb); + + PAGED_CODE(); + + if (ExAcquireResourceShared( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { + + return TRUE; + } + + if (RaiseOnCantWait) { + + NtfsRaiseStatus( IrpContext, STATUS_CANT_WAIT, NULL, NULL ); + + } else { + + return FALSE; + } +} + + +VOID +NtfsReleaseVcbCheckDelete ( + IN PIRP_CONTEXT IrpContext, + IN PVCB Vcb, + IN UCHAR MajorCode, + IN PFILE_OBJECT FileObject OPTIONAL + ) + +/*++ + +Routine Description: + + This routine will release the Vcb. We will also test here whether we should + teardown the Vcb at this point. If this is the last open queued to a dismounted + volume or the last close from a failed mount or the failed mount then we will + want to test the Vcb for a teardown. + +Arguments: + + Vcb - Supplies the Vcb to acquire + + MajorCode - Indicates what type of operation we were called from. + + FileObject - Optionally supplies the file object whose VPB pointer we need to + zero out + +Return Value: + + None. + +--*/ + +{ + ASSERT_IRP_CONTEXT(IrpContext); + ASSERT_VCB(Vcb); + + if (FlagOn( Vcb->VcbState, VCB_STATE_PERFORMED_DISMOUNT ) && + (Vcb->CloseCount == 0)) { + + ULONG ReferenceCount; + ULONG ResidualCount; + + KIRQL SavedIrql; + BOOLEAN DeleteVcb = FALSE; + + ASSERT_EXCLUSIVE_RESOURCE( &Vcb->Resource ); + + // + // The volume has gone through dismount. Now we need to decide if this + // release of the Vcb is the last reference for this volume. If so we + // can tear the volume down. + // + // We compare the reference count in the Vpb with the state of the volume + // and the type of operation. We also need to check if there is a + // referenced log file object. + // + + IoAcquireVpbSpinLock( &SavedIrql ); + + ReferenceCount = Vcb->Vpb->ReferenceCount; + + IoReleaseVpbSpinLock( SavedIrql ); + + ResidualCount = 0; + + if (Vcb->LogFileObject != NULL) { + + ResidualCount = 1; + } + + if (MajorCode == IRP_MJ_CREATE) { + + ResidualCount += 1; + } + + // + // If the residual count is the same as the count in the Vpb then we + // can delete the Vpb. + // + + if (ResidualCount == ReferenceCount) { + + SetFlag( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY ); + + ExReleaseResource( &Vcb->Resource ); + + // + // Never delete the Vcb unless this is the last release of + // this Vcb. + // + + if (!ExIsResourceAcquiredExclusive( &Vcb->Resource ) && + (ExIsResourceAcquiredShared( &Vcb->Resource ) == 0)) { + + if (ARGUMENT_PRESENT(FileObject)) { FileObject->Vpb = NULL; } + + // + // If this is a create then the IO system will handle the + // Vpb. + // + + if (MajorCode == IRP_MJ_CREATE) { + + ClearFlag( Vcb->VcbState, VCB_STATE_TEMP_VPB ); + } + + // + // Use the global resource to synchronize the DeleteVcb process. + // + + (VOID) ExAcquireResourceExclusive( &NtfsData.Resource, TRUE ); + + RemoveEntryList( &Vcb->VcbLinks ); + + ExReleaseResource( &NtfsData.Resource ); + + NtfsDeleteVcb( IrpContext, &Vcb ); + + } else { + + ClearFlag( Vcb->VcbState, VCB_STATE_DELETE_UNDERWAY ); + } + + } else { + + ExReleaseResource( &Vcb->Resource ); + } + + } else { + + ExReleaseResource( &Vcb->Resource ); + } +} + + +BOOLEAN +NtfsAcquireFcbWithPaging ( + IN PIRP_CONTEXT IrpContext, + IN PFCB Fcb, + IN BOOLEAN DontWait + ) + +/*++ + +Routine Description: + + This routine is used in the create path only. It acquires the Fcb + and also the paging IO resource if it exists but only if the create + operation was doing a supersede/overwrite operation. + + This routine will raise if it cannot acquire the resource and wait + in the IrpContext is false. + +Arguments: + + Fcb - Supplies the Fcb to acquire + + DontWait - If TRUE this overrides the wait value in the IrpContext. + We won't wait for the resource and return whether the resource + was acquired. + +Return Value: + + BOOLEAN - TRUE if acquired. FALSE otherwise. + +--*/ + +{ + BOOLEAN Status = FALSE; + BOOLEAN Wait = FALSE; + BOOLEAN PagingIoAcquired = FALSE; + + ASSERT_IRP_CONTEXT(IrpContext); + ASSERT_FCB(Fcb); + + PAGED_CODE(); + + // + // Sanity check that this is create. The supersede flag is only + // set in the create path and only tested here. + // + + ASSERT( IrpContext->MajorFunction == IRP_MJ_CREATE ); + + if (!DontWait && FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { + + Wait = TRUE; + } + + // + // Free any exclusive paging I/O resource, we currently have, which + // must presumably be from a directory with a paging I/O resource. + // + // We defer releasing the paging io resource when we have logged + // changes against a stream. The only transaction that should be + // underway at this point is the create file case where we allocated + // a file record. In this case it is OK to release the paging io + // resource for the parent. + // + + if (IrpContext->FcbWithPagingExclusive != NULL) { + // ASSERT(IrpContext->TransactionId == 0); + NtfsReleasePagingIo( IrpContext, IrpContext->FcbWithPagingExclusive ); + } + + // + // Loop until we get it right - worst case is twice through loop. + // + + while (TRUE) { + + // + // Acquire Paging I/O first. Testing for the PagingIoResource + // is not really safe without holding the main resource, so we + // correct for that below. + // + + if (FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) && + (Fcb->PagingIoResource != NULL)) { + if (!ExAcquireResourceExclusive( Fcb->PagingIoResource, Wait )) { + break; + } + IrpContext->FcbWithPagingExclusive = Fcb; + PagingIoAcquired = TRUE; + } + + // + // Let's acquire this Fcb exclusively. + // + + if (!NtfsAcquireExclusiveFcb( IrpContext, Fcb, NULL, TRUE, DontWait )) { + + if (PagingIoAcquired) { + ASSERT(IrpContext->TransactionId == 0); + NtfsReleasePagingIo( IrpContext, Fcb ); + } + break; + } + + // + // If we now do not see a paging I/O resource we are golden, + // othewise we can absolutely release and acquire the resources + // safely in the right order, since a resource in the Fcb is + // not going to go away. + // + + if (!FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_ACQUIRE_PAGING ) || + PagingIoAcquired || + (Fcb->PagingIoResource == NULL)) { + + Status = TRUE; + break; + } + + NtfsReleaseFcb( IrpContext, Fcb ); + } + + return Status; +} + + +VOID +NtfsReleaseFcbWithPaging ( + IN PIRP_CONTEXT IrpContext, + IN PFCB Fcb + ) + +/*++ + +Routine Description: + + This routine releases access to the Fcb, including its + paging I/O resource if it exists. + +Arguments: + + Fcb - Supplies the Fcb to acquire + +Return Value: + + None. + +--*/ + +{ + ASSERT_IRP_CONTEXT(IrpContext); + ASSERT_FCB(Fcb); + + PAGED_CODE(); + + // + // We test that we currently hold the paging Io exclusive before releasing + // it. Checking the ExclusivePagingFcb in the IrpContext tells us if + // it is ours. + // + + if ((IrpContext->TransactionId == 0) && + (IrpContext->FcbWithPagingExclusive == Fcb)) { + NtfsReleasePagingIo( IrpContext, Fcb ); + } + + NtfsReleaseFcb( IrpContext, Fcb ); +} + + +VOID +NtfsReleaseScbWithPaging ( + IN PIRP_CONTEXT IrpContext, + IN PSCB Scb + ) + +/*++ + +Routine Description: + + This routine releases access to the Scb, including its + paging I/O resource if it exists. + +Arguments: + + Scb - Supplies the Fcb to acquire + +Return Value: + + None. + +--*/ + +{ + PFCB Fcb = Scb->Fcb; + + ASSERT_IRP_CONTEXT(IrpContext); + ASSERT_SCB(Scb); + + PAGED_CODE(); + + // + // Release the paging Io resource in the Scb under the following + // conditions. + // + // - No transaction underway + // - This paging Io resource is in the IrpContext + // (This last test insures there is a paging IO resource + // and we own it). + // + + if ((IrpContext->TransactionId == 0) && + (IrpContext->FcbWithPagingExclusive == Fcb)) { + NtfsReleasePagingIo( IrpContext, Fcb ); + } + + NtfsReleaseScb( IrpContext, Scb ); +} + + +BOOLEAN +NtfsAcquireExclusiveFcb ( + IN PIRP_CONTEXT IrpContext, + IN PFCB Fcb, + IN PSCB Scb OPTIONAL, + IN BOOLEAN NoDeleteCheck, + IN BOOLEAN DontWait + ) + +/*++ + +Routine Description: + + This routine acquires exclusive access to the Fcb. + + This routine will raise if it cannot acquire the resource and wait + in the IrpContext is false. + +Arguments: + + Fcb - Supplies the Fcb to acquire + + Scb - This is the Scb for which we are acquiring the Fcb + + NoDeleteCheck - If TRUE, we don't do any check for deleted files but + always acquire the Fcb. + + DontWait - If TRUE this overrides the wait value in the IrpContext. + We won't wait for the resource and return whether the resource + was acquired. + +Return Value: + + BOOLEAN - TRUE if acquired. FALSE otherwise. + +--*/ + +{ + NTSTATUS Status; + BOOLEAN Wait; + + ASSERT_IRP_CONTEXT(IrpContext); + ASSERT_FCB(Fcb); + + PAGED_CODE(); + + Status = STATUS_CANT_WAIT; + + if (DontWait || + !FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { + + Wait = FALSE; + + } else { + + Wait = TRUE; + } + + if (ExAcquireResourceExclusive( Fcb->Resource, Wait )) { + + // + // The link count should be non-zero or the file has been + // deleted. We allow deleted files to be acquired for close and + // also allow them to be acquired recursively in case we + // acquire them a second time after marking them deleted (i.e. rename) + // + + if (NoDeleteCheck + + || + + (IrpContext->MajorFunction == IRP_MJ_CLOSE) + + || + + (IrpContext->MajorFunction == IRP_MJ_CREATE) + + || + + (!FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED ) + && (!ARGUMENT_PRESENT( Scb ) + || !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )))) { + + // + // Put Fcb in the exclusive Fcb list for this IrpContext, + // excluding the bitmap for the volume, since we do not need + // to modify its file record and do not want unnecessary + // serialization/deadlock problems. + // + + if ((Fcb->Vcb->BitmapScb == NULL) || + (Fcb->Vcb->BitmapScb->Fcb != Fcb)) { + + // + // We need to check if this Fcb is already in an + // exclusive list. If it is then we want to attach + // the current IrpContext to the IrpContext holding + // this Fcb. + // + + if (Fcb->ExclusiveFcbLinks.Flink == NULL) { + + ASSERT( Fcb->BaseExclusiveCount == 0 ); + + InsertTailList( &IrpContext->ExclusiveFcbList, + &Fcb->ExclusiveFcbLinks ); + } + + Fcb->BaseExclusiveCount += 1; + } + + return TRUE; + } + + // + // We need to release the Fcb and remember the status code. + // + + ExReleaseResource( Fcb->Resource ); + Status = STATUS_FILE_DELETED; + + } else if (DontWait) { + + return FALSE; + } + + NtfsRaiseStatus( IrpContext, Status, NULL, NULL ); +} + + +VOID +NtfsAcquireSharedFcb ( + IN PIRP_CONTEXT IrpContext, + IN PFCB Fcb, + IN PSCB Scb OPTIONAL, + IN BOOLEAN NoDeleteCheck + ) + +/*++ + +Routine Description: + + This routine acquires shared access to the Fcb. + + This routine will raise if it cannot acquire the resource and wait + in the IrpContext is false. + +Arguments: + + Fcb - Supplies the Fcb to acquire + + Scb - This is the Scb for which we are acquiring the Fcb + + NoDeleteCheck - If TRUE then acquire the file even if it has been deleted. + +Return Value: + + None. + +--*/ + +{ + NTSTATUS Status; + ASSERT_IRP_CONTEXT(IrpContext); + ASSERT_FCB(Fcb); + + Status = STATUS_CANT_WAIT; + + if (ExAcquireResourceShared( Fcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) { + + // + // The link count should be non-zero or the file has been + // deleted. + // + + if (NoDeleteCheck || + (!FlagOn( Fcb->FcbState, FCB_STATE_FILE_DELETED ) && + (!ARGUMENT_PRESENT( Scb ) || + !FlagOn( Scb->ScbState, SCB_STATE_ATTRIBUTE_DELETED )))) { + + // + // It's possible that this is a recursive shared aquisition of an + // Fcb we own exclusively at the top level. In that case we + // need to bump the acquisition count. + // + + if (Fcb->ExclusiveFcbLinks.Flink != NULL) { + + Fcb->BaseExclusiveCount += 1; + } + + return; + } + + // + // We need to release the Fcb and remember the status code. + // + + ExReleaseResource( Fcb->Resource ); + Status = STATUS_FILE_DELETED; + } + + NtfsRaiseStatus( IrpContext, Status, NULL, NULL ); +} + + +VOID +NtfsReleaseFcb ( + IN PIRP_CONTEXT IrpContext, + IN PFCB Fcb + ) + +/*++ + +Routine Description: + + This routine releases the specified Fcb resource. If the Fcb is acquired + exclusive, and a transaction is still active, then the release is nooped + in order to preserve two-phase locking. If there is no longer an active + transaction, then we remove the Fcb from the Exclusive Fcb List off the + IrpContext, and clear the Flink as a sign. Fcbs are released when the + transaction is commited. + +Arguments: + + Fcb - Fcb to release + +Return Value: + + None. + +--*/ + +{ + // + // Check if this resource is owned exclusively and we are at the last + // release for this transaction. + // + + if (Fcb->ExclusiveFcbLinks.Flink != NULL) { + + if (Fcb->BaseExclusiveCount == 1) { + + // + // If there is a transaction then noop this request. + // + + if (IrpContext->TransactionId != 0) { + + return; + } + + RemoveEntryList( &Fcb->ExclusiveFcbLinks ); + Fcb->ExclusiveFcbLinks.Flink = NULL; + + + // + // This is a good time to free any Scb snapshots for this Fcb. + // + + NtfsFreeSnapshotsForFcb( IrpContext, Fcb ); + } + + Fcb->BaseExclusiveCount -= 1; + } + + ASSERT((Fcb->ExclusiveFcbLinks.Flink == NULL && Fcb->BaseExclusiveCount == 0) || + (Fcb->ExclusiveFcbLinks.Flink != NULL && Fcb->BaseExclusiveCount != 0)); + + ExReleaseResource( Fcb->Resource ); +} + + +VOID +NtfsAcquireExclusiveScb ( + IN PIRP_CONTEXT IrpContext, + IN PSCB Scb + ) + +/*++ + +Routine Description: + + This routine acquires exclusive access to the Scb. + + This routine will raise if it cannot acquire the resource and wait + in the IrpContext is false. + +Arguments: + + Scb - Scb to acquire + +Return Value: + + None. + +--*/ + +{ + PAGED_CODE(); + + NtfsAcquireExclusiveFcb( IrpContext, Scb->Fcb, Scb, FALSE, FALSE ); + + ASSERT( Scb->Fcb->ExclusiveFcbLinks.Flink != NULL + || (Scb->Vcb->BitmapScb != NULL + && Scb->Vcb->BitmapScb == Scb) ); + + if (FlagOn(Scb->ScbState, SCB_STATE_FILE_SIZE_LOADED)) { + + NtfsSnapshotScb( IrpContext, Scb ); + } +} + + +VOID +NtfsAcquireSharedScbForTransaction ( + IN PIRP_CONTEXT IrpContext, + IN PSCB Scb + ) + +/*++ + +Routine Description: + + This routine is called to acquire an Scb shared in order to perform updates to + the an Scb stream. This is used if the transaction writes to a range of the + stream without changing the size or position of the data. The caller must + already provide synchronization to the data itself. + + There is no corresponding Scb release. It will be released when the transaction commits. + We will acquire the Scb exclusive if it is not yet in the open attribute table. + +Arguments: + + Scb - Scb to acquire + +Return Value: + + None. + +--*/ + +{ + PSCB *Position; + PSCB *ScbArray; + ULONG Count; + + PAGED_CODE(); + + // + // Make sure we have a free spot in the Scb array in the IrpContext. + // + + if (IrpContext->SharedScb == NULL) { + + Position = (PSCB *) &IrpContext->SharedScb; + IrpContext->SharedScbSize = 1; + + // + // Too bad the first one is not available. If the current size is one then allocate a + // new block and copy the existing value to it. + // + + } else if (IrpContext->SharedScbSize == 1) { + + ScbArray = NtfsAllocatePool( PagedPool, sizeof( PSCB ) * 4 ); + RtlZeroMemory( ScbArray, sizeof( PSCB ) * 4 ); + *ScbArray = IrpContext->SharedScb; + IrpContext->SharedScb = ScbArray; + IrpContext->SharedScbSize = 4; + Position = ScbArray + 1; + + // + // Otherwise look through the existing array and look for a free spot. Allocate a larger + // array if we need to grow it. + // + + } else { + + Position = IrpContext->SharedScb; + Count = IrpContext->SharedScbSize; + + do { + + if (*Position == NULL) { + + break; + } + + Count -= 1; + Position += 1; + + } while (Count != 0); + + // + // If we didn't find one then allocate a new structure. + // + + if (Count == 0) { + + ScbArray = NtfsAllocatePool( PagedPool, sizeof( PSCB ) * IrpContext->SharedScbSize * 2 ); + RtlZeroMemory( ScbArray, sizeof( PSCB ) * IrpContext->SharedScbSize * 2 ); + RtlCopyMemory( ScbArray, + IrpContext->SharedScb, + sizeof( PSCB ) * IrpContext->SharedScbSize ); + + NtfsFreePool( IrpContext->SharedScb ); + IrpContext->SharedScb = ScbArray; + Position = ScbArray + IrpContext->SharedScbSize; + IrpContext->SharedScbSize *= 2; + } + } + + ExAcquireResourceShared( Scb->Header.Resource, TRUE ); + + if (Scb->NonpagedScb->OpenAttributeTableIndex == 0) { + + ExReleaseResource( Scb->Header.Resource ); + ExAcquireResourceExclusive( Scb->Header.Resource, TRUE ); + } + + *Position = Scb; + + return; +} + +VOID +NtfsReleaseSharedResources ( + IN PIRP_CONTEXT IrpContext + ) + +/*++ + +Routine Description: + + The routine releases all of the resources acquired shared for + transaction. The SharedScb structure is freed if necessary and + the Irp Context field is cleared. + +Arguments: + + +Return Value: + + None. + +--*/ +{ + + PAGED_CODE(); + + // + // If only one then free the Scb main resource. + // + + if (IrpContext->SharedScbSize == 1) { + +#ifdef _CAIRO_ + if (SafeNodeType(IrpContext->SharedScb) == NTFS_NTC_QUOTA_CONTROL) { + NtfsReleaseQuotaControl( IrpContext, + (PQUOTA_CONTROL_BLOCK) IrpContext->SharedScb ); + } else { + ExReleaseResource( ((PSCB) IrpContext->SharedScb)->Header.Resource ); + } + +#else + ExReleaseResource( ((PSCB) IrpContext->SharedScb)->Header.Resource ); +#endif // _CAIRO_ + + // + // Otherwise traverse the array and look for Scb's to release. + // + + } else { + + PSCB *NextScb; + ULONG Count; + + NextScb = IrpContext->SharedScb; + Count = IrpContext->SharedScbSize; + + do { + + if (*NextScb != NULL) { + +#ifdef _CAIRO_ + if (SafeNodeType(*NextScb) == NTFS_NTC_QUOTA_CONTROL) { + + NtfsReleaseQuotaControl( IrpContext, + (PQUOTA_CONTROL_BLOCK) *NextScb ); + } else { + + ExReleaseResource( (*NextScb)->Header.Resource ); + } + +#else + ExReleaseResource( (*NextScb)->Header.Resource ); +#endif // _CAIRO_ + + } + + Count -= 1; + NextScb += 1; + + } while (Count != 0); + + NtfsFreePool( IrpContext->SharedScb ); + } + + IrpContext->SharedScb = NULL; + IrpContext->SharedScbSize = 0; + +} + +BOOLEAN +NtfsAcquireVolumeForClose ( + IN PVOID OpaqueVcb, + IN BOOLEAN Wait + ) + +/*++ + +Routine Description: + + The address of this routine is specified when creating a CacheMap for + a file. It is subsequently called by the Lazy Writer prior to its + performing closes to the file. This callback is necessary to + avoid deadlocks with the Lazy Writer. (Note that normal closes + acquire the Vcb, and then call the Cache Manager, who must acquire + some of his internal structures. If the Lazy Writer could not call + this routine first, and were to issue a write after locking Caching + data structures, then a deadlock could occur.) + +Arguments: + + Vcb - The Vcb which was specified as a close context parameter for this + routine. + + Wait - TRUE if the caller is willing to block. + +Return Value: + + FALSE - if Wait was specified as FALSE and blocking would have + been required. The Fcb is not acquired. + + TRUE - if the Vcb has been acquired + +--*/ + +{ + PVCB Vcb = (PVCB)OpaqueVcb; + + ASSERT_VCB(Vcb); + + PAGED_CODE(); + + // + // Do the code of acquire exclusive Vcb but without the IrpContext + // + + if (ExAcquireResourceExclusive( &Vcb->Resource, Wait )) { + + return TRUE; + } + + return FALSE; +} + + +VOID +NtfsReleaseVolumeFromClose ( + IN PVOID OpaqueVcb + ) + +/*++ + +Routine Description: + + The address of this routine is specified when creating a CacheMap for + a file. It is subsequently called by the Lazy Writer after its + performing closes on the file. + +Arguments: + + Vcb - The Vcb which was specified as a close context parameter for this + routine. + +Return Value: + + None + +--*/ + +{ + PVCB Vcb = (PVCB)OpaqueVcb; + + ASSERT_VCB(Vcb); + + PAGED_CODE(); + + NtfsReleaseVcb( NULL, Vcb ); + + return; +} + + +BOOLEAN +NtfsAcquireScbForLazyWrite ( + IN PVOID OpaqueScb, + IN BOOLEAN Wait + ) + +/*++ + +Routine Description: + + The address of this routine is specified when creating a CacheMap for + a file. It is subsequently called by the Lazy Writer prior to its + performing lazy writes to the file. This callback is necessary to + avoid deadlocks with the Lazy Writer. (Note that normal writes + acquire the Fcb, and then call the Cache Manager, who must acquire + some of his internal structures. If the Lazy Writer could not call + this routine first, and were to issue a write after locking Caching + data structures, then a deadlock could occur.) + +Arguments: + + OpaqueScb - The Scb which was specified as a context parameter for this + routine. + + Wait - TRUE if the caller is willing to block. + +Return Value: + + FALSE - if Wait was specified as FALSE and blocking would have + been required. The Fcb is not acquired. + + TRUE - if the Scb has been acquired + +--*/ + +{ + BOOLEAN AcquiredFile = TRUE; + + ULONG CompressedStream = (ULONG)OpaqueScb & 1; + PSCB Scb = (PSCB)((ULONG)OpaqueScb & ~1); + PFCB Fcb = Scb->Fcb; + + ASSERT_SCB(Scb); + + PAGED_CODE(); + + // + // Acquire the Scb only for those files that the write will + // acquire it for, i.e., not the first set of system files. + // Otherwise we can deadlock, for example with someone needing + // a new Mft record. + // + + if (NtfsSegmentNumber( &Fcb->FileReference ) <= MASTER_FILE_TABLE2_NUMBER) { + + // + // We need to synchronize the lazy writer with the clean volume + // checkpoint. We do this by acquiring and immediately releasing this + // Scb. This is to prevent the lazy writer from flushing the log file + // when the space may be at a premium. + // + + if (ExAcquireResourceShared( Scb->Header.Resource, Wait )) { + + ExReleaseResource( Scb->Header.Resource ); + AcquiredFile = TRUE; + } + + // + // Now acquire either the main or paging io resource depending on the + // state of the file. + // + + } else if (Scb->Header.PagingIoResource != NULL) { + AcquiredFile = ExAcquireResourceShared( Scb->Header.PagingIoResource, Wait ); + } else { + AcquiredFile = ExAcquireResourceShared( Scb->Header.Resource, Wait ); + } + + if (AcquiredFile) { + + // + // We assume the Lazy Writer only acquires this Scb once. When he + // has acquired it, then he has eliminated anyone who would extend + // valid data, since they must take out the resource exclusive. + // Therefore, it should be guaranteed that this flag is currently + // clear (the ASSERT), and then we will set this flag, to insure + // that the Lazy Writer will never try to advance Valid Data, and + // also not deadlock by trying to get the Fcb exclusive. + // + + ASSERT( Scb->LazyWriteThread[CompressedStream] == NULL ); + + Scb->LazyWriteThread[CompressedStream] = PsGetCurrentThread(); + + // + // Make Cc top level, so that we will not post or retry on errors. + // (If it is not NULL, it must be one of our internal calls to this + // routine, such as from Restart or Hot Fix.) + // + + if (IoGetTopLevelIrp() == NULL) { + IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); + } + } + + return AcquiredFile; +} + + +VOID +NtfsReleaseScbFromLazyWrite ( + IN PVOID OpaqueScb + ) + +/*++ + +Routine Description: + + The address of this routine is specified when creating a CacheMap for + a file. It is subsequently called by the Lazy Writer after its + performing lazy writes to the file. + +Arguments: + + Scb - The Scb which was specified as a context parameter for this + routine. + +Return Value: + + None + +--*/ + +{ + ULONG CompressedStream = (ULONG)OpaqueScb & 1; + PSCB Scb = (PSCB)((ULONG)OpaqueScb & ~1); + PFCB Fcb = Scb->Fcb; + + ASSERT_SCB(Scb); + + PAGED_CODE(); + + // + // Clear the toplevel at this point, if we set it above. + // + + if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) { + IoSetTopLevelIrp( NULL ); + } + + Scb->LazyWriteThread[CompressedStream] = NULL; + + if (NtfsSegmentNumber( &Fcb->FileReference ) <= MASTER_FILE_TABLE2_NUMBER) { + + NOTHING; + + } else if (Scb->Header.PagingIoResource != NULL) { + ExReleaseResource( Scb->Header.PagingIoResource ); + } else { + ExReleaseResource( Scb->Header.Resource ); + } + + return; +} + + +NTSTATUS +NtfsAcquireFileForModWrite ( + IN PFILE_OBJECT FileObject, + IN PLARGE_INTEGER EndingOffset, + OUT PERESOURCE *ResourceToRelease, + IN PDEVICE_OBJECT DeviceObject + ) + +{ + BOOLEAN AcquiredFile; + + PSCB Scb = (PSCB) (FileObject->FsContext); + PFCB Fcb = Scb->Fcb; + + ASSERT_SCB(Scb); + + UNREFERENCED_PARAMETER( DeviceObject ); + + PAGED_CODE(); + + // + // Acquire the Scb only for those files that the write will + // acquire it for, i.e., not the first set of system files. + // Otherwise we can deadlock, for example with someone needing + // a new Mft record. + // + + if (NtfsSegmentNumber( &Fcb->FileReference ) <= MASTER_FILE_TABLE2_NUMBER) { + + // + // We need to synchronize the lazy writer with the clean volume + // checkpoint. We do this by acquiring and immediately releasing this + // Scb. This is to prevent the lazy writer from flushing the log file + // when the space may be at a premium. + // + + if (AcquiredFile = ExAcquireResourceShared( Scb->Header.Resource, FALSE )) { + ExReleaseResource( Scb->Header.Resource ); + } + *ResourceToRelease = NULL; + + // + // Now acquire either the main or paging io resource depending on the + // state of the file. + // + + } else { + + // + // Figure out which resource to acquire. + // + + if (Scb->Header.PagingIoResource != NULL) { + *ResourceToRelease = Scb->Header.PagingIoResource; + } else { + *ResourceToRelease = Scb->Header.Resource; + } + + // + // Try to acquire the resource with Wait FALSE + // + + AcquiredFile = ExAcquireResourceShared( *ResourceToRelease, FALSE ); + + // + // If we got the resource, check if he is possibly trying to extend + // ValidDataLength. If so that will cause us to go into useless mode + // possibly doing actual I/O writing zeros out to the file past actual + // valid data in the cache. This is so inefficient that it is better + // to tell MM not to do this write. + // + + if (AcquiredFile) { + if (Scb->CompressionUnit != 0) { + ExAcquireFastMutex( Scb->Header.FastMutex ); + if ((EndingOffset->QuadPart > Scb->ValidDataToDisk) && + (EndingOffset->QuadPart < (Scb->Header.FileSize.QuadPart + PAGE_SIZE - 1)) && + !FlagOn(Scb->Header.Flags, FSRTL_FLAG_USER_MAPPED_FILE)) { + + ExReleaseResource(*ResourceToRelease); + AcquiredFile = FALSE; + *ResourceToRelease = NULL; + } + ExReleaseFastMutex( Scb->Header.FastMutex ); + } + } else { + *ResourceToRelease = NULL; + } + } + + return (AcquiredFile ? STATUS_SUCCESS : STATUS_CANT_WAIT); +} + +NTSTATUS +NtfsAcquireFileForCcFlush ( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject + ) +{ + PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext; + + PAGED_CODE(); + + if (Header->PagingIoResource != NULL) { + ExAcquireResourceShared( Header->PagingIoResource, TRUE ); + } + + return STATUS_SUCCESS; + + UNREFERENCED_PARAMETER( DeviceObject ); +} + +NTSTATUS +NtfsReleaseFileForCcFlush ( + IN PFILE_OBJECT FileObject, + IN PDEVICE_OBJECT DeviceObject + ) +{ + PFSRTL_COMMON_FCB_HEADER Header = FileObject->FsContext; + + PAGED_CODE(); + + if (Header->PagingIoResource != NULL) { + ExReleaseResource( Header->PagingIoResource ); + } + + return STATUS_SUCCESS; + + UNREFERENCED_PARAMETER( DeviceObject ); +} + +VOID +NtfsAcquireForCreateSection ( + IN PFILE_OBJECT FileObject + ) + +{ + PSCB Scb = (PSCB)FileObject->FsContext; + + PAGED_CODE(); + + if (Scb->Header.PagingIoResource != NULL) { + + ExAcquireResourceExclusive( Scb->Header.PagingIoResource, TRUE ); + } +} + +VOID +NtfsReleaseForCreateSection ( + IN PFILE_OBJECT FileObject + ) + +{ + PSCB Scb = (PSCB)FileObject->FsContext; + + PAGED_CODE(); + + if (Scb->Header.PagingIoResource != NULL) { + + ExReleaseResource( Scb->Header.PagingIoResource ); + } +} + + +BOOLEAN +NtfsAcquireScbForReadAhead ( + IN PVOID OpaqueScb, + IN BOOLEAN Wait + ) + +/*++ + +Routine Description: + + The address of this routine is specified when creating a CacheMap for + a file. It is subsequently called by the Lazy Writer prior to its + performing read ahead to the file. + +Arguments: + + Scb - The Scb which was specified as a context parameter for this + routine. + + Wait - TRUE if the caller is willing to block. + +Return Value: + + FALSE - if Wait was specified as FALSE and blocking would have + been required. The Fcb is not acquired. + + TRUE - if the Scb has been acquired + +--*/ + +{ + PREAD_AHEAD_THREAD ReadAheadThread; + PVOID CurrentThread; + KIRQL OldIrql; + PSCB Scb = (PSCB)OpaqueScb; + PFCB Fcb = Scb->Fcb; + BOOLEAN AcquiredFile = FALSE; + + ASSERT_SCB(Scb); + + // + // Acquire the Scb only for those files that the read wil + // acquire it for, i.e., not the first set of system files. + // Otherwise we can deadlock, for example with someone needing + // a new Mft record. + // + + if ((Scb->Header.PagingIoResource == NULL) || + ExAcquireResourceShared( Scb->Header.PagingIoResource, Wait )) { + + AcquiredFile = TRUE; + + // + // Add our thread to the read ahead list. + // + + KeAcquireSpinLock( &NtfsData.StrucSupSpinLock, &OldIrql ); + + CurrentThread = (PVOID)PsGetCurrentThread(); + ReadAheadThread = (PREAD_AHEAD_THREAD)NtfsData.ReadAheadThreads.Flink; + + while ((ReadAheadThread != (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) && + (ReadAheadThread->Thread != NULL)) { + + // + // We better not already see ourselves. + // + + ASSERT( ReadAheadThread->Thread != CurrentThread ); + + ReadAheadThread = (PREAD_AHEAD_THREAD)ReadAheadThread->Links.Flink; + } + + // + // If we hit the end of the list, then allocate a new one. Note we + // should have at most one entry per critical worker thread in the + // system. + // + + if (ReadAheadThread == (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) { + + ReadAheadThread = ExAllocatePoolWithTag( NonPagedPool, sizeof(READ_AHEAD_THREAD), 'RftN' ); + + // + // If we failed to allocate an entry, clean up and raise. + // + + if (ReadAheadThread == NULL) { + + KeReleaseSpinLock( &NtfsData.StrucSupSpinLock, OldIrql ); + + if (NtfsSegmentNumber( &Fcb->FileReference ) > VOLUME_DASD_NUMBER) { + + if (Scb->Header.PagingIoResource != NULL) { + ExReleaseResource( Scb->Header.PagingIoResource ); + } + } + + ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); + } + InsertTailList( &NtfsData.ReadAheadThreads, &ReadAheadThread->Links ); + } + + ReadAheadThread->Thread = CurrentThread; + + KeReleaseSpinLock( &NtfsData.StrucSupSpinLock, OldIrql ); + } + + return AcquiredFile; +} + + +VOID +NtfsReleaseScbFromReadAhead ( + IN PVOID OpaqueScb + ) + +/*++ + +Routine Description: + + The address of this routine is specified when creating a CacheMap for + a file. It is subsequently called by the Lazy Writer after its + read ahead. + +Arguments: + + Scb - The Scb which was specified as a context parameter for this + routine. + +Return Value: + + None + +--*/ + +{ + PREAD_AHEAD_THREAD ReadAheadThread; + PVOID CurrentThread; + KIRQL OldIrql; + PSCB Scb = (PSCB)OpaqueScb; + PFCB Fcb = Scb->Fcb; + + ASSERT_SCB(Scb); + + // + // Free our read ahead entry. + // + + KeAcquireSpinLock( &NtfsData.StrucSupSpinLock, &OldIrql ); + + CurrentThread = (PVOID)PsGetCurrentThread(); + ReadAheadThread = (PREAD_AHEAD_THREAD)NtfsData.ReadAheadThreads.Flink; + + while ((ReadAheadThread != (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads) && + (ReadAheadThread->Thread != CurrentThread)) { + + ReadAheadThread = (PREAD_AHEAD_THREAD)ReadAheadThread->Links.Flink; + } + + ASSERT(ReadAheadThread != (PREAD_AHEAD_THREAD)&NtfsData.ReadAheadThreads); + + ReadAheadThread->Thread = NULL; + + // + // Move him to the end of the list so all the allocated entries are at + // the front, and we simplify our scans. + // + + RemoveEntryList( &ReadAheadThread->Links ); + InsertTailList( &NtfsData.ReadAheadThreads, &ReadAheadThread->Links ); + + KeReleaseSpinLock( &NtfsData.StrucSupSpinLock, OldIrql ); + + if (Scb->Header.PagingIoResource != NULL) { + ExReleaseResource( Scb->Header.PagingIoResource ); + } + + return; +} + + +BOOLEAN +NtfsAcquireVolumeFileForClose ( + IN PVOID Null, + IN BOOLEAN Wait + ) + +/*++ + +Routine Description: + + The address of this routine is specified when creating a CacheMap for + the volume file. It is subsequently called by the Lazy Writer prior to its + performing lazy writes to the volume file. This callback may one day be + necessary to avoid deadlocks with the Lazy Writer, however, now + we do not need to acquire any resource for the volume file, + so this routine is simply a noop. + +Arguments: + + Null - Not required. + + Wait - TRUE if the caller is willing to block. + +Return Value: + + TRUE + +--*/ + +{ + UNREFERENCED_PARAMETER( Null ); + UNREFERENCED_PARAMETER( Wait ); + + PAGED_CODE(); + + return TRUE; +} + + +VOID +NtfsReleaseVolumeFileFromClose ( + IN PVOID Null + ) + +/*++ + +Routine Description: + + The address of this routine is specified when creating a CacheMap for + a file. It is subsequently called by the Lazy Writer after its + performing lazy writes to the file. + +Arguments: + + Null - Not required. + +Return Value: + + None + +--*/ + +{ + UNREFERENCED_PARAMETER( Null ); + + PAGED_CODE(); + + return; +} + + + +BOOLEAN +NtfsAcquireVolumeFileForLazyWrite ( + IN PVOID Vcb, + IN BOOLEAN Wait + ) + +/*++ + +Routine Description: + + The address of this routine is specified when creating a CacheMap for + the volume file. It is subsequently called by the Lazy Writer prior to its + performing lazy writes to the volume file. This callback may one day be + necessary to avoid deadlocks with the Lazy Writer, however, now + NtfsCommonWrite does not need to acquire any resource for the volume file, + so this routine is simply a noop. + +Arguments: + + Vcb - The Vcb which was specified as a context parameter for this + routine. + + Wait - TRUE if the caller is willing to block. + +Return Value: + + TRUE + +--*/ + +{ + UNREFERENCED_PARAMETER( Vcb ); + UNREFERENCED_PARAMETER( Wait ); + + PAGED_CODE(); + + return TRUE; +} + + +VOID +NtfsReleaseVolumeFileFromLazyWrite ( + IN PVOID Vcb + ) + +/*++ + +Routine Description: + + The address of this routine is specified when creating a CacheMap for + a file. It is subsequently called by the Lazy Writer after its + performing lazy writes to the file. + +Arguments: + + Vcb - The Vcb which was specified as a context parameter for this + routine. + +Return Value: + + None + +--*/ + +{ + UNREFERENCED_PARAMETER( Vcb ); + + PAGED_CODE(); + + return; +} |