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.
"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 –
Nun, es _is_ Programmierung verwandt ist, da ich frage, weil ich ein Kernel-Modul schreibe. – mipadi
Bitte klären Sie die Frage, um das Programmierproblem zu zeigen, das Sie versuchen zu lösen. –