Sdílet prostřednictvím


Vyžádání a udělení oplocků

Když přesměrovač sítě přistupuje k souborům na vzdálených serverech, požádá o oplock ze vzdáleného serveru. Klientské aplikace přímo požadují oplocks pouze v případě, že zámek je určený pro soubor na místním serveru.

oplocks se vyžadují prostřednictvím FSCTLs. Následující FSCTLs se používají pro různé typy oplock, které mohou být vydávány jak aplikacemi v uživatelském režimu, tak i ovladači v režimu jádra.

Žádost o oplock v uživatelském režimu

Pokud chcete požádat o oplock systému Windows 7 v uživatelském režimu, zavolejte DeviceIoControl:

Pro další informace viz FSCTL_REQUEST_OPLOCK.

Pokud lze požadované oplock udělit, DeviceIoControl vrátí hodnotu FALSE a GetLastError vrátí ERROR_IO_PENDING. Z tohoto důvodu nejsou zámky oplock nikdy poskytovány pro synchronní vstupně-výstupní operace. Překrývající se operace se nedokončí, dokud nedojde k přerušení oplocku. Po dokončení operace bude REQUEST_OPLOCK_OUTPUT_BUFFER obsahovat informace o přerušení oplocku.

Pokud oplock nelze udělit, systém souborů vrátí odpovídající kód chyby. Nejčastěji vrácené kódy chyb jsou ERROR_OPLOCK_NOT_GRANTED a ERROR_INVALID_PARAMETER.

Vyžádání oplocku v režimu jádra

Pokud chcete požádat o oplocky Windows 7 v režimu jádra:

Minifiltry systému souborů

Minifiltr systému souborů musí používat FltAllocateCallbackData a vyplnit přidělené FLT_CALLBACK_DATA takto:

  • Nastavte ->MajorFunction pole na IRP_MJ_FILE_SYSTEM_CONTROL.
  • Nastavte pole Iopb->MinorFunction na IRP_MN_USER_FS_REQUEST.
  • Nastavte proměnnou člena Iopb->Parametry.FileSystemControl.Buffered.FsControlCode na FSCTL_REQUEST_OPLOCK.
  • Přidělit vyrovnávací paměť, jejíž velikost je rovna většímu z čísel mezi REQUEST_OPLOCK_INPUT_BUFFER a REQUEST_OPLOCK_OUTPUT_BUFFER.
    • Nastavte přidělený FLT_CALLBACK_DATAIopb->Parameters.FileSystemControl.Buffered.SystemBuffer člen tak, aby odkazoval na danou vyrovnávací paměť.
    • Nastavte přidělené FLT_CALLBACK_DATAIopb->Parameters.FileSystemControl.Buffered.InputBufferLength a Iopb->Parameters.FileSystemControl.Buffered.OutputBufferLength pole na velikost této vyrovnávací paměti.

Informace o tom, jak formátovat požadavek oplock, najdete v dokumentaci struktury REQUEST_OPLOCK_INPUT_BUFFER.

Poté musí minifiltr souborového systému zavolat FltPerformAsynchronousIoa předat jako parametr CallbackData přidělené FLT_CALLBACK_DATA.

Pokud je možné udělit požadovaný oplock, vrátí volání FltPerformAsynchronousIo STATUS_PENDING. Z tohoto důvodu nejsou zámky oplock nikdy poskytovány pro synchronní vstupně-výstupní operace. Operace se nedokončí, dokud nedojde k přerušení oplocku. Po dokončení operace bude REQUEST_OPLOCK_OUTPUT_BUFFER obsahovat informace o přerušení oplocku.

Pokud oplock nelze udělit, systém souborů vrátí odpovídající kód chyby. Nejčastěji vrácené kódy chyb jsou STATUS_OPLOCK_NOT_GRANTED a STATUS_INVALID_PARAMETER.

Další druhy ovladačů

Jiné druhy ovladačů mohou volat ZwFsControlFile:

Informace o tom, jak formátovat požadavek oplock, najdete v dokumentaci struktury REQUEST_OPLOCK_INPUT_BUFFER.

Pokud lze požadované oplock udělit, volání ZwFsControlFile vrátí STATUS_PENDING. Z tohoto důvodu nejsou zámky oplock nikdy poskytovány pro synchronní vstupně-výstupní operace. Operace se nedokončí, dokud není oplock zrušen. Po dokončení operace bude REQUEST_OPLOCK_OUTPUT_BUFFER obsahovat informace o přerušení oplocku.

