2009-01-15 6 views
61

Wenn ich ein Kernel-Modul laden und die geladenen Module mit lsmod auflisten, kann ich die "Nutzungsanzahl" des Moduls (Anzahl der anderen Module mit einer Referenz auf das Modul) abrufen. Gibt es eine Möglichkeit, herauszufinden, was verwendet ein Modul, obwohl?Gibt es eine Möglichkeit, herauszufinden, was ein Linux-Kernel-Modul verwendet?

Das Problem ist, dass ein Modul, das ich entwickle besteht darauf, dass seine Verwendung zählt 1 ist und ich kann rmmod nicht verwenden, um es zu entladen, aber seine Spalte "von" ist leer. Das bedeutet, dass ich jedes Mal, wenn ich das Modul neu kompilieren und neu laden will, den Rechner neu starten muss (oder zumindest keine andere Möglichkeit finde, das Gerät zu entladen).

+0

"was" in den Begriffen? Welcher Code? Welches Modul? Welcher Benutzer? welches Programm? tho ich leicht das Gefühl, das ist nicht Programmierung bezogen :) interessant nicht weniger –

+1

Nun, es _is_ Programmierung verwandt ist, da ich frage, weil ich ein Kernel-Modul schreibe. – mipadi

+0

Bitte klären Sie die Frage, um das Programmierproblem zu zeigen, das Sie versuchen zu lösen. –

Antwort

1

Sie könnten versuchen lsof oder fuser.

+2

Hast du das wirklich versucht? –

+0

Ich dachte zuerst daran, aber es funktioniert nicht. – mipadi

+0

'lsof' half mir, es herauszufinden. +1 –

4

Alles, was Sie bekommen, ist eine Liste, welche Module davon abhängen, welche anderen Module (die Used by Spalte in lsmod). Sie können kein Programm schreiben, um zu erfahren, warum das Modul geladen wurde, ob es noch für irgendwas benötigt wird oder was beim Entfernen des Moduls und allem, was davon abhängt, kaputt gehen könnte.

6

Es steht auf der Linux Kernel Module Programming Guide, dass die Nutzungszahl eines Moduls durch die Funktionen try_module_get und try_module_put gesteuert wird. Vielleicht können Sie herausfinden, wo diese Funktionen für Ihr Modul aufgerufen werden.

40

Eigentlich scheint es eine Möglichkeit zu geben, Prozesse aufzulisten, die ein Modul/Treiber beanspruchen - allerdings habe ich es nicht angekündigt (außerhalb der Linux-Kernel-Dokumentation), also notiere ich hier meine Notizen:

Zuerst vielen Dank für @haggai_e Antwort; Der Zeiger auf die Funktionen try_module_get und try_module_put als Verantwortliche für die Verwaltung der Nutzungszählung (Refcount) war der Schlüssel, mit dem ich den Vorgang aufspüren konnte.

Wenn Sie weiter online suchen, stolperte ich irgendwie über die Post Linux-Kernel Archive: [PATCH 1/2] tracing: Reduce overhead of module tracepoints; was schließlich auf eine im Kernel vorhandene Einrichtung hinwies, bekannt als (ich denke) "Tracing"; Die Dokumentation hierfür befindet sich im Verzeichnis Documentation/trace - Linux kernel source tree. Insbesondere erklären zwei Dateien die Suchfunktion, events.txt und ftrace.txt.

Aber es gibt auch ein kurzes "Tracing-Mini-HOWTO" auf einem laufenden Linux-System in /sys/kernel/debug/tracing/README (siehe auch I'm really really tired of people saying that there's no documentation…); Beachten Sie, dass diese Datei in der Kernel-Quellstruktur tatsächlich von der Datei kernel/trace/trace.c generiert wird. Ich habe dies auf Ubuntu getestet natty, und beachten Sie, dass seit /sys dem Benutzer root gehört, Sie haben sudo zu verwenden, um diese Datei zu lesen, wie in sudo cat oder

sudo less /sys/kernel/debug/tracing/README 

... und das für so ziemlich alles geht andere Operationen unter , die hier beschrieben werden.


Vor allem hier ist eine einfache minimal Modul/Treiber-Code (die ich aus den genannten Mittel zusammen), die einfach einen Knoten /proc/testmod-sample Datei erstellt, die die Zeichenfolge zurückgibt „Das ist TestMod.", Wenn es gelesen wird, das ist testmod.c:

