2014年7月10日星期四

FltDoCompletionProcessingWhenSafe

#include <fltKernel.h>

PFLT_FILTER gFilterHandle;

/*
文件名:FltDoCompletionProcessingWhenSafe.c 

起因在写的后操作直接调用FltGetFileNameInformation蓝屏。
后来得知是后操作的IRQL <= DISPATCH_LEVEL。
解决办法有2:
1.FltDoCompletionProcessingWhenSafe
2.FltQueueDeferredIoWorkItem(自己试验失败,总是蓝屏)
3.个人不建议使用普通的线程队列,因为有些内核对象不能使用。还是用官方建议的吧!

made by correy
made at 2014.07.10
homepage:http://correy.webs.com
*/

//这些在WDK 7600.16385.1中没有定义,在WDK8.0中定义了.
//一下代码是解决办法之一.
#ifndef _In_
#define _Inout_
#define _In_
#define _In_opt_
#endif
//另一思路可参考:http://msdn.microsoft.com/zh-cn/library/windows/hardware/ff554695(v=vs.85).aspx


FLT_POSTOP_CALLBACK_STATUS WritePostOPerationWhenSafe (__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in_opt PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags)
{
    PFLT_FILE_NAME_INFORMATION    pfni;
    NTSTATUS                      status;

    status = FltGetFileNameInformation( Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &pfni);    
    if (!NT_SUCCESS( status )) 
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    status = FltParseFileNameInformation(pfni);
    if (!NT_SUCCESS( status )) 
    {
        FltReleaseFileNameInformation(pfni); 
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    KdPrint(("写文件:%wZ\n", &pfni->Name));

    FltReleaseFileNameInformation(pfni); 

    return FLT_POSTOP_FINISHED_PROCESSING;

    /*
    If a minifilter calls FltDoCompletionProcessingWhenSafe and the SafePostCallback is invoked in a worker thread because it is not safe to invoke it in the current thread context, 
    the filter manager will resume completion processing as long as the minifilter does not return FLT_POSTOP_MORE_PROCESSING_REQUIRED from the SafePostCallback. 

    If the minifilter does return FLT_POSTOP_MORE_PROCESSING_REQUIRED from the SafePostCallback, 
    the minifilter must call FltCompletePendedPostOperation to resume completion processing.
    理解为,如果这个函数返回了FLT_POSTOP_MORE_PROCESSING_REQUIRED,后操作要调用FltCompletePendedPostOperation。
    */
}


FLT_POSTOP_CALLBACK_STATUS WritePostOPeration(__inout PFLT_CALLBACK_DATA Data, __in PCFLT_RELATED_OBJECTS FltObjects, __in PVOID CompletionContext, __in FLT_POST_OPERATION_FLAGS Flags)
    /*
    A minifilter driver's post-operation callback routine performs completion processing for one or more types of I/O operations.
    Post-operation callback routines are similar to the completion routines used by legacy file system filter drivers. 
    Post-operation callback routines are called in an arbitrary thread context, at IRQL <= DISPATCH_LEVEL. 
    Because this callback routine can be called at IRQL DISPATCH_LEVEL, it is subject to the following constraints: 

    It cannot safely call any kernel-mode routine that must run at a lower IRQL. 
    Any data structures used in this routine must be allocated from nonpaged pool. 
    It cannot be made pageable. 
    It cannot acquire resources, mutexes, or fast mutexes. However, it can acquire spin locks. 
    It cannot get, set, or delete contexts, but it can release contexts. 

    Any I/O completion processing that needs to be performed at IRQL < DISPATCH_LEVEL cannot be performed directly in the postoperation callback routine. 
    Instead, it must be posted to a work queue by calling a routine such as FltDoCompletionProcessingWhenSafe or FltQueueDeferredIoWorkItem. 

    Be aware that FltDoCompletionProcessingWhenSafe should never be called if the Flags parameter of the post-operation callback has the FLTFL_POST_OPERATION_DRAINING bit set. 
    The following are exceptions to this rule: 

    If a minifilter driver's pre-operation callback routine returns FLT_PREOP_SYNCHRONIZE for an IRP-based I/O operation, 
    the corresponding post-operation callback routine is guaranteed to be called at IRQL <= APC_LEVEL, in the same thread context as the pre-operation callback. 

    Post-create callback routines are guaranteed to be called at IRQL PASSIVE_LEVEL, in the context of the thread that originated the IRP_MJ_CREATE operation. 

    */
{
    FLT_POSTOP_CALLBACK_STATUS retValue = FLT_POSTOP_FINISHED_PROCESSING;

    /*
    FltDoCompletionProcessingWhenSafe can only be called for IRP-based operations. 
    To determine whether the operation is an IRP-based operation, use the FLT_IS_IRP_OPERATION macro.
    */
    if (!FLT_IS_IRP_OPERATION(Data)) //FlagOn( (Data)->Flags, FLTFL_CALLBACK_DATA_IRP_OPERATION )
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    /*
    Note that FltDoCompletionProcessingWhenSafe should never be called if the Flags parameter of the postoperation callback has the FLTFL_POST_OPERATION_DRAINING bit set. 
    */
    if (FlagOn(Flags,FLTFL_POST_OPERATION_DRAINING))
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    /*
    FltDoCompletionProcessingWhenSafe cannot be used to post completion of a paging I/O operation to a worker thread.
    */
    if (FlagOn(Data->Iopb->IrpFlags, IRP_PAGING_IO) || FlagOn(Data->Iopb->IrpFlags, IRP_SYNCHRONOUS_PAGING_IO)) //IRP_NOCACHE
    {
        return FLT_POSTOP_FINISHED_PROCESSING;
    }

    /*
    FltDoCompletionProcessingWhenSafe can only be called from a minifilter driver's postoperation callback routine (PFLT_POST_OPERATION_CALLBACK).   
    */
    if (!FltDoCompletionProcessingWhenSafe( Data, FltObjects, CompletionContext, Flags, WritePostOPerationWhenSafe, &retValue ))
    {
        Data->IoStatus.Status = STATUS_UNSUCCESSFUL;
        Data->IoStatus.Information = 0;
        return retValue;
    }

    //FltCompletePendedPostOperation();//如果返回了FLT_POSTOP_MORE_PROCESSING_REQUIRED就调用这个。

    return retValue;
}


CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
    { IRP_MJ_WRITE,  0, 0, WritePostOPeration},
    { IRP_MJ_OPERATION_END }
};


