다음을 통해 공유


oplock 요청 및 부여

네트워크 리다이렉터에서 원격 서버의 파일에 액세스하면 원격 서버에서 oplock을 요청합니다. 클라이언트 애플리케이션은 잠금이 로컬 서버의 파일에 대한 경우에만 oplock을 직접 요청합니다.

oplocksFSCTL을 통해 요청됩니다. 다음 FSCTL은 사용자 모드 애플리케이션과 커널 모드 드라이버가 모두 실행할 수 있는 다양한 oplock 형식의에 사용됩니다.

사용자 모드에서 oplock 요청

사용자 모드에서 Windows 7 oplock을 요청하려면 DeviceIoControl호출합니다.

  • dwIoControlCodeFSCTL_REQUEST_OPLOCK로 설정합니다.
  • lpInBuffer 매개 변수의 REQUEST_OPLOCK_INPUT_BUFFER 구조체에 포인터를 전달합니다.
    • oplock 요청의 형식을 지정하는 방법에 대한 자세한 내용은 해당 구조의 설명서를 참조하세요.
  • lpOutBuffer 매개 변수의 REQUEST_OPLOCK_OUTPUT_BUFFER 구조체에 포인터를 전달합니다.

자세한 내용을 보려면 FSCTL_REQUEST_OPLOCK참조하십시오.

요청된 oplock을 부여할 수 있는 경우, DeviceIoControl 은 FALSE를 반환하고 GetLastError 은 ERROR_IO_PENDING을 반환합니다. 이러한 이유로, 동기 I/O에는 oplock이 절대 설정되지 않습니다. 중첩된 작업은 oplock이 끊어질 때까지 완료되지 않습니다. 작업이 완료되면 REQUEST_OPLOCK_OUTPUT_BUFFER에 oplock 중단에 대한 정보가 포함됩니다.

oplock을 부여할 수 없는 경우 파일 시스템은 적절한 오류 코드를 반환합니다. 가장 일반적으로 반환되는 오류 코드는 ERROR_OPLOCK_NOT_GRANTED 및 ERROR_INVALID_PARAMETER.

커널 모드에서 oplock 요청

커널 모드에서 Windows 7 oplock을 요청하려면 다음을 수행합니다.

파일 시스템 미니 필터

파일 시스템 미니 필터는 FltAllocateCallbackData 사용하고 다음과 같이 할당된 FLT_CALLBACK_DATA 입력해야 합니다.

  • Iopb->MajorFunction 필드를 IRP_MJ_FILE_SYSETM_CONTROL설정합니다.
  • IRP_MN_USER_FS_REQUEST를 Iopb->MinorFunction 필드에 설정하십시오.
  • 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.InputBufferLengthIopb->Parameters.FileSystemControl.Buffered.OutputBufferLength 필드를 해당 버퍼의 크기로 설정합니다.

oplock 요청의 형식을 지정하는 방법에 대한 자세한 내용은 REQUEST_OPLOCK_INPUT_BUFFER 구조의 설명서를 참조하세요.

다음으로 파일 시스템 미니 필터는 FltPerformAsynchronousIo을(를) 호출하여, 할당된 FLT_CALLBACK_DATACallbackData 매개 변수로 전달해야 합니다.

요청된 oplock을 부여할 수 있는 경우 FltPerformAsynchronousIo 호출은 STATUS_PENDING 반환합니다. 이러한 이유로, 동기 I/O에는 oplock이 절대 설정되지 않습니다. oplock이 끊어질 때까지 작업이 완료되지 않습니다. 작업이 완료되면 REQUEST_OPLOCK_OUTPUT_BUFFER에 oplock 중단에 대한 정보가 포함됩니다.

oplock을 부여할 수 없는 경우 파일 시스템은 적절한 오류 코드를 반환합니다. 가장 일반적으로 반환되는 오류 코드는 STATUS_OPLOCK_NOT_GRANTED 및 STATUS_INVALID_PARAMETER.

다른 종류의 드라이버

다른 종류의 드라이버는 ZwFsControlFile호출할 수 있습니다.

  • FsControlCodeFSCTL_REQUEST_OPLOCK로 설정하십시오.
  • InputBuffer 매개 변수의 REQUEST_OPLOCK_INPUT_BUFFER 구조에 포인터를 전달하고 InputBufferLength 매개 변수를 해당 버퍼의 크기로 설정합니다.
  • OutputBuffer 매개 변수의 REQUEST_OPLOCK_OUTPUT_BUFFER 구조에 포인터를 전달하고 OutputBufferLength 매개 변수를 해당 버퍼의 크기로 설정합니다.

oplock 요청의 형식을 지정하는 방법에 대한 자세한 내용은 REQUEST_OPLOCK_INPUT_BUFFER 구조의 설명서를 참조하세요.

요청된 oplock을 부여할 수 있는 경우 ZwFsControlFile 호출은 STATUS_PENDING 반환합니다. 이러한 이유로, 동기 I/O에는 oplock이 절대 설정되지 않습니다. oplock이 끊어질 때까지 작업이 완료되지 않습니다. 작업이 완료되면 REQUEST_OPLOCK_OUTPUT_BUFFER에 oplock 중단에 대한 정보가 포함됩니다.

oplock을 부여할 수 없는 경우 파일 시스템은 적절한 오류 코드를 반환합니다. 가장 일반적으로 반환되는 오류 코드는 STATUS_OPLOCK_NOT_GRANTED 및 STATUS_INVALID_PARAMETER.

Oplock을 요청할 때 공유 위반 방지

Atomic Create-With-Oplock 메서드 사용

Atomic create-with-oplock은 oplock 형식이 아닙니다. 대신 파일을 열고 oplock을 받는 시간 범위에서 공유 모드 위반을 방지하기 위해 열린 작업을 허용하는 절차입니다. 레거시 oplock을 사용할 때는 필터 oplock과 두 개의 핸들을 열어야 합니다. Windows 7 oplocks를 사용하면 애플리케이션 또는 드라이버가 이 절차를 사용하여 어떤 유형의 oplock도 요청할 수 있으며 하나의 핸들만 열기만 하면 됩니다.

atomic create-with-oplock 프로시저를 수행하려면 다음 단계를 따라야 합니다.

  1. FltCreateFileEx2 또는 ZwCreateFile를 사용하여 파일을 여십시오. CreateOptions 매개 변수에서 플래그 FILE_OPEN_REQUIRING_OPLOCK전달합니다. DesiredAccessShareAccess 매개 변수를 원하는 대로 설정할 수 있습니다. 예를 들어, 파일을 읽을 수 있도록 DesiredAccess 매개 변수에 GENERIC_READ를 설정하고, ShareAccess 매개 변수에는 플래그 FILE_SHARE_READ | FILE_SHARE_DELETE를 설정하여, 다른 사용자가 파일을 읽고, 이름을 바꾸거나, 삭제 대상으로 표시할 수 있도록 합니다.
  2. FSCTL_REQUEST_OPLOCK 제어 코드를 사용하여 결과 파일 개체 또는 핸들에 대한 oplock을 요청하고, 이것은 커널 모드에서 oplock 요청에서 설명한 대로입니다.

1단계와 2단계 사이에 파일에 대한 파일 시스템 작업을 수행하지 마세요. 이렇게 하면 교착 상태가 발생할 수 있습니다.

이 프로시저를 사용하여 요청하는 가장 일반적인 oplock은 Read-Handle 형식입니다. 이렇게 하면 다른 호출자에게 가능한 한 많은 동시 액세스를 허용하면서도, 충돌로 인해 공유 위반을 일으키지 않도록 핸들을 닫아야 하는 경우 알림을 받을 수 있습니다.

레거시 필터 Oplock 사용

또한 레거시 필터 oplock을 사용하면 다른 애플리케이션/클라이언트가 동일한 스트림에 액세스하려고 할 때 애플리케이션이 "백아웃"할 수 있지만 원자성 create-with-oplock 메서드보다 유연성이 떨어집니다. 이 메커니즘을 사용하면 스트림을 열려고 할 때 다른 스트림 접근자가 공유 위반을 수신하지 않고도 애플리케이션이 스트림에 액세스할 수 있습니다. 공유 위반을 방지하기 위해서는 다음 3단계 절차를 따라 필터 oplock을 요청해야 합니다.

  1. 파일을 여는 데 요구되는 액세스 권한은 FILE_READ_ATTRIBUTES이며, 공유 모드는 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE입니다. 이 단계에서 열린 핸들은 데이터 액세스(FILE_READ_DATA)가 아닌 특성 액세스(FILE_READ_ATTRIBUTES)에 대해서만 열려 있으므로 다른 애플리케이션에서 공유 위반을 수신하지 않습니다. 이 핸들은 필터 잠금 요청에는 적합하지만, 데이터 스트림에서 실제 I/O를 수행하는 데는 적합하지 않습니다.

  2. 1단계의 핸들에서 필터 oplock(FSCTL_REQUEST_FILTER_OPLOCK)을 요청합니다. 이 단계에서 부여된 oplock을 통해 oplock 소유자가 스트림에 액세스하려고 시도하는 다른 애플리케이션에 공유 위반을 일으키지 않도록 방해를 피할 수 있습니다.

  3. 읽기 액세스를 위해 파일을 다시 엽니다. 이 단계에서 핸들이 열리면 oplock 홀더가 스트림에서 I/O를 수행할 수 있습니다.

NTFS 파일 시스템은 FILE_RESERVE_OPFILTER 만들기 옵션 플래그를 통해 이 절차에 대한 최적화를 제공합니다. 이 플래그를 이전 절차의 1단계에서 지정하면 파일 시스템이 2단계가 실패할 것이라고 판단할 수 있는 경우 STATUS_OPLOCK_NOT_GRANTED로 만들어 요청을 실패시킬 수 있습니다. 1단계가 성공하면 만들기 요청에 대해 FILE_RESERVE_OPFILTER 지정되었더라도 2단계가 성공한다는 보장은 없습니다.

Oplock을 부여하기 위한 조건

다음 표에서는 oplock을 부여하는 데 필요한 조건을 식별합니다.

요청 유형 여건

수준 1

필터

일괄

다음 조건이 모두 충족되는 경우에만 허용됩니다.

  • 요청은 지정된 파일 스트림에 대한 것입니다.
    • 디렉터리인 경우 STATUS_INVALID_PARAMETER 반환됩니다.
  • 비동기적 액세스를 위해 스트림이 열립니다.
    • SYNCHRONOUS 액세스로 열 경우, STATUS_OPLOCK_NOT_GRANTED가 반환됩니다(동기 I/O 요청에 대해 oplock이 부여되지 않습니다).
  • 파일 스트림에는 TxF 트랜잭션이 없습니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 동일한 스레드에서도 스트림에 열린 것이 없습니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.

현재 oplock 상태가 다음과 같은 경우:

  • Oplock이 없을 경우: 요청이 승인되었습니다.

  • 수준 2: 원래 수준 2 요청이 FILE_OPLOCK_BROKEN_TO_NONE으로 손실되었습니다. 요청한 배타적 oplock이 그러면 부여됩니다.

  • 수준 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 이전에는 운영 체제가 마지막으로 열렸을 때부터 스트림에 바이트 범위 잠금이 존재했는지를 확인하고, 존재할 경우 요청을 실패로 처리합니다.

현재 oplock 상태가 다음과 같은 경우:

  • Oplock이 없을 경우: 요청이 승인되었습니다.

  • 2레벨 및/또는 읽기: 요청이 허가되었습니다. 동일한 스트림에서 동시에 여러 개의 Level 2/읽기 oplock을 부여할 수 있습니다. 레벨 2 oplock(읽기 전용은 아님)이 동일한 핸들에서도 존재할 수 있습니다.
    • 읽기 oplock이 이미 부여된 핸들에 대해 또 다른 읽기 oplock이 요청될 경우, 두 번째 읽기 oplock이 부여되기 전에 첫 번째 읽기 oplock의 IRP는 STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE로 완료됩니다.
  • 수준 1, 일괄 처리, 필터, 읽기 핸들, 읽기-쓰기, 읽기-쓰기 핸들: STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.

읽다

다음 조건이 모두 충족되는 경우에만 허용됩니다.

  • 요청은 지정된 파일 스트림에 대한 것입니다.
  • 비동기적 액세스를 위해 스트림이 열립니다.
    • SYNCHRONOUS 액세스를 위해 열린 경우 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 파일에 TxF 트랜잭션이 없습니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 스트림에 현재 바이트 범위 잠금이 없습니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 스트림에 쓰기 가능한 사용자 매핑 섹션이 없습니다.
    • 그렇지 않으면 STATUS_CANNOT_GRANT_REQUESTED_OPLOCK가 반환됩니다. The REQUEST_OPLOCK_OUTPUT_BUFFER 플래그 필드에는 REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT 플래그가 설정됩니다.

현재 oplock 상태가 다음과 같은 경우:

  • Oplock이 없을 경우: 요청이 승인되었습니다.

  • 2레벨 및/또는 읽기: 요청이 허가되었습니다. 동일한 스트림에서 동시에 여러 개의 Level 2/읽기 oplock을 부여할 수 있습니다.
    • 또한 기존의 oplock에 새 요청과 동일한 oplock 키가 있는 경우, 해당 IRP는 STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE로 완료됩니다.
  • Read-Handle 기존 oplock은 새 요청과 다른 oplock 키를 가지고 있습니다. 요청이 승인됩니다. 여러 읽기와 Read-Handle oplock이 동일한 스트림에서 공존할 수 있습니다(이 표 다음의 참고 사항을 참조하세요).
    • 만약 oplock 키가 동일하다면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 수준 1, 일괄 처리, 필터, 읽기-쓰기, 읽기-쓰기-핸들: STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.

Read-Handle