/* 
https://github.com/spotify/linux/blob/master/samples/tracepoints/tracepoint-sample.c 
https://www.linux.com/learn/linux-training/37985-the-kernel-newbie-corner-kernel-debugging-using-proc-qsequenceq-files-part-1 
*/ 

#include <linux/module.h> 
#include <linux/sched.h> 
#include <linux/proc_fs.h> 
#include <linux/seq_file.h> // for sequence files 

struct proc_dir_entry *pentry_sample; 

char *defaultOutput = "This is testmod."; 


static int my_show(struct seq_file *m, void *v) 
{ 
    seq_printf(m, "%s\n", defaultOutput); 
    return 0; 
} 

static int my_open(struct inode *inode, struct file *file) 
{ 
    return single_open(file, my_show, NULL); 
} 

static const struct file_operations mark_ops = { 
    .owner = THIS_MODULE, 
    .open = my_open, 
    .read = seq_read, 
    .llseek = seq_lseek, 
    .release = single_release, 
}; 


static int __init sample_init(void) 
{ 
    printk(KERN_ALERT "sample init\n"); 
    pentry_sample = proc_create(
    "testmod-sample", 0444, NULL, &mark_ops); 
    if (!pentry_sample) 
    return -EPERM; 
    return 0; 
} 

static void __exit sample_exit(void) 
{ 
    printk(KERN_ALERT "sample exit\n"); 
    remove_proc_entry("testmod-sample", NULL); 
} 

module_init(sample_init); 
module_exit(sample_exit); 

MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("Mathieu Desnoyers et al."); 
MODULE_DESCRIPTION("based on Tracepoint sample"); 

Dieses Modul kann mit dem eingebauten werden folgende Makefile (nur haben sie im selben Verzeichnis wie testmod.c platziert, und dann laufen make im selben Verzeichnis):.

CONFIG_MODULE_FORCE_UNLOAD=y 
# for oprofile 
DEBUG_INFO=y 
EXTRA_CFLAGS=-g -O0 

obj-m += testmod.o 

# mind the tab characters needed at start here: 
all: 
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules 

clean: 
    make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean 

Wenn dieses Modul/Treiber eingebaut ist, der Ausgang ist eine Kernel-Objektdatei, testmod.ko


An dieser Stelle können wir die Ereignisverfolgung für try_module_get und try_module_put vorbereiten; das sind in /sys/kernel/debug/tracing/events/module:

$ sudo ls /sys/kernel/debug/tracing/events/module 
enable filter module_free module_get module_load module_put module_request 

Beachten Sie, dass auf meinem System-Tracing ist standardmäßig aktiviert:

$ sudo cat /sys/kernel/debug/tracing/tracing_enabled 
1 

... aber das Modul (speziell) Tracing ist nicht:

$ sudo cat /sys/kernel/debug/tracing/events/module/enable 
0 

Jetzt sollten wir zuerst einen Filter machen, der auf die Ereignisse module_get, module_put etc reagiert, aber nur für das Modul testmod. Um dies zu erreichen, sollten wir zunächst das Format der Veranstaltung überprüfen:

$ sudo cat /sys/kernel/debug/tracing/events/module/module_put/format 
name: module_put 
ID: 312 
format: 
... 
    field:__data_loc char[] name; offset:20; size:4; signed:1; 

print fmt: "%s call_site=%pf refcnt=%d", __get_str(name), (void *)REC->ip, REC->refcnt 

Hier können wir sehen, dass es ein Feld name, genannt ist, die die Treibernamen halten, die wir filtern gegen können. Um einen Filter zu erstellen, wir einfach echo die Filterzeichenfolge in die entsprechende Datei:

sudo bash -c "echo name == testmod > /sys/kernel/debug/tracing/events/module/filter" 

Hier erste Hinweis, dass da wir sudo nennen haben, müssen wir die ganze echo Umleitung als Argument Befehl eines sudo wickeln -ed bash. Zweitens, beachten Sie, dass, da wir an die "Eltern" module/filter geschrieben haben, nicht die spezifischen Ereignisse (die usw. sein würden), dieser Filter auf alle Ereignisse angewendet wird, die als "Kinder" von module Verzeichnis aufgeführt sind.

schließlich die Ablaufverfolgung aktivieren wir für Modul:

sudo bash -c "echo 1 > /sys/kernel/debug/tracing/events/module/enable" 

Von diesem Zeitpunkt an haben wir die Traceprotokolldatei lesen kann; für mich, die Blockierung zu lesen, „geleitet“ Version der Trace-Datei gearbeitet - wie folgt aus:

sudo cat /sys/kernel/debug/tracing/trace_pipe | tee tracelog.txt 

An dieser Stelle werden wir nichts im Protokoll sehen - so ist es an der Zeit zu laden (und nutzen und entfernen), um den Fahrer (in einem anderen Terminal, von wo aus trace_pipe) gelesen wird:

$ sudo insmod ./testmod.ko 
$ cat /proc/testmod-sample 
This is testmod. 
$ sudo rmmod testmod 

Wenn wir an das Terminal zurück, wo trace_pipe gelesen wird, sollten wir so etwas wie sehen:

# tracer: nop 
# 
#   TASK-PID CPU# TIMESTAMP FUNCTION 
#    | |  |   |   | 
      insmod-21137 [001] 28038.101509: module_load: testmod 
      insmod-21137 [001] 28038.103904: module_put: testmod call_site=sys_init_module refcnt=2 
      rmmod-21354 [000] 28080.244448: module_free: testmod 

Das ist so ziemlich alles, was wir für unseren testmod Treiber erhalten - der Refcount ändert sich nur, wenn der Treiber geladen (insmod) oder entladen (rmmod) wird, nicht wenn wir cat lesen. So können wir einfach das Lesen von trace_pipe mit CTRL + C in diesem Terminal unterbrechen; und die Verfolgung ganz zu stoppen:

sudo bash -c "echo 0 > /sys/kernel/debug/tracing/tracing_enabled" 

Hier ist zu beachten, dass die meisten Beispiele beziehen sich auf das Lesen der Datei /sys/kernel/debug/tracing/trace statt trace_pipe wie hier. Ein Problem besteht jedoch darin, dass diese Datei nicht "piped" sein soll (Sie sollten also keinen tail -f für diese trace Datei ausführen); aber stattdessen sollten Sie die trace nach jeder Operation erneut lesen. Nach der ersten insmod, erhalten wir die gleiche Ausgabe von cat -sowohl trace als auch trace_pipe; jedoch nach den rmmod, dem Lesen der trace Datei geben würde:

<...>-21137 [001] 28038.101509: module_load: testmod 
    <...>-21137 [001] 28038.103904: module_put: testmod call_site=sys_init_module refcnt=2 
    rmmod-21354 [000] 28080.244448: module_free: testmod 

... das heißt: an diesem Punkt hatte die insmod schon lange verlassen, und so ist es nicht mehr existiert im Prozess Liste - und daher nicht über die aufgezeichnete Prozess-ID (PID) zu der Zeit gefunden werden - so erhalten wir eine leere <...> als Prozessname. Daher ist es besser, in diesem Fall eine laufende Ausgabe von trace_pipe (über tee) zu protokollieren. Auch beachten, dass um/Reset zu löschen/Löschen der trace Datei, schreibt man einfach eine 0 bis es:

sudo bash -c "echo 0 > /sys/kernel/debug/tracing/trace" 

Wenn dies nicht eingängig scheint, beachten Sie, dass trace ist eine spezielle Datei, und wird immer eine Datei melden Größe von Null sowieso:

$ sudo ls -la /sys/kernel/debug/tracing/trace 
-rw-r--r-- 1 root root 0 2013-03-19 06:39 /sys/kernel/debug/tracing/trace 

... auch wenn es "voll" ist.

Schließlich ist zu beachten, dass, wenn wir nicht einen Filter implementieren würden, würden wir ein Protokoll der erhalten haben alle Modul auf dem laufenden System ruft - die jede Anrufprotokoll würde (auch Hintergrund) grep und so, wie die Verwenden Sie das binfmt_misc Modul:

... 
    tr-6232 [001] 25149.815373: module_put: binfmt_misc call_site=search_binary_handler refcnt=133194 
.. 
    grep-6231 [001] 25149.816923: module_put: binfmt_misc call_site=search_binary_handler refcnt=133196 
.. 
    cut-6233 [000] 25149.817842: module_put: binfmt_misc call_site=search_binary_handler refcnt=129669 
.. 
    sudo-6234 [001] 25150.289519: module_put: binfmt_misc call_site=search_binary_handler refcnt=133198 
.. 
    tail-6235 [000] 25150.316002: module_put: binfmt_misc call_site=search_binary_handler refcnt=129671 

...das fügt ziemlich viel Overhead hinzu (sowohl in der Log-Datenmenge als auch in der Verarbeitungszeit, die benötigt wird, um es zu erzeugen).


Während dies auf der Suche stieß ich auf Debugging Linux Kernel by Ftrace PDF, was zu einem Werkzeug trace-cmd, was ziemlich viel kostet das ähnlich wie oben bezeichnet - aber durch eine einfachere Kommandozeilen-Schnittstelle. Es gibt auch eine "Front-End-Leser" GUI für trace-cmd namens KernelShark; Beide sind auch in Debian/Ubuntu-Repositories unter sudo apt-get install trace-cmd kernelshark. Diese Werkzeuge könnten eine Alternative zu dem oben beschriebenen Verfahren darstellen.

Schließlich würde ich nur feststellen, dass, während das obige testmod Beispiel nicht wirklich im Zusammenhang mit mehreren Ansprüchen zeigen, habe ich die gleiche Ablaufverfolgung zu entdecken, dass ein USB-Modul, das ich codiere, wiederholt wurde beansprucht von pulseaudio, sobald das USB-Gerät eingesteckt wurde - so scheint das Verfahren für solche Anwendungsfälle zu funktionieren.

+5

Danke für den Kommentar, @RichardHansen - die Frage ist "Gibt es einen Weg herauszufinden, was _ ein Modul verwendet"; und Sie können in der Modul-Ablaufverfolgung sehen, dass zum Beispiel 'rmmod-21354' oder' tr-6232' (Prozessname - Prozess-ID) diejenigen sind, die den 'module_put' ausführen, dh den Refcount des Moduls ändern - das ist, dass diese Prozesse das Modul "benutzen"; also würde ich argumentieren, dass es genau das beantwortet, was das OP verlangt ... Prost! – sdaau

2

Wenn Sie rmmod OHNE die Option --force verwenden, wird Ihnen angezeigt, was ein Modul verwendet. Beispiel:

$ lsmod | grep firewire 
firewire_ohci   24695 0 
firewire_core   50151 1 firewire_ohci 
crc_itu_t    1717 1 firewire_core 

$ sudo modprobe -r firewire-core 
FATAL: Module firewire_core is in use. 

$ sudo rmmod firewire_core 
ERROR: Module firewire_core is in use by firewire_ohci 

$ sudo modprobe -r firewire-ohci 
$ sudo modprobe -r firewire-core 
$ lsmod | grep firewire 
$ 
+3

Nun, das stimmt im Allgemeinen nicht: Ich habe auf meinem Rechner: '$ lsmod | grep snd snd_seq 47263 1 snd_timer 19130 1 snd_seq snd_seq_device 5100 1 snd_seq ... ' ; also 'snd_seq' wird von etwas beansprucht (refcount ist 1), aber man kann nicht sagen warum, da die Spalte danach leer ist und so kein anderes Modul es explizit behauptet (aber vielleicht wenn man den Kernel schon vom Start weg ftrace des Boot-Prozesses könnte man herausfinden, denke ich). – sdaau

+0

Dies scheint nicht in allen Fällen zu funktionieren. – Martin

+3

Dies funktioniert nur in der Situation, wo lsmod auch etwas in der Spalte "used by" anzeigt; rmmod hat keine Logik mehr als lsmod im Hinblick auf die Anzeige von Abhängigkeiten. – dannysauer

-2

Für alle verzweifelt, um herauszufinden, warum sie nicht Module nachladen kann, konnte ich durch

  • Erhalten Sie den Pfad des aktuell verwendeten Modul, um dieses Problem arbeiten „modinfo“
  • rm es
  • Kopieren des neuen Moduls -rfing ich auf dem Weg war es in
  • Typing "modprobe DRIVER_NAME.ko" laden wollte.
+0

Diese Antwort beantwortet die Frage nicht wirklich. – kelnos

0

try kgdb und setzte Haltepunkt zu Ihrem Modul