Поделиться через


Написание процедур обратного вызова перед операцией

Драйвер минифильтра использует одну или несколько процедур обратного вызова перед операцией для фильтрации операций ввода-вывода. Процедуры обратного вызова перед операцией аналогичны подпрограммам диспетчеризации, используемым в устаревшей модели фильтра.

Минифильтр регистрирует подпрограмму обратного вызова перед операцией для определенного типа операций ввода-вывода, сохраняя точку входа подпрограммы обратного вызова в элементе OperationRegistrationструктуры FLT_REGISTRATION . Минифильтр передает этот элемент в FltMgr в качестве параметра FltRegisterFilter в своей подпрограмме DriverEntry .

Минифильтры получают только те типы операций ввода-вывода, для которых они зарегистрировали подпрограмму обратного вызова перед операцией или после операции. Минифильтр может зарегистрировать подпрограмму обратного вызова перед операцией для определенного типа операций ввода-вывода без регистрации подпрограммы обратного вызова после операции и наоборот.

Каждая подпрограмма обратного вызова перед операцией определяется следующим образом:

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

Когда FltMgr вызывает подпрограмму обратного вызова минифильтра перед операцией ввода-вывода для определенной операции ввода-вывода, минифильтр временно управляет операцией ввода-вывода. Минифильтр сохраняет этот элемент управления до тех пор, пока не будет:

  • Возвращает значение состояния, отличное от FLT_PREOP_PENDING из подпрограммы обратного вызова перед операцией.

  • Вызывает FltCompletePendedPreOperation из рабочей процедуры, которая обработала операцию, которая ранее была выполнена в процедуре обратного вызова перед операцией.

В следующей таблице перечислены несколько возможных сценариев использования процедуры обратного вызова минифильтра перед операцией, а также приведены сведения о реализации и возвращаемое значение для каждого сценария.

Сценарии использования Реализация Возвращаемое значение
Подпрограмма не относится к операции и не требует окончательного состояния операции или не имеет обратного вызова после операции. Передайте операцию ввода-вывода и попросите FltMgr не вызывать обратный вызов минифильтра после операции после завершения. FLT_PREOP_SUCCESS_NO_CALLBACK
Подпрограмме требуется окончательное состояние операции. Передайте операцию и попросите FltMgr вызвать подпрограмму обратного вызова минифильтра после операции. FLT_PREOP_SUCCESS_WITH_CALLBACK
Минифильтр должен завершить или продолжить обработку этой операции в будущем. Переведите операцию в состояние ожидания. Используйте FltCompletePendedPreOperation , чтобы завершить операцию позже. Может существовать допустимая гонка между подпрограммой перед операцией, возвращающей FLT_PREOP_PENDING, и вызовом FltCompletePendingOperation . FltMgr обрабатывает этот сценарий без входных данных от драйвера. FLT_PREOP_PENDING
Обработка после операции должна выполняться в контексте того же потока, что и подпрограмма диспетчеризации. Это условие обеспечивает согласованность IRQL и поддерживает состояние локальной переменной. Синхронизируйте операцию с последующей операцией. FLT_PREOP_SYNCHRONIZE
Подпрограмма обратного вызова перед операцией должна завершить операцию. Остановите обработку для операции и назначьте окончательное значение NTSTATUS. FLT_PREOP_COMPLETE

Процедуры обратного вызова IRQL и перед операцией

FltMgr не может узнать, что минифильтр может делать при обратном вызове перед операцией (или любом обратном вызове). Таким образом, FltMgr не может определить, может ли вызов обратного вызова мини-порта до операции вызвать проблему. (Есть вещи, которые вы можете безопасно делать при повышенных irQL и вещи, которые вы не можете). Таким образом, минифильтр должен знать о IRQL и обрабатывать его соответствующим образом. Минифильтр может безопасно и дешево вызывать KeGetCurrentIRQL в ситуациях, когда ему необходимо знать IRQL, по которому он был вызван.

Полезно знать следующие сведения о процедуре обратного вызова irQL перед операцией минифильтра:

  • Обратный вызов перед операцией можно вызвать по адресу IRQL = PASSIVE_LEVEL или IRQL = APC_LEVEL. Большинство обратных вызовов перед операцией вызываются по адресу IRQL = PASSIVE_LEVEL в контексте потока, из которого был создан запрос ввода-вывода. В IRQL = APC_LEVEL можно вызвать только несколько обратных вызовов перед операцией.

  • Для операций на основе IRP обратный вызов минифильтра можно вызвать в контексте системного рабочего потока, если более высокий фильтр или драйвер минифильтра выполняет операцию для обработки рабочим потоком. Обратный вызов перед операцией эквивалентен подпрограмме диспетчеризации устаревшего фильтра, поэтому знание контекста IRQL и потока подпрограммы диспетчеризации устаревшего фильтра может быть полезным.

  • Объекты контекста нельзя получить в подпрограммах после операции на APC_LEVEL IRQL > . Вместо этого можно либо получить объект контекста во время процедуры перед операцией и передать его в подпрограмму после операции, либо выполнить обработку после операции в IRQL <= APC_LEVEL. Дополнительные сведения о контекстах см. в разделе Управление контекстами.

Передача операции ввода-вывода вниз по стеку экземпляров минифильтра

Завершение операции ввода-вывода в процедуре обратного вызова перед операцией

Запрет быстрых операций ввода-вывода в процедуре обратного вызова перед операцией

Ожидание операции ввода-вывода в подпрограмме обратного вызова перед операцией