|
|
/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
FilObSup.c
Abstract:
This module implements the Rx File object support routines.
Author:
Gary Kimura [GaryKi] 30-Aug-1990
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// The Bug check file id for this module
//
#define BugCheckFileId (RDBSS_BUG_CHECK_FILOBSUP)
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_FILOBSUP)
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RxForceCacheMiss)
//#pragma alloc_text(PAGE, RxPurgeReferencedFileObjects)
#pragma alloc_text(PAGE, RxSetFileObject)
//#pragma alloc_text(PAGE, RxDecodeFileObject)
#endif
VOID RxSetFileObject ( IN PFILE_OBJECT FileObject OPTIONAL, IN TYPE_OF_OPEN TypeOfOpen, IN PVOID VcbOrFcbOrDcb, IN PFOBX Fobx OPTIONAL )
/*++
Routine Description:
This routine sets the file system pointers within the file object
Arguments:
FileObject - Supplies a pointer to the file object being modified, and can optionally be null.
TypeOfOpen - Supplies the type of open denoted by the file object. This is only used by this procedure for sanity checking. //joejoe i disabled this because i'm not using the same open types
VcbOrFcbOrDcb - Supplies a pointer to either a vcb, fcb, or dcb
Fobx - Optionally supplies a pointer to a ccb
Return Value:
None.
--*/
{ RxDbgTrace(+1, Dbg, ("RxSetFileObject, FileObject = %08lx\n", FileObject ));
ASSERT((Fobx == NULL) || (NodeType(Fobx) == RDBSS_NTC_FOBX));
/*
ASSERT(((TypeOfOpen == UnopenedFileObject))
||
((TypeOfOpen == UserFileOpen) && (NodeType(VcbOrFcbOrDcb) == RDBSS_NTC_FCB) && (Fobx != NULL))
||
((TypeOfOpen == EaFile) && (NodeType(VcbOrFcbOrDcb) == RDBSS_NTC_FCB) && (Fobx == NULL))
||
((TypeOfOpen == UserDirectoryOpen) && ((NodeType(VcbOrFcbOrDcb) == RDBSS_NTC_DCB) || (NodeType(VcbOrFcbOrDcb) == RDBSS_NTC_ROOT_DCB)) && (Fobx != NULL))
||
((TypeOfOpen == UserVolumeOpen) && (NodeType(VcbOrFcbOrDcb) == RDBSS_NTC_VCB) && (Fobx != NULL))
||
((TypeOfOpen == VirtualVolumeFile) && (NodeType(VcbOrFcbOrDcb) == RDBSS_NTC_VCB) && (Fobx == NULL))
||
((TypeOfOpen == DirectoryFile) && ((NodeType(VcbOrFcbOrDcb) == RDBSS_NTC_DCB) || (NodeType(VcbOrFcbOrDcb) == RDBSS_NTC_ROOT_DCB)) && (Fobx == NULL))); */
//
// If we were given an Fcb, Dcb, or Vcb, we have some processing to do.
//
ASSERT((Fobx == NULL) || (NodeType(Fobx) == RDBSS_NTC_FOBX));
if ( VcbOrFcbOrDcb != NULL ) {
//
// Set the Vpb field in the file object, and if we were given an
// Fcb or Dcb move the field over to point to the nonpaged Fcb/Dcb
//
if (NodeType(VcbOrFcbOrDcb) == RDBSS_NTC_VCB) {
NOTHING; //FileObject->Vpb = ((PVCB)VcbOrFcbOrDcb)->Vpb;
} else {
//joejoe we don't do vpbs
//FileObject->Vpb = ((PFCB)VcbOrFcbOrDcb)->Vcb->Vpb;
//
// If this is a temporary file, note it in the FcbState
//
if (FlagOn(((PFCB)VcbOrFcbOrDcb)->FcbState, FCB_STATE_TEMPORARY)) {
SetFlag(FileObject->Flags, FO_TEMPORARY_FILE); } } }
ASSERT((Fobx == NULL) || (NodeType(Fobx) == RDBSS_NTC_FOBX));
//
// Now set the fscontext fields of the file object
//
if (ARGUMENT_PRESENT( FileObject )) {
FileObject->FsContext = VcbOrFcbOrDcb; FileObject->FsContext2 = Fobx; }
ASSERT((Fobx == NULL) || (NodeType(Fobx) == RDBSS_NTC_FOBX));
//
// And return to our caller
//
RxDbgTrace(-1, Dbg, ("RxSetFileObject -> VOID\n", 0));
return; }
#if 0
TYPE_OF_OPEN RxDecodeFileObject ( IN PFILE_OBJECT FileObject, OUT PVCB *Vcb, OUT PFCB *FcbOrDcb, OUT PFOBX *Fobx )
/*++
Routine Description:
This procedure takes a pointer to a file object, that has already been opened by the Rx file system and figures out what really is opened.
Arguments:
FileObject - Supplies the file object pointer being interrogated
Vcb - Receives a pointer to the Vcb for the file object.
FcbOrDcb - Receives a pointer to the Fcb/Dcb for the file object, if one exists.
Fobx - Receives a pointer to the Fobx for the file object, if one exists.
Return Value:
TYPE_OF_OPEN - returns the type of file denoted by the input file object.
UserFileOpen - The FO represents a user's opened data file. Fobx, FcbOrDcb, and Vcb are set. FcbOrDcb points to an Fcb.
UserDirectoryOpen - The FO represents a user's opened directory. Fobx, FcbOrDcb, and Vcb are set. FcbOrDcb points to a Dcb/RootDcb
UserVolumeOpen - The FO represents a user's opened volume. Fobx and Vcb are set. FcbOrDcb is null.
VirtualVolumeFile - The FO represents the special virtual volume file. Vcb is set, and Fobx and FcbOrDcb are null.
DirectoryFile - The FO represents a special directory file. Vcb and FcbOrDcb are set. Fobx is null. FcbOrDcb points to a Dcb/RootDcb.
EaFile - The FO represents an Ea Io stream file. FcbOrDcb, and Vcb are set. FcbOrDcb points to an Fcb, and Fobx is null.
--*/
{ TYPE_OF_OPEN TypeOfOpen; PVOID FsContext; PVOID FsContext2;
RxDbgTrace(+1, Dbg, ("RxDecodeFileObject, FileObject = %08lx\n", FileObject));
//
// Reference the fs context fields of the file object, and zero out
// the out pointer parameters.
//
FsContext = FileObject->FsContext; FsContext2 = FileObject->FsContext2;
//
// Special case the situation where FsContext is null
//
if (FsContext == NULL) {
*Fobx = NULL; *FcbOrDcb = NULL; *Vcb = NULL;
TypeOfOpen = UnopenedFileObject;
} else {
//
// Now we can case on the node type code of the fscontext pointer
// and set the appropriate out pointers
//
switch (NodeType(FsContext)) {
case RDBSS_NTC_VCB:
*Fobx = FsContext2; *FcbOrDcb = NULL; *Vcb = FsContext;
TypeOfOpen = ( *Fobx == NULL ? VirtualVolumeFile : UserVolumeOpen );
break;
case RDBSS_NTC_ROOT_DCB: case RDBSS_NTC_DCB:
*Fobx = FsContext2; *FcbOrDcb = FsContext; *Vcb = (*FcbOrDcb)->Vcb;
TypeOfOpen = ( *Fobx == NULL ? DirectoryFile : UserDirectoryOpen );
RxDbgTrace(0, Dbg, ("Referencing directory: %wZ\n", &(*FcbOrDcb)->FullFileName));
break;
case RDBSS_NTC_FCB:
*Fobx = FsContext2; *FcbOrDcb = FsContext; *Vcb = (*FcbOrDcb)->Vcb;
TypeOfOpen = ( *Fobx == NULL ? EaFile : UserFileOpen );
RxDbgTrace(0, Dbg, ("Referencing file: %wZ\n", &(*FcbOrDcb)->FullFileName));
break;
default:
RxBugCheck( NodeType(FsContext), 0, 0 ); } }
//
// and return to our caller
//
RxDbgTrace(-1, Dbg, ("RxDecodeFileObject -> %08lx\n", TypeOfOpen));
return TypeOfOpen; }
VOID RxPurgeReferencedFileObjects ( IN PRX_CONTEXT RxContext, IN PFCB Fcb, IN BOOLEAN FlushFirst )
/*++
Routine Description:
This routine non-recursively walks from the given FcbOrDcb and trys to force Cc or Mm to close any sections it may be holding on to.
Arguments:
Fcb - Supplies a pointer to either an fcb or a dcb
FlushFirst - If given as TRUE, then the files are flushed before they are purged.
Return Value:
None.
--*/
{ PFCB OriginalFcb = Fcb; PFCB NextFcb;
RxDbgTrace(+1, Dbg, ("RxPurgeReferencedFileObjects, Fcb = %08lx\n", Fcb ));
ASSERT(FALSE); //this shouldn't happen in the rdr.....it may play with volume opens
ASSERT( FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT) );
//close //
//close // First, if we have a delayed close, force it closed.
//close //
//close
//close RxFspClose(Fcb->Vcb);
//
// Walk the directory tree forcing sections closed.
//
// Note that it very important to get the next node to visit before
// acting on the current node. This is because acting on a node may
// make it, and an arbitrary number of direct ancestors, vanish.
// Since we never visit ancestors in our enumeration scheme, we can
// safely continue the enumeration even when the tree is vanishing
// beneath us. This is way cool.
//
while ( Fcb != NULL ) {
NextFcb = RxGetNextFcb(RxContext, Fcb, OriginalFcb);
//
// Check for the EA file fcb
//
if ( !FlagOn(Fcb->DirentRxFlags, RDBSS_DIRENT_ATTR_VOLUME_ID) ) {
RxForceCacheMiss( RxContext, Fcb, FlushFirst ); }
Fcb = NextFcb; }
RxDbgTrace(-1, Dbg, ("RxPurgeReferencedFileObjects (VOID)\n", 0 ));
return; } #endif
VOID RxForceCacheMiss ( IN PRX_CONTEXT RxContext, IN PFCB Fcb, IN BOOLEAN FlushFirst )
/*++
Routine Description:
The following routine asks either Cc or Mm to get rid of any cached pages on a file. Note that this will fail if a user has mapped a file.
If there is a shared cache map, purge the cache section. Otherwise we have to go and ask Mm to blow away the section.
NOTE: This caller MUST own the Vcb exclusive.
Arguments:
Fcb - Supplies a pointer to an fcb
FlushFirst - If given as TRUE, then the files are flushed before they are purged.
Return Value:
None.
--*/
{ PVCB Vcb; BOOLEAN ChildrenAcquired = FALSE;
//
// If we can't wait, bail.
//
ASSERT( RxVcbAcquiredExclusive( RxContext, Fcb->Vcb ) || FlagOn( Fcb->Vcb->VcbState, VCB_STATE_FLAG_LOCKED ) );
if (!FlagOn(RxContext->Flags, RX_CONTEXT_FLAG_WAIT)) {
RxRaiseStatus( RxContext, RxStatus(CANT_WAIT) ); }
(VOID)RxAcquireExclusiveFcb( RxContext, Fcb );
//
// If we are purging a directory file object, we must acquire all the
// FCBs exclusive so that the parent directory is not being pinned.
//
if ((NodeType(Fcb) != RDBSS_NTC_FCB) && !IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) {
PLIST_ENTRY Links; PFCB TempFcb;
ChildrenAcquired = TRUE;
for (Links = Fcb->Specific.Dcb.ParentDcbQueue.Flink; Links != &Fcb->Specific.Dcb.ParentDcbQueue; Links = Links->Flink) {
TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
(VOID)RxAcquireExclusiveFcb( RxContext, TempFcb ); } }
//
// We use this flag to indicate to a close beneath us that
// the Fcb resource should be freed before deleting the Fcb.
//
Vcb = Fcb->Vcb;
SetFlag( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS );
ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
try {
BOOLEAN DataSectionExists; BOOLEAN ImageSectionExists;
PSECTION_OBJECT_POINTERS Section;
if ( FlushFirst ) {
(VOID)RxFlushFile( RxContext, Fcb ); }
//
// The Flush may have made the Fcb go away
//
if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB)) {
Section = &Fcb->NonPaged->SectionObjectPointers;
DataSectionExists = (BOOLEAN)(Section->DataSectionObject != NULL); ImageSectionExists = (BOOLEAN)(Section->ImageSectionObject != NULL);
//
// Note, it is critical to do the Image section first as the
// purge of the data section may cause the image section to go
// away, but the opposite is not true.
//
if (ImageSectionExists) {
(VOID)MmFlushImageSection( Section, MmFlushForWrite ); }
if (DataSectionExists) {
CcPurgeCacheSection( Section, NULL, 0, FALSE ); } }
} finally {
//
// If we purging a directory file object, release all the Fcb
// resources that we acquired above. The Dcb cannot have vanished
// if there were Fcbs underneath it, and the Fcbs couldn't have gone
// away since I own the Vcb.
//
if (ChildrenAcquired) {
PLIST_ENTRY Links; PFCB TempFcb;
for (Links = Fcb->Specific.Dcb.ParentDcbQueue.Flink; Links != &Fcb->Specific.Dcb.ParentDcbQueue; Links = Links->Flink) {
TempFcb = CONTAINING_RECORD( Links, FCB, ParentDcbLinks );
RxReleaseFcb( RxContext, TempFcb ); } }
//
// Since we have the Vcb exclusive we know that if any closes
// come in it is because the CcPurgeCacheSection caused the
// Fcb to go away. Also in close, the Fcb was released
// before being freed.
//
if ( !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB) ) {
ClearFlag( Fcb->FcbState, FCB_STATE_FORCE_MISS_IN_PROGRESS );
RxReleaseFcb( (RXCONTEXT), Fcb ); } } }
|