Запрос и предоставление оплоков
Когда средство перенаправления сети обращается к файлам на удаленных серверах, оно запрашивает блокировку с удаленного сервера. Клиентские приложения напрямую запрашивают оппортунистические блокировки (oplocks) только в том случае, если блокировка предназначена для файла на локальном сервере.
oplocks запрашиваются через FSCTLs. Следующие FSCTLs используются для различных типов oplock, которые могут выдавать как приложения в пользовательском режиме, так и драйверы в режиме ядра.
- Чтобы запросить оплоки для Windows 7, выполните следующие действия.
- Запрос устаревших оплоков:
Запрос оплока в пользовательском режиме
Чтобы запросить oplock Windows 7 в режиме пользователя, вызовите DeviceIoControl:
- Установите для dwIoControlCode значение на FSCTL_REQUEST_OPLOCK.
- Передайте указатель на структуру REQUEST_OPLOCK_INPUT_BUFFER в параметре lpInBuffer.
- Для получения информации о том, как форматировать запрос oplock, см. документацию по этой структуре.
- Передайте указатель на структуру REQUEST_OPLOCK_OUTPUT_BUFFER в параметре lpOutBuffer.
Дополнительные сведения см. в FSCTL_REQUEST_OPLOCK.
Если запрошенная блокировка может быть предоставлена, DeviceIoControl возвращает значение FALSE и GetLastError возвращает ERROR_IO_PENDING. По этой причине оплоки никогда не предоставляются при синхронных операциях ввода-вывода. Перекрываемая операция не завершается до тех пор, пока не будет снята блокировка. Как только операция завершится, REQUEST_OPLOCK_OUTPUT_BUFFER будет содержать информацию о разрыве оплока.
Если не удается предоставить оплок, файловая система возвращает соответствующий код ошибки. Чаще всего возвращаются коды ошибок ERROR_OPLOCK_NOT_GRANTED и ERROR_INVALID_PARAMETER.
Запрос блокировки в режиме ядра
Чтобы запросить оплоки Windows 7 в режиме ядра:
Мини-фильтры файловой системы
Мини-фильтр файловой системы должен использовать FltAllocateCallbackData и заполнить выделенные FLT_CALLBACK_DATA следующим образом:
- Задайте поле Iopbна>MajorFunction значение IRP_MJ_FILE_SYSTEM_CONTROL.
- Задайте для поля Iopb->MinorFunction значение IRP_MN_USER_FS_REQUEST.
- Задайте параметру Iopb->элемента FileSystemControl.Buffered.FsControlCode значение FSCTL_REQUEST_OPLOCK.
- Выделите буфер, размер которого равен большему из REQUEST_OPLOCK_INPUT_BUFFER или REQUEST_OPLOCK_OUTPUT_BUFFER.
- Задайте выделенный элемент FLT_CALLBACK_DATAIopb->Parameters.FileSystemControl.Buffered.SystemBuffer, чтобы указать на этот буфер.
- Задайте выделенные FLT_CALLBACK_DATAIopb->Parameters.FileSystemControl.Buffered.InputBufferLength и Iopb->Parameters.FileSystemControl.Buffered.OutputBufferLength поля в размере этого буфера.
Сведения о форматировании запроса oplock см. в документации по структуре REQUEST_OPLOCK_INPUT_BUFFER.
Затем мини-фильтр файловой системы должен вызывать FltPerformAsynchronousIo, передав выделенный FLT_CALLBACK_DATA в качестве параметра CallbackData.
Если запрошенный оплок можно предоставить, вызов FltPerformAsynchronousIo возвращает STATUS_PENDING. По этой причине оплоки никогда не предоставляются при синхронных операциях ввода-вывода. Операция не завершается до тех пор, пока не будет нарушена блокировка. Как только операция завершится, REQUEST_OPLOCK_OUTPUT_BUFFER будет содержать информацию о разрыве оплока.
Если не удается предоставить оплок, файловая система возвращает соответствующий код ошибки. Чаще всего возвращаются коды ошибок STATUS_OPLOCK_NOT_GRANTED и STATUS_INVALID_PARAMETER.
Другие типы драйверов
Другие типы драйверов могут вызывать ZwFsControlFile:
- Задайте значением FsControlCodeFSCTL_REQUEST_OPLOCK.
- Передайте указатель на структуру REQUEST_OPLOCK_INPUT_BUFFER в параметре InputBuffer и задайте параметру InputBufferLength значение размера этого буфера.
- Передайте указатель на структуру REQUEST_OPLOCK_OUTPUT_BUFFER в параметре OutputBuffer и задайте параметру OutputBufferLength значение размера этого буфера.
Сведения о форматировании запроса oplock см. в документации по структуре REQUEST_OPLOCK_INPUT_BUFFER.
Если запрошенный оплок может быть предоставлен, вызов ZwFsControlFile возвращает STATUS_PENDING. По этой причине оплоки никогда не предоставляются при синхронных операциях ввода-вывода. Операция не завершается до тех пор, пока не будет нарушена блокировка. Как только операция завершится, REQUEST_OPLOCK_OUTPUT_BUFFER будет содержать информацию о разрыве оплока.
Если не удается предоставить оплок, файловая система возвращает соответствующий код ошибки. Чаще всего возвращаются коды ошибок STATUS_OPLOCK_NOT_GRANTED и STATUS_INVALID_PARAMETER.
Предотвращение нарушений общего доступа при запросе оплоков
Использование метода Atomic Create-With-Oplock
Атомарный тип create-with-oplock не является типом oplock. Скорее, это процедура, которая позволяет открывать операции, чтобы избежать нарушений режима общего доступа в интервале времени между открытием файла и получением оплока. При использовании устаревших оплоков требуются фильтрационные оплоки и открытие двух ручек. При использовании oplock в Windows 7 приложение или драйвер может запрашивать любой тип oplock с помощью этой процедуры и требуется открыть только один дескриптор.
Чтобы выполнить атомарную процедуру create-with-oplock, необходимо:
- Для открытия файла используйте FltCreateFileEx2 или ZwCreateFile, в зависимости от необходимости. В параметре CreateOptions передайте флаг FILE_OPEN_REQUIRING_OPLOCK. Вы можете задать параметры DesiredAccess и ShareAccess как угодно. Например, в наборе параметров DesiredAccess установите GENERIC_READ, чтобы можно было прочитать файл, а в параметре ShareAccess установите флаги FILE_SHARE_READ | FILE_SHARE_DELETE, позволяющие другим пользователям читать, переименовывать и/или помечать файл для удаления, пока он открыт вами.
- Используйте код элемента управления FSCTL_REQUEST_OPLOCK, чтобы запросить оплок в результирующем объекте файла или дескрипторе, как описано в запросе оплока в режиме ядра.
Не выполняйте никаких операций файловой системы в файле между шагами 1 и 2. Это может привести к взаимоблокировкам.
Наиболее распространённый оплок для запроса с помощью этой процедуры — это тип Read-Handle. Это позволяет предоставить другим абонентам максимальный одновременный доступ, при этом уведомляться, если необходимо закрыть дескриптор, чтобы избежать нарушения общего доступа в случае конфликта при открытии.
Использование устаревшего фильтра Oplock
Устаревшая блокировка фильтра также позволяет приложению "вернуться", когда другие приложения или клиенты пытаются получить доступ к тому же потоку, но менее гибким, чем атомарный метод create-with-oplock. Этот механизм позволяет приложению получать доступ к потоку, не приводя к нарушениям общего доступа у других объектов доступа при попытке открыть поток. Чтобы избежать нарушений общего доступа, следует использовать следующую трехэтапную процедуру для запроса оплока фильтра:
Откройте файл с доступом, необходимым для FILE_READ_ATTRIBUTES, и с режимом совместного использования FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE. Дескриптор, открытый на этом шаге, не приведет к нарушениям общего доступа к другим приложениям, так как он открыт только для доступа к атрибутам (FILE_READ_ATTRIBUTES), а не доступа к данным (FILE_READ_DATA). Этот дескриптор подходит для запроса оплока фильтра, но не для выполнения фактических операций ввода-вывода в потоке данных.
Запрос блокировки фильтра (FSCTL_REQUEST_FILTER_OPLOCK) на дескриптор из шага 1. Оплок, предоставленный на этом шаге, позволяет владельцу oplock "выйти из пути", не вызывая нарушение общего доступа к другому приложению, которое пытается получить доступ к потоку.
Снова откройте файл для доступа на чтение. Рукоятка, открытая на этом шаге, позволяет держателю блокировки oplock выполнять ввод-вывод на потоке.
Файловая система NTFS обеспечивает оптимизацию этой процедуры с помощью флага параметра создания FILE_RESERVE_OPFILTER. Если этот флаг указан на шаге 1 предыдущей процедуры, он позволяет файловой системе завершить запрос на создание со статусом STATUS_OPLOCK_NOT_GRANTED, если файловая система сможет определить, что шаг 2 потерпит неудачу. Если шаг 1 успешно выполнен, нет гарантии успешности шага 2, даже если FILE_RESERVE_OPFILTER был указан для запроса на создание.
Условия предоставления oplocks
В следующей таблице определены необходимые условия, необходимые для предоставления оплока.
Тип запроса | Условия |
---|---|
Уровень 1 Фильтр Партия |
Предоставляется только в том случае, если выполняются все следующие условия:
Если текущее состояние оплока:
|
Уровень 2 |
Предоставляется только в том случае, если выполняются все следующие условия:
Если текущее состояние оплока:
|
Читать |
Предоставляется только в том случае, если выполняются все следующие условия:
Если текущее состояние оплока:
|
Read-Handle |
Предоставляется только в том случае, если выполняются все следующие условия:
Если текущее состояние оплока:
|
Read-Write |
Предоставляется только в том случае, если выполняются все следующие условия:
Если текущее состояние оплока:
|
Прочтите —Write-Handle |
Предоставлено только в случае, если все следующие утверждения истинны:
Если текущее состояние оплока:
|
Заметка
Операции чтения и оплоки уровня 2 могут сосуществовать в одном потоке. Операции чтения и оплоки Read-Handle могут сосуществовать. Однако оплоки уровня 2 и Read-Handle не могут сосуществовать.