lru_add_drain_all problem Feb 8, 2009

http://lkml.org/lkml/2008/10/21/205
http://lkml.org/lkml/2008/11/5/347

또 다시 circulary dependency problem이다.
문제의 원인은 lru_add_drain_all이 mmap_sem을 hold한 채로 worqueue를 사용하기 때문이다. 이 문제는 작년 10월 처음으로 보고 되었고, 쓰레드를 읽어 보면 알수 있는 바와 같이,
문제를 해결하려는 시도는 2가지의 방향으로 시도 되었다.

첫번째는 keventd가 아닌 별도의 workqueue를 만들어 schedule_on_each_cpu를 keventd가 아닌 별도의 workqueue안에서 호출하자는 것이다.

이렇게 한 이유는, 이미 많은 드라이버들이 keventd를 이용한 workqueue를 사용하고 있는 상황에서 그 driver들이 어떤 lock을 hold한채로 workqueue 사용하고 있는지를 알 수 없기 때문에, 비교적 적게 사용되는 schedule_on_each_cpu로 하여금 별도의 workqueue를 사용하자는 주장이다.

하지만 이 방법에 대해서는 Peter가 별로 달가워하지 않았다.

그 이유는 이미 커널에는 수많은 커널 쓰레드들이 있다는 것이다. 그 상황을 더욱 악화시키지 말자는 것이다. barrios의 생각도 마찬가지이다. 비록 지금은 schedule_on_each_cpu를 호출하는 것이 pagevec을 drain하는 lru_add_drain_all 함수 하나이지만, 그러한 함수들은 얼마든지 더 생길 수 있고 그럴때마다 새로운 workqueue를 만드는 것은 시스템의 커널 쓰레드들의 수를 증가시키게 된다.

하지만 이 상황은 지금은 더 나아질 수도 있을 것 같다. 왜냐하면 이전에 소개했던 기사 처럼 Arjan의 An asynchronous function call infrastructure가 mainline에 merge될 것이기 때문이다. 이 설비를 이용하게 되면 worker function을 새로운 쓰레드에서 실행하게 할 수 있으며, 해당 쓰레드는 필요 없을 때 종료될 수 있기 때문이다. 하지만 생성된 쓰레드를 재활용하는 Arjan의 패치에 약간의 개선이 필요하다. 모든 함수가 새로운 쓰레드에서 호출되며, 그 쓰레드는 다른 함수를 호출하지 않고 종료되게 끔 되어야 ciculary locking problem이 발생하지 않기 때문이다.
이와 함께 이 패치 또한 고려되어야 한다. 이는 비동기 함수 호출이 아닌 커널 쓰레드 자체에 관하여 비동기적으로 생성하자는 패치이다. 하지만 Arjan의 패치와 역할이 많이 겹치고 있다. http://lkml.org/lkml/2009/1/27/410)

두번째는 lru_add_drain_all을 호출하는 path에서 mmap_sem를 hold하지 않은 채로 호출하자는 것이다. Christoph는 migration중 mmap_sem을 hold하는 문제의 패치를 만들어 제출하였고, Kosaki 또한 munlockpath에서 lru_add_drain_all을 호출하지 않아도 시스템의 mlocked page memory leak이 발생하지 않는다는 문제에 agree하였고, 결국 다시 패치를 만들어 제출하였다.

barrios가 이 문제를 언급하는 이유는 작년 11월에 반영된 kosaki의 패치가 아직 반영되지 않았기 때문이다. 그러므로 barrios는 28-rc2-mm1의 테스트 중 그러한 circulary dependency locking report를 받았기 때문이다.

이 문제에 대해서 차주 kosaki와 얘기를 좀 더 해볼 필요가 있으며, 필요하다면 Arjan의 패치에 새로운 기능을 넣어 해결 할 수도 있을 것 같다.

1 개의 덧글:

barrios said...

현재, Linus의 git-kernel에는 Kosaki-san의 패치가 반영이 되어 있는 것을 확인하였다. 그러므로 barrios가 겪은 이 lockdep warning은 더 이상 발생하지 않을 것이다. kevent와의 lock inversion 문제는 asynchronous function call을 확장하여 해결 할 수 있지만 mmap과 cpu_hotplug의 lock inversion 문제는 asynchronous function call을 사용하여도 마찬가지로 발생할 수 있다. asynchonous function call interface가 해결책이 될 수는 없다. 그러므로 Nick의 주장처럼, lru_add_drain_all을 mmap_sem을 hold한채로 사용하지 않는 이번 패치가 현재로선 최선의 해결책이다.