www.pudn.com > filesys.rar > flush.c


/************************************************************************* 
* 
* File: flush.c 
* 
* Module: Sample File System Driver (Kernel mode execution only) 
* 
* Description: 
*	Contains code to handle the "Flush Buffers" dispatch entry point. 
* 
* Author: R. Nagar 
* 
* (c) 1996-97 Rajeev Nagar, All Rights Reserved 
* 
*************************************************************************/ 
 
#include			"sfsd.h" 
 
// define the file specific bug-check id 
#define			SFSD_BUG_CHECK_ID				SFSD_FILE_FLUSH 
 
 
 
/************************************************************************* 
* 
* Function: SFsdFlush() 
* 
* Description: 
*	The I/O Manager will invoke this routine to handle a flush buffers 
*	request 
* 
* Expected Interrupt Level (for execution) : 
* 
*  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution 
*	to be deferred to a worker thread context) 
* 
* Return Value: STATUS_SUCCESS/Error 
* 
*************************************************************************/ 
NTSTATUS SFsdFlush( 
PDEVICE_OBJECT		DeviceObject,		// the logical volume device object 
PIRP					Irp)					// I/O Request Packet 
{ 
	NTSTATUS				RC = STATUS_SUCCESS; 
   PtrSFsdIrpContext	PtrIrpContext = NULL; 
	BOOLEAN				AreWeTopLevel = FALSE; 
 
	FsRtlEnterFileSystem(); 
	ASSERT(DeviceObject); 
	ASSERT(Irp); 
 
	// set the top level context 
	AreWeTopLevel = SFsdIsIrpTopLevel(Irp); 
 
	try { 
 
		// get an IRP context structure and issue the request 
		PtrIrpContext = SFsdAllocateIrpContext(Irp, DeviceObject); 
		ASSERT(PtrIrpContext); 
 
		RC = SFsdCommonFlush(PtrIrpContext, Irp); 
 
	} except (SFsdExceptionFilter(PtrIrpContext, GetExceptionInformation())) { 
 
		RC = SFsdExceptionHandler(PtrIrpContext, Irp); 
 
		SFsdLogEvent(SFSD_ERROR_INTERNAL_ERROR, RC); 
	} 
 
	if (AreWeTopLevel) { 
		IoSetTopLevelIrp(NULL); 
	} 
 
	FsRtlExitFileSystem(); 
 
	return(RC); 
} 
 
 
 
/************************************************************************* 
* 
* Function: SFsdCommonFlush() 
* 
* Description: 
*	The actual work is performed here. This routine may be invoked in one' 
*	of the two possible contexts: 
*	(a) in the context of a system worker thread 
*	(b) in the context of the original caller 
* 
* Expected Interrupt Level (for execution) : 
* 
*  IRQL_PASSIVE_LEVEL 
* 
* Return Value: STATUS_SUCCESS/Error 
* 
*************************************************************************/ 
NTSTATUS	SFsdCommonFlush( 
PtrSFsdIrpContext			PtrIrpContext, 
PIRP							PtrIrp) 
{ 
	NTSTATUS					RC = STATUS_SUCCESS; 
	PIO_STACK_LOCATION	PtrIoStackLocation = NULL; 
	PFILE_OBJECT			PtrFileObject = NULL; 
	PtrSFsdFCB				PtrFCB = NULL; 
	PtrSFsdCCB				PtrCCB = NULL; 
	PtrSFsdVCB				PtrVCB = NULL; 
	PtrSFsdNTRequiredFCB	PtrReqdFCB = NULL; 
	BOOLEAN					AcquiredFCB = FALSE; 
	BOOLEAN					PostRequest = FALSE; 
	BOOLEAN					CanWait = TRUE; 
 
	try { 
		// First, get a pointer to the current I/O stack location 
		PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp); 
		ASSERT(PtrIoStackLocation); 
 
		PtrFileObject = PtrIoStackLocation->FileObject; 
		ASSERT(PtrFileObject); 
 
		// Get the FCB and CCB pointers 
		PtrCCB = (PtrSFsdCCB)(PtrFileObject->FsContext2); 
		ASSERT(PtrCCB); 
		PtrFCB = PtrCCB->PtrFCB; 
		ASSERT(PtrFCB); 
		PtrReqdFCB = &(PtrFCB->NTRequiredFCB); 
 
		// Get some of the parameters supplied to us 
		CanWait = ((PtrIrpContext->IrpContextFlags & SFSD_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE); 
 
		// If we cannot wait, post the request immediately since a flush is inherently blocking/synchronous. 
		if (!CanWait) { 
			PostRequest = TRUE; 
			try_return(RC); 
		} 
 
		// Check the type of object passed-in. That will determine the course of 
		// action we take. 
		if ((PtrFCB->NodeIdentifier.NodeType == SFSD_NODE_TYPE_VCB) || (PtrFCB->FCBFlags & SFSD_FCB_ROOT_DIRECTORY)) { 
 
			if (PtrFCB->NodeIdentifier.NodeType == SFSD_NODE_TYPE_VCB) { 
				PtrVCB = (PtrSFsdVCB)(PtrFCB); 
			} else { 
				PtrVCB = PtrFCB->PtrVCB; 
			} 
 
			// The caller wishes to flush all files for the mounted 
			// logical volume. The flush volume routine below should simply 
			// walk through all of the open file streams, acquire the 
			// FCB resource, and request the flush operation from the Cache 
			// Manager. Basically, the sequence of operations listed below 
			// for a single file should be executed on all open files. 
 
			SFsdFlushLogicalVolume(PtrIrpContext, PtrIrp, PtrVCB); 
 
			try_return(RC); 
		} 
 
		if (!(PtrFCB->FCBFlags & SFSD_FCB_DIRECTORY)) { 
			// This is a regular file. 
			ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE); 
			AcquiredFCB = TRUE; 
 
			// Request the Cache Manager to perform a flush operation. 
			// Further, instruct the Cache Manager that we wish to flush the 
			// entire file stream. 
			SFsdFlushAFile(PtrReqdFCB, &(PtrIrp->IoStatus)); 
			RC = PtrIrp->IoStatus.Status; 
			// All done. You may want to also flush the directory entry for the 
			// file stream at this time. 
 
			// Some log-based FSD implementations may wish to flush their 
			// log files at this time. Finally, you should update the time-stamp 
			// values for the file stream appropriately. This would involve 
			// obtaining the current time and modifying the appropriate directory 
			// entry fields. 
		} 
 
		try_exit: 
 
		if (AcquiredFCB) { 
			SFsdReleaseResource(&(PtrReqdFCB->MainResource)); 
			AcquiredFCB = FALSE; 
		} 
 
		if (!PostRequest) { 
			PIO_STACK_LOCATION		PtrNextIoStackLocation = NULL; 
			NTSTATUS						RC1 = STATUS_SUCCESS; 
 
			// Send the request down at this point. 
			// To do this, you must set the next IRP stack location, and 
			// maybe set a completion routine. 
			// Be careful about marking the IRP pending if the lower level 
			// driver returned pending and you do have a completion routine! 
			PtrNextIoStackLocation = IoGetNextIrpStackLocation(PtrIrp); 
			*PtrNextIoStackLocation = *PtrIoStackLocation; 
 
			// Set the completion routine to "eat-up" any 
			// STATUS_INVALID_DEVICE_REQUEST error code returned by the lower 
			// level driver. 
			IoSetCompletionRoutine(PtrIrp, SFsdFlushCompletion, NULL, TRUE, TRUE, TRUE); 
 
			RC1 = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp); 
 
			RC = ((RC1 == STATUS_INVALID_DEVICE_REQUEST) ? RC : RC1); 
		} 
 
	} finally { 
		if (PostRequest) { 
			// Nothing to lock now. 
			RC = SFsdPostRequest(PtrIrpContext, PtrIrp); 
		} else { 
			// Release the IRP context at this time. 
  			SFsdReleaseIrpContext(PtrIrpContext); 
		} 
	} 
 
	return(RC); 
} 
 
 
/************************************************************************* 
* 
* Function: SFsdFlushAFile() 
* 
* Description: 
*	Tell the Cache Manager to perform a flush. 
* 
* Expected Interrupt Level (for execution) : 
* 
*  IRQL_PASSIVE_LEVEL 
* 
* Return Value: None 
* 
*************************************************************************/ 
void SFsdFlushAFile( 
PtrSFsdNTRequiredFCB	PtrReqdFCB, 
PIO_STATUS_BLOCK		PtrIoStatus) 
{ 
	CcFlushCache(&(PtrReqdFCB->SectionObject), NULL, 0, PtrIoStatus); 
	return; 
} 
 
 
/************************************************************************* 
* 
* Function: SFsdFlushLogicalVolume() 
* 
* Description: 
*	Flush everything beginning at root directory. 
* 
* Expected Interrupt Level (for execution) : 
* 
*  IRQL_PASSIVE_LEVEL 
* 
* Return Value: None 
* 
*************************************************************************/ 
void SFsdFlushLogicalVolume( 
PtrSFsdIrpContext			PtrIrpContext, 
PIRP							PtrIrp, 
PtrSFsdVCB					PtrVCB) 
{ 
	BOOLEAN			AcquiredVCB = FALSE; 
	PtrSFsdFCB		PtrFCB = NULL; 
	PLIST_ENTRY		PtrNextFCB = NULL; 
 
	try { 
		ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), TRUE); 
		AcquiredVCB = TRUE; 
 
		// Go through the list of FCB's. You would probably 
		// flush all of the files. Then, you could flush the 
		// directories that you may have have pinned into memory. 
 
		// NOTE: This function may also be invoked internally as part of 
		// processing a shutdown request. 
 
	} finally { 
 
		if (AcquiredVCB) { 
			SFsdReleaseResource(&(PtrVCB->VCBResource)); 
		} 
	} 
 
	return; 
} 
 
 
/************************************************************************* 
* 
* Function: SFsdFlushCompletion() 
* 
* Description: 
*	Eat up any bad errors. 
* 
* Expected Interrupt Level (for execution) : 
* 
*  IRQL_PASSIVE_LEVEL 
* 
* Return Value: None 
* 
*************************************************************************/ 
NTSTATUS SFsdFlushCompletion( 
PDEVICE_OBJECT	PtrDeviceObject, 
PIRP				PtrIrp, 
PVOID				Context) 
{ 
	NTSTATUS		RC = STATUS_SUCCESS; 
 
	if (PtrIrp->PendingReturned) { 
		IoMarkIrpPending(PtrIrp); 
	} 
 
	if (PtrIrp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) { 
		// cannot do much here, can we? 
		PtrIrp->IoStatus.Status = STATUS_SUCCESS; 
	} 
 
	return(STATUS_SUCCESS); 
}