1. 程式人生 > >檔案系統Minifilter驅動(八)

檔案系統Minifilter驅動(八)

寫Callback例程的Pre-oper和Post-oper

一個minifilter驅動可以在它的DriverEntry例程中為它需要過濾的任何型別的I/O操作註冊至多一個pre-oper callback例程和至多一個post-oper callback例程. 

Minifilter可以選擇要過濾哪種型別的I/O. minifilter驅動可以為一個給定型別的I/O操作只註冊一個pre-oper callback 例程,也可只註冊一個post-oper callback例程. Minifilter驅動只會收到那些它已經為之註冊了一個pre-oper或post-oper callback例程的I/O操作. 

pre-oper callback例程和legacy過濾驅動模型中的分發例程類似.當filter管理器處理一個I/O操作時,它會呼叫已經為這種型別的I/O操作註冊過的minifilter驅動例項棧中的每個minifilter驅動的pre-oper callback例程. 棧中頂端的minifilter驅動—就是其例項擁有最高altitude的那個—會首先收到這個操作. 當該 minifilter驅動結束了對這個操作的處理時,它會把此操作返回給filter管理器,然後filter管理器會把操作傳給下一個最高的(除了剛剛處理過這個操作的那個之外最高的)minifilter驅動,以此類推. 當 minifilter驅動例項棧中的所有minifilter驅動已經處理過了這個I/O操作—除非某個minifilter驅動已經完成了這個I/O操作— filter管理器傳送此操作給legacy過濾器和檔案系統. 

post-oper callback例程與legacy過濾驅動模型中的完成例程類似.當I/O管理器把操作傳給已經為某個I/O操作註冊了完成例程的檔案系統和legacy過濾器時,該操作的完成處理就開始了. 在這些完成例程結束之後,filter管理器會執行對此操作的完成處理. 接著filter管理器會呼叫已經為這種型別的I/O操作註冊過的minifilter驅動例項棧中的每個minifilter驅動的post-oper callback例程.棧中的底部minifilter驅動—就是其例項擁有最低 altitude的那個—會首先收到這個操作.當該minifilter驅動結束對這個操作的處理時,它把操作返回給filter管理器,然後filter管理器會把操作傳給下一個最低的minifilter驅動,以此類推. 

本節包括: 

一、註冊Pre-oper和Post-oper Callback例程

要註冊pre-oper callback例程和 post-oper callback例程,minifilter驅動只需在其DriverEntry例程中呼叫FltRegisterFilter.minifilter驅動要把一個FLT_REGISTRATION結構的指標傳給該函式的 Registration引數. 這個結構的成員OperationRegistration包含一組FLT_OPERATION_REGISTRATION 結構的指標, 其中之一是minifilter驅動必須過濾的. 

此指標組中的每一個FLT_OPERATION_REGISTRATION結構,除了最後一個, 都包含以下資訊: 

操作的主函式程式碼

對read和write操作(IRP_MJ_READ和IRP_MJ_WRITE)來說,有一套用於基於IRP的I/O操作的標記,它們指定了是否要忽視cached I/O或分頁I/O或兩者都忽視 

至多一個pre-oper callback例程和一個post-oper callback例程的入口點

此指標組的最後一個元素必須是{IRP_MJ_OPERATION_END}. 

以下從Scanner minifilter驅動中節選出來的程式碼展示了一組 FLT_OPERATION_REGISTRATION結構.Scanner minifilter驅動為IRP_MJ_CREATE註冊了pre-oper和post-oper callback例程,為IRP_MJ_CLEANUP和IRP_MJ_WRITE例子註冊了pre-oper callback例程. 

const FLT_OPERATION_REGISTRATION Callbacks[] = {    {IRP_MJ_CREATE,     0,     ScannerPreCreate,     ScannerPostCreate},    {IRP_MJ_CLEANUP,     0,      ScannerPreCleanup,     NULL},    {IRP_MJ_WRITE,     0,      ScannerPreWrite,     NULL},    {IRP_MJ_OPERATION_END}};

二、在Minifilter驅動中過濾I/O操作

以下是幾個在檔案系統minifilter驅動中過濾指定型別的I/O操作的幾個指導方針: 

IRP_MJ_CREATE的pre-oper callback例程不能為檔案、流或流控制代碼查詢或設定context,因為在pre-create時,計劃要建立的檔案或流還沒有被確定. 

IRP_MJ_CLOSE的post-oper callback 例程不能為檔案、流或流控制代碼查詢context,因為相關的系統內部結構都在呼叫post-close例程之前被釋放了. 

Minifilter驅動一定不能令IRP_MJ_CLEANUP 或IRP_MJ_CLOSE 操作失敗. 這些操作可以被pend,被返回給filter管理器或以STATUS_SUCCESS被完成. 不過,一個pre-oper callback例程一定不能令這些操作失敗. 

Minifilter驅動不可以為IRP_MJ_SHUTDOWN 註冊一個post-oper callback例程. 

三、寫Pre-oper Callback例程

一個檔案系統minifilter驅動用一個或多個pre-oper callback例程來過濾I/O操作. Pre-oper callback例程 與legacy FSFD中使用的分發例程類似. 

Minifilter驅動通過儲存callback例程的入口點到FLT_REGISTRATION結構的成員OperationRegistration 中來為某個特定型別的I/O操作註冊一個pre-oper callback例程,此結構會被minifilter驅動在其DriverEntry例程中作為一個引數傳給 FltRegisterFilter. 

Minifilter驅動僅接收那些它們已經為之註冊了一個pre-oper或post-oper callback例程的I/O操作.minifilter驅動可以只註冊一個pre-oper callback例程或只註冊一個post-oper callback例程. 

pre-oper callback例程的定義如下: 

typedef FLT_PREOP_CALLBACK_STATUS (*PFLT_PRE_OPERATION_CALLBACK) (     IN OUT PFLT_CALLBACK_DATA Data,     IN PCFLT_RELATED_OBJECTS FltObjects,     OUT PVOID *CompletionContext     ); 

像一個分發例程一樣,一個pre-oper callback例程可以在IRQL = PASSIVE_LEVEL 或在IRQL = APC_LEVEL被呼叫.一般它在發起I/O請求的執行緒的context中在IRQL = PASSIVE_LEVEL被呼叫.對fast I/O和FsFilter操作來說,pre-oper callback例程總在IRQL = PASSIVE_LEVEL被呼叫.不過,對一個基於IRP的操作來說,如果一個更高層的過濾器或minifilter驅動pend此操作來讓用worker執行緒做處理的話,minifilter驅動的pre-oper callback例程可以在一個系統worker執行緒的context中被呼叫. 

當filter管理器為一個給定的I/O操作呼叫某個minifilter驅動的pre-oper callback例程時,該minifilter驅動臨時地控制此I/O操作.minifilter驅動在它做完以下事情之前會保持其控制權: 

從pre-oper callback 例程中返回一個除了FLT_PREOP_PENDING之外的狀態值. 

從一個已經處理了在pre-oper callback例程中被pend的操作的工作例程中呼叫FltCompletePendedPre-oper

這節包括: 

1.在minifilter例項棧上向下傳I/O操作

當某個minifilter驅動的pre-oper callback例程 或工作例程返回一個I/O操作給filter管理器時, filter管理器把該操作傳送給minifilter驅動例項棧中在當前minifilter驅動之下的minifilter驅動,或給legacy過濾器和檔案系統來做進一步處理. 

pre-oper callback例程通過返回下列狀態值之一來返回I/O操作給filter管理器進行深入處理: 

FLT_PREOP_SUCCESS_NO_CALLBACK (所有操作型別) 

FLT_PREOP_SUCCESS_WITH_CALLBACK (所有操作型別) 

FLT_PREOP_SYNCHRONIZE (僅基於IRP的I/O) 

注意  儘管FLT_PREOP_SYNCHRONIZE只針對基於IRP的I/O操作,你也可以為其他操作型別返回這個值.如果是為了非基於IRP的I/O操作返回此值,則filter管理器會把它當做FLT_PREOP_SUCCESS_WITH_CALLBACK來處理. 

在pre-oper callback例程中被pend的操作的工作例程,當它呼叫FltCompletePendedPre-oper來恢復對被pend的I/O的處理時filter管理器通過在CallbackStatus引數中傳遞上述狀態值之一返回I/O操作給filter管理器. 

本節包括: 

1) Returning FLT_PREOP_SUCCESS_WITH_CALLBACK 

如果某個minifilter驅動的pre-oper callback例程 返回了FLT_PREOP_SUCCESS_WITH_CALLBACK, filter管理器就會在I/O完成期間呼叫它的post-oper callback例程. 

注意  如果minifilter驅動的pre-oper callback例程返回了 FLT_PREOP_SUCCESS_WITH_CALLBACK但該驅動還沒有為操作註冊一個post-oper callback例程,那麼系統會在checked build上assert. 

如果這個minifilter驅動的pre-oper callback例程返回了 FLT_PREOP_SUCCESS_WITH_CALLBACK, 那它就可以在其輸出引數CompletionContext中返回一個非NULL的值. 該引數是一個可選的context指標,它被傳給相應的post-oper callback例程.此例程會在其 CompletionContext 入參中收到這個指標. 

對所有型別的I/O操作都可以返回FLT_PREOP_SUCCESS_WITH_CALLBACK狀態值. 

2) Returning FLT_PREOP_SUCCESS_NO_CALLBACK 

如果某個minifilter驅動的pre-oper callback例程 返回了 FLT_PREOP_SUCCESS_NO_CALLBACK, 那麼在I/O操作期間filter管理器就不能呼叫它的 post-oper callback例程

如果這個minifilter驅動的pre-oper callback例程返回了FLT_PREOP_SUCCESS_NO_CALLBACK, 那麼它必須在它的出參CompletionContext 返回NULL. 

對所有型別的I/O操作都可以返回FLT_PREOP_SUCCESS_NO_CALLBACK狀態值. 

3) Returning FLT_PREOP_SYNCHRONIZE 

如果某個minifilter驅動的pre-oper callback例程 通過返回FLT_PREOP_SYNCHRONIZE 來同步一個I/O操作,那麼filter管理器就會在I/O完成期間呼叫它的post-oper callback例程

Filter管理器像呼叫pre-oper callback一樣在同一執行緒的上下文中在 IRQL <= APC_LEVEL呼叫這個minifilter驅動的post-oper callback例程. (注意這個執行緒上下文不一定是發起執行緒上下文.) 

注意  如果minifilter驅動的pre-oper callback例程返回了 FLT_PREOP_SYNCHRONIZE, 但它還沒有為操作註冊一個 post-oper callback例程,系統會在checked build上assert. 

若minifilter驅動pre-oper callback例程返回FLT_PREOP_SYNCHRONIZE, 那麼它就可以在其出參CompletionContext中返回一個非NULL值. 此引數是一個可選的context指標,它被傳給相應的post-oper callback例程.該例程會在其入參CompletionContext 中收到這個指標. 

Minifilter驅動的pre-oper callback例程應只對IRP-I/O操作返回FLT_PREOP_SYNCHRONIZE.不過,此狀態值可以作為其他操作型別的返回值. 如果它作為返回值是不是IRP-I/O操作,filter管理器會把這個值當FLT_PREOP_SUCCESS_WITH_CALLBACK來處理. 

用FLT_IS_IRP_OPERATION巨集可以確定一個操作是不是一個IRP-I/O操作. 

Minifilter驅動不應為create操作返回FLT_PREOP_SYNCHRONIZE, 因為這些操作已經被filter管理器同步了. 如果一個minifilter驅動已經註冊了 IRP_MJ_CREATE 操作的pre-oper和post-oper例程,則這兩個例程都會在IRQL = PASSIVE_LEVEL在同一執行緒上下文中被呼叫. 

Minifilter不允許為非同步讀寫操作返回FLT_PREOP_SYNCHRONIZE. 這麼做嚴重地降低minifilter驅動和系統的效能,甚至引起死鎖,例如,已修改的頁writer thread會被阻塞.在為IRP的讀寫返回FLT_PREOP_SYNCHRONIZE之前,minifilter驅動應呼叫FltIsOperationSynchronous來校驗操作是否同步. 

以下型別的I/O操作不能被同步: 

· Oplock檔案系統控制(FSCTL)操作(MajorFunction為 IRP_MJ_FILE_SYSTEM_CONTROL; FsControlCode為FSCTL_REQUEST_FILTER_OPLOCKFSCTL_REQUEST_BATCH_OPLOCKFSCTL_REQUEST_OPLOCK_LEVEL_1, 或FSCTL_REQUEST_OPLOCK_LEVEL_2.) 

· 通知改變目錄操作(MajorFunction為IRP_MJ_DIRECTORY_CONTROL; MinorFunction為 IRP_MN_NOTIFY_CHANGE_DIRECTORY.) 

· Byte-range鎖請求(MajorFunction為IRP_MJ_LOCK_CONTROL; MinorFunction為IRP_MN_LOCK.) 

FLT_PREOP_SYNCHRONIZE不能作為以上任何操作的返回值。

2.在Pre-oper Callback例程中完成一個I/O操作

完成一個I/O操作意味著你得停止該操作的處理,給它指定一個最終的NTSTATUS值並把它返回給filter manager. 

當某個minifilter驅動完成了一個I/O操作時,filter管理器做以下這些事情: 

· 不再把此操作傳送給當前minifilter驅動之下的minifilter驅動、legacy過濾器以及檔案系統. 

· 呼叫minifilter驅動例項棧中在當前minifilter驅動之上的minifilter驅動的post-oper callback例程

· 不再呼叫當前minifilter驅動對此操作的post-oper callback例程(如果存在一個的話). 

Minifilter驅動的pre-oper callback例程 通過執行以下這些步驟完成一個I/O操作: 

1. 設定callback資料結構的IoStatus.Status域為此操作最終的NTSTATUS值. 

2. 返回FLT_PREOP_COMPLETE. 

一個完成一個I/O操作的pre-oper callback例程不可以設定一個非NULL的完成context (在出參CompletionContext 中). 

Minifilter驅動也可以在一個之前被pend的I/O操作的工作例程中完成一個操作,它要執行的步驟如下: 

1. 設定callback資料結構的IoStatus.Status域為此操作最終的NTSTATUS值. 

2. 當工作例程呼叫FltCompletePendedPost-oper時,在引數CallbackStatus中傳遞FLT_PREOP_COMPLETE. 

當完成一個I/O操作時,minifilter驅動必須設定callback資料結構的 IoStatus.Status域為此操作最終的NTSTATUS值,但是這個NTSTATUS值不可以是STATUS_PENDING或STATUS_FLT_DISALLOW_FAST_IO.對於一個 cleanup或close操作來說,這個域必須是STATUS_SUCCESS.這些操作不能以其他任何NTSTATUS值完成. 

完成一個I/O操作常常牽涉依賴於NTSTATUS值令該操作成功或失敗的操作: 

· 要令I/O操作成功意味著以一個成功或如STATUS_SUCCESS值這樣的資訊化的NTSTATUS值完成它. 

· 要令I/O操作失敗意味著以一個錯誤或像STATUS_INVALID_DEVICE_REQUEST或者 STATUS_BUFFER_OVERFLOW這樣的警告NTSTATUS值完成它. 

NTSTATUS值的定義在ntstatus.h中.這些值分為四類:成功,資訊化的, 警告和錯誤. 更多這些值的資訊可以參考Using NTSTATUS Values一文. 

3.在Pre-oper Callback例程中拒絕一個Fast I/O操作

在某些情況下,minifilter驅動可能會選擇拒絕一個fast I/O操作而非完成它.這會阻止該操作使用fast I/O. 

和完成I/O操作一樣,拒絕fast I/O操作意味著停止在它上的處理並把它返回給filter管理器。不過,拒絕和完成不同。如果某個minifilter驅動拒絕一個由I/O管理器發出的fast I/O,I/O管理器可能會以等價的基於IRP的操作重發同一操作。

當某個minifilter驅動的pre-oper callback例程 拒絕了一個fast I/O操作時,filter管理器會做以下這些: 

· 不再發送操作給在當前minifilter驅動之下的minifilter驅動、legacy過濾器以及檔案系統。 

· 呼叫minifilter驅動例項棧中處於當前minifilter驅動之上的minifilter驅動的post-oper callback例程

· 不再帶哦用當前minifilter驅動用於此操作的post-oper callback例程,如果有一個的話. 

Minifilter驅動通過從操作的pre-oper callback例程中返回FLT_PREOP_DISALLOW_FASTIO來拒絕一個fast I/O操作. 

Pre-oper callback例程不應設定callback資料結構的IoStatus.Status域,因為filter管理器會自動設定此域為STATUS_FLT_DISALLOW_FAST_IO. 