Pokud oplock nelze udělit, systém souborů vrátí odpovídající kód chyby. Nejčastěji vrácené kódy chyb jsou STATUS_OPLOCK_NOT_GRANTED a STATUS_INVALID_PARAMETER.

Zabránění porušení sdílení při vyžádání oplocků

Použití metody Atomic Create-With-Oplock

Atomic create-with-oplock není typ oplocku. Jedná se spíše o postup, který umožňuje otevřeným operacím zabránit porušení režimu sdílení v časovém intervalu mezi otevřením souboru a příjmem oplocku. U starších oplocků jsou vyžadovány filtrační oplocky a otevření dvou popisovačů. V případě oplocků ve Windows 7 může aplikace nebo ovladač požádat o libovolný typ oplock pomocí tohoto postupu a stačí otevřít pouze jeden popisovač.

Pokud chcete provést atomickou proceduru create-with-oplock, měli byste:

  1. K otevření souboru použijte FltCreateFileEx2 nebo ZwCreateFile. V parametru CreateOptions předejte příznak FILE_OPEN_REQUIRING_OPLOCK. Podle potřeby můžete nastavit parametry DesiredAccess a ShareAccess. Například v sadě parametrů DesiredAccessGENERIC_READ, abyste mohli soubor číst, a v parametru ShareAccess nastavte FILE_SHARE_READ | FILE_SHARE_DELETE příznaky, které ostatním umožní číst, přejmenovat nebo označit soubor pro odstranění, když ho máte otevřený.
  2. Pomocí řídicího kódu FSCTL_REQUEST_OPLOCK požádejte o zámek (oplock) u výsledného objektu nebo popisovače souboru, jak je popsáno v Žádost o zámek (oplock) v režimu jádra.

Neprovádějte žádné operace se systémem souborů v souboru mezi kroky 1 a 2. To může způsobit zablokování.

Nejběžnější oplock pro vyžádání pomocí tohoto postupu je typ Read-Handle. To vám umožní poskytnout ostatním volajícím co nejvíce souběžného přístupu, zatímco stále můžete být upozorněni, pokud potřebujete zavřít svůj popisovač, abyste zabránili narušení sdílení při konfliktním otevření.

Použití starší verze filtrového oplocku

Starší oplock filtru také umožňuje aplikaci "back out", když se ostatní aplikace nebo klienti pokusí o přístup ke stejnému streamu, ale je méně flexibilní než atomická metoda create-with-oplock. Tento mechanismus umožňuje aplikaci přistupovat k datovému proudu, aniž by způsoboval, že ostatní uživatelé datového proudu při pokusu o jeho otevření obdrží porušení sdílení. Abyste se vyhnuli porušení sdílení, měli byste použít následující třístupňový postup k vyžádání oplocku filtrů:

  1. Otevřete soubor s požadovaným přístupem FILE_READ_ATTRIBUTES v režimu sdílení FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE. Popisovač otevřený v tomto kroku nezpůsobí, že ostatní aplikace obdrží porušení sdílení, protože je otevřený jenom pro přístup k atributům (FILE_READ_ATTRIBUTES) a ne pro přístup k datům (FILE_READ_DATA). Tento popisovač je vhodný pro vyžádání oplocku filtru, ale ne pro provádění skutečných vstupně-výstupních operací datového streamu.

  2. Na popisovači z kroku 1 požádejte o oplock filtru (FSCTL_REQUEST_FILTER_OPLOCK). Oplock udělený v tomto kroku umožňuje držiteli oplocku "vyjít z cesty", aniž by způsobil porušení sdílení jiné aplikace, která se pokusí o přístup ke streamu.

  3. Znovu otevřete soubor pro čtení. Popisovač otevřený v tomto kroku umožňuje držiteli oplocku provádět vstupně-výstupní operace ve streamu.

Systém souborů NTFS poskytuje optimalizaci pro tento postup prostřednictvím příznaku FILE_RESERVE_OPFILTER vytvořit možnost. Pokud je tento příznak zadán v kroku 1 předchozího postupu, umožní systému souborů zamítnout žádost o vytvoření se STATUS_OPLOCK_NOT_GRANTED, pokud systém souborů může určit, že krok 2 selže. Pokud krok 1 proběhne úspěšně, neexistuje žádná záruka, že krok 2 bude úspěšný, i když FILE_RESERVE_OPFILTER byl zadán pro požadavek vytvoření.