#pragma PAGEDCODE
NTSTATUS PtInstanceQueryTeardown (__in PCFLT_RELATED_OBJECTS FltObjects,__in FLT_INSTANCE_QUERY_TEARDOWN_FLAGS Flags)
{
    return STATUS_SUCCESS;
}


#pragma PAGEDCODE//#pragma alloc_text(PAGE, PtUnload)
NTSTATUS PtUnload (__in FLT_FILTER_UNLOAD_FLAGS Flags)
{
    FltUnregisterFilter( gFilterHandle );
    return STATUS_SUCCESS;
}


CONST FLT_REGISTRATION FilterRegistration = {
    sizeof( FLT_REGISTRATION ),         //  Size
    FLT_REGISTRATION_VERSION,           //  Version
    0,                                  //  Flags
    NULL,                               //  Context
    Callbacks,                          //  Operation callbacks
    PtUnload,                           //  MiniFilterUnload
    NULL,                               //  InstanceSetup
    PtInstanceQueryTeardown,            //  InstanceQueryTeardown
    NULL,                               //  InstanceTeardownStart
    NULL,                               //  InstanceTeardownComplete
    NULL,                               //  GenerateFileName
    NULL,                               //  GenerateDestinationFileName
    NULL                                //  NormalizeNameComponent
};


DRIVER_INITIALIZE DriverEntry;
#pragma alloc_text(INIT, DriverEntry)//#pragma INITCODE
NTSTATUS DriverEntry (_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
{
    NTSTATUS status;

    UNREFERENCED_PARAMETER( RegistryPath );

    KdBreakPoint();

    status = FltRegisterFilter( DriverObject, &FilterRegistration, &gFilterHandle );
    if (!NT_SUCCESS( status )) //FLT_ASSERT( NT_SUCCESS( status ) );
    {        
        return status;
    }

    status = FltStartFiltering( gFilterHandle );
    if (!NT_SUCCESS( status )) {
        FltUnregisterFilter( gFilterHandle );
    }

    return status;
}

没有评论:

发表评论