/*++ Copyright (c) 1996-2000 Microsoft Corporation Module Name: ResrcSup.c Abstract: This module implements the Udfs Resource acquisition routines // @@BEGIN_DDKSPLIT Author: Dan Lovinger [DanLo] 10-Jul-1996 Tom Jolly [tomjolly] 21-Jan-2000 Revision History: // @@END_DDKSPLIT --*/ #include "UdfProcs.h" // // The Bug check file id for this module // #define BugCheckFileId (UDFS_BUG_CHECK_RESRCSUP) // // The local debug trace level // #define Dbg (UDFS_DEBUG_LEVEL_RESRCSUP) #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, UdfAcquireForCache) #pragma alloc_text(PAGE, UdfAcquireForCreateSection) #pragma alloc_text(PAGE, UdfAcquireResource) #pragma alloc_text(PAGE, UdfNoopAcquire) #pragma alloc_text(PAGE, UdfNoopRelease) #pragma alloc_text(PAGE, UdfReleaseForCreateSection) #pragma alloc_text(PAGE, UdfReleaseFromCache) #endif BOOLEAN UdfAcquireResource ( IN PIRP_CONTEXT IrpContext, IN PERESOURCE Resource, IN BOOLEAN IgnoreWait, IN TYPE_OF_ACQUIRE Type ) /*++ Routine Description: This is the single routine used to acquire file system resources. It looks at the IgnoreWait flag to determine whether to try to acquire the resource without waiting. Returning TRUE/FALSE to indicate success or failure. Otherwise it is driven by the WAIT flag in the IrpContext and will raise CANT_WAIT on a failure. Arguments: Resource - This is the resource to try and acquire. IgnoreWait - If TRUE then this routine will not wait to acquire the resource and will return a boolean indicating whether the resource was acquired. Otherwise we use the flag in the IrpContext and raise if the resource is not acquired. Type - Indicates how we should try to get the resource. Return Value: BOOLEAN - TRUE if the resource is acquired. FALSE if not acquired and IgnoreWait is specified. Otherwise we raise CANT_WAIT. --*/ { BOOLEAN Wait = FALSE; BOOLEAN Acquired; PAGED_CODE(); // // We look first at the IgnoreWait flag, next at the flag in the Irp // Context to decide how to acquire this resource. // if (!IgnoreWait && FlagOn( IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT )) { Wait = TRUE; } // // Attempt to acquire the resource either shared or exclusively. // switch (Type) { case AcquireExclusive: Acquired = ExAcquireResourceExclusiveLite( Resource, Wait ); break; case AcquireShared: Acquired = ExAcquireResourceSharedLite( Resource, Wait ); break; case AcquireSharedStarveExclusive: Acquired = ExAcquireSharedStarveExclusive( Resource, Wait ); break; default: ASSERT( FALSE ); Acquired = FALSE; } // // If not acquired and the user didn't specifiy IgnoreWait then // raise CANT_WAIT. // if (!Acquired && !IgnoreWait) { UdfRaiseStatus( IrpContext, STATUS_CANT_WAIT ); } return Acquired; } BOOLEAN UdfAcquireForCache ( IN PFCB 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 for synchronization. Arguments: Fcb - The pointer supplied as context to the cache initialization routine. Wait - TRUE if the caller is willing to block. Return Value: None --*/ { PAGED_CODE(); ASSERT(IoGetTopLevelIrp() == NULL); IoSetTopLevelIrp((PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); return ExAcquireResourceSharedLite( Fcb->Resource, Wait ); } VOID UdfReleaseFromCache ( IN PFCB Fcb ) /*++ Routine Description: The address of this routine is specified when creating a CacheMap for a virtual file. It is subsequently called by the Lazy Writer to release a resource acquired above. Arguments: Fcb - The pointer supplied as context to the cache initialization routine. Return Value: None --*/ { PAGED_CODE(); ASSERT(IoGetTopLevelIrp() == (PIRP)FSRTL_CACHE_TOP_LEVEL_IRP); IoSetTopLevelIrp( NULL ); ExReleaseResourceLite( Fcb->Resource ); } BOOLEAN UdfNoopAcquire ( IN PVOID Fcb, IN BOOLEAN Wait ) /*++ Routine Description: This routine does nothing. Arguments: Fcb - The Fcb/Vcb which was specified as a context parameter for this routine. Wait - TRUE if the caller is willing to block. Return Value: TRUE --*/ { PAGED_CODE(); return TRUE; } VOID UdfNoopRelease ( IN PVOID Fcb ) /*++ Routine Description: This routine does nothing. Arguments: Fcb - The Fcb/Vcb which was specified as a context parameter for this routine. Return Value: None --*/ { PAGED_CODE(); } VOID UdfAcquireForCreateSection ( IN PFILE_OBJECT FileObject ) /*++ Routine Description: This is the callback routine for MM to use to acquire the file exclusively. Arguments: FileObject - File object for a Udffs stream. Return Value: None --*/ { PAGED_CODE(); // // Get the Fcb resource exclusively. // ExAcquireResourceExclusiveLite( &((PFCB) FileObject->FsContext)->FcbNonpaged->FcbResource, TRUE ); // // Take the File resource shared. We need this later on when MM calls // QueryStandardInfo to get the file size. // // If we don't use StarveExclusive, then we can get wedged behind an // exclusive waiter who is waiting on someone else holding it shared in the // read->initializecachemap path (which calls createsection) who is in turn // waiting on us to finish the create section. // ExAcquireSharedStarveExclusive( ((PFCB) FileObject->FsContext)->Resource, TRUE ); } VOID UdfReleaseForCreateSection ( IN PFILE_OBJECT FileObject ) /*++ Routine Description: This is the callback routine for MM to use to release a file acquired with the AcquireForCreateSection call above. Arguments: FileObject - File object for a Udffs stream. Return Value: None --*/ { PAGED_CODE(); // // Release the resources. // ExReleaseResourceLite( &((PFCB) FileObject->FsContext)->FcbNonpaged->FcbResource ); ExReleaseResourceLite( ((PFCB) FileObject->FsContext)->Resource ); }