Podmínky pro udělení oplocků

Následující tabulka uvádí požadované podmínky nezbytné k udělení oplocku.

Typ požadavku Podmínky

Úroveň 1

Filtr

Várka

Uděleno pouze v případě, že jsou splněny všechny následující podmínky:

  • Požadavek je určený pro daný datový proud souboru.
    • Pokud se jedná o adresář, je vrácen STATUS_INVALID_PARAMETER.
  • Datový proud je otevřen pro asynchronní přístup.
    • Pokud je otevřen pro synchronní přístup, vrátí se STATUS_OPLOCK_NOT_GRANTED (pro synchronní I/O požadavky se neudělují oplocky).
  • Na žádném datovém proudu souboru neexistují žádné TxF transakce.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Ve streamu nejsou žádné další otevření (dokonce i stejným vláknem).
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.

Pokud je aktuální stav oplocku:

  • Bez oplocku: Žádost byla schválena.

  • Úroveň 2: Původní požadavek úrovně 2 se přerušuje s FILE_OPLOCK_BROKEN_TO_NONE. Poté se udělí požadovaný výhradní „oplock“.

  • Vrátí se úroveň 1, dávka, filtr, čtení, popisovač pro čtení, zápis nebo popisovač pro čtení i zápis: STATUS_OPLOCK_NOT_GRANTED.

Úroveň 2

Uděleno pouze v případě, že jsou splněny všechny následující podmínky:

  • Požadavek je určený pro daný datový proud souboru.
    • Pokud se jedná o adresář, je vrácen STATUS_INVALID_PARAMETER.
  • Datový proud je otevřen pro asynchronní přístup.
    • Pokud je otevřen pro SYNCHRONNÍ přístup, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Soubor neobsahuje žádné transakce TxF.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • V datovém proudu nejsou žádné aktuální zámky rozsahu bajtů.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
    • Před Windows 7 operační systém zjistí, zda od posledního otevření datového proudu existoval zámek rozsahu bajtů, a pokud ano, zamítne požadavek.

Pokud je aktuální stav oplocku:

  • Bez oplocku: Žádost byla schválena.

  • Úroveň 2 a/nebo povolení ke čtení: Žádost byla schválena. Ve stejném datovém proudu můžete mít najednou udělených více oplocků úrovně 2/Read. Na stejném popisovači může existovat i více oplocků úrovně 2 (ale ne typu Read).
    • Pokud se požaduje oplock čtení na popisovači, který už má udělený oplock čtení, první oplock čtení IRP se dokončí se stavem STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE před udělením druhého oplocku čtení.
  • Úroveň 1, dávka, filtr, popisovač pro čtení, čtení a zápis, popisovač pro čtení i zápis: STATUS_OPLOCK_NOT_GRANTED se vrátí.

Číst

Uděleno pouze v případě, že jsou splněny všechny následující podmínky:

  • Požadavek je určený pro daný datový proud souboru.
  • Datový proud je otevřen pro asynchronní přístup.
    • Pokud je otevřen pro SYNCHRONNÍ přístup, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Soubor neobsahuje žádné transakce TxF.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • V datovém proudu nejsou žádné aktuální zámky rozsahu bajtů.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Na toku nejsou žádné uživatelem mapované oddíly, které by byly zapisovatelné.
    • Jinak se vrátí STATUS_CANNOT_GRANT_REQUESTED_OPLOCK. Pole REQUEST_OPLOCK_OUTPUT_BUFFER.Flags bude mít nastaven příznak REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT.

Pokud je aktuální stav oplocku:

  • Bez oplocku: Žádost byla schválena.

  • Úroveň 2 a/nebo povolení ke čtení: Žádost byla schválena. Ve stejném datovém proudu můžete mít najednou udělených více oplocků úrovně 2/Read.
    • Kromě toho platí, že pokud má existující oplock stejný klíč oplock jako nový požadavek, jeho IRP se dokončí s STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE.
  • Read-Handle a stávající oplock mají jiný klíč oplocku než nový požadavek: Žádosti je vyhověno. Více operací čtení a Read-Handle může existovat ve stejném datovém proudu (viz poznámka následující v této tabulce).
    • Pokud jsou klíče oplock stejné, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Úroveň 1, dávka, filtr, čtení a zápis, popisovač pro čtení i zápis: je vrácen stav STATUS_OPLOCK_NOT_GRANTED.

