На самом деле, похоже, есть способ перечислить процессы, требующие модуля/драйвера, однако я не видел его рекламируемым (вне документации ядра Linux), поэтому я напишу свои заметки здесь:
Прежде всего, большое спасибо за ответ @haggai_e; указателем на функции try_module_get
и try_module_put
в качестве тех, кто отвечает за управление подсчетом использования (refcount), был ключ, который позволил мне отследить процедуру.
Глядя далее на это, я как-то наткнулся на сообщение Linux-Kernel Archive: [PATCH 1/2] tracing: Reduce overhead of module tracepoints; который, наконец, указал на объект, присутствующий в ядре, известный как (я думаю) «отслеживание»; документация для этого находится в каталоге Documentation/trace - Linux kernel source tree. В частности, два файла объясняют механизм трассировки, events.txt и ftrace.txt.
Но есть также короткая «трассировка мини-HOWTO» в бегущей системе Linux в /sys/kernel/debug/tracing/README
(см. Также I'm really really tired of people saying that there's no documentation…); обратите внимание, что в исходном дереве ядра этот файл фактически генерируется файлом kernel/trace/trace.c. Я проверил это на Ubuntu natty
, и обратите внимание, что поскольку /sys
принадлежит корню, вы должны использовать sudo
читать этот файл, как в sudo cat
или
sudo less /sys/kernel/debug/tracing/README
... и это касается почти всех другие операции под /sys
, которые будут описаны здесь.
Прежде всего, здесь простой минимальный код модуля/драйвер (который я наношу вместе с указанными ресурсов), который просто создает /proc/testmod-sample
файла узел, который возвращает строку «Это testmod."Когда он читается, это 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");
Этот модуль может быть построен следующим Makefile
(просто он помещается в тот же каталог, testmod.c
, а затем запустить make
в том же каталог):.
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
Когда этот модуль/драйвер построен, выходной файл объект ядра, testmod.ko
На этом этапе мы можем подготовить отслеживание событий, относящихся к try_module_get
и try_module_put
; те, в /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
Обратите внимание, что в моей системе, трассировка по умолчанию включено:
$ sudo cat /sys/kernel/debug/tracing/tracing_enabled
1
... Однако, прослеживая модуль (в частности) не является:
$ sudo cat /sys/kernel/debug/tracing/events/module/enable
0
Теперь мы должны сначала создать фильтр, который будет реагировать на события module_get
, module_put
и т. Д., Но только для модуля testmod
. Чтобы сделать это, мы должны сначала проверить формат события:
$ 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
Здесь мы можем видеть, что есть поле, называемое name
, который содержит имя драйвера, который мы можем фильтровать против. Чтобы создать фильтр, мы просто echo
фильтр строки в соответствующий файл:
sudo bash -c "echo name == testmod > /sys/kernel/debug/tracing/events/module/filter"
Здесь, сначала заметим, что, так как мы должны называть sudo
, мы должны обернуть все echo
Перенаправление как команда аргумента sudo
-ed bash
. Во-вторых, обратите внимание, что поскольку мы написали «родительский» module/filter
, а не конкретные события (которые были бы module/module_put/filter
и т. Д.), Этот фильтр будет применяться ко всем событиям, перечисленным как «дети» из module
.
Наконец, включите трассировку для модуля:
sudo bash -c "echo 1 > /sys/kernel/debug/tracing/events/module/enable"
С этого момента, мы можем прочитать файл журнала трассировки; для меня, чтения блокирования, «конвейера» версия файла трассировки работала - как это:
sudo cat /sys/kernel/debug/tracing/trace_pipe | tee tracelog.txt
На данный момент мы ничего не увидим в журнале - так это время, чтобы загрузить (и использовать и удалить) драйвер (в другом терминале, откуда trace_pipe
читается):
$ sudo insmod ./testmod.ko
$ cat /proc/testmod-sample
This is testmod.
$ sudo rmmod testmod
Если вернуться к терминалу, где trace_pipe
считываемого, мы должны увидеть что-то вроде:
# 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
Это почти все, что мы получим для нашего testmod
. Поэтому мы можем просто прервать чтение из trace_pipe
с CTRL + C в этом терминале; и остановить трассировку в целом:
sudo bash -c "echo 0 > /sys/kernel/debug/tracing/tracing_enabled"
При этом следует отметить, что большинство примеров относятся к чтению файла /sys/kernel/debug/tracing/trace
вместо trace_pipe
как здесь. Тем не менее, одна из проблем заключается в том, что этот файл не предназначен для «передачи по каналам» (поэтому вы не должны запускать tail -f
в этом файле trace
); но вместо этого вы должны перечитать trace
после каждой операции. После первого insmod
мы получили бы тот же результат от cat
- как trace
, так и trace_pipe
; Однако, после rmmod
, чтение файла trace
даст:
<...>-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
... то есть: на данный момент, insmod
уже выходили долго, и поэтому он больше не существует в процессе список - и поэтому не может быть найден через зарегистрированный идентификатор процесса (PID) в то время - таким образом, мы получаем пустое имя <...>
как имя процесса. Поэтому в этом случае лучше зарегистрировать (через tee
) выходной сигнал от trace_pipe
. Кроме того, обратите внимание, что для того, чтобы очистить/сбросить/удалить файл trace
, один просто записывает 0 на него:
sudo bash -c "echo 0 > /sys/kernel/debug/tracing/trace"
Если это кажется нелогичным, обратите внимание, что trace
представляет собой специальный файл, и всегда будет сообщать файл размер ноля в любом случае:
$ 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
... даже если это «полный».
Наконец, следует отметить, что если мы не реализовали фильтр, мы получили бы журнал все модуль вызывает на работающей системе - что бы войти любой вызов (также фон) в grep
и такие, как те, используйте модуль 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
...что добавляет довольно много накладных расходов (как в объёме данных журнала, так и в времени обработки, необходимых для его создания).
Ища это, я наткнулся на Debugging Linux Kernel by Ftrace PDF, который относится к инструменту trace-cmd, который в значительной степени делает подобное, как описано выше, - но через более простой интерфейс командной строки. Существует также графический интерфейс «front-end reader» для trace-cmd
под названием KernelShark; оба из них также находятся в репозиториях Debian/Ubuntu через sudo apt-get install trace-cmd kernelshark
. Эти инструменты могут быть альтернативой описанной выше процедуре.
В заключение, я хотел бы отметить, что, хотя приведенный выше пример testmod
на самом деле не показывает использование в контексте множества претензий, я использовал ту же процедуру трассировки, чтобы обнаружить, что модуль USB, который я кодирую, неоднократно заявлено pulseaudio
, как только устройство USB было подключено, - поэтому процедура, похоже, работает для таких случаев использования.
«что» в какие сроки? какой код? какой модуль? какой пользователь? какая программа? я немного чувствую, что это не связано с программированием :) интересный нет- –
Ну, это связано с программированием, так как я спрашиваю, потому что я пишу модуль ядра. – mipadi
, пожалуйста, уточните вопрос, чтобы показать проблему программирования, которую вы пытаетесь решить. –