FLT_PREOP_DISALLOW_FASTIO僅可作為fast I/O操作的返回值.要決定一個操作是否為一個fast I/O操作,參考FLT_IS_FASTIO_OPERATION. 

Minifilter驅動不可為IRP_MJ_SHUTDOWN,IRP_MJ_VOLUME_MOUNT或IRP_MJ_VOLUME_DISMOUNT操作返回FLT_PREOP_DISALLOW_FASTIO. 

4.在Pre-oper Callback例程中Pend一個I/O操作

Minifilter驅動的pre-oper callback例程 可以通過把操作發到一個系統工作佇列並返回FLT_PREOP_PENDING來pend一個I/O操作.返回這個狀態值表示minifilter驅動將保留I/O操作的控制直到它呼叫 FltCompletePendedPreOperation來恢復對I/O操作的處理

Minifilter驅動的pre-oper callback例程通過執行以下步驟來pend一個I/O操作: 

1. 通過呼叫像FltQueueDeferredIoWorkItem這樣的一個例程來傳送I/O操作給一個系統工作佇列. 

2. 返回FLT_PREOP_PENDING. 

必須pend所有(或大多數)引入的I/O操作的Minifilter驅動不應使用像 FltQueueDeferredIoWorkItem這樣的例程來pend操作,因為呼叫此例程會引起系統工作佇列溢位.換句話說,這樣的minifilter驅動應使用一個安全取消佇列.更多關於使用安全取消佇列的資訊參考FltCbdqInitialize

注意如果以下條件為真則對FltQueueDeferredIoWorkItem的呼叫將會失敗

· 操作不是IRP-I/O操作. 

· 操作是一個分頁I/O操作. 

· 當前執行緒的TopLevelIrp域不為NULL. (更多關於如何找出此域的值的資訊參考IoGetTopLevelIrp.) 

· I/O操作的目標例項正被拆卸. 

如果minifilter驅動的pre-oper callback 例程返回FLT_PREOP_PENDING, 則它必須在出參CompletionContext 中返回NULL. 

Minifilter驅動只可為IRP-I/O操作返回FLT_PREOP_PENDING .要決定一個操作是否為IRP-I/O操作,使用FLT_IS_IRP_OPERATION巨集. 

出列和處理I/O操作的工作例程必須呼叫 FltCompletePendedPreOperation來恢復對操作的處理

四、寫Post-oper Callback例程

檔案系統minifilter驅動用一個或多個post-opera callback例程來過濾I/O操作. 

Post-oper callback例程 與legacy FSFD中使用的完成例程類似. 

Minifilter驅動為某個特定型別的I/O操作註冊一個post-oper callback例程的方法與它為之註冊一個pre-oper callback例程的方法相同—就是說,都是通過把callback例程的入口點儲存到FLT_REGISTRATION結構(它將作為引數被傳給DriverEntry例程中FltRegisterFilter)的OperationRegistration 成員來實現的. 

Minifilter僅接收它們已經為之註冊了一個pre-oper或post-oper callback例程的I/O操作.minifilter驅動可以為一個給定型別的I/O操作只註冊一個pre-oper或只註冊一個post-oper callback例程. 

Post-oper callback例程的定義如下: 

typedef FLT_POSTOP_CALLBACK_STATUS (*PFLT_POST_OPERATION_CALLBACK) (     IN OUT PFLT_CALLBACK_DATA Data,     IN PCFLT_RELATED_OBJECTS FltObjects,     IN PVOID CompletionContext,     IN FLT_POST_OPERATION_FLAGS Flags     ); 

和完成例程一樣,post-oper callback例程在IRQL <= DISPATCH_LEVEL及任意執行緒的上下文中被呼叫. 

因為它在DISPATCH_LEVEL被呼叫,所以它不能呼叫必須在更低 IRQL呼叫的核心模式例程,如FltLockUserBuffer或RtlCompareUnicodeString.因為同樣的原因,post-oper callback例程中使用的一切資料結構都必須從非分頁池中分配. 

以下情形是上述規則的幾個例外: 

· 如果minifilter驅動的pre-oper callback例程為一個IRP-I/O操作返回了FLT_PREOP_SYNCHRONIZE,相應的post-oper callback例程就會在IRQL <= APC_LEVEL及在與pre-oper callback例程相同的執行緒上下文中被呼叫. 

