필요성
사람들이 이 블로그에 찾아오는 이유는 여기에 있을 가능성이 높다고 생각한다. Read, Write, Open, Close가 아닌 모든 명령어가 들어가는 곳, ioctl. 정확히는 윈도우에서 DeviceIoControl이라고 부르는 그 API다. 학부 시절에 잘 하면 존재 정도는 들었을 이 API로 모든 명령이 오간다. 나 역시 처음 들었을 때는 매우 막연해서 어디에서 자료를 찾아야 할지도 잘 몰랐다. 이 편부터는 그 내용을 공개하려 한다.
우리는 이제 운영체제에서 제공해주는 대부분의 보호 장치와 작별을 해야 한다. 저 위의 네 명령어는 여러가지 보호 장치가 있지만, ioctl의 경우는 최소한의 보호를 제외하면 그 어느 것도 제공되지 않기 때문이다. 또한 알아서 각 장치가 알아들을 수 있도록 변환을 해주지도 않기 때문에, 우리가 알아서 모든 장치에 각각 알아들을 수 있는 언어로 말을 해야 한다.
저장장치의 언어, 명령 집합
ioctl을 만진다는 건, 각 장치가 하는 언어를(최소한 드라이버가 지원하는 언어를) 해야 한다는 것이다. SATA 장치에 해당하는 ATAPI, 최신 M.2(중 일부)와 PCIe 장치에 해당하는 NVM express, USB 장치에 해당하는 SCSI(SAT) 규격을 모두 구사해야 하는 것이다. 이것들을 부르는 이름이 명령 집합(Command set)이다.
무시할 수 없는 드라이버의 존재감, passthrough
위에서 말했듯이 우리는 이제 대부분의 보호 장치와 작별을 하고 ioctl을 선택했다. 그리고 명령 집합도 공부를 했다. 그러면 모든 일이 잘 끝나는 걸까? 아니다. 드라이버에서 해당 ioctl code를 지원해줘야 가능하다. 장치에 직접 명령을 내리려면, 그 명령을 장치에 내리라는 명령을 먼저 드라이버에 내려야 하는 것이다. 그것이 바로 passthrough다.
나는 IOCTL_ATA_PASS_THROUGH가 없는 시대에 살아보지는 못했다. 하지만 이 역시 ATA 표준이 나오고 한참 뒤인 XP SP2가 나오고 나서야 지원이 되기 시작했다. 다른 표준 역시 드라이버 상에서 passthrough를 지원해야 디스크 툴이 하는 모든 일들이 가능하다. 그러므로 최근 NVMe처럼 새 표준이 나오면, 툴 개발자들 사이에서 이처럼 ioctl code를 찾기 위한 노력이 이어진다.
명령 집합의 표준화: TCommandSet
디스크 툴에서는 명령 집합을 추상화 하는 편이 사용하기 편하다. 각 표준을 그대로 받아들이면 새로운 표준이 나올 때마다 구조를 많이 바꾸어야 하기 때문이다. 나도 지원해야 하는 표준이 한 가지일 때는 명령 단위로 추상화 하였으나 더 많아지자 각 표준을 객체로 분리할 수 밖에 없었다. 나래온 툴에서 다루는 명령들이자, TCommandSet에 정의된 명령은 다음과 같다.
- Identify: BIOS나 장치 관리자에 나오는 장치 이름, 펌웨어 버전, 시리얼 번호, 용량 등은 다 여기서 가져오는 것이다. 요약하면, 단어가 보여주듯 장치의 정체에 관한 명령이다.
- SMART: 장치의 현재 상태를 보여주는 명령이다. 각 벤더 별로 다른 기준으로 보여진다. 따라서 해석을 못하면 그냥 비트 덩어리일 뿐이며, 실제 뜻을 밝혀내기는 쉽지 않다.
- Trim(Data Set Management): 이 공간을 더 이상 사용하지 않는다는 표시를 SSD로 보내, 다른 작업을 할 때 자유롭게 덮어 씌울 수 있도록 한다.
버퍼 해석의 표준화: TBufferInterpreter
출력 버퍼 또한 표준화의 대상이다. 디스크 툴에서는 정해진 정보만을 필요로 하는데, 표준마다 출력 방식은 매우 다양하기 때문이다. 그 사이에서 변환을 해주는 도구가 있으면, 새 표준이 생길 때마다 UI 코드가 복잡해지는 일을 막을 수 있다. 나래온 툴에서는 Identify 명령과 SMART 명령에 대해서 이 표준화를 적용하고 있다.