mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
967 lines
23 KiB
C
967 lines
23 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989-2000 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
ResrcSup.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the Fat Resource acquisition routines
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "fatprocs.h"
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, FatAcquireFcbForLazyWrite)
|
|||
|
#pragma alloc_text(PAGE, FatAcquireFcbForReadAhead)
|
|||
|
#pragma alloc_text(PAGE, FatAcquireExclusiveFcb)
|
|||
|
#pragma alloc_text(PAGE, FatAcquireSharedFcb)
|
|||
|
#pragma alloc_text(PAGE, FatAcquireSharedFcbWaitForEx)
|
|||
|
#pragma alloc_text(PAGE, FatAcquireExclusiveVcb_Real)
|
|||
|
#pragma alloc_text(PAGE, FatAcquireSharedVcb)
|
|||
|
#pragma alloc_text(PAGE, FatNoOpAcquire)
|
|||
|
#pragma alloc_text(PAGE, FatNoOpRelease)
|
|||
|
#pragma alloc_text(PAGE, FatReleaseFcbFromLazyWrite)
|
|||
|
#pragma alloc_text(PAGE, FatReleaseFcbFromReadAhead)
|
|||
|
#pragma alloc_text(PAGE, FatAcquireForCcFlush)
|
|||
|
#pragma alloc_text(PAGE, FatReleaseForCcFlush)
|
|||
|
#pragma alloc_text(PAGE, FatFilterCallbackAcquireForCreateSection)
|
|||
|
#endif
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
_When_(return != FALSE && NoOpCheck != FALSE, _Acquires_exclusive_lock_(Vcb->Resource))
|
|||
|
FINISHED
|
|||
|
FatAcquireExclusiveVcb_Real (
|
|||
|
IN PIRP_CONTEXT IrpContext,
|
|||
|
IN PVCB Vcb,
|
|||
|
IN BOOLEAN NoOpCheck
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine acquires exclusive access to the Vcb.
|
|||
|
|
|||
|
After we acquire the resource check to see if this operation is legal.
|
|||
|
If it isn't (ie. we get an exception), release the resource.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Vcb - Supplies the Vcb to acquire
|
|||
|
|
|||
|
NoOpCheck - if TRUE then don't do any verification of the request/volume state.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FINISHED - TRUE if we have the resource and FALSE if we needed to block
|
|||
|
for the resource but Wait is FALSE.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
#ifdef _MSC_VER
|
|||
|
#pragma prefast( suppress: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
|
|||
|
#endif
|
|||
|
if (ExAcquireResourceExclusiveLite( &Vcb->Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
|
|||
|
|
|||
|
if (!NoOpCheck) {
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
FatVerifyOperationIsLegal( IrpContext );
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if ( _SEH2_AbnormalTermination() ) {
|
|||
|
|
|||
|
FatReleaseVcb( IrpContext, Vcb );
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
}
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
_When_(return != 0, _Acquires_shared_lock_(Vcb->Resource))
|
|||
|
FINISHED
|
|||
|
FatAcquireSharedVcb (
|
|||
|
IN PIRP_CONTEXT IrpContext,
|
|||
|
IN PVCB Vcb
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine acquires shared access to the Vcb.
|
|||
|
|
|||
|
After we acquire the resource check to see if this operation is legal.
|
|||
|
If it isn't (ie. we get an exception), release the resource.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Vcb - Supplies the Vcb to acquire
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FINISHED - TRUE if we have the resource and FALSE if we needed to block
|
|||
|
for the resource but Wait is FALSE.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
if (ExAcquireResourceSharedLite( &Vcb->Resource,
|
|||
|
BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
FatVerifyOperationIsLegal( IrpContext );
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if ( _SEH2_AbnormalTermination() ) {
|
|||
|
|
|||
|
FatReleaseVcb( IrpContext, Vcb );
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
_Acquires_exclusive_lock_(*Fcb->Header.Resource)
|
|||
|
FINISHED
|
|||
|
FatAcquireExclusiveFcb (
|
|||
|
IN PIRP_CONTEXT IrpContext,
|
|||
|
IN PFCB Fcb
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine acquires exclusive access to the Fcb.
|
|||
|
|
|||
|
After we acquire the resource check to see if this operation is legal.
|
|||
|
If it isn't (ie. we get an exception), release the resource.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fcb - Supplies the Fcb to acquire
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FINISHED - TRUE if we have the resource and FALSE if we needed to block
|
|||
|
for the resource but Wait is FALSE.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
RetryFcbExclusive:
|
|||
|
|
|||
|
#ifdef _MSC_VER
|
|||
|
#pragma prefast( suppress: 28137, "prefast wants the wait to be a constant, but that isn't possible for the way fastfat is designed" )
|
|||
|
#endif
|
|||
|
if (ExAcquireResourceExclusiveLite( Fcb->Header.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
|
|||
|
|
|||
|
//
|
|||
|
// Check for anything other than a non-cached write if the
|
|||
|
// async count is non-zero in the Fcb, or if others are waiting
|
|||
|
// for the resource. Then wait for all outstanding I/O to finish,
|
|||
|
// drop the resource, and wait again.
|
|||
|
//
|
|||
|
|
|||
|
if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) &&
|
|||
|
((IrpContext->MajorFunction != IRP_MJ_WRITE) ||
|
|||
|
!FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) ||
|
|||
|
(ExGetSharedWaiterCount(Fcb->Header.Resource) != 0) ||
|
|||
|
(ExGetExclusiveWaiterCount(Fcb->Header.Resource) != 0))) {
|
|||
|
|
|||
|
KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
(PLARGE_INTEGER) NULL );
|
|||
|
|
|||
|
FatReleaseFcb( IrpContext, Fcb );
|
|||
|
|
|||
|
goto RetryFcbExclusive;
|
|||
|
}
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
FatVerifyOperationIsLegal( IrpContext );
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if ( _SEH2_AbnormalTermination() ) {
|
|||
|
|
|||
|
FatReleaseFcb( IrpContext, Fcb );
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
_Acquires_shared_lock_(*Fcb->Header.Resource)
|
|||
|
FINISHED
|
|||
|
FatAcquireSharedFcb (
|
|||
|
IN PIRP_CONTEXT IrpContext,
|
|||
|
IN PFCB Fcb
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine acquires shared access to the Fcb.
|
|||
|
|
|||
|
After we acquire the resource check to see if this operation is legal.
|
|||
|
If it isn't (ie. we get an exception), release the resource.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fcb - Supplies the Fcb to acquire
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FINISHED - TRUE if we have the resource and FALSE if we needed to block
|
|||
|
for the resource but Wait is FALSE.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
RetryFcbShared:
|
|||
|
|
|||
|
if (ExAcquireResourceSharedLite( Fcb->Header.Resource, BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT))) {
|
|||
|
|
|||
|
//
|
|||
|
// Check for anything other than a non-cached write if the
|
|||
|
// async count is non-zero in the Fcb, or if others are waiting
|
|||
|
// for the resource. Then wait for all outstanding I/O to finish,
|
|||
|
// drop the resource, and wait again.
|
|||
|
//
|
|||
|
|
|||
|
if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) &&
|
|||
|
((IrpContext->MajorFunction != IRP_MJ_WRITE) ||
|
|||
|
!FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) ||
|
|||
|
(ExGetSharedWaiterCount(Fcb->Header.Resource) != 0) ||
|
|||
|
(ExGetExclusiveWaiterCount(Fcb->Header.Resource) != 0))) {
|
|||
|
|
|||
|
KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
(PLARGE_INTEGER) NULL );
|
|||
|
|
|||
|
FatReleaseFcb( IrpContext, Fcb );
|
|||
|
|
|||
|
goto RetryFcbShared;
|
|||
|
}
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
FatVerifyOperationIsLegal( IrpContext );
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if ( _SEH2_AbnormalTermination() ) {
|
|||
|
|
|||
|
FatReleaseFcb( IrpContext, Fcb );
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
_When_(return != 0, _Acquires_shared_lock_(*Fcb->Header.Resource))
|
|||
|
FINISHED
|
|||
|
FatAcquireSharedFcbWaitForEx (
|
|||
|
IN PIRP_CONTEXT IrpContext,
|
|||
|
IN PFCB Fcb
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine acquires shared access to the Fcb, waiting first for any
|
|||
|
exclusive accessors to get the Fcb first.
|
|||
|
|
|||
|
After we acquire the resource check to see if this operation is legal.
|
|||
|
If it isn't (ie. we get an exception), release the resource.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fcb - Supplies the Fcb to acquire
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
FINISHED - TRUE if we have the resource and FALSE if we needed to block
|
|||
|
for the resource but Wait is FALSE.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
NT_ASSERT( FlagOn(IrpContext->OriginatingIrp->Flags, IRP_NOCACHE) );
|
|||
|
NT_ASSERT( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
|
|||
|
|
|||
|
RetryFcbSharedWaitEx:
|
|||
|
|
|||
|
if (ExAcquireSharedWaitForExclusive( Fcb->Header.Resource, FALSE )) {
|
|||
|
|
|||
|
//
|
|||
|
// Check for anything other than a non-cached write if the
|
|||
|
// async count is non-zero in the Fcb. Then wait for all
|
|||
|
// outstanding I/O to finish, drop the resource, and wait again.
|
|||
|
//
|
|||
|
|
|||
|
if ((Fcb->NonPaged->OutstandingAsyncWrites != 0) &&
|
|||
|
(IrpContext->MajorFunction != IRP_MJ_WRITE)) {
|
|||
|
|
|||
|
KeWaitForSingleObject( Fcb->NonPaged->OutstandingAsyncEvent,
|
|||
|
Executive,
|
|||
|
KernelMode,
|
|||
|
FALSE,
|
|||
|
(PLARGE_INTEGER) NULL );
|
|||
|
|
|||
|
FatReleaseFcb( IrpContext, Fcb );
|
|||
|
|
|||
|
goto RetryFcbSharedWaitEx;
|
|||
|
}
|
|||
|
|
|||
|
_SEH2_TRY {
|
|||
|
|
|||
|
FatVerifyOperationIsLegal( IrpContext );
|
|||
|
|
|||
|
} _SEH2_FINALLY {
|
|||
|
|
|||
|
if ( _SEH2_AbnormalTermination() ) {
|
|||
|
|
|||
|
FatReleaseFcb( IrpContext, Fcb );
|
|||
|
}
|
|||
|
} _SEH2_END;
|
|||
|
|
|||
|
|
|||
|
return TRUE;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
BOOLEAN
|
|||
|
NTAPI
|
|||
|
FatAcquireFcbForLazyWrite (
|
|||
|
IN PVOID Fcb,
|
|||
|
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.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fcb - The Fcb 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 Fcb has been acquired
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Check here for the EA File. It turns out we need the normal
|
|||
|
// resource shared in this case. Otherwise we take the paging
|
|||
|
// I/O resource shared.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Note that we do not need to disable APC delivery to guard
|
|||
|
// against a rogue user issuing a suspend APC. That is because
|
|||
|
// it is guaranteed that the caller is either in the system context,
|
|||
|
// to which a user cannot deliver a suspend APC, or the caller has
|
|||
|
// already disabled kernel APC delivery before calling. This is true
|
|||
|
// for all the other pre-acquire routines as well.
|
|||
|
//
|
|||
|
|
|||
|
if (!ExAcquireResourceSharedLite( Fcb == ((PFCB)Fcb)->Vcb->EaFcb ?
|
|||
|
((PFCB)Fcb)->Header.Resource :
|
|||
|
((PFCB)Fcb)->Header.PagingIoResource,
|
|||
|
Wait )) {
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// We assume the Lazy Writer only acquires this Fcb once.
|
|||
|
// 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.
|
|||
|
//
|
|||
|
|
|||
|
|
|||
|
NT_ASSERT( NodeType(((PFCB)Fcb)) == FAT_NTC_FCB );
|
|||
|
NT_ASSERT( ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread == NULL );
|
|||
|
|
|||
|
((PFCB)Fcb)->Specific.Fcb.LazyWriteThread = PsGetCurrentThread();
|
|||
|
|
|||
|
NT_ASSERT( NULL != PsGetCurrentThread() );
|
|||
|
|
|||
|
if (NULL == FatData.LazyWriteThread) {
|
|||
|
|
|||
|
FatData.LazyWriteThread = PsGetCurrentThread();
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This is a kludge because Cc is really the top level. When it
|
|||
|
// enters the file system, we will think it is a resursive call
|
|||
|
// and complete the request with hard errors or verify. It will
|
|||
|
// then have to deal with them, somehow....
|
|||
|
//
|
|||
|
|
|||
|
NT_ASSERT(IoGetTopLevelIrp() == NULL);
|
|||
|
|
|||
|
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
VOID
|
|||
|
NTAPI
|
|||
|
FatReleaseFcbFromLazyWrite (
|
|||
|
IN PVOID Fcb
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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:
|
|||
|
|
|||
|
Fcb - The Fcb which was specified as a context parameter for this
|
|||
|
routine.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Assert that this really is an fcb and that this thread really owns
|
|||
|
// the lazy writer mark in the fcb.
|
|||
|
//
|
|||
|
|
|||
|
NT_ASSERT( NodeType(((PFCB)Fcb)) == FAT_NTC_FCB );
|
|||
|
NT_ASSERT( NULL != PsGetCurrentThread() );
|
|||
|
NT_ASSERT( ((PFCB)Fcb)->Specific.Fcb.LazyWriteThread == PsGetCurrentThread() );
|
|||
|
|
|||
|
//
|
|||
|
// Release the lazy writer mark.
|
|||
|
//
|
|||
|
|
|||
|
((PFCB)Fcb)->Specific.Fcb.LazyWriteThread = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Check here for the EA File. It turns out we needed the normal
|
|||
|
// resource shared in this case. Otherwise it was the PagingIoResource.
|
|||
|
//
|
|||
|
|
|||
|
ExReleaseResourceLite( Fcb == ((PFCB)Fcb)->Vcb->EaFcb ?
|
|||
|
((PFCB)Fcb)->Header.Resource :
|
|||
|
((PFCB)Fcb)->Header.PagingIoResource );
|
|||
|
|
|||
|
//
|
|||
|
// Clear the kludge at this point.
|
|||
|
//
|
|||
|
|
|||
|
NT_ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
|||
|
|
|||
|
IoSetTopLevelIrp( NULL );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
BOOLEAN
|
|||
|
NTAPI
|
|||
|
FatAcquireFcbForReadAhead (
|
|||
|
IN PVOID Fcb,
|
|||
|
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:
|
|||
|
|
|||
|
Fcb - The Fcb 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 Fcb has been acquired
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// We acquire the normal file resource shared here to synchronize
|
|||
|
// correctly with purges.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Note that we do not need to disable APC delivery to guard
|
|||
|
// against a rogue user issuing a suspend APC. That is because
|
|||
|
// it is guaranteed that the caller is either in the system context,
|
|||
|
// to which a user cannot deliver a suspend APC, or the caller has
|
|||
|
// already disabled kernel APC delivery before calling. This is true
|
|||
|
// for all the other pre-acquire routines as well.
|
|||
|
//
|
|||
|
|
|||
|
if (!ExAcquireResourceSharedLite( ((PFCB)Fcb)->Header.Resource,
|
|||
|
Wait )) {
|
|||
|
|
|||
|
return FALSE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// This is a kludge because Cc is really the top level. We it
|
|||
|
// enters the file system, we will think it is a resursive call
|
|||
|
// and complete the request with hard errors or verify. It will
|
|||
|
// have to deal with them, somehow....
|
|||
|
//
|
|||
|
|
|||
|
NT_ASSERT(IoGetTopLevelIrp() == NULL);
|
|||
|
|
|||
|
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
VOID
|
|||
|
NTAPI
|
|||
|
FatReleaseFcbFromReadAhead (
|
|||
|
IN PVOID Fcb
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
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:
|
|||
|
|
|||
|
Fcb - The Fcb which was specified as a context parameter for this
|
|||
|
routine.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Clear the kludge at this point.
|
|||
|
//
|
|||
|
|
|||
|
NT_ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
|||
|
|
|||
|
IoSetTopLevelIrp( NULL );
|
|||
|
|
|||
|
ExReleaseResourceLite( ((PFCB)Fcb)->Header.Resource );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
_Function_class_(FAST_IO_ACQUIRE_FOR_CCFLUSH)
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
NTSTATUS
|
|||
|
NTAPI
|
|||
|
FatAcquireForCcFlush (
|
|||
|
IN PFILE_OBJECT FileObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
)
|
|||
|
{
|
|||
|
PFCB Fcb;
|
|||
|
PCCB Ccb;
|
|||
|
PVCB Vcb;
|
|||
|
PFSRTL_COMMON_FCB_HEADER Header;
|
|||
|
TYPE_OF_OPEN Type;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
UNREFERENCED_PARAMETER( DeviceObject );
|
|||
|
|
|||
|
//
|
|||
|
// Once again, the hack for making this look like
|
|||
|
// a recursive call if needed. We cannot let ourselves
|
|||
|
// verify under something that has resources held.
|
|||
|
//
|
|||
|
// This value is good. We should never try to acquire
|
|||
|
// the file this way underneath of the cache.
|
|||
|
//
|
|||
|
|
|||
|
NT_ASSERT( IoGetTopLevelIrp() != (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP );
|
|||
|
|
|||
|
if (IoGetTopLevelIrp() == NULL) {
|
|||
|
|
|||
|
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Time for some exposition.
|
|||
|
//
|
|||
|
// Lockorder for FAT is main->bcb->pagingio. Invert this at your obvious peril.
|
|||
|
// The default logic for AcquireForCcFlush breaks this since in writethrough
|
|||
|
// unpinrepinned we will grab the bcb then Mm will use the callback (which
|
|||
|
// orders us with respect to the MmCollidedFlushEvent) to help us. If for
|
|||
|
// directories/ea we then grab the main we are out of order.
|
|||
|
//
|
|||
|
// Fortunately, we do not need main. We only need paging - just look at the write
|
|||
|
// path. This is basic pre-acquisition.
|
|||
|
//
|
|||
|
// Regular files require both resources, and are safe since we never pin them.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Note that we do not need to disable APC delivery to guard
|
|||
|
// against a rogue user issuing a suspend APC. That is because
|
|||
|
// it is guaranteed that the caller is either in the system context,
|
|||
|
// to which a user cannot deliver a suspend APC, or the caller has
|
|||
|
// already disabled kernel APC delivery before calling. This is true
|
|||
|
// for all the other pre-acquire routines as well.
|
|||
|
//
|
|||
|
|
|||
|
Type = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
|
|||
|
Header = (PFSRTL_COMMON_FCB_HEADER) FileObject->FsContext;
|
|||
|
|
|||
|
if (Type < DirectoryFile) {
|
|||
|
|
|||
|
if (Header->Resource) {
|
|||
|
|
|||
|
if (!ExIsResourceAcquiredSharedLite( Header->Resource )) {
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite( Header->Resource, TRUE );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
ExAcquireResourceSharedLite( Header->Resource, TRUE );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Header->PagingIoResource) {
|
|||
|
|
|||
|
ExAcquireResourceSharedLite( Header->PagingIoResource, TRUE );
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
NTSTATUS
|
|||
|
NTAPI
|
|||
|
FatReleaseForCcFlush (
|
|||
|
IN PFILE_OBJECT FileObject,
|
|||
|
IN PDEVICE_OBJECT DeviceObject
|
|||
|
)
|
|||
|
{
|
|||
|
PFCB Fcb;
|
|||
|
PCCB Ccb;
|
|||
|
PVCB Vcb;
|
|||
|
PFSRTL_COMMON_FCB_HEADER Header;
|
|||
|
TYPE_OF_OPEN Type;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
UNREFERENCED_PARAMETER( DeviceObject );
|
|||
|
|
|||
|
//
|
|||
|
// Clear up our hint.
|
|||
|
//
|
|||
|
|
|||
|
if (IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP) {
|
|||
|
|
|||
|
IoSetTopLevelIrp( NULL );
|
|||
|
}
|
|||
|
|
|||
|
Type = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );
|
|||
|
Header = (PFSRTL_COMMON_FCB_HEADER) FileObject->FsContext;
|
|||
|
|
|||
|
if (Type < DirectoryFile) {
|
|||
|
|
|||
|
if (Header->Resource) {
|
|||
|
|
|||
|
ExReleaseResourceLite( Header->Resource );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (Header->PagingIoResource) {
|
|||
|
|
|||
|
ExReleaseResourceLite( Header->PagingIoResource );
|
|||
|
}
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
BOOLEAN
|
|||
|
NTAPI
|
|||
|
FatNoOpAcquire (
|
|||
|
IN PVOID Fcb,
|
|||
|
IN BOOLEAN Wait
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine does nothing.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fcb - The Fcb/Dcb/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( Fcb );
|
|||
|
UNREFERENCED_PARAMETER( Wait );
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// This is a kludge because Cc is really the top level. We it
|
|||
|
// enters the file system, we will think it is a resursive call
|
|||
|
// and complete the request with hard errors or verify. It will
|
|||
|
// have to deal with them, somehow....
|
|||
|
//
|
|||
|
|
|||
|
NT_ASSERT(IoGetTopLevelIrp() == NULL);
|
|||
|
|
|||
|
IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
|||
|
|
|||
|
return TRUE;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
NTAPI
|
|||
|
FatNoOpRelease (
|
|||
|
IN PVOID Fcb
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine does nothing.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Fcb - The Fcb/Dcb/Vcb which was specified as a context parameter for this
|
|||
|
routine.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
//
|
|||
|
// Clear the kludge at this point.
|
|||
|
//
|
|||
|
|
|||
|
NT_ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP);
|
|||
|
|
|||
|
IoSetTopLevelIrp( NULL );
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( Fcb );
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
_Requires_lock_held_(_Global_critical_region_)
|
|||
|
NTSTATUS
|
|||
|
NTAPI
|
|||
|
FatFilterCallbackAcquireForCreateSection (
|
|||
|
IN PFS_FILTER_CALLBACK_DATA CallbackData,
|
|||
|
OUT PVOID *CompletionContext
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the callback routine for MM to use to acquire the file exclusively.
|
|||
|
|
|||
|
NOTE: This routine expects the default FSRTL routine to be used to release
|
|||
|
the resource. If this routine is ever changed to acquire something
|
|||
|
other than main, a corresponding release routine will be required.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
FS_FILTER_CALLBACK_DATA - Filter based callback data that provides the file object we
|
|||
|
want to acquire.
|
|||
|
|
|||
|
CompletionContext - Ignored.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
On success we return STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY.
|
|||
|
|
|||
|
If SyncType is SyncTypeCreateSection, we return a status that indicates whether there
|
|||
|
are any writers to this file. Note that main is acquired, so new handles cannot be opened.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PFCB Fcb;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
NT_ASSERT( CallbackData->Operation == FS_FILTER_ACQUIRE_FOR_SECTION_SYNCHRONIZATION );
|
|||
|
NT_ASSERT( CallbackData->SizeOfFsFilterCallbackData == sizeof(FS_FILTER_CALLBACK_DATA) );
|
|||
|
|
|||
|
//
|
|||
|
// Grab the Fcb from the callback data file object.
|
|||
|
//
|
|||
|
|
|||
|
Fcb = CallbackData->FileObject->FsContext;
|
|||
|
|
|||
|
//
|
|||
|
// Take main exclusive.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Note that we do not need to disable APC delivery to guard
|
|||
|
// against a rogue user issuing a suspend APC. That is because
|
|||
|
// it is guaranteed that the caller is either in the system context,
|
|||
|
// to which a user cannot deliver a suspend APC, or the caller has
|
|||
|
// already disabled kernel APC delivery before calling. This is true
|
|||
|
// for all the other pre-acquire routines as well.
|
|||
|
//
|
|||
|
|
|||
|
if (Fcb->Header.Resource) {
|
|||
|
|
|||
|
ExAcquireResourceExclusiveLite( Fcb->Header.Resource, TRUE );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Return the appropriate status based on the type of synchronization and whether anyone
|
|||
|
// has write access to this file.
|
|||
|
//
|
|||
|
|
|||
|
if (CallbackData->Parameters.AcquireForSectionSynchronization.SyncType != SyncTypeCreateSection) {
|
|||
|
|
|||
|
return STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY;
|
|||
|
|
|||
|
} else if (Fcb->ShareAccess.Writers == 0) {
|
|||
|
|
|||
|
return STATUS_FILE_LOCKED_WITH_ONLY_READERS;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
return STATUS_FILE_LOCKED_WITH_WRITERS;
|
|||
|
}
|
|||
|
|
|||
|
UNREFERENCED_PARAMETER( CompletionContext );
|
|||
|
}
|
|||
|
|