· Fast I/O操作的post-oper callback例程在IRQL = PASSIVE_LEVEL及在與pre-oper callback例程相同的執行緒上下文中被呼叫. 

· Post-create callback例程在IRQL = PASSIVE_LEVEL及發起這個IRP_MJ_CREATE操作的執行緒上下文中被呼叫. 

當filter管理器為一個給定的I/O操作呼叫某個minifilter驅動的post-oper callback例程時,該minifilter驅動臨時地控制此I/O操作.這個minifilter驅動在它做了以下事情之一時才會返回控制權: 

· 從post-oper callback例程中返回FLT_POSTOP_FINISHED_PROCESSING. 

· 從已經處理了一個在post-oper callback例程中被pend的IRP-I/O操作的工作歷程中呼叫FltCompletePendedPostOperation

本節包括: 

1.執行一個I/O操作的完成處理

minifilter驅動的post-oper callback例程會在底層檔案系統或legacy過濾器或minifilter驅動例項棧中有lower altitude的另外一個minifilter驅動已經完成了一個I/O操作時被呼叫. 

另外,當某個minifilter驅動例項正被拆卸時,filter管理器會"耗盡"該例項已經接收到其pre-oper callback而正等候其post-oper callback的I/O操作.在此情形之下,即使這個I/O操作還沒有被完成filter管理器也會呼叫該minifilter驅動的post-oper callback例程並在入參Flag中設定標記 FLTFL_POST_OPERATION_DRAINING . 

當設定了FLTFL_POST_OPERATION_DRAINING標記時,該minifilter驅動一定不可以執行常規的完成處理.它應該只執行必要的cleanup,比如釋放它在pre-oper callback例程中的CompletionContext引數分配的記憶體並返回FLT_POSTOP_FINISHED_PROCESSING. 

本節內容還包括以下這篇文章:

確保完成處理的執行在安全的IRQL

寫Post-oper Callback例程一文中提到的, IRP-I/O操作的post-oper callback例程 可以在DISPATCH_LEVEL呼叫,除非minifilter驅動的pre-oper callback例程通過返回FLT_PREOP_SYNCHRONIZE同步了這個操作或此操作是一個create操作(create操作本來就是同步的). (更多關於這個返回值的資訊,參考 返回FLT_PREOP_SYNCHRONIZE.) 

不過,對還沒有被同步的IRP-I/O操作來說,minifilter驅動可以兩種技術來確保完成處理的執行在IRQL <= APC_LEVEL. 

第一種技術是post-oper callback例程pend I/O操作直到完成例程可以在IRQL <= APC_LEVEL被執行.此技術的描述參考文章

第二種技術是post-oper callback例程呼叫FltDoCompletionProcessingWhenSafe. 僅噹噹前IRQL >= DISPATCH_LEVEL時FltDoCompletionProcessingWhenSafe才會pend I/O操作.否則,這個例程會直接執行minifilter驅動的SafePostCallback 例程. 此技術的描述參考文章FltDoCompletionProcessingWhenSafe

2.在post-oper callback例程中pend一個I/O操作

Minifilter驅動的post-oper callback例程 可以通過執行以下步驟來pend一個I/O操作: 

1. 呼叫FltAllocateDeferredIoWorkItem來為此I/O操作分配一個工作項

2. 呼叫 FltQueueDeferredIoWorkItem來把此I/O操作發給一個系統工作佇列

3. 返回FLT_POSTOP_MORE_PROCESSING_REQUIRED. 

注意如果以下條件為真則對FltQueueDeferredIoWorkItem的呼叫將會失敗

· 該操作不是IRP-I/O操作. 

· 該操作是分頁I/O操作. 

· 當前執行緒的TopLevelIrp域不為NULL. (更多如何找出此域的值的資訊參考IoGetTopLevelIrp.) 

· 該操作的目標例項正被拆卸. (filter管理器通過在post-oper callback例程的入參Flags 中設定FLTFL_POST_OPERATION_DRAINING標記來指示這個情況.) 

Minifilter驅動必須準備好處理失敗的情形.如果你的minifilter驅動不能處理這樣的失敗,你就應該考慮使用返回FLT_PREOP_SYNCHRONIZE 中的技術來取代pend該操作. 