다음 조건이 모두 충족되는 경우에만 허용됩니다.

  • 요청은 지정된 파일 스트림에 대한 것입니다.
  • 비동기적 액세스를 위해 스트림이 열립니다.
    • SYNCHRONOUS 액세스를 위해 열린 경우 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 파일에 TxF 트랜잭션이 없습니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 스트림에 현재 바이트 범위 잠금이 없습니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 스트림에 쓰기 가능한 사용자 매핑 섹션이 없습니다.
    • 그렇지 않으면 STATUS_CANNOT_GRANT_REQUESTED_OPLOCK가 반환됩니다. The REQUEST_OPLOCK_OUTPUT_BUFFER 플래그 필드에는 REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT 플래그가 설정됩니다.

현재 oplock 상태가 다음과 같은 경우:

  • oplock 없음: 요청이 승인되었습니다.

  • 요청이 승인되었습니다.
    • 기존 읽기 oplock에 새 요청과 동일한 oplock 키가 있는 경우, 해당 IRP는 STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE 상태 코드로 완료됩니다. 그 결과 oplock이 읽기에서 읽기-핸들로 업그레이드됩니다.
    • 새 요청과 동일한 oplock 키가 없는 기존 읽기 oplock은 변경되지 않은 상태로 유지됩니다.
  • 수준 2, 수준 1, 일괄 처리, 필터, 읽기-쓰기, 읽기-쓰기-핸들: STATUS_OPLOCK_NOT_GRANTED 반환됩니다.

읽기-쓰기

다음 조건이 모두 충족되는 경우에만 허용됩니다.

  • 요청은 지정된 파일 스트림에 대한 것입니다.
    • 디렉터리인 경우 STATUS_INVALID_PARAMETER 반환됩니다.
  • 비동기적 액세스를 위해 스트림이 열립니다.
    • SYNCHRONOUS 액세스를 위해 열린 경우 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 파일에 TxF 트랜잭션이 없습니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 스트림에 열린 다른 것이 있는 경우(심지어 동일한 스레드에서도), 동일한 oplock 키를 가져야 합니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 스트림에 쓰기 가능한 사용자 매핑 섹션이 없습니다.
    • 그렇지 않으면 STATUS_CANNOT_GRANT_REQUESTED_OPLOCK가 반환됩니다. The REQUEST_OPLOCK_OUTPUT_BUFFER 플래그 필드에는 REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT 플래그가 설정됩니다.

현재 oplock 상태가 다음과 같은 경우:

  • oplock 없음: 요청이 승인되었습니다.

  • 읽기 또는 Read-Write이 기존 oplock와 요청의 oplock 키가 동일한 경우, 기존 oplock의 IRP는 STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE로 완료되며 요청이 승인됩니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 수준 2, 수준 1, 일괄 처리, 필터, 읽기 핸들, 읽기-쓰기 핸들의 경우 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.

읽기:Write-Handle

다음이 모두 true인 경우에만 허용됩니다.

  • 요청은 지정된 파일 스트림에 대한 것입니다.
    • 디렉터리인 경우 STATUS_INVALID_PARAMETER 반환됩니다.
  • 비동기적 액세스를 위해 스트림이 열립니다.
    • SYNCHRONOUS 액세스를 위해 열린 경우 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 파일에 TxF 트랜잭션이 없습니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 스트림에 다른 열린 요청이 있을 경우, 동일한 스레드에서도 동일한 oplock 키를 사용해야 합니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 스트림에 쓰기 가능한 사용자 매핑 섹션이 없습니다.
    • 그렇지 않으면 STATUS_CANNOT_GRANT_REQUESTED_OPLOCK가 반환됩니다. The REQUEST_OPLOCK_OUTPUT_BUFFER 플래그 필드에는 REQUEST_OPLOCK_OUTPUT_FLAG_WRITABLE_SECTION_PRESENT 플래그가 설정됩니다.

현재 oplock 상태가 다음과 같은 경우:

  • oplock 없음: 요청이 승인되었습니다.

  • 읽기, 읽기-핸들, 읽기-쓰기, 또는 읽기Write-Handle와 같은 작업의 경우, 기존 oplock이 요청과 동일한 oplock 키를 가집니다. 그러면 기존 oplock의 IRP가 STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE로 완료되고, 요청이 승인됩니다.
    • 그렇지 않으면 STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.
  • 수준 2, 수준 1, 일괄 처리, 필터: STATUS_OPLOCK_NOT_GRANTED가 반환됩니다.

메모

읽기 및 레벨 2 오플록은 동일한 스트림에서 공존할 수 있으며, 읽기 및 Read-Handle 오플록도 함께 있을 수 있지만, 레벨 2와 Read-Handle 오플록은 공존할 수 없습니다.