Read-Handle

Uděleno pouze v případě, že jsou splněny všechny následující podmínky:

  • Požadavek je určený pro daný datový proud souboru.
  • Datový proud je otevřen pro asynchronní přístup.
    • Pokud je otevřen pro SYNCHRONNÍ přístup, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Soubor neobsahuje žádné transakce TxF.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • V datovém proudu nejsou žádné aktuální zámky rozsahu bajtů.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Na toku nejsou žádné uživatelem mapované oddíly, které by byly zapisovatelné.
    • Jinak se vrátí STATUS_CANNOT_GRANT_REQUESTED_OPLOCK. Pole REQUEST_OPLOCK_OUTPUT_BUFFER.Flags bude mít nastaven příznak REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT.

Pokud je aktuální stav oplocku:

  • Bez oplocku: Žádost je udělena.

  • Přečtěte si: Žádost je udělena.
    • Pokud má existující oplock pro čtení stejný klíč oplock jako nový požadavek, dokončí se jeho IRP s STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE. Výsledkem je, že oplock je upgradován ze stavu Čtení na Čtení-Popisovač.
    • Jakýkoli existující oplock pro čtení, který nemá stejný klíč oplocku jako nový požadavek, zůstane beze změny.
  • Úroveň 2, úroveň 1, dávka, filtr, čtení a zápis, popisovač pro čtení i zápis: STATUS_OPLOCK_NOT_GRANTED se vrátí.

Read-Write

Uděleno pouze v případě, že jsou splněny všechny následující podmínky:

  • Požadavek je určený pro daný datový proud souboru.
    • Pokud se jedná o adresář, je vrácen STATUS_INVALID_PARAMETER.
  • Datový proud je otevřen pro asynchronní přístup.
    • Pokud je otevřen pro SYNCHRONNÍ přístup, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Soubor neobsahuje žádné transakce TxF.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Pokud jsou ve streamu další otevření (i ve stejném vlákně), musí mít stejný klíč oplock.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Na toku nejsou žádné uživatelem mapované oddíly, které by byly zapisovatelné.
    • Jinak se vrátí STATUS_CANNOT_GRANT_REQUESTED_OPLOCK. Pole REQUEST_OPLOCK_OUTPUT_BUFFER.Flags bude mít nastaven příznak REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT.

Pokud je aktuální stav oplocku:

  • Bez oplocku: Žádost je udělena.

  • Přečíst nebo Read-Write a pokud existující oplock má stejný klíč oplock jako požadavek: stávající IRP oplock se dokončí s STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE a požadavek je schválen.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Úroveň 2, úroveň 1, dávka, filtr, obsluha čtení, obsluha čtení a zápisu: STATUS_OPLOCK_NOT_GRANTED je vrácen.

Čtení –Write-Handle

Uděleno pouze v případě, že jsou splněny všechny následující podmínky:

  • Požadavek je určený pro daný datový proud souboru.
    • Pokud se jedná o adresář, je vrácen STATUS_INVALID_PARAMETER.
  • Datový proud je otevřen pro asynchronní přístup.
    • Pokud je otevřen pro SYNCHRONNÍ přístup, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Soubor neobsahuje žádné transakce TxF.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Pokud ve streamu existují další otevřené požadavky, a to i ve stejném vlákně, musí mít stejný klíč oplock.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Na toku nejsou žádné uživatelem mapované oddíly, které by byly zapisovatelné.
    • Jinak se vrátí STATUS_CANNOT_GRANT_REQUESTED_OPLOCK. Pole REQUEST_OPLOCK_OUTPUT_BUFFER.Flags bude mít nastaven příznak REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT.

Pokud je aktuální stav oplocku:

  • Bez oplocku: Žádost je udělena.

  • Read, Read-Handle, Read-Write nebo Read-Write-Handle a existující oplock má stejný klíč oplock jako požadavek: stávající IRP oplock se dokončí s STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE a žádost se udělí.
    • Pokud ne, vrátí se STATUS_OPLOCK_NOT_GRANTED.
  • Úroveň 2, úroveň 1, dávka, filtr: STATUS_OPLOCK_NOT_GRANTED je vráceno.

Poznámka

Operace čtení a spolupráce úrovně 2 mohou existovat ve stejném datovém proudu a operace čtení a Read-Handle můžou existovat společně, ale spolupráce úrovně 2 a Read-Handle nemůže existovat.