在minifilter驅動的post-oper callback例程返回FLT_POSTOP_MORE_PROCESSING_REQUIRED之後,filter管理器將不會對該I/O操作進行任何深入處理直到minifilter驅動的工作例程呼叫 FltCompletePendedPostOperation來把操作的控制權返回給filter管理器. 在此情形之下filter管理器不會做任何深入處理即使工作執行緒在操作的callback資料結構的IoStatus.Status域中設定了一個失敗的NTSTATUS值.

出列和執行該I/O操作的完成的工作例程必須呼叫 FltCompletePendedPostOperation來把操作的控制權返回給filter管理器.

3.在post-oper callback例程中令一個I/O失敗

Minifilter驅動的post-oper callback例程 可以令一個成功的I/O操作失敗,但是簡單地令一個I/O操作失敗不會撤銷該操作的影響.minifilter驅動要負責執行撤銷該操作的一切所需的處理. 

例如,minifilter驅動的post-create callback例程可以通過執行以下步驟來令一個成功的IRP_MJ_CREATE操作失敗: 

1. 呼叫FltCancelFileOpen來關閉被create操作建立或開啟的檔案.注意FltCancelFileOpen不會撤銷對檔案的一切修改.例如FltCancelFileOpen不會刪除一個最新建立的檔案或恢復被刪減的檔案到以前的大小

2. 設定callback資料結構的IoStatus.Status域為該操作最終的NTSTATUS值.此值必須是一個有效的錯誤NTSTATUS值,比如 STATUS_ACCESS_DENIED. 

3. 設定callback資料結構的IoStatus.Information域為零

4. 返回FLT_POSTOP_FINISHED_PROCESSING. 

當設定callback資料結構的IoStatus.Status域為該操作最終的NTSTATUS值時,minifilter驅動必須指定一個有效的錯誤NTSTATUS值.注意這個minifilter驅動不可以指定STATUS_FLT_DISALLOW_FAST_IO;只有filter管理器可以使用這個NTSTATUS值. 

FltCancelFileOpen的呼叫者必須執行在IRQL <= APC_LEVEL.不過,一個minifilter驅動可以從post-create callback例程中安全地呼叫這個例程,因為, 對IRP_MJ_CREATE操作來說,post-oper callback例程在PASSIVE_LEVEL及發起這個create操作的執行緒的上下文中被呼叫. 

五、修改一個I/O操作的引數

Minifilter驅動可以修改一個I/O操作的引數.例如,一個minifilter驅動的pre-oper callback例程 可以通過改變操作的目標例項來把一個I/O操作重定向到另一個捲上. 新的目標例項必須是同一minifilter驅動在另一卷上並處於同一altitude的一個例項.

I/O操作的引數在這個操作的callback資料(FLT_CALLBACK_DATA)結構和I/O引數塊(FLT_IO_PARAMETER_BLOCK)結構中.minifilter驅動的pre-oper callback例程和post-oper callback例程會在入參Data中獲得此操作的callback資料結構指標.callback資料結構的成員Iopb是一個I/O引數塊結構(它包含這個操作的引數)的指標.

如果minifilter驅動的pre-oper callback例程修改了某個I/O操作的引數,則minifilter驅動例項棧中在它之下的所有minifilter驅動都會在它們的pre-oper和post-oper callback例程中收到修改後的引數.

已修改的引數不會被當前minifilter驅動的post-oper callback例程或minifilter驅動棧中一切在它之上的minifilter驅動接收到.在所有情況下,一個minifilter驅動的pre-oper和post-oper callback例程都會接收到一個給定的I/O操作的相同的入參值.

在修改了一個I/O操作的引數之後,pre-oper或post-oper callback例程必須指示通過呼叫FltSetCallbackDataDirty已經這樣做了(即修改了引數),除非它已經改變了callback資料結構的IoStatus域的內容.否則,過濾器管理器會忽視對引數值的一切改變. FltSetCallbackDataDirty會在I/O操作的callback資料結構中設定FLTFL_CALLBACK_DATA_DIRTY標記. Minifilter驅動可以呼叫FltIsCallbackDataDirty測試此標記或呼叫FltClearCallbackDataDirty來清除這個標記

如果某個minifilter驅動的pre-oper callback例程