Share via


分派常式的條件約束

注意

為了獲得最佳可靠性和效能,請使用 檔案系統迷你篩選驅動程式 搭配篩選管理員支援,而不是舊版檔案系統篩選驅動程式。 若要將舊版驅動程式移植到迷你篩選驅動程式,請參閱 移植舊版篩選驅動程式的指導方針

下列指導方針簡短討論舊版檔案系統篩選驅動程式如何避免分派常式中的常見程式設計錯誤。

如需分頁 I/O 中使用哪些 IRP 類型的資訊,請參閱 分派常式 IRQL 和執行緒內容

  • 分頁 I/O 路徑中的分派常式絕對不應該在任何大於 APC_LEVEL的 IRQL 上呼叫 IoCallDriver 。 您無法在DISPATCH_LEVEL執行分頁 I/O (或任何 I/O) ,因為系統會使用 APC 來處理 I/O 完成,因此您永遠不會看到作業已完成。 如果分派常式引發 IRQL,它必須先將其降低,才能呼叫 IoCallDriver

  • 在所有情況下,分派常式在APC_LEVEL呼叫 IoCallDriver 並不一定安全。 請參閱 分派常式 IRQL 和執行緒內容 ,以判斷您是否可以在 APC_LEVEL,或必須位於 PASSIVE_LEVEL。

  • 分頁 I/O 路徑中的分派常式,例如讀取和寫入,無法安全地呼叫任何需要呼叫端在 IRQL PASSIVE_LEVEL執行的核心模式常式。

  • 分派分頁檔案 I/O 路徑中的常式無法安全地呼叫任何需要呼叫端在 IRQL < DISPATCH_LEVEL執行的核心模式常式。

  • 分派不在分頁 I/O 路徑中的常式,絕對不應該在任何 IRQL 呼叫大於 PASSIVE_LEVEL 的 IoCallDriver 。 如果分派常式引發 IRQL,它必須先將其降低,才能呼叫 IoCallDriver

處理 IRP 的條件約束

  • 如果 IRP 參數包含任何使用者空間位址,則必須在使用這些位址之前先驗證這些位址。 如需詳細資訊,請參閱 緩衝 I/O 中的錯誤

  • 此外,如果 IRP 包含從 32 位平臺傳送到 64 位平臺的 IOCTL 或 FSCTL 緩衝區,則可能需要叫用緩衝區內容。 如需詳細資訊,請參閱 在 64 位驅動程式中支援 32 位 I/O

  • 不同于檔案系統,檔案系統篩選驅動程式應該永遠不會呼叫 FsRtlEnterFileSystemFsRtlExitFileSystem ,但呼叫 ExAcquireFastMutexUnsafeExAcquireResourceExclusiveLite之前除外。 FsRtlEnterFileSystemFsRtlExitFileSystem 會停用大部分檔案系統所需的一般核心 APC。

  • 您無法從分頁 I/O 路徑發出其他 IRP。 您可以將發出 I/O 的背景工作執行緒排入佇列,但不得同步等候該背景工作執行緒完成,因為等候會導致死結。

完成 IRP 的條件約束

  • 檔案系統篩選驅動程式應該只在完成 IRP 時使用成功和錯誤狀態值。

  • 雖然STATUS_PENDING是成功的 NTSTATUS 值,但它是使用 STATUS_PENDING 完成 IRP 的程式設計錯誤。

  • 分派常式呼叫 IoCompleteRequest之後,IRP 指標已不再有效且無法安全地取值。

設定完成常式的條件約束

如需設定完成常式的詳細資訊,請參閱 使用完成常式

  • 當分派常式呼叫 IoSetCompletionRoutine時,它可以選擇性地將 內容 指標傳遞至結構,讓完成常式在處理指定的 IRP 時使用。 此結構必須從非分頁集區配置,因為完成常式可以稱為 IRQL DISPATCH_LEVEL。

  • 如果分派常式設定可能會傳回STATUS_MORE_PROCESSING_REQUIRED的完成常式,則必須執行下列其中一項動作,以防止 I/O 管理員提前完成 IRP:

關閉 IRP 的條件約束

  • 分派常式呼叫 IoCallDriver之後,IRP 指標已不再有效,而且無法安全地取值,除非分派常式等候完成常式發出已呼叫的訊號。

  • 從檔案系統篩選驅動程式呼叫 PoCallDriver 是程式設計錯誤。 (PoCallDriver 可用來將IRP_MJ_POWER要求傳遞至較低層級的驅動程式。檔案系統篩選驅動程式永遠不會收到IRP_MJ_POWER requests。)

傳回狀態的條件約束

  • 除了完成 IRP 時,未設定完成常式的分派常式應該一律傳回 IoCallDriver所傳回的 NTSTATUS 值。 除非此值STATUS_PENDING,否則它必須符合完成 IRP 的驅動程式所設定的 Irp-IoStatus.Status > 值。

  • 當 IoCallDriver傳回STATUS_PENDING時,除非它等候完成常式發出事件訊號,否則分派常式也應該傳回STATUS_PENDING。

  • 當分派常式將 IRP 張貼到背景工作佇列以供稍後處理時,應該將 IRP 標示為擱置中,並傳回STATUS_PENDING。

  • 當分派常式設定可能會將 IRP 張貼到背景工作佇列以供稍後處理的完成常式時,它應該標示 IRP 擱置中並傳回STATUS_PENDING。

  • 標示 IRP 暫止的分派常式必須傳回STATUS_PENDING。

  • 無法將 Oplock 作業貼上 (張貼到背景工作佇列) ,而且分派常式無法傳回STATUS_PENDING。

將 IRP 張貼至工作佇列的條件約束

  • 如果分派常式將 IRP 張貼到工作佇列,它必須先呼叫 IoMarkIrpPending ,再將每個 IRP 張貼到背景工作佇列。 否則,IRP 可能會清除佇列、由另一個驅動程式常式完成,並在呼叫 IoMarkIrpPending 之前由系統釋放,因而造成當機。