実際、モジュール/ドライバーを要求するプロセスを一覧表示する方法があるようですが、(Linux カーネルのドキュメント以外で) 宣伝されているのを見たことがないので、ここにメモを書き留めておきます。
まず、@haggai_eの回答に感謝します。try_module_get
関数へのポインターとtry_module_put
、使用カウント (refcount) の管理を担当するものは、手順を追跡するための鍵でした。
これをオンラインでさらに調べたところ、どういうわけか投稿Linux-Kernel Archive: [PATCH 1/2] トレース: モジュール トレースポイントのオーバーヘッドの削減;に出くわしました。これは最終的に、「トレース」として知られる、カーネルに存在する機能を指していました。このドキュメントはDocumentation/trace - Linux kernel source treeディレクトリにあります。具体的には、2 つのファイルevents.txtとftrace.txtでトレース機能について説明しています。
しかし、実行中の Linux システムに関する短い "tracing mini-HOWTO"もあります (ドキュメントがないと言う人には本当にうんざりです...</a>/sys/kernel/debug/tracing/README
も参照してください)。カーネル ソース ツリーでは、このファイルは実際にはファイルkernel/trace/trace.cによって生成されることに注意してください。私はこれを Ubuntu でテストしましたが、はルートによって所有されているため、このファイルを読み取るには、またはのように使用する必要があることにnatty
注意してください。/sys
sudo
sudo cat
sudo less /sys/kernel/debug/tracing/README
...そして、それはここで説明する他のほとんどすべての操作に当てはまり/sys
ます。
まず最初に、単純な最小限のモジュール/ドライバー コード (参照されたリソースからまとめたもの) を/proc/testmod-sample
示します。このコードは、"This is 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
全体を-edの引数コマンドとしてラップする必要があることに注意してください。次に、特定のイベント (など) ではなく「親」に書き込んだため、このフィルターはディレクトリの「子」としてリストされているすべてのイベントに適用されることに注意してください。echo
sudo
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
。refcount は、ドライバがロード ( insmod
) またはアンロード ( )されたときにのみ変更されrmmod
ますcat
。したがって、その端末trace_pipe
でCTRL+を使用して読み取りを中断するだけです。Cトレースを完全に停止するには:
sudo bash -c "echo 0 > /sys/kernel/debug/tracing/tracing_enabled"
/sys/kernel/debug/tracing/trace
ここで、ほとんどの例は、ここではなくファイルの読み取りを参照していることに注意してtrace_pipe
ください。ただし、1 つの問題は、このファイルが「パイプ」されることを意図していないことです (したがってtail -f
、このtrace
ファイルに対して a を実行しないでください)。代わりにtrace
、各操作の後に再読み込みする必要があります。最初の の後、と の両方を-inginsmod
すると同じ出力が得られます。ただし、ファイルを読み取ると、次のようになります。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
はすでに長い間終了していたため、プロセス リストには存在しません。そのため、その時点で記録されたプロセス ID (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ツールを参照しており、上記とほとんど同じことを行いますが、より簡単なコマンドライン インターフェイスを使用します。KernelSharktrace-cmd
と呼ばれる「フロントエンド リーダー」GUI もあります。これらは両方とも、 を介して Debian/Ubuntu リポジトリにもあります。これらのツールは、上記の手順の代わりになる可能性があります。sudo apt-get install trace-cmd kernelshark
最後に、上記のtestmod
例は複数のクレームのコンテキストでの使用を実際には示していませんが、同じトレース手順を使用して、コーディングしている USB モジュールがpulseaudio
すぐに繰り返しクレームされたことを発見したことに注意してください。 USB デバイスが差し込まれているため、このようなユース ケースではこの手順が機能するようです。