커널 모드에서 코드를 작성한다는 것은 유저모드에서 보다 훨씬 어렵다.
언어도 자유롭게 사용할 수 없고 디버깅도 힘들며 한 줄이라도 실수하면 여지없이 블루스크린이 발생한다.
그럼 디바이스 드라이버를 커널 모드가 아니라 유저 모드에서 구현 할 수는 없을까? 그러면 좀 편할텐데.

리눅스 세상에는 FUSE라는 것이 있다.
File system in User Space 라는 뜻인데, 유저모드에서 파일 시스템을 구현하도록 제공되는 인터페이스이다.
FUSE가 커널 모드와 유저 모드의 코드를 중재해준다.

FUSE

윈도우에도 물론 비슷한 것들이 있다.
상용 제품인 CBFS는 콜백 인터페이스를 제공해준다.
유저모드에서 이 콜백 인터페이스를 구현하기만 하면 되는 것이다.

CBFS

위 그림에서 Your Application 부분만을 구현하면 되는 것이다.
우측에 있는 Callback File System에서 ReadFile WriteFile등 우리가 미리 등록해둔 콜백 오퍼레이션들을 호출해 준다.

한 일본인 혼자서 열심히 만들고 있는 것 같아 보이는 Dokan 이라는 오픈소스도 있다.
네이버의 NDrive가 이 Dokan을 이용해서 만들었다.

Dokan

  1. File System Application(우측 초록색)이 처음 구동되면 워커 쓰레드를 여러개 만들어 DeviceIoControl 함수를 호출해 Dokan File System Driver(아래 파랑색)에게 집어 넣어놓는다.
    DeviceIoControl 함수는 비동기 호출도 가능하고 IOCP도 지원이 되지만 Dokan에서는 간단하게 구현하기 위해서 쓰레드를 여러개 만들어 동기적으로 호출하고 있다.
  2. Application(좌측 초록색)으로 부터 I/O가 들어오면 Dokan File System Driver(아래 파랑색)가 이 Irp들을 받아서 잘 정리한 뒤 File System Application(우측 초록색)이 미리 넣어두었던 DeviceIoControl의 버퍼에 데이터를 복사하고 완료시킴으로 유저모드로 작업을 위임한다.
  3. File System Application에서는 해당 이벤트가 뭔지 확인해본 뒤에 이벤트에 대한 처리를 한 후 Dokan File System Driver에게 다시 그 결과를 전달해준다.
  4. 그러면 Dokan File System Driver는 받은 결과 그대로 Application(좌측 초록색)의Irp를 완료시킨다.

이렇게 드라이버가 유저모드의 구현을 위한 인터페이스만을 제공함으로서 파일 시스템 로직 구현을 유저모드로 옮길 수 있으며 유저모드 개발시의 여러 장점들을 가져올 수 있다.
그림에서 보이는 것처럼 두번씩 왔다 갔다 해야하는 것이 성능의 저하를 가져올 수 있고, 유저모드로 구현이 넘어감에 따라 커널 모드 라이브러리 루틴들을 마음껏 쓸 수 없다는 것은 약간의 단점이라 할 수 있겠다.

함께 읽으면 좋은 글: