2016-05-31 24 views
27

Recentemente sto giocando con ftrace per monitorare alcune caratteristiche di comportamento del mio sistema. Ho gestito la commutazione della traccia on/off tramite un piccolo script. Dopo aver eseguito lo script, il mio sistema si bloccava e si riavviava da solo. Inizialmente, credevo che potesse esserci un errore con lo script stesso, ma da allora ho determinato che il crash e il riavvio sono il risultato di echo un tracciante in/sys/kernel/debug/tracing/current_tracer quando current_tracer è impostato su function_graph .ftrace: arresto anomalo del sistema quando si cambia current_tracer da function_graph via echo

Cioè, la seguente sequenza di comandi produrrà l'arresto/reboot:

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

Durning il riavvio dopo l'incidente causato dalle suddette echo dichiarazioni, vedo un sacco di uscita che recita:

compensazione orfano node <inode>

ho cercato di riprodurre questo problema sostituendo il valore da function_graph a qualcosa d'altro in un programma 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; 
} 

Stranamente, il programma C non in crash il sistema.

Originariamente ho riscontrato questo problema durante l'utilizzo di Ubuntu (Unity environment) 16.04 LTS e ho confermato che si trattava di un problema nei kernel 4.4.0 e 4.5.5. Ho anche testato questo problema su una macchina che esegue Ubuntu (ambiente Mate) 15.10, sui kernel 4.2.0 e 4.5.5, ma non è stato in grado di riprodurre il problema. Questo mi ha solo confuso ulteriormente.

Qualcuno può darmi una visione di ciò che sta accadendo? In particolare, perché dovrei essere in grado di write() ma non echo in/sys/kernel/debug/tracing/current_tracer?

Aggiornamento

Come Vielmetti sottolineato, altri hanno avuto un problema simile (come visto here).

Il ftrace_disable_ftrace_graph_caller() modifica istruzione JMP a ftrace_graph_call supponendo che è un 5 byte vicino JMP (e9). Tuttavia è un breve jmp composto da solo 2 byte (eb). E ftrace_stub() si trova appena sotto la ftrace_graph_caller modo modifica precedente rompe l'istruzione conseguente kernel oops sul la ftrace_stub() con il codice operativo non valido come di seguito:

Il cerotto (mostrato di seguito) risolto il problema echo, ma ancora non capisco perché echo si è rotto in precedenza quando write() non lo era.

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) 

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

+1

Hai provato a riprodurre utilizzando un singolo programma C (senza chiamate 'exec' tranne che per la chiamata a' dd')? A volte le shell fanno cose strane. – o11c

+2

Hai mai pensato di porre la tua domanda su uno dei siti Linux Stack Exchange? – ashes999

+0

@ o11c, l'errore sembra verificarsi solo durante la scrittura in '/ sys/kernel/debug/tracing/current_tracer'. Dico questo perché posso produrre questo problema senza invocare l'intero script, ma semplicemente "echo" su quel file. Ho ascoltato il tuo suggerimento con questo in mente, e ho aggiornato il mio post. – buratino

risposta

2

Sembra che non sei l'unica persona a notare questo comportamento.Vedo

come un rapporto del problema, e

come patch al kernel che affronta esso. Leggendo l'intero thread, sembra che il problema riguardi alcune ottimizzazioni del compilatore.

+0

La patch risolve il problema, ma non sono ancora chiaro su cosa stia succedendo esattamente. Se potresti essere più specifico nella tua risposta su cosa sta succedendo (anche se ciò implica citare l'articolo che hai collegato) ** e ** offri spunti sul perché echo'ing il tracciante function_graph avrebbe fatto crashare un sistema ma 'write()' would not, quindi contrassegnerò volentieri questa risposta come completa e assegnerò la taglia. – buratino

+1

Il testo pertinente dell'articolo si legge come segue. Non so se questo si applica al 100% al tuo problema, ma dovrebbe essere utile. "The ftrace_disable_ftrace_graph_caller() modifica JMP a ftrace_graph_call supponendo che è un 5 byte vicino JMP (e9 ). Tuttavia un breve JMP composto da soli 2 byte (EB ). E ftrace_stub() si trova appena al di sotto la modifica ftrace_graph_caller in modo interrompe l'istruzione risultante nel kernel oops su ftrace_stub() con l'opcode non valido. " – vielmetti

+0

Si applica al mio problema, ma non sono chiaro sul motivo per cui questo è il caso solo per 'echo' e non' write() '. – buratino