it-swarm-eu.dev

Existuje způsob, jak zjistit, co používá modul jádra Linuxu?

Pokud načtím modul jádra a zobrazí seznam načtených modulů s lsmod, mohu získat "počet použití" modulu (počet dalších modulů s odkazem na modul). Existuje však způsob, jak zjistit co používá modul?

Problém je v tom, že modul, který vyvíjím, trvá na tom, že počet jeho použití je 1, a proto nemohu použít rmmod k jeho uvolnění, ale sloupec „by“ je prázdný. To znamená, že pokaždé, když chci re-kompilovat a znovu načíst modul, musím restartovat počítač (nebo alespoň nemohu přijít na jiný způsob, jak ho vyložit).

64
mipadi

Ve skutečnosti se zdá, že existuje způsob, jak vypsat procesy, které si nárokují modul/ovladač - ale neviděl jsem inzerovaný (mimo dokumentaci jádra Linuxu), takže si zapíšu své poznámky zde:

Za prvé, mnohokrát děkujeme za @ haggai_e odpověď; ukazatel na funkce try_module_get a try_module_put jako osoby odpovědné za správu počtu použití (refcount) byl klíč, který mi umožnil sledovat postup.

Podíváme-li se dále na tento online, nějak jsem narazil na post Linux-Kernel Archive: [PATCH 1/2] trasování: Snižte režii sledovacích bodů modul ; který nakonec ukázal na zařízení přítomné v jádře, označované jako „trasování“; dokumentace je v adresáři Documentation/trace - zdrojový strom jádra Linux . Zejména dva soubory vysvětlují sledovací zařízení, events.txt a ftrace.txt .

V systému Linux v systému /sys/kernel/debug/tracing/README je však také krátký "trasovací mini-HOWTO" (viz také jsem opravdu unavený z lidí, kteří říkají, že neexistuje žádná dokumentace ... ); Všimněte si, že ve zdrojovém stromu jádra je tento soubor vlastně generován souborem kernel/trace/trace.c . Testovali jsme to na Ubuntu nattya všimněte si, že protože /sys je vlastněn rootem, musíte použít Sudopro čtení tohoto souboru, jako v Sudo cat nebo

Sudo less /sys/kernel/debug/tracing/README

... a to platí téměř pro všechny ostatní operace pod /sys, které budou popsány zde.


Především zde je jednoduchý minimální modul/kód ovladače (který jsem dal dohromady z uvedených zdrojů), který jednoduše vytvoří souborový uzel /proc/testmod-sample, který vrací řetězec "To je testmod." při čtení; toto je 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");

Tento modul může být sestaven s následujícími MakefileNAME _ (stačí jej umístit do stejného adresáře jako testmod.c a pak spustit makev tomtéž adresáři):

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

Když je tento modul/ovladač vytvořen, výstup je soubor jádra, testmod.ko.


V tomto okamžiku můžeme připravit trasování událostí týkající se try_module_get a try_module_put; ty jsou v /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

V mém systému je ve výchozím nastavení povoleno sledování:

$ Sudo cat /sys/kernel/debug/tracing/tracing_enabled
1

... ale sledování modulu (konkrétně) není:

$ Sudo cat /sys/kernel/debug/tracing/events/module/enable
0

Nyní bychom měli nejprve vytvořit filtr, který bude reagovat na události module_get, module_put atd., Ale pouze na modul testmodname__. Nejprve bychom měli zkontrolovat formát události:

$ 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

Zde vidíme, že existuje pole nazvané namename__, které obsahuje jméno ovladače, proti kterému můžeme filtrovat. Chcete-li vytvořit filtr, jednoduše echořetězec filtru do odpovídajícího souboru:

Sudo bash -c "echo name == testmod > /sys/kernel/debug/tracing/events/module/filter"

Zde si nejprve povšimněte, že protože musíme volat Sudoname__, musíme celý příkaz echozabalit jako příkaz argumentu Sudoname __- ed bashname__. Za druhé, všimněte si, že jelikož jsme psali "rodiči" module/filter, ne specifickým událostem (které by byly module/module_put/filter atd.), Tento filtr bude použit na všechny události uvedené jako "děti" v adresáři modulename__.

Nakonec povolíme sledování modulu:

Sudo bash -c "echo 1 > /sys/kernel/debug/tracing/events/module/enable"

Od tohoto okamžiku můžeme číst soubor protokolu trasování; pro mě, čtení blokování, "piped" verze souboru trasování pracoval - takto:

Sudo cat /sys/kernel/debug/tracing/trace_pipe | tee tracelog.txt

V tomto okamžiku se v logu nic nezobrazí - je tedy na čase načíst (a využít a odebrat) ovladač (v jiném terminálu, ze kterého se čte trace_pipe):

$ Sudo insmod ./testmod.ko
$ cat /proc/testmod-sample 
This is testmod.
$ Sudo rmmod testmod

Pokud se vrátíme do terminálu, kde se čte trace_pipe, měli bychom vidět něco jako:

# 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

To je skoro vše, co pro náš ovladač testmodzískáme - refcount se změní pouze v případě, že je ovladač načten (insmodname__) nebo unloaded (rmmodname__), ne když čteme pomocí catname__. Můžeme tedy jednoduše přerušit čtení z trace_pipe pomocí CTRL+C v tomto terminálu; a zastavit stopování úplně:

Sudo bash -c "echo 0 > /sys/kernel/debug/tracing/tracing_enabled"

Všimněte si, že většina příkladů odkazuje na čtení souboru /sys/kernel/debug/tracing/trace místo trace_pipe jako zde. Jedním problémem však je, že tento soubor nemá být "piped" (takže byste neměli spouštět tail -f v tomto souboru tracename__); ale místo toho byste měli po každé operaci znovu přečíst tracename__. Po prvním insmodbychom získali stejný výstup z catname tracea trace_pipe; po rmmodby však čtení souboru tracedalo:

   <...>-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

... to je: v tomto okamžiku insmodbyl již ukončen na dlouhou dobu, a tak již neexistuje v seznamu procesů - a proto nemůže být nalezen přes zaznamenaný proces ID (PID) v té době - ​​tedy dostaneme prázdný název <...> jako název procesu. Proto je lepší v tomto případě logovat (prostřednictvím teename__) běžící výstup z trace_pipe. Všimněte si také, že pro vymazání/reset/vymazání souboru tracestačí na něj zapsat 0:

Sudo bash -c "echo 0 > /sys/kernel/debug/tracing/trace"

Pokud se to jeví jako neintuitivní, poznamenejte si, že traceje speciální soubor a vždy bude vykazovat velikost souboru nula:

$ 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

... i když je "plná".

Nakonec si všimněte, že kdybychom neimplementovali filtr, dostali bychom log všechny volání modulů na běžícím systému - což by zaprotokolovalo jakýkoliv hovor (také pozadí) do grepa takové jako ty, které používají modul 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

... který přidává docela trochu režie (v obou log data ammount, a doba zpracování potřebná pro jeho generování).


Zatímco jsem to hledal, narazil jsem na Debugging Linux Kernel by Ftrace PDF , což se týká nástroje trace-cmd , který se do značné míry podobá výše uvedenému, ale prostřednictvím jednodušší rozhraní příkazového řádku. K dispozici je také GUI "front-end reader" pro trace-cmd nazvané KernelShark ; oba jsou také v Debianu/Ubuntu repository přes Sudo apt-get install trace-cmd kernelshark. Tyto nástroje by mohly být alternativou výše popsaného postupu.

Nakonec bych si všiml, že zatímco výše uvedený testmodpříklad ve skutečnosti nevykazuje použití v kontextu více nároků, použil jsem stejný postup sledování, abych zjistil, že modul USB, který kóduji, byl opakovaně deklarován pulseaudiojako jakmile je zařízení USB připojeno - tak se zdá, že postup pro takové případy použití funguje.

47
sdaau

Říká se v Linux Kernel Module Programming Guide , že počet použití modulu je řízen funkcemi try_module_get a try_module_put. Možná zjistíte, kde jsou tyto funkce volány pro váš modul.

6
haggai_e

Vše, co dostanete, je seznam modulů, které závisí na tom, které další moduly (sloupec Used by v lsmod). Nemůžete napsat program, abyste zjistili, proč byl modul načten, pokud je stále potřeba pro cokoliv, nebo co by se mohlo rozbít, pokud ho vyložíte a vše, co na něm záleží.

4
Norman Ramsey

Pokud použijete možnost rmmod BEZ možnosti --force, řekne vám, co používá modul. Příklad:

$ lsmod | grep firewire
firewire_ohci          24695  0 
firewire_core          50151  1 firewire_ohci
crc_itu_t               1717  1 firewire_core

$ Sudo modprobe -r firewire-core
FATAL: Module firewire_core is in use.

$ Sudo rmmod firewire_core
ERROR: Module firewire_core is in use by firewire_ohci

$ Sudo modprobe -r firewire-ohci
$ Sudo modprobe -r firewire-core
$ lsmod | grep firewire
$
2
JonahB 9L

Můžete zkusit soubor lsof nebo fuser.

1
jedihawk

zkuste kgdb a nastavte breakpoint na váš modul

0
river