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
und try_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 getestet natty
und /sys
festgestellt, dass sudo
Sie diese Datei wie in sudo cat
oder verwenden müssen , da sie Root gehört
sudo less /sys/kernel/debug/tracing/README
... 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 ist testmod.c
:
#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 platzieren testmod.c
und dann make
im selben Verzeichnis ausführen ):
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 / 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 vorbereiten try_module_put
. die 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 die Ablaufverfolgung standardmäßig aktiviert ist:
$ sudo cat /sys/kernel/debug/tracing/tracing_enabled
1
... jedoch ist die Modulverfolgung (speziell) nicht:
$ sudo cat /sys/kernel/debug/tracing/events/module/enable
0
Nun sollten wir zunächst einen Filter machen, die auf den reagieren module_get
, module_put
usw. Ereignissen, sondern nur für das testmod
Modul. Dazu sollten wir zuerst das Format des Ereignisses ü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 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 einfach echo
die Filterzeichenfolge in die entsprechende Datei ein:
sudo bash -c "echo name == testmod > /sys/kernel/debug/tracing/events/module/filter"
Beachten Sie hier zunächst, dass wir, da wir aufrufen sudo
müssen, die gesamte echo
Umleitung als Argumentbefehl eines sudo
-ed umschließen müssen bash
. 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 haben module/filter
, nicht an die spezifischen Ereignisse (die module/module_put/filter
usw. wären ) module
.
Schließlich aktivieren wir die Ablaufverfolgung für das Modul:
sudo bash -c "echo 1 > /sys/kernel/debug/tracing/events/module/enable"
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:
sudo cat /sys/kernel/debug/tracing/trace_pipe | tee tracelog.txt
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):
$ sudo insmod ./testmod.ko
$ cat /proc/testmod-sample
This is testmod.
$ sudo rmmod testmod
Wenn wir zu dem Terminal zurückkehren, in trace_pipe
dem gelesen wird, sollten wir Folgendes 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 ihn durchlesen cat
. Wir können also einfach den Lesevorgang trace_pipe
mit CTRL+ Cin diesem Terminal unterbrechen . und um die Verfolgung insgesamt zu stoppen:
sudo bash -c "echo 0 > /sys/kernel/debug/tracing/tracing_enabled"
Beachten Sie hier, dass sich die meisten Beispiele auf das Lesen der Datei beziehen, /sys/kernel/debug/tracing/trace
anstatt trace_pipe
wie hier. Ein Problem ist jedoch, dass diese Datei nicht als "Piping" gedacht ist (Sie sollten also keine Datei tail -f
für diese trace
Datei ausführen ). Stattdessen sollten Sie die trace
nach jeder Operation erneut lesen . Nach dem ersten insmod
würden wir die gleiche Ausgabe von cat
-ing sowohl trace
als auch erhalten trace_pipe
; Nach dem würde das rmmod
Lesen der trace
Datei jedoch Folgendes ergeben:
<...>-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: 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 protokollieren trace_pipe
. Beachten Sie außerdem, dass zum Löschen / Zurücksetzen / Löschen der trace
Datei einfach eine 0 geschrieben wird:
sudo bash -c "echo 0 > /sys/kernel/debug/tracing/trace"
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:
$ 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.
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 das binfmt_misc
Modul verwenden:
...
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
... 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 demtrace-cmd
Namen KernelShark . Beide befinden sich auch in Debian / Ubuntu-Repositories über sudo 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 wurde pulseaudio
, sobald Das USB-Gerät wurde angeschlossen - daher scheint das Verfahren für solche Anwendungsfälle zu funktionieren.