Wenn ich ein Kernelmodul lade und die geladenen Module mit aufliste lsmod
, kann ich die "Verwendungsanzahl" des Moduls erhalten (Anzahl anderer Module mit Bezug auf das Modul). Gibt es eine Möglichkeit herauszufinden, was ein Modul verwendet?
Das Problem ist, dass ein Modul, das ich entwickle, darauf besteht, dass seine Verwendungsanzahl 1 ist und ich es daher nicht rmmod
zum Entladen verwenden kann, aber seine "by" -Spalte leer ist. Dies bedeutet, dass ich jedes Mal, wenn ich das Modul neu kompilieren und laden möchte, den Computer neu starten muss (oder zumindest keine andere Möglichkeit zum Entladen finden kann).
linux
kernel
kernel-module
Mipadi
quelle
quelle
Antworten:
Tatsächlich scheint es eine Möglichkeit zu geben, Prozesse aufzulisten, die ein Modul / einen Treiber beanspruchen. Ich habe jedoch keine Werbung dafür gesehen (außerhalb der Linux-Kerneldokumentation), daher schreibe ich meine Notizen hier auf:
Zunächst einmal vielen Dank für die Antwort von @haggai_e ; Der Zeiger auf die Funktionen
try_module_get
undtry_module_put
als Verantwortliche für die Verwaltung der Nutzungsanzahl (refcount) war der Schlüssel, mit dem ich die Prozedur aufspüren konnte.Als ich online weiter danach suchte , stieß ich irgendwie auf das Post- Linux-Kernel-Archiv: [PATCH 1/2] Tracing: Reduzieren Sie den Overhead von Modul-Tracepoints ; was schließlich auf eine im Kernel vorhandene Einrichtung hinwies, die als (ich denke) "Tracing" bekannt ist; Die Dokumentation dazu befindet sich im Verzeichnis Documentation / trace - Linux-Kernel-Quellbaum . Insbesondere erläutern zwei Dateien die Ablaufverfolgungsfunktion events.txt und ftrace.txt .
Es gibt aber auch ein kurzes "Tracing Mini-HOWTO" auf einem laufenden Linux-System in
/sys/kernel/debug/tracing/README
(siehe auch, ich habe es wirklich satt, dass Leute sagen, dass es keine Dokumentation gibt ... ); Beachten Sie, dass diese Datei im Kernel-Quellbaum tatsächlich von der Datei kernel / trace / trace.c generiert wird . Ich habe dies unter Ubuntu getestetnatty
und/sys
festgestellt, dasssudo
Sie diese Datei wie insudo cat
oder verwenden müssen , da sie Root gehört... und das gilt für so ziemlich alle anderen Operationen, unter
/sys
denen hier beschrieben wird.Hier ist zunächst ein einfacher minimaler Modul- / Treibercode (den ich aus den angegebenen Ressourcen zusammengestellt habe), der einfach einen
/proc/testmod-sample
Dateiknoten erstellt , der die Zeichenfolge "This is testmod" zurückgibt. wenn es gelesen wird; das isttestmod.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 wie folgt erstellt werden
Makefile
(lassen Sie es einfach im selben Verzeichnis wie platzierentestmod.c
und dannmake
im selben Verzeichnis ausführen ):Wenn dieses Modul / dieser Treiber erstellt wird, ist die Ausgabe eine Kernel-Objektdatei
testmod.ko
.An diesem Punkt können wir die Ereignisverfolgung in Bezug auf
try_module_get
und vorbereitentry_module_put
. die sind in/sys/kernel/debug/tracing/events/module
:Beachten Sie, dass auf meinem System die Ablaufverfolgung standardmäßig aktiviert ist:
... jedoch ist die Modulverfolgung (speziell) nicht:
Nun sollten wir zunächst einen Filter machen, die auf den reagieren
module_get
,module_put
usw. Ereignissen, sondern nur für dastestmod
Modul. Dazu sollten wir zuerst das Format des Ereignisses überprüfen:Hier sehen wir, dass es ein Feld namens gibt
name
, das den Treibernamen enthält, nach dem wir filtern können. Um einen Filter zu erstellen, fügen wir einfachecho
die Filterzeichenfolge in die entsprechende Datei ein:Beachten Sie hier zunächst, dass wir, da wir aufrufen
sudo
müssen, die gesamteecho
Umleitung als Argumentbefehl einessudo
-ed umschließen müssenbash
. Zweitens ist zu beachten, dass dieser Filter auf alle Ereignisse angewendet wird, die als "Kinder" des Verzeichnisses aufgeführt sind, da wir an das "übergeordnete Element" geschrieben habenmodule/filter
, nicht an die spezifischen Ereignisse (diemodule/module_put/filter
usw. wären )module
.Schließlich aktivieren wir die Ablaufverfolgung für das Modul:
Ab diesem Zeitpunkt können wir die Trace-Protokolldatei lesen. Für mich hat das Lesen der blockierenden "Piped" -Version der Trace-Datei wie folgt funktioniert:
Zu diesem Zeitpunkt wird im Protokoll nichts angezeigt. Daher ist es an der Zeit, den Treiber zu laden (und zu verwenden und zu entfernen) (in einem anderen Terminal als dem
trace_pipe
, an dem gelesen wird):Wenn wir zu dem Terminal zurückkehren, in
trace_pipe
dem gelesen wird, sollten wir Folgendes sehen: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 ihn durchlesencat
. Wir können also einfach den Lesevorgangtrace_pipe
mit CTRL+ Cin diesem Terminal unterbrechen . und um die Verfolgung insgesamt zu stoppen:Beachten Sie hier, dass sich die meisten Beispiele auf das Lesen der Datei beziehen,
/sys/kernel/debug/tracing/trace
anstatttrace_pipe
wie hier. Ein Problem ist jedoch, dass diese Datei nicht als "Piping" gedacht ist (Sie sollten also keine Dateitail -f
für diesetrace
Datei ausführen ). Stattdessen sollten Sie dietrace
nach jeder Operation erneut lesen . Nach dem ersteninsmod
würden wir die gleiche Ausgabe voncat
-ing sowohltrace
als auch erhaltentrace_pipe
; Nach dem würde dasrmmod
Lesen dertrace
Datei jedoch Folgendes ergeben:... das heißt: zu diesem Zeitpunkt war das
insmod
schon lange beendet und existiert daher nicht mehr in der Prozessliste - und kann daher zu diesem Zeitpunkt nicht über die aufgezeichnete Prozess-ID (PID) gefunden werden - also wir Holen Sie sich ein Leerzeichen<...>
als Prozessname. Daher ist es in diesem Fall besser,tee
eine laufende Ausgabe (über ) zu protokollierentrace_pipe
. Beachten Sie außerdem, dass zum Löschen / Zurücksetzen / Löschen dertrace
Datei einfach eine 0 geschrieben wird:Wenn dies nicht
trace
intuitiv erscheint, beachten Sie, dass es sich um eine spezielle Datei handelt, die ohnehin immer eine Dateigröße von Null meldet:... auch wenn es "voll" ist.
Beachten Sie schließlich, dass wir, wenn wir keinen Filter implementiert hätten, ein Protokoll aller Modulaufrufe auf dem laufenden System erhalten hätten, das jeden Aufruf (auch Hintergrund) an
grep
und solche protokollieren würde , wie diejenigen, die dasbinfmt_misc
Modul verwenden:... was einen erheblichen Mehraufwand verursacht (sowohl bei der Menge der Protokolldaten als auch bei der Verarbeitungszeit, die zum Generieren erforderlich ist).
Während ich dies nachgeschlagen habe , bin ich auf das Debuggen des Linux-Kernels von Ftrace PDF gestoßen , das sich auf ein Tool trace- cmd bezieht , das so ziemlich das Gleiche wie oben tut - aber über eine einfachere Befehlszeilenschnittstelle. Es gibt auch eine "Front-End-Reader" -GUI mit dem
trace-cmd
Namen KernelShark . Beide befinden sich auch in Debian / Ubuntu-Repositories übersudo apt-get install trace-cmd kernelshark
. Diese Tools könnten eine Alternative zu dem oben beschriebenen Verfahren sein.Abschließend möchte ich nur darauf hinweisen, dass das obige
testmod
Beispiel zwar nicht wirklich die Verwendung im Zusammenhang mit mehreren Ansprüchen zeigt, ich jedoch das gleiche Ablaufverfolgungsverfahren verwendet habe, um festzustellen, dass ein von mir codiertes USB-Modul wiederholt von beansprucht wurdepulseaudio
, sobald Das USB-Gerät wurde angeschlossen - daher scheint das Verfahren für solche Anwendungsfälle zu funktionieren.quelle
rmmod-21354
odertr-6232
(Prozessname - Prozess-ID) diejenigenmodule_put
sind, die die Refcount des Moduls ändern, dh diese Prozesse "verwenden" das Modul; Ich würde also argumentieren, dass es genau das beantwortet, wonach das OP gefragt hat ... Prost!Im Programmierhandbuch für Linux-Kernelmodule heißt es, dass die Anzahl der Verwendungen eines Moduls durch die Funktionen
try_module_get
und gesteuert wirdmodule_put
. Vielleicht können Sie herausfinden, wo diese Funktionen für Ihr Modul aufgerufen werden.Weitere Informationen: https://www.kernel.org/doc/htmldocs/kernel-hacking/routines-module-use-counters.html
quelle
Sie erhalten
Used by
lediglich eine Liste der Module, die von welchen anderen Modulen abhängen (die Spalte in lsmod). Sie können kein Programm schreiben, um festzustellen, warum das Modul geladen wurde, ob es noch für irgendetwas benötigt wird oder was möglicherweise kaputt geht, wenn Sie es entladen und alles, was davon abhängt.quelle
Wenn Sie rmmod OHNE die Option --force verwenden, erfahren Sie, was ein Modul verwendet. Beispiel:
quelle
$ lsmod | grep snd snd_seq 47263 1 snd_timer 19130 1 snd_seq snd_seq_device 5100 1 snd_seq ...
; sosnd_seq
wird von etwas behauptet (refcount ist 1), aber man kann nicht sagen warum, da die Spalte danach leer ist und daher kein anderes Modul dies spezifisch behauptet (aber vielleicht, wenn manftrace
den Kernel bereits vom Beginn des Startvorgangs an hat, eine könnte herausfinden, denke ich).Sie könnten versuchen
lsof
oderfuser
.quelle
/dev
darin erstellt, kann von aufgelistet werdenlsof
.Versuchen Sie es mit kgdb und setzen Sie den Haltepunkt auf Ihr Modul
quelle
Für alle, die unbedingt herausfinden möchten, warum sie keine Module neu laden können, konnte ich dieses Problem umgehen, indem ich sie umging
quelle