[PATCH] Avoid lost wakeups in lock_page_killable() Jan 18, 2009

http://lkml.org/lkml/2009/1/17/195

이 패치는 lock_page_killable 함수의 버그를 패치하는 함수이다.
lock_page_killable 함수는 Matthew Wilcox에 의해 추가된 함수이다.

http://lkml.org/lkml/2007/10/18/424

NFS-mounted file system의 파일에 대하여 'cat' 명령어시 중간에 명령을 멈출 수가 없었던 문제를 해결하기 위하여,
page lock에 대하여 task들을 TASK_KILLABLE 상태로 signal에 반응하며 lock을 대기할 수 있게 해준 패치이다.

하지만 이 패치는 문제를 가지고 있다.
다음과 같은 경우를 생각해보자.

1) Task A가 lock을 소유하고 있다.
2) Task B와 Task C가 lock을 대기하고 있다.
3) Task A가 lock을 unlock하고 Task B를 깨운다.
4) 이때 마침 administator는 Task B를 kill한다.
5) 깨어난 Task B는 lock을 소유하지 않고, kill된다.
6) Task C는 아무도 잡지 않고 있는 lock을 누군가가 unlock하길 기다리며, 끝까지 기다린다!!!

이 버그가 여태까지 보고되지 않았던 이유는, 누구나 참을성을 가지고 ctrl + C를 하면 hang한 프로세스들을 kill할 수 있기 때문에 대부분 application의 버그라고 생각한 것 같다.

이 문제는 oracle의 Chris Mason(현재 btrfs의 maintainer)에 의해 패치되었다. 하지만 __lock_page_killable을 패치한 Chris의 아이디어 보다는, __wait_on_bit_lock을 패치한 Johannes Weiner의 아이디어가 더욱 make sense하다. Johannes는 다음과 같이 언급하고 있다.


__wait_on_bit_lock() employs exclusive waiters, which means that every
contender has to make sure to wake up the next one in the queue after
releasing the lock.

If the passed in action() returns a non-zero value, the lock is not
taken but the next waiter is not woken up either, leading to endless
waiting on an unlocked lock.


즉,__wait_on_bit_lock이 next wake up을 보장해 주어야 한다는 것이다. 그러므로 이것은
상위 layer에서 풀 문제가 아니라 __wait_on_bit_lock에서 푸는 것이 더욱 좋다는 것이다.
또한 Peter Zijlistra는 Chris의 패치에 대해서 spurious wakeup이 우려되긴 하나,
영원히 wake up을 읽어버리는 것 보다는 좋다고 말하고 있다. spurious wakeup문제는 Johannes의 패치에서도
여전히 나타날 수 있다. 단지 가능성을 약간 줄였을 뿐이다. (test_bit operation을 중간에 추가함으로써.. barrios는 이 부분의 패치에 대해서는 별로 agree하지 않는다. 단지 가능성을 줄일 뿐이지, spurious 문제는 여전히
발생할 수 있기 때문이다. 쓸데 없이 test_bit operation을 낭비하는 것이 될 것 같다.)
아직 Johannes는 패치는 peter에 의해 ack되진 않았다.
과연 이 패치가 spurious wakeup을 피할 수 있게 될지 좀더 주목해 볼 필요가 있다.

0 개의 덧글: