여러 가지 이유로 Intel 가상화 기술(Virtualization Technology)을 직접 활용한 시스템 소프트웨어를 구현한 이야기를 예전에 잠시 했었습니다. Shadow-box라고 부르고 있는데... 그 녀석(?!)으로 인해 영혼까지 탈탈 털리고 있는 중입니다. ^^;;; 2015년에 처음 개발을 시작했으니까 올해가 5년 차인데, 뮤택스와 스핀락 관련 이야기(https://kkamagui.tistory.com/925)에서 잠깐 소개를 하기도 했죠.

경량 가상화 기술을 이용한 영역(World) 분리

처음 가상화 기술로 영역을 분리하고 나니 잘 되는 듯 하지만 실제로는 잘 안 되는(?!) 상황이 많이 발생했는데요, 이러한 일들이 커널이 변경되어 새로운 기능이 추가되거나 단말이 바뀔 때마다 나와서... 정말 탈탈 털리고 있다는 표현이 맞는 것 같네요. 정말 멜트다운(Meltdown) 때문에 PTI(Page Table Isolation)이 커널에 들어갔을 때는 죽을 맛이었는데... 어쨌거나 큰 산을 넘고 또 넘어서 지금은 많이 안정화가 되었습니다. 물론... 새로운 문제가 나오기 전까지 안정적인 거지만요. ^^;;;

이번에 단말을 바꾸면서 여러가지 시험을 진행하고 있었는데요, 특정 단말에서만 한 20분을 못 넘기고 멈추는 문제가 발생했습니다. 이 문제 때문에 며칠 밤을 새웠는데요, 딱히 의심되는 부분이 없어서 계속 반복 실행하면서 로그를 확인했는데 별다른 로그가 없이 시스템이 정지했습니다. 사실 Shadow-box에 문제가 있거나 페이지 테이블 맵핑에 문제가 있으면 이런 현상이 생겼던 경험이 있어서 페이지 테이블 쪽을 의심하고 있던 찰나... 인터럽트 발생 횟수를 아래처럼 살펴보다 보니 NMI(Non-Maskable Interrupt)가 꽤 많이 발생한 것이 보이더라구요.  

$ cat /proc/interrupts
            CPU0       CPU1       CPU2       CPU3       CPU4       CPU5       CPU6       CPU7       CPU8       CPU9       CPU10      CPU11      CPU12      CPU13      CPU14      CPU15      
 NMI:         51        179        778         16        241         33         77         90         47        127        408        136        268         62        192        219   Non-maskable interrupts

NMI는 마스킹, 즉 비활성화가 불가능해서 언제 어디서건 발생할 수 있기 때문에 핸들러가 반드시 있어야 합니다. 당연히 게스트(Guest), 즉 리눅스가 동작하는 일반 영역에서 발생하면 커널의 핸들러가 불려서 처리가 되니 문제가 없을 거라 생각했는데... 문득 호스트(Host), 즉 커널 보호 기술이 동작하고 있는 영역에서 발생하면 문제가 생길 것 같은 느낌이 들었습니다. 아니나 다를까, 실제로 인터럽트 핸들러를 생성해서 로그를 찍어보니 아주 간간히 NMI 인터럽트가 호스트에서도 발생하고 있었습니다. 그리고 그때마다 게스트의 NMI 핸들러를 불러서 처리를 하고 있더라구요. 아아... 이러면 안 되는데... ㅠ^ㅠ

호스트는 리눅스 커널의 기능을 최소로 활용하기 때문에 NMI 핸들러를 실행할 만큼 자원이나 호출 가능한 함수가 충분치 않거든요. 그래서 이번 기회에 인터럽트 핸들러를 호스트용 하나 더 만들고 게스트와 분리시켜줬습니다. 호스트의 인터럽트 핸들러는 아무것도 할 필요가 없기 때문에 로그만 찍는 더미(Dummy) 핸들로로 모두 연결했죠. 그랬더니 새로운 단말에서도 다시 안정적으로 동작을 하기 시작했습니다. >ㅁ<)/~ 로그를 보니 거의 몇 분 단위로 NMI 인터럽트가 발생하고 있더라구요.

$> sudo journalctl -f | grep shadow-box
 8월 03 00:22:11 machine kernel: shadow-box: VM [3] INT NMI callback
 8월 03 00:24:18 machine kernel: shadow-box: VM [5] INT NMI callback
 8월 03 00:26:02 machine kernel: shadow-box: VM [8] INT NMI callback
 8월 03 00:26:32 machine kernel: shadow-box: VM [0] INT NMI callback
 8월 03 00:27:52 machine kernel: shadow-box: VM [13] INT NMI callback
 8월 03 00:29:45 machine kernel: shadow-box: VM [6] INT NMI callback
 8월 03 00:31:21 machine kernel: shadow-box: VM [7] INT NMI callback
 8월 03 00:36:26 machine kernel: shadow-box: VM [9] INT NMI callback
 8월 03 00:37:36 machine kernel: shadow-box: VM [11] INT NMI callback
 8월 03 00:42:54 machine kernel: shadow-box: VM [1] INT NMI callback
 8월 03 00:44:30 machine kernel: shadow-box: VM [14] INT NMI callback
 8월 03 00:48:18 machine kernel: shadow-box: VM [15] INT NMI callback
 8월 03 00:51:03 machine kernel: shadow-box: VM [4] INT NMI callback
 8월 03 00:54:26 machine kernel: shadow-box: VM [12] INT NMI callback
 8월 03 01:12:17 machine kernel: shadow-box: VM [10] INT NMI callback
 8월 03 01:59:58 machine kernel: shadow-box: VM [2] INT NMI callback

어휴... 진땀을 뺐네요. 자칫 잘못하면 엄청 길어질 뻔했는데, 운이 좋아서 다행입니다.

그럼 좋은 밤 보내세요. ^^

ps) CPU의 인터럽트 핸들러나 실제 핸들링 과정이 궁금하신 분은 64비트 멀티코어 OS 원리와 구조*(http://www.yes24.com/Product/Goods/65061299)를 참고하시면 좋을 것 같습니다.

 

+ Recent posts