28 votes

ftrace: plantage du système lors du changement de current_tracer de function_graph via echo

J'ai été jouer avec ftrace récemment pour surveiller certaines caractéristiques de comportement de mon système. J'ai été la manipulation de commutation de la trace on/off via un petit script. Après avoir exécuté le script, mon système plante et reboot de lui-même. Au départ, j'ai cru qu'il pourrait y avoir une erreur dans le script lui-même, mais depuis, j'ai déterminé que le crash et reboot est un résultat de l' echoing certains traceur de /sys/kernel/debug/traçage/current_tracer lorsqu' current_tracer est fixé à function_graph.

Qui est, la séquence de commandes suivante va produire de l'arrêt/redémarrage:

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

Pendant le redémarrage après l'accident causé par le ci - echo des déclarations, je vois beaucoup de sortie qui se lit comme suit:

elimination des orphelins inode <inode>

J'ai essayé de reproduire ce problème en remplaçant l' current_tracer de la valeur de function_graph à autre chose dans un programme C:

#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;
}

Curieusement, le programme C ne pas planter mon système.

J'ai d'abord été confronté à ce problème lors de l'utilisation d'Ubuntu (Unity environnement) 16.04 LTS et confirmé être un problème sur la 4.4.0 et 4.5.5 les noyaux. J'ai aussi testé ce problème sur un ordinateur fonctionnant sous Ubuntu (Mate environnement) 15.10, sur la 4.2.0 et 4.5.5 les noyaux, mais a été incapable de reproduire le problème. Cela n'a fait que me troublait encore.

Quelqu'un peut-il me donner un aperçu sur ce qui se passe? Plus précisément, pourquoi serais-je capable d' write() mais pas echo d' /sys/kernel/debug/traçage/current_tracer?

Mise à jour

Comme vielmetti souligné, d'autres ont eu un problème similaire (comme on le voit ici).

L' ftrace_disable_ftrace_graph_caller() modifie instruction jmp à ftrace_graph_call en supposant que c'est un 5 octets près de jmp (e9 ). Cependant, c'est une courte jmp composé de 2 octets seulement (eb ). Et ftrace_stub() est situé juste en dessous de l' ftrace_graph_callerdonc la modification ci-dessus des sauts de l'instruction résultant en kernel oops sur l' ftrace_stub() avec le code d'opération non valide comme ci-dessous:

Le patch (voir ci-dessous) a résolu le echo question, mais je ne comprends toujours pas pourquoi echo était en rupture précédemment lors de l' write() ne l'était pas.

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

3voto

user2694 Points 71

On dirait que vous n'êtes pas le seul à remarquer ce problème. Je vois

en tant que rapport du problème, et

comme un patch pour le noyau qui en traite. De la lecture à travers l'ensemble de thread, il apparaît que la question est certaines optimisations du compilateur.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X