📄 operations.c
字号:
UNREFERENCED_PARAMETER( FltObjects );
PAGED_CODE();
*CompletionContext = NULL;
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPreDeviceControl -> Enter (IoControlCode = 0x%x, Cbd = %p, FileObject = %p)\n",
Cbd->Iopb->Parameters.DeviceIoControl.Common.IoControlCode,
Cbd,
FltObjects->FileObject) );
switch (Cbd->Iopb->Parameters.DeviceIoControl.Common.IoControlCode) {
//
// System IOCTLs that we are interested in
//
case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES:
//
// We want the snapshot to have a consistent image
// of our metadata file and we would not like it to
// have pages that are not consistent with each other
//
//
// Here the filter must flush any portion of its metadata
// that it has not flushed to disk
//
// If the filter is using mapped cache buffers to read/write
// its metadata then the File System will take care of all the
// flushing. The filter just needs to ensure that it do not
// write to any of its mapped cache buffers while the FS is
// trying to flush changes out to disk.
//
// Get the instance context
//
status = FltGetInstanceContext( Cbd->Iopb->TargetInstance,
&instanceContext );
if (!NT_SUCCESS( status )) {
DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS,
("[Fmm]: Failed to get instance context in FmmPreDeviceControl.\n") );
goto FmmPreDeviceControlCleanup;
}
//
// We acquire the instance context resource shared to prevent any modifications
// to the metadata from pre to post. The basic goal is to prevent any metadata
// updates while the file system is performing IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES
//
FmmAcquireResourceShared( &instanceContext->MetadataResouce );
if (FlagOn( instanceContext->Flags, INSTANCE_CONTEXT_F_TRANSITION)) {
//
// If this instance context is in a transition state, it implies that
// the instance context lock has been release while sending an operation
// down to the file system. The reason for doing so is to prevent a potential
// deadlock if an underlying filter sends an IO to the top of the filter
// stack while we are holding the resource
//
// We have managed to acquire this resource in this state of transition.
// In this situation, acquiring the lock shared does not guarantee that no
// other thread is modifying the instance context. So we simply let go.
//
FmmReleaseResource( &instanceContext->MetadataResouce);
status = STATUS_FILE_LOCK_CONFLICT;
DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS,
("[Fmm]: Failed to get shared access to instance context since it is in a state of transition.\n") );
goto FmmPreDeviceControlCleanup;
}
//
// Set the owner of this resource. The resource is acquired in the
// pre-op callback and released in the post-op callback. It is not
// guaranteed that the post-op callback will be called in the context
// of the pre-operation callback thread at all times. Hence we assign
// an owner to this resource, so that, we may release the resource
// with the matching owner pointer
//
FmmTransferResourceOwnership( &instanceContext->MetadataResouce, instanceContext );
//
// Do not release the instance context but instead pass it to the PostOp
// because we do not want to fail to release the lock because we cannot acquire the
// instance context in the post-op
//
*CompletionContext = instanceContext;
//
// Force a post-op so we may release the lock
//
callbackStatus = FLT_PREOP_SUCCESS_WITH_CALLBACK;
break;
}
FmmPreDeviceControlCleanup:
//
// If any operation has failed then complete and fail the call
//
if (!NT_SUCCESS( status )) {
DebugTrace( DEBUG_TRACE_ERROR,
("[Fmm]: FmmPreDeviceControl -> Failed with status 0x%x \n",
status) );
//
// We are not having a post-op since the pre-op failed
// Release the instance context
//
if (instanceContext != NULL) {
FltReleaseContext( instanceContext );
*CompletionContext = NULL;
}
Cbd->IoStatus.Status = status;
callbackStatus = FLT_PREOP_COMPLETE;
}
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPreDeviceControl -> Exit (IoControlCode = 0x%x, Cbd = %p, FileObject = %p)\n",
Cbd->Iopb->Parameters.DeviceIoControl.Common.IoControlCode,
Cbd,
FltObjects->FileObject) );
return callbackStatus;
}
FLT_POSTOP_CALLBACK_STATUS
FmmPostDeviceControl (
IN OUT PFLT_CALLBACK_DATA Cbd,
IN PCFLT_RELATED_OBJECTS FltObjects,
IN PVOID CbdContext,
IN FLT_POST_OPERATION_FLAGS Flags
)
{
PFMM_INSTANCE_CONTEXT instanceContext = NULL;
UNREFERENCED_PARAMETER( Flags );
UNREFERENCED_PARAMETER( FltObjects );
PAGED_CODE();
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPostDeviceControl -> Enter (IoControlCode = 0x%x, Cbd = %p, FileObject = %p)\n",
Cbd->Iopb->Parameters.DeviceIoControl.Common.IoControlCode,
Cbd,
FltObjects->FileObject) );
//
// We need to do this even if we are draining
//
switch (Cbd->Iopb->Parameters.DeviceIoControl.Common.IoControlCode) {
//
// System IOCTLs that we are interested in
//
case IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES:
//
// Assign the instance context
//
instanceContext = (PFMM_INSTANCE_CONTEXT) CbdContext;
//
// Sanity
//
ASSERT( instanceContext != NULL );
//
// We release the instance context resource that we acquired in the pre-op
// The resource must be released with the same owner pointer as that assigned
// in the pre-op callback
//
FmmReleaseResourceForOwner( &instanceContext->MetadataResouce, instanceContext );
//
// Release the instance context
//
FltReleaseContext( instanceContext );
break;
}
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPostDeviceControl -> Exit (IoControlCode = 0x%x, Cbd = %p, FileObject = %p)\n",
Cbd->Iopb->Parameters.DeviceIoControl.Common.IoControlCode,
Cbd,
FltObjects->FileObject) );
return FLT_POSTOP_FINISHED_PROCESSING;
}
FLT_PREOP_CALLBACK_STATUS
FmmPreShutdown (
IN OUT PFLT_CALLBACK_DATA Cbd,
IN PCFLT_RELATED_OBJECTS FltObjects,
OUT PVOID *CompletionContext
)
{
NTSTATUS status;
UNREFERENCED_PARAMETER( CompletionContext );
UNREFERENCED_PARAMETER( Cbd );
PAGED_CODE();
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPreShutdown -> Enter (Cbd = %p, FileObject = %p, Volume = %p)\n",
Cbd,
FltObjects->FileObject,
FltObjects->Volume) );
status = FltDetachVolume( Globals.Filter, FltObjects->Volume, NULL );
if (!NT_SUCCESS( status )) {
DebugTrace( DEBUG_TRACE_ERROR,
("[Fmm]: Failed to detach instance with status 0x%x on system shutdown\n",
status) );
//
// Doesn't really make sense to fail a shutdown, even if this operation failed
//
}
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPreShutdown -> Exit (Cbd = %p, FileObject = %p, Volume = %p)\n",
Cbd,
FltObjects->FileObject,
FltObjects->Volume) );
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}
FLT_PREOP_CALLBACK_STATUS
FmmPrePnp (
IN OUT PFLT_CALLBACK_DATA Cbd,
IN PCFLT_RELATED_OBJECTS FltObjects,
OUT PVOID *CompletionContext
)
/*
Routine Description:
This routine handles the pre-processing of all PNP operations received
on this instance. It handles query, cancel and suprise device removal.
For query device removal we have to close all open file handles we hold
so that the base file system can correctly response to these PNP requests.
Arguments:
Cbd - Pointer to the FLT_CALLBACK_DATA structure containing all the relevant
parameters for this operation.
FltObject - Pointer to the FLT_RELATED_OBJECTS data structure containing,
opaque handles to this filter, instance and its associated volume.
CompletionContext - Not used.
Return Value:
FLT_PREOP_SUCCESS_NO_CALLBACK as we are done with our processing and are
not interested in a post-operartion callback.
*/
{
NTSTATUS status;
FLT_PREOP_CALLBACK_STATUS callbackStatus;
UNREFERENCED_PARAMETER( CompletionContext );
PAGED_CODE();
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPrePnp -> Enter (Cbd = %p, FileObject = %p, Volume = %p)\n",
Cbd,
FltObjects->FileObject,
FltObjects->Volume) );
//
// default to no post op callback
//
callbackStatus = FLT_PREOP_SUCCESS_NO_CALLBACK;
switch (Cbd->Iopb->MinorFunction) {
case IRP_MN_QUERY_REMOVE_DEVICE:
//
// Give up the metadata file handle and the metadata file object
//
status = FmmReleaseMetadataFileReferences( Cbd );
if (!NT_SUCCESS( status )) {
//
// Fail the query removal
//
DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS,
("[Fmm]: Failed to release metadata file references with status 0x%x for query removal\n",
status) );
Cbd->IoStatus.Status = status;
callbackStatus = FLT_PREOP_COMPLETE;
}
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
//
// The device removal was cancelled - reaquire our references to the
// metadata file handle and the metadata file object
//
status = FmmReacquireMetadataFileReferences( Cbd );
if (!NT_SUCCESS( status )) {
DebugTrace( DEBUG_TRACE_ERROR | DEBUG_TRACE_METADATA_OPERATIONS,
("[Fmm]: Failed to re-open metadata with status 0x%x after cancel device removal.\n",
status,
Cbd->IoStatus.Status) );
//
// Sanity - we are now in a bad state. The removal has been
// cancelled but we have not been able to re-acquire references
// to our metadata file
//
// It is always possible to fail with STATUS_INSUFFICIENT_RESOURCES
// so we should ignore that.
//
// It is also possible to fail if the instance context was in a transition state
// so we should ignore STATUS_FILE_LOCK_CONFLICT too.
//
ASSERT( (status == STATUS_INSUFFICIENT_RESOURCES) ||
(status == STATUS_FILE_LOCK_CONFLICT) );
}
break;
case IRP_MN_SURPRISE_REMOVAL:
//
// Teardown our instance because its no longer valid.
//
status = FltDetachVolume( Globals.Filter, FltObjects->Volume, NULL );
if (!NT_SUCCESS( status )) {
DebugTrace( DEBUG_TRACE_ERROR,
("[Fmm]: Failed to detach instance with status 0x%x after a surprise removal\n",
status) );
}
break;
default:
//
// Pass all PNP minor codes we don't care about.
//
break;
}
DebugTrace( DEBUG_TRACE_ALL_IO,
("[Fmm]: FmmPrePnp -> Exit (Cbd = %p, FileObject = %p, Volume = %p)\n",
Cbd,
FltObjects->FileObject,
FltObjects->Volume) );
return FLT_PREOP_SUCCESS_NO_CALLBACK;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -