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


Запрос и предоставление оплоков

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

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

Чтобы запросить блокировку Windows 7 в пользовательском режиме, вызовите DeviceIoControl:

Аналогичным образом, чтобы запросить блокировки Windows 7 в режиме ядра:

Чтобы указать, какой из четырех блокировок Windows 7 требуется, установите один или несколько следующих флагов в элементе RequestedOplockLevel структуры REQUEST_OPLOCK_INPUT_BUFFER :

  • OPLOCK_LEVEL_CACHE_READ
  • OPLOCK_LEVEL_CACHE_HANDLE
  • OPLOCK_LEVEL_CACHE_WRITE

Дополнительные сведения см. в разделе FSCTL_REQUEST_OPLOCK.

Если запрошенную блокировку можно предоставить, файловая система возвращает STATUS_PENDING. По этой причине операции блокировки никогда не предоставляются для синхронных операций ввода-вывода. FSCTL IRP не завершается до тех пор, пока не будет нарушена блокировка.

Если не удается предоставить блокировку, файловая система возвращает соответствующий код ошибки. Чаще всего возвращаются коды ошибок STATUS_OPLOCK_NOT_GRANTED и STATUS_INVALID_PARAMETER (а также их эквивалентные аналоги в пользовательском режиме).

Блокировка фильтра позволяет приложению "вернуться", когда другие приложения или клиенты пытаются получить доступ к тому же потоку. Этот механизм позволяет приложению получить доступ к потоку, не вызывая при попытке открытия потока другие методы доступа к потоку. Чтобы избежать нарушений общего доступа, для запроса блокировки фильтра (FSCTL_REQUEST_FILTER_OPLOCK) следует использовать специальную трехэтапную процедуру:

  1. Откройте файл с требуемым доступом FILE_READ_ATTRIBUTES и режимом общего доступа FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE.

  2. Запрос блокировки фильтра на дескрипторе из шага 1.

  3. Откройте файл еще раз для чтения.

Дескриптор, открытый на шаге 1, не приведет к тому, что другие приложения будут получать нарушения общего доступа, так как он открыт только для доступа к атрибутам (FILE_READ_ATTRIBUTES), а не для доступа к данным (FILE_READ_DATA). Этот дескриптор подходит для запроса блокировки фильтра, но не для выполнения фактических операций ввода-вывода в потоке данных. Дескриптор, открытый на шаге 3, позволяет владельцу блокировки выполнять операции ввода-вывода в потоке; блокировка, предоставленная на шаге 2, позволяет владельцу блокировки "выйти из пути", не вызывая нарушения общего доступа к другому приложению, которое пытается получить доступ к потоку.

Файловая система NTFS обеспечивает оптимизацию для этой процедуры с помощью флага параметра FILE_RESERVE_OPFILTER создания. Если этот флаг указан на шаге 1 предыдущей процедуры, это позволяет файловой системе завершить запрос на создание с STATUS_OPLOCK_NOT_GRANTED если файловая система может определить, что шаг 2 завершится ошибкой. Если шаг 1 завершается успешно, нет никакой гарантии, что шаг 2 будет выполнен успешно, даже если для запроса на создание было указано FILE_RESERVE_OPFILTER.

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

Тип запроса Условия

уровне 1

Фильтр

Пакетная служба

Предоставляется, только если выполняются все следующие условия:

  • Запрос предназначен для заданного потока файла.
    • Если каталог, возвращается STATUS_INVALID_PARAMETER.
  • Поток открывается для доступа АСИНХРОННЫЙ.
    • При открытии для доступа SYNCHRONOUS возвращается STATUS_OPLOCK_NOT_GRANTED (операции блокировки не предоставляются для синхронных запросов ввода-вывода).
  • Транзакции TxF отсутствуют ни в одном потоке файла.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.
  • В потоке нет других открытий (даже в том же потоке).
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.

Если текущее состояние блокировки операции:

  • Без блокировки: запрос предоставлен.

  • Уровень 2. Исходный запрос уровня 2 нарушается с FILE_OPLOCK_BROKEN_TO_NONE. Затем предоставляется запрошенная монопольная блокировка.

  • Уровень 1, пакетная обработка, фильтрация, чтение, чтение, чтение, запись или дескриптор чтения и записи: возвращается STATUS_OPLOCK_NOT_GRANTED.

Уровень 2

Предоставляется, только если выполняются все следующие условия:

  • Запрос предназначен для заданного потока файла.
    • Если каталог, возвращается STATUS_INVALID_PARAMETER.
  • Поток открывается для доступа АСИНХРОННЫЙ.
    • Если он открыт для доступа SYNCHRONOUS, возвращается STATUS_OPLOCK_NOT_GRANTED.
  • Транзакции TxF в файле отсутствуют.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.
  • В потоке нет текущих блокировок диапазона байтов.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.
    • До Windows 7 операционная система проверяет, существовала ли блокировка диапазона байтов в потоке с момента последнего открытия, и, если это так, не выполняет запрос.

Если текущее состояние блокировки операции:

  • Без блокировки: запрос предоставлен.

  • Уровень 2 и (или) Чтение: запрос предоставлен. Вы можете одновременно предоставить несколько блокировок чтения или уровня 2 в одном потоке. Несколько блокировок уровня 2 (но не чтение) могут даже существовать на одном дескрипторове.
    • Если операция read запрашивается на дескрипторов, для которого уже предоставлена блокировка Read, IRP первого операции Read завершается с STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE до предоставления второго операции read.
  • Уровень 1, пакетная обработка, фильтр, чтение- дескриптор, чтение и запись, чтение и запись: STATUS_OPLOCK_NOT_GRANTED возвращается.

Read

Предоставляется, только если выполняются все следующие условия:

  • Запрос предназначен для заданного потока файла.
  • Поток открывается для доступа АСИНХРОННЫЙ.
    • Если он открыт для доступа SYNCHRONOUS, возвращается STATUS_OPLOCK_NOT_GRANTED.
  • Транзакции TxF в файле отсутствуют.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.
  • В потоке нет текущих блокировок диапазона байтов.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.

Имейте в виду, что, если текущее состояние блокировки:

  • Без блокировки: запрос предоставлен.

  • Уровень 2 и (или) Чтение: запрос предоставлен. Вы можете одновременно предоставить несколько блокировок чтения или уровня 2 в одном потоке.
    • Кроме того, если существующий oplock имеет тот же ключ, что и новый запрос, его IRP завершается с STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
  • Read-Handle и существующей операции блокировки имеют другой ключ блокировки, отличный от нового запроса: запрос предоставлен. Несколько операций чтения и Read-Handle могут сосуществовать в одном потоке (см. примечание ниже).
    • В противном случае (ключи блокировки совпадают) STATUS_OPLOCK_NOT_GRANTED возвращается.
  • Уровень 1, пакетная обработка, фильтр, чтение и запись, чтение и запись: возвращается STATUS_OPLOCK_NOT_GRANTED.

Read-Handle

Предоставляется, только если выполняются все следующие условия:

  • Запрос предназначен для заданного потока файла.
  • Поток открыт для доступа ASYNCHRONOUS.
    • При открытии для доступа SYNCHRONOUS возвращается STATUS_OPLOCK_NOT_GRANTED.
  • В файле нет транзакций TxF.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.
  • В потоке нет текущих блокировок диапазона байтов.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.

Если текущее состояние oplock равно:

  • Без блокировки: запрос предоставлен.

  • Чтение: запрос предоставлен.
    • Если существующий блок read oplock имеет тот же ключ, что и новый запрос, его IRP завершается с помощью STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE. В результате операция будет обновлена с read до Read-Handle.
    • Все существующие операции read oplock, которые не имеют того же ключа oplock, что и новый запрос, остаются без изменений.
  • Уровень 2, уровень 1, пакетная обработка, фильтрация, чтение и запись, чтение и запись: возвращается STATUS_OPLOCK_NOT_GRANTED.

Read-Write

Предоставляется, только если выполняются все следующие условия:

  • Запрос предназначен для заданного потока файла.
    • Если каталог, возвращается STATUS_INVALID_PARAMETER.
  • Поток открыт для доступа ASYNCHRONOUS.
    • При открытии для доступа SYNCHRONOUS возвращается STATUS_OPLOCK_NOT_GRANTED.
  • В файле нет транзакций TxF.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.
  • Если в потоке есть другие открытия (даже в том же потоке), они должны иметь тот же ключ oplock.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.

Если текущее состояние oplock равно:

  • Без блокировки: запрос предоставлен.

  • Чтение или Read-Write, и существующий oplock имеет тот же ключ oplock, что и запрос: IRP существующего oplock завершается с помощью STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE, запрос предоставляется.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.
  • Уровень 2, уровень 1, пакетная служба, фильтр, дескриптор чтения, чтение и запись: возвращается STATUS_OPLOCK_NOT_GRANTED.

Дескриптор чтения и записи

Предоставляется только в том случае, если выполняются все перечисленные ниже условия.

  • Запрос предназначен для заданного потока файла.
    • Если каталог, возвращается STATUS_INVALID_PARAMETER.
  • Поток открыт для доступа ASYNCHRONOUS.
    • При открытии для доступа SYNCHRONOUS возвращается STATUS_OPLOCK_NOT_GRANTED.
  • В файле нет транзакций TxF.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.
  • При наличии других открытых запросов в потоке (даже в том же потоке) у них должен быть один и тот же ключ oplock.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.

Если текущее состояние oplock равно:

  • Без блокировки: запрос предоставлен.

  • Read, Read-Handle, Read-Write или Read-Write-Handle, и существующий oplock имеет тот же ключ oplock, что и запрос: IRP существующего oplock завершается с STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE, запрос предоставляется.
    • В противном случае возвращается STATUS_OPLOCK_NOT_GRANTED.
  • Уровень 2, уровень 1, пакетная служба, фильтр: возвращается STATUS_OPLOCK_NOT_GRANTED.

Примечание

Операции чтения и операции уровня 2 могут сосуществовать в одном потоке, а операции чтения и Read-Handle могут сосуществовать, но уровни 2 и Read-Handle не могут сосуществовать.