COW and Direct I/O problem Apr 17, 2009

barrios는 이 문제에 대해서 작년에 살짝 언급한 바 있다.
http://barriosstory.blogspot.com/2008/12/corruption-with-odirect-and-unaligned.html

사안이 사안이니만큼 한번 더 언급하기로 한다.
사실 이것은 리눅스 커널의 전형적인 core bug이다. 그러므로 이 문제를 이해하기 위해서는 kernel core의 page handling과정에 대한 이해가 필요하다.

이 문제를 다시 언급하는 이유는 두가지이다.

1. 이 문제는 아직 리눅스 커널에서 해결되지 못하고 있다.
2. 이 문제를 보고서도 뭐가 문제인지조차 알기 쉽지 않다는 것이다.

1에 대한 comment

해결되지 못하는 이유는 Linus때문이다. 이미 Nick과 Andrea는 이 문제를 풀기위한 solution을 진작에 내놓았었다. 성능을 최대한 떨어뜨리지 않으면서 이 문제를 풀기 위해 code가 다소 복잡하다.
반면 Kosaki가 내놓은 이 패치는 간단하긴 하지만(하지만 아직도 fast gup에 대한 concurrency 문제와 fork에 대한 latency, 특히 이 fork의 문제는 다소 심각해질 것 같다. 오늘 날짜로 보고된 Christoph의 report에 따르면 fork의 overhead가 2.6.22에 비해서 2.6.29는 2배 이하로 커진 것을 알 수 있기 때문이다.) 아직 많은 지적이 있다. 하지만 Linus는 코드수의 변경이 적은 Kosaki의 패치에 손들 들어주었다. Linus는 그때까지만 해도 fork에 대한 overhead는 크지 않다고 봤다. 물론이다. fork와 O_direct가 race condition이 될 확률은 크지 않다. 하지만 direct I/O가 계속해서 발생하게 되면 fork는 starvation 문제를 가질 수도 있으며, 안 그래도 overhead가 심각한 현재 fork의 구조에서 또 다른 lock을 check하는 것은 좋은 생각이 아닐 수도 있다.

2에 대한 comment

이 문제에 관심을 가질수 있는 사람들을 위해 barrios는 최대한 쉽게 설명할 수 있는 그림을 그려 보았다. 여기까지가 barrios가 할 수 있는 최선이다.

아래 그림은 이 패치의 테스트 프로그램이 왜 실패하는지에 대한 설명을 하는 그림이다. 패치의 테스트 프로그램과 함께 이 내용을 보아야 한다.

mm: more likely reclaim MADV_SEQUENTIAL mappings Apr 11, 2009

http://lkml.org/lkml/2008/7/19/130

이번 2.6.29에 패치된 기능중의 하나이다.
Hannes에 의해 추가되었으며, Rik과 Nick간의 다소 격양된 언쟁이 있었던 패치이기도 하다.
어쨌든, Andrew는 이 패치의 유용성에 대해 인정하였으며, 이번 2.6.29에 반영되었다.

Barrios가 2008년 7월에 언급되었던 이 패치를 지금 다시 이야기 하는 나름데로의 이유가 있다.

먼저 이 패치가 이루고자 하는 목표는 Page 회수를 좀더 똑똑하게 하자는 것이며,
리눅스 커널의 Man page의 madvise에 대한 기능을 완수하기 위한 것이기도 하다.

먼저 madvise의 man page를 살펴보면 다음과 같은 언급이 있다.


The madvise() system call advises the kernel about how to handle paging input/output in the address range beginning at address start and with size length bytes.
...
MADV_SEQUENTIAL
Expect page references in sequential order. (Hence, pages in the given range can be aggressively read ahead, and may be freed soon after they are accessed.)

위와 같이 sequential한 access는 첫째, readahead를 보다 공격적으로 하기 시작할 것이다.
둘째, 그리고 그 페이지들을 곧 회수될 수 있다.

리눅스 커널은 현재까지 첫째에 대해서는 충실했었지만 둘째에 대해서는 충실하지 못했다.
이번 패치는 Hannes에 의해 두번째 문제를 충족시켜주기 위한 패치이다.
패치는 정말 간단하다. 페이지를 promotion 시키기 전, vma의 seqential access 체크를 하여
그렇다면 promotion 시키지 않는다는 것이다.
즉, inactive list에 있는 page들을 active list로 옮기기 위한 확률을 줄이는 것이다. 그러므로 page reclaimer는 sequential access 페이지들을 보다 빨리 회수할 수 있게 된다.
이는 결과적으로 시스템의 working set들을 유지하는 데 도움을 주게 되므로 시스템의 전반적인 성능 또한 향상 시킬 수 있다.


많은 시스템 프로그래머들은 데이터 파일을 읽어들여본 경험이 있을 것이다.
물론 random한 offset으로 파일을 읽어들이는 경우도 많지만, 동영상을 재생하는 경우나 파일을 복사하는 경우, 또는 파일을 읽어들여 네트워크로 전송하는 경우와 같이 데이터 파일을 sequential하게 읽어들여야 하는 경우도 많이 있다.

이 블로그를 읽고 있는 사람이라면 너무나도 잘 알듯이 리눅스 커널의 메모리 관리 정책은 파일에 대한 접근을 모두 page cache에 보관하게 된다는 점을 잘 알고 있을 것이다.

위와 같은 스트림 데이터들을 page cache에 보관하면 어떤 이점이 있을까?
없다.

하지만 커널에서는 유저가 스트림 데이터와 같이 한번 접근하고 나서는 불필요한 파일을 접근하는지, 아니면 두고두고 참조할 파일을 정확하게 알 수 있는 방법은 없다. 그래서 나름데로 커널은 readahead 정책을 활용하여 heuristic하게 적용한다.

그러므로 파일의 사용패턴을 그 누구보다 잘 아는 것은 application 그 자신이다.
Application은 자신이 사용할 파일이기 때문에 어떻게 그 파일을 사용할 것인지 이미 알고 있다.
그러므로 이런 Application들이 커널에게 hint를 준다면 얼마나 고마운 일인가 ?

그러면 커널은 그러한 hint가 없다면 무엇을 하는가?

리눅스 커널의 page reclaim 관련 루틴들은 자주 참조되는 페이지와 그렇지 않은 페이지들을 잘 관리해보려고 애쓴다. 애는쓰되 효율적이지 못할 경우도 있다.
커널은 최선을 다할 뿐이지 결과는 장담할 수 없다.

너무 커널이 무책임하다고 생각하는가?

그렇게 커널이 무책임하지는 않다.
그래서 커널이 제공하는 시스템 콜이 mdvise, fadvise, open(O_DIRECT)와 같은 것들이
있는 것이다.

최소한 지각있는 application 개발자라면 커널에게 hint 정도는 줄 수 있는 것 아닌가?

내가 지금부터 이 파일을 sequential하게 읽을거야!
정도는.

응용 프로그램 개발자들은 최소한 커널이 제공하는 수준의 시스템 콜을 잘 이용할 수 있는 의무와 권리가 있다.
이를 이행하지 않으며 모든 것을 커널에게 맡기겠다는 것은 사실 응용 어플리케이션 개발자들의 직무유기이다.

꼬랑지)
Kernel이 applictaion들을 위해 얼마나 많은 것들을 제공해주어야 하는지에 대한 논쟁은 언제나 뜨거운 감자이지만, 새로운 기능을 넣고자 하는 자는 언제나 자신의 기능에 대한 benefit이 기존의 커널에 대한 regression보다 우월하다는 쉽지 않은 증명을 해야만 할 것이다.

Memory Failure Report throuth MCE Apr 9, 2009

http://lkml.org/lkml/2009/4/7/368

Intel의 앞으로 나올 CPU에 background로 memory를 check하여 error를 report해주는 기능이 들어간다고 Andi는 전하고 있다.
Report는 기존의 x86 specific한 Machine Check Exception을 그대로 사용할 것이며, MCE register를 통해 error가 발생한 물리 주소를 얻을 수 있게 된다.

그러므로 OS가 이 기능을 적절히 활용하기 위해서 Andi는 하드웨어가 나오기전 먼저 Linux OS에 대해서 상기 기능을 어떻게 활용할 것인지에 대해 RFC를 내놓았다.

Andi가 이번 패치에서 주 target으로 정한 것은 KVM이다. Host에서 error정보를 전달 받아 그 내용을 KVM guest들에게 전달하기 위한 설비이다. 하지만 이 기능은 KVM에 종속되지 않으며 얼마든지 다른 응용 프로그램들도 사용할 수 있도록 generic하게 설계되었다.

정보를 알리는 방식은 새로운 signal을 사용하는 방식이며, error가 발생한 page의 특성에 따라 다르게 동작한다.

1. slab page
2. reserved page
3. page cache clean page
4. page cache dirty page
5. unknown page
6. free page
7. swap clean page
8. swap dirty page
9. anonymous page
10. unevictable page
11. huge page
12.compound page

하지만 현재는 RFC단계로 위의 모든 type에 대해 구현되어 있지 않은 상태이다.

이 패치의 tricky한 part는 다른 VM 사용자들의 page에 대해 비동기적으로 접근하게 된다는 점이다. 그것은 page 동기화에 대한 rule을 해치는 일이 될 수 있기 때문에 매우 조심해야 한다. Andi가 이 패치에 대해 제일 걱정하는 부분이 바로 이 부분이다. 리눅스 커널의 page관련 lock 처리는 매우 골치아픈 부분이다.

현재, mainline에서 이 패치의 기능에 대해서는 모두 수긍하는 편이며 구현 또한 RFC 단계 치고는 상당히 깖끔하다. 앞으로 남은 주제는 아직 구현되어 있지 않은 page type에 대해 어떻게 처리할 것인가와 함께 비동기적인 page에 대한 접근에서 발생할 수 있는 문제에 대한 coverage등이 될 것으로 보인다.

이 패치는 하드웨어적으로 아직 들어가 있지 않은 구현에 대한 검증을 위해서 소프트웨어적으로 프로세스의 page를 poisoning할 수 있는 별도의 test 기능까지 구현되어 있다.

꼬랑지)
이 패치를 보면 Andi가 속한 Intel의 Open Source Lab이 무엇을 하는지 잘 알 수 있다.
아직 시장에 나오지 않은 기능에 대해 OS community에 선행 학습을 시키며 앞으로 나올 자신들의 하드웨어의 판매전략을 위해 기존 OS에 미리 기능을 구현해 놓겠다는 것인데..

아직까지도 하드웨어에만 목을 매는 우리나라의 몇몇 기업들의 우둔한 전략에 대해 할말이 너무나도 많지만..