2016-05-31 17 views
27

Grałem ostatnio z ftrace, aby monitorować niektóre cechy zachowania mojego systemu. Zajmowałem się włączaniem/wyłączaniem śledzenia za pomocą małego skryptu. Po uruchomieniu skryptu mój system ulegnie awarii i uruchomi się ponownie. Początkowo sądziłem, że może wystąpić błąd w samym skrypcie, ale od tego czasu ustaliłem, że awaria i ponowne uruchomienie są wynikiem echo włożenia niektórych znaczników do/sys/kernel/debug/tracing/current_tracer, gdy current_tracer jest ustawione na function_graph .ftrace: awaria systemu przy zmianie current_tracer z function_graph przez echo

Oznacza to, że następująca sekwencja poleceń spowoduje katastrofy/reboot:

echo "function_graph" > /sys/kernel/debug/tracing/current_tracer 
echo "function" > /sys/kernel/debug/tracing/current_tracer 

Durning restart po katastrofie spowodowanej przez wyżej echo wypowiedzi, widzę dużo mocy, który brzmi:

polana osierocony iwęzeł <inode>

starałem się odtworzyć ten problem, zastępując wartość z function_graph do czegoś innego w programie C current_tracer:

#include <stdio.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <string.h> 
#include <stdlib.h> 

int openCurrentTracer() 
{ 
     int fd = open("/sys/kernel/debug/tracing/current_tracer", O_WRONLY); 
     if(fd < 0) 
       exit(1); 

     return fd; 
} 

int writeTracer(int fd, char* tracer) 
{ 
     if(write(fd, tracer, strlen(tracer)) != strlen(tracer)) { 
       printf("Failure writing %s\n", tracer); 
       return 0; 
     } 

     return 1; 
} 

int main(int argc, char* argv[]) 
{ 
     int fd = openCurrentTracer(); 

     char* blockTracer = "blk"; 
     if(!writeTracer(fd, blockTracer)) 
       return 1; 
     close(fd); 

     fd = openCurrentTracer(); 
     char* graphTracer = "function_graph"; 
     if(!writeTracer(fd, graphTracer)) 
       return 1; 
     close(fd); 

     printf("Preparing to fail!\n"); 

     fd = openCurrentTracer(); 
     if(!writeTracer(fd, blockTracer)) 
       return 1; 
     close(fd); 

     return 0; 
} 

Co ciekawe, program C nie psuje mój system.

Początkowo napotkałem ten problem podczas korzystania z Ubuntu (środowisko Unity) 16.04 LTS i potwierdziłem, że jest to problem w jądrach 4.4.0 i 4.5.5. Przetestowałem również ten problem na komputerze z systemem Ubuntu (środowisko Mate) 15.10, w jądrach 4.2.0 i 4.5.5, ale nie udało się odtworzyć problemu. To tylko jeszcze bardziej mnie zdezorientowało.

Czy ktoś może dać mi wgląd w to, co się dzieje? W szczególności, dlaczego miałbym być w stanie write(), ale nie echo na/sys/kernel/debug/tracing/current_tracer?

Aktualizacja

Jak vielmetti wskazał, inni mieli podobny problem (jak widać here).

ftrace_disable_ftrace_graph_caller() modyfikuje instrukcja jmp w ftrace_graph_call zakładając, że jest to 5 bajtów pobliżu JMP (e9). Jednak jest to krótki jmp składający się tylko z 2 bajtów (eb). I ftrace_stub() znajduje się tuż poniżej ftrace_graph_caller tak modyfikacja powyżej łamie instrukcji otrzymanej w jądrze oops na ftrace_stub() z niepoprawny kod operacji jak poniżej:

Łatka (przedstawione poniżej) rozwiązał echo problem, ale ja wciąż nie rozumiem, dlaczego echo pękało wcześniej, gdy nie było write().

diff --git a/arch/x86/kernel/mcount_64.S b/arch/x86/kernel/mcount_64.S 
index ed48a9f465f8..e13a695c3084 100644 
--- a/arch/x86/kernel/mcount_64.S 
+++ b/arch/x86/kernel/mcount_64.S 
@@ -182,7 +182,8 @@ GLOBAL(ftrace_graph_call) 
    jmp ftrace_stub 
    #endif 

-GLOBAL(ftrace_stub) 
+/* This is weak to keep gas from relaxing the jumps */ 
+WEAK(ftrace_stub) 
    retq 
    END(ftrace_caller) 

poprzez https://lkml.org/lkml/2016/5/16/493

+1

Czy próbowałeś odtwarzać używając jednego programu C (bez wywołań 'exec' z wyjątkiem możliwego wywołania' dd')? Czasami muszle robią fajne rzeczy. – o11c

+2

Czy zastanawiałeś się nad zadaniem pytania na jednej z witryn z wymianą stosu systemu Linux? – ashes999

+0

@ o11c, błąd wydaje się występować tylko przy zapisie do '/ sys/kernel/debug/tracing/current_tracer'. Mówię to, ponieważ mogę wygenerować ten problem bez wywoływania całego skryptu, ale zamiast tego po prostu "echo" do tego pliku. Wysłuchałem waszej sugestii mając to na uwadze i zaktualizowałem swój post. – buratino

Odpowiedz

2

Wygląda na to, że nie jesteś jedyną osobą, która zauważy to zachowanie.Widzę

jako sprawozdanie problemu i

jako patch do kernela, który adresuje go. Czytając cały ten wątek wydaje się, że problemem są niektóre optymalizacje kompilatora.

+0

Poprawka rozwiązuje problem, ale nadal nie jestem pewien, co dokładnie się dzieje. Jeśli mógłbyś być bardziej konkretny w swojej odpowiedzi na pytanie, co się dzieje (nawet jeśli zawiera cytowanie artykułu, który został połączony) ** i ** oferując wgląd w to, dlaczego "echo funkcji znacznika function_graph spowodowałoby awarię systemu ale "write()" nie, wtedy z chęcią oznaczyłbym tę odpowiedź jako kompletną i nagrodzę nagrodę. – buratino

+1

Odpowiedni tekst artykułu wygląda następująco. Nie wiem, czy to w 100% dotyczy Twojego problemu, ale powinno być pomocne. „The ftrace_disable_ftrace_graph_caller() modyfikuje instrukcja jmp w ftrace_graph_call zakładając, że jest to 5 bajtów pobliżu JMP (E9 ). Jednak jest to krótki jmp składający się z zaledwie 2 bajty (EB .) A ftrace_stub() znajduje się tuż poniżej modyfikacja ftrace_graph_caller tak łamie instrukcję powodującą, że jądro oops na ftrace_stub() z niepoprawnym opcode. " – vielmetti

+0

Ma to zastosowanie do mojego problemu, ale nie jestem pewien, dlaczego tak jest tylko w przypadku "echo", a nie "write()". – buratino

Powiązane problemy