Linux서버의 uptime이 208.5일을 경과시에 재부팅 할 가능성이 있는 문제

Posted on Updated on

Pentium 4이후의 모든 x86프로세서를 채용한 Linux 서버에 대해서 208.5일을 경과할 경우, 갑자기 시스템이 재부팅 할 가능성이 있습니다. 이를 두고 208.5일 문제 라고 일본에서는 부르고 있습니다.

발생 가능성이 있는 Linux Kernel의 버전은 2.6.28 ~ 2.6.32.49 / 3.0.12 / 3.1.4 입니다.

원인이 되는 분은 Kernel 2.6.28에 패치로 적용된 소스 코드 __cycles_2_ns() 부분 입니다.

Pentium 4이후의 x86프로세서에는 Time Slice Stamp Counter라고 불리우는 64비트 카운터가 들어 있는데, 이 카운터는 클럭단위로 카운트업 됩니다. 즉, 1Ghz가 있으면, 1초당 1G가 늘어나도록 되어 있습니다.
이말은 나노초 단위로 카운트가 된다는 말이기도 합니다.

그렇지만, CPU의 저전력 기술로 인하여, CPU클럭이 변경가능하도록 설계됨에 따라서, Linux Kernel은 cycles_2_ns()라는 함수를 제공하여 TSC의 값을 나노초단위로 환산 할수 있도록 제공 하고 있습니다.

바로 이 부분의 함수 코드에 버그가 있어, 208.5일이 경과하게 되면, 계산중의 수치에 오버플로우가 발생하여, 변환치가 이상한 값을 반환하게 되고, 이부분의 값으로 인하여 시스템에 크래쉬가 발생 재부팅을 하게 되는것 입니다.

이 문제에 대해서 가장 빠른 해결책은 커널의 커널의 업그레이드 입니다.

보통의 경우 해당 문제의 커널 패치를 제공 하고 있으니, 커널 패치를 통하여 문제 해결이 가능합니다.

해당 문제가 해결된 Kernel의 버전은 2.6.32.50 / 3.0.13 / 3.1.5 이상 버전입니다.

커널의 업그레이드가 어렵거나 불가한 경우에는 아래오 같이 해당 코드를 수정하고 커널을 재컴파일 해주시면 문제가 해결 될 것입니다.

static inline unsigned long long __cycles_2_ns(unsigned long long cyc)
 {
+    unsigned long long quot;
+    unsigned long long rem;
     int cpu = smp_processor_id();
     unsigned long long ns = per_cpu(cyc2ns_offset, cpu);
-    ns += cyc * per_cpu(cyc2ns, cpu) >> CYC2NS_SCALE_FACTOR;
+    quot = (cyc >> CYC2NS_SCALE_FACTOR);
+    rem = cyc & ((1ULL << CYC2NS_SCALE_FACTOR) - 1);
+    ns += quot * per_cpu(cyc2ns, cpu) +
+        ((rem * per_cpu(cyc2ns, cpu)) >> CYC2NS_SCALE_FACTOR);
     return ns;
 }

+행은 추가된 부분, -행은 삭제된 부분입니다.

물론 펜티엄 CPU x86계열 이외의 서버에 경우에는 해당 문제가 발생하지 않습니다.

Leave a comment