En realidad, parece haber una manera de enumerar procesos que reclaman un módulo/controlador; sin embargo, no lo he visto anunciado (fuera de la documentación del kernel de Linux), así que anotaré mis notas aquí:
Antes que nada, muchas gracias por la respuesta de @haggai_e; el puntero a las funciones try_module_get
y try_module_put
como los responsables de gestionar el conteo de uso (refcount) fue la clave que me permitió rastrear el procedimiento.
Buscando más a fondo en línea, de alguna manera encontré la publicación Linux-Kernel Archive: [PATCH 1/2] tracing: Reduce overhead of module tracepoints; que finalmente apuntó a una instalación presente en el kernel, conocida como (supongo) "rastreo"; la documentación para esto está en el directorio Documentation/trace - Linux kernel source tree. En particular, dos archivos explican la función de rastreo, events.txt y ftrace.txt.
Pero también hay un breve "mini-HOW de rastreo" en un sistema Linux en ejecución en /sys/kernel/debug/tracing/README
(vea también I'm really really tired of people saying that there's no documentation…); tenga en cuenta que en el árbol fuente del kernel, este archivo es realmente generado por el archivo kernel/trace/trace.c. He probado esto en Ubuntu natty
, y tenga en cuenta que, dado que /sys
es propiedad de root, usted tiene que utilizar sudo
para leer este archivo, como en sudo cat
o
sudo less /sys/kernel/debug/tracing/README
... y eso va para casi todo otras operaciones bajo /sys
que se describirán aquí.
En primer lugar, aquí es un simple código mínimo módulo/controlador (que he creado a partir de los recursos mencionados), que simplemente crea un nodo /proc/testmod-sample
archivo, que devuelve la cadena "Esto es testmod."Cuando se está leyendo, lo que es 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");
Este módulo puede ser construido con el siguiente Makefile
(solo tiene que colocar en el mismo directorio que testmod.c
y ejecute make
en ese mismo directorio):.
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
Cuando este módulo/controlador está integrado, la salida es un archivo de objeto de núcleo, testmod.ko
En este punto, podemos preparar el seguimiento de eventos relacionado con try_module_get
y try_module_put
; ellos están en /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
Tenga en cuenta que en mi sistema, el seguimiento está activado por defecto:
$ sudo cat /sys/kernel/debug/tracing/tracing_enabled
1
... Sin embargo, el módulo de rastreo (en concreto) no es:
$ sudo cat /sys/kernel/debug/tracing/events/module/enable
0
Ahora, primero debemos hacer un filtro, que reaccionará en los eventos module_get
, module_put
, etc., pero solo para el módulo testmod
. Para ello, lo primero que debe comprobar el formato de la prueba:
$ 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
Aquí podemos ver que hay un campo llamado name
, que tiene el nombre del controlador, que podemos filtrar en contra. Para crear un filtro, simplemente echo
la cadena de filtro en el archivo correspondiente:
sudo bash -c "echo name == testmod > /sys/kernel/debug/tracing/events/module/filter"
Aquí, primera nota que ya que tenemos que llamar sudo
, tenemos que envolver todo el echo
redirección como un comando de argumentos de una sudo
-ed bash
. En segundo lugar, tenga en cuenta que, dado que escribimos al "padre" module/filter
, no a los eventos específicos (que serían module/module_put/filter
etc.), este filtro se aplicará a todos los eventos enumerados como "hijos" del directorio module
.
Por último, habilitar el seguimiento para el módulo:
sudo bash -c "echo 1 > /sys/kernel/debug/tracing/events/module/enable"
partir de este punto, podemos leer el archivo de registro de seguimiento; para mí, la lectura del bloqueo, "hilo" versión del archivo de rastreo trabajó - como esto:
sudo cat /sys/kernel/debug/tracing/trace_pipe | tee tracelog.txt
En este punto, no vamos a ver nada en el registro - por lo que es tiempo para cargar (y utilizar y eliminar) el conductor (en un terminal diferente de donde se está leyendo trace_pipe
):
$ sudo insmod ./testmod.ko
$ cat /proc/testmod-sample
This is testmod.
$ sudo rmmod testmod
Si volvemos a la terminal donde se está leyendo trace_pipe
, deberíamos ver algo como:
# 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
Eso es casi todo lo que obtendremos para nuestro controlador testmod
- el recuento cambia solo cuando el controlador está cargado (insmod
) o descargado(), no cuando leemos cat
. Entonces podemos simplemente interrumpir la lectura de trace_pipe
con CTRL + C en ese terminal; y para detener el rastreo completo:
sudo bash -c "echo 0 > /sys/kernel/debug/tracing/tracing_enabled"
Aquí, tenga en cuenta que la mayoría de los ejemplos se refieren a la lectura del archivo en lugar de /sys/kernel/debug/tracing/trace
trace_pipe
como en este caso. Sin embargo, un problema es que este archivo no está destinado a ser "canalizado" (por lo que no debe ejecutar un tail -f
en este archivo trace
); pero en su lugar, debe volver a leer el trace
después de cada operación. Después de la primera insmod
, obtendríamos la misma salida de cat
-tanto trace
como trace_pipe
; Sin embargo, después de la rmmod
, leyendo el archivo trace
daría:
<...>-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
... es decir: en este punto, la insmod
ya se había salido por mucho tiempo, por lo que ya no existe en el proceso lista - y, por lo tanto, no se puede encontrar a través del ID del proceso registrado (PID) en ese momento - así obtenemos un <...>
en blanco como nombre del proceso. Por lo tanto, es mejor registrar (a través de tee
) una salida en ejecución de trace_pipe
en este caso. Además, tenga en cuenta que con el fin de borrar/reiniciar/borrar el archivo trace
, uno simplemente escribe un 0 a él:
sudo bash -c "echo 0 > /sys/kernel/debug/tracing/trace"
Si esto parece contrario a la intuición, tenga en cuenta que trace
es un archivo especial, y siempre informar de un archivo tamaño de cero de todos modos:
$ 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
... incluso si está "lleno".
Por último, tenga en cuenta que si no ha aplicado un filtro, habríamos obtenido un registro de todos los módulos de llama en el sistema actual - que ingrese cualquier llamada (también de fondo) a grep
y tal, como las utilice el módulo binfmt_misc
:
...
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
...lo cual agrega bastante sobrecarga (tanto en la cantidad de datos de registro como en el tiempo de procesamiento requerido para generarla).
Mientras mira esto, yo nos topamos con Debugging Linux Kernel by Ftrace PDF, que se refiere a una herramienta trace-cmd, que prácticamente hace lo similar a la anterior - pero a través de una interfaz de línea de comandos fácil. También hay una GUI de "lector front-end" para trace-cmd
llamada KernelShark; ambos están también en los repositorios de Debian/Ubuntu a través del sudo apt-get install trace-cmd kernelshark
. Estas herramientas podrían ser una alternativa al procedimiento descrito anteriormente.
Por último, me gustaría señalar que, aunque el ejemplo anterior testmod
no muestra realmente el uso en contexto de varias notificaciones, he utilizado el mismo procedimiento de localización para descubrir que un módulo USB que estoy codificando fue repetidamente reclamado por pulseaudio
tan pronto como se enchufa el dispositivo USB, por lo que el procedimiento parece funcionar para tales casos de uso.
"qué" en la que los términos? ¿qué código? ¿qué módulo? que usuario? ¿que programa? Aunque tengo la sensación de que esto no está relacionado con la programación :) interesante, sin embargo, –
Bueno, está relacionado con la programación, ya que estoy preguntando porque estoy escribiendo un módulo kernel. – mipadi
aclare la pregunta para mostrar el problema de programación que está tratando de resolver. –