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 wftrace_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). Iftrace_stub()
znajduje się tuż poniżejftrace_graph_caller
tak modyfikacja powyżej łamie instrukcji otrzymanej w jądrze oops naftrace_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
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
Czy zastanawiałeś się nad zadaniem pytania na jednej z witryn z wymianą stosu systemu Linux? – ashes999
@ 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