[Linux] Kernel oops/análisis de errores de página

Vi una publicación bien escrita
Fuente: https://www.zhihu.com/question/317992090/answer/2561856956

ups

La palabra Oops originalmente significa sorpresa. Generalmente, la información de Oops aparece en el kernel, lo que indica que el sistema actual encuentra un problema importante. El kernel arrojará cierta información sobre el estado actual del sistema a través de Oops, lo cual es conveniente para localizar el problema. Al comprender el formato de la estructura de información de Oops, puede encontrar el punto problemático de la excepción, o la dirección de la solución. Oops ordinario incluye principalmente información: dirección de tabla de página global (pdg) de tipo Oops, número de CPU actual y registro estado Pila de llamada de ejecución de función normal Interrupción de pila de excepción Sistema actualmente cargado información del proceso del módulo Escriba a continuación Un módulo de kernel simple para demostrar cómo analizar un error de kernel oops.

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>

static void creat_oops(void)
{
    
    
	printk("******start*****\n");
	*(int *)0 = 0;  //人为制造一个空指针
	printk("******end*****\n");
	
}

static int __init regulator_pmc_voltage_init(void)
{
    
    
	printk("oops module init\n");
	creat_oops();
	return 0;
}
subsys_initcall(regulator_pmc_voltage_init);

static void __exit regulator_pmc_voltage_exit(void)
{
    
    
	printk("regulator_pmc_voltage_exit goodbye\n");
}
module_exit(regulator_pmc_voltage_exit);

MODULE_LICENSE("GPL");

Después de compilar, empaquetar y actualizar el firmware, aparecerá el siguiente registro:

[    1.079767] oops module init
[    1.079834] ******start*****
[    1.079919] Unable to handle kernel write to read-only memory at virtual address 0000000000000000
[    1.088829] Mem abort info:
[    1.091521]   ESR = 0x96000045
[    1.094653]   EC = 0x25: DABT (current EL), IL = 32 bits
[    1.099899]   SET = 0, FnV = 0
[    1.102874]   EA = 0, S1PTW = 0
[    1.106050] Data abort info:
[    1.108854]   ISV = 0, ISS = 0x00000045
[    1.112724]   CM = 0, WnR = 1
[    1.115615] [0000000000000000] user address but active_mm is swapper
[    1.122028] Internal error: Oops: 96000045 [#1] PREEMPT SMP
[    1.127478] Modules linked in:
[    1.130515] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.4.99-00006-g02e5b77f5cd8-dirty #5
[    1.138656] Hardware name: sun50iw10 (DT)
[    1.142646] pstate: 80400005 (Nzcv daif +PAN -UAO)
[    1.147420] pc : regulator_pmc_voltage_init+0x2c/0x48
[    1.152439] lr : regulator_pmc_voltage_init+0x28/0x48
[    1.157462] sp : ffffffc01002bd90
[    1.160756] x29: ffffffc01002bd90 x28: 0000000000000000
[    1.166043] x27: ffffffc011293000 x26: ffffffc011267860
[    1.171329] x25: 0000000000000000 x24: ffffffc011267888
[    1.176616] x23: ffffffc010a2ee1c x22: ffffffc011266e50
[    1.181903] x21: ffffffc0110e0000 x20: ffffffc010d1b000
[    1.187189] x19: ffffffc011267000 x18: 000000000000000a
[    1.192476] x17: 000000004aeaa4e0 x16: 00000000b1cadfb9
[    1.197763] x15: 00000000000137da x14: ffffffc09002bab7
[    1.203049] x13: ffffffffffffffff x12: 0000000000000030
[    1.208336] x11: 00000000fffffffe x10: ffffffc01002bac5
[    1.213622] x9 : 0000000005f5e0ff x8 : ffffff803f5586e4
[    1.218909] x7 : 0000000000000038 x6 : 0000000000000004
[    1.224196] x5 : 0000000000000000 x4 : 0000000000000001
[    1.229483] x3 : ffffffc010d1b018 x2 : 0411eecd9ba58e00
[    1.234769] x1 : 0000000000000000 x0 : 0000000000000000
[    1.240056] Call trace:
[    1.242486]  regulator_pmc_voltage_init+0x2c/0x48
[    1.247168]  do_one_initcall+0x110/0x2c8
[    1.251067]  kernel_init_freeable+0x158/0x1f8
[    1.255400]  kernel_init+0x18/0x108
[    1.258866]  ret_from_fork+0x10/0x18
[    1.262428] Code: f0fff900 9126e800 97f3ffbc d2800000 (b900001f)
[    1.268509] ---[ end trace 06967c0c0dd91e52 ]---
[    1.273118] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b
[    1.280712] SMP: stopping secondary CPUs
[    1.284637] ---[ end Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b ]---

El puntero de la PC apunta a la dirección señalada por el error, y el seguimiento de la llamada muestra la relación de llamada del programa cuando ocurre el error. Primero observe la función de error regulator_pmc_voltage_init+0x2c/0x48, donde 0x2c indica que el puntero de instrucción está en el byte 0x2c de la función, y la función en sí tiene un total de 0x48 bytes.

Se puede analizar con gdb cuando hay una tabla de símbolos

Usando gdb, puede ver el código cerca del error y también dar la ruta de la función de error específica.

$ ./out/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gdb ./out/kernel/build/vmlinux
GNU gdb (Linaro_GDB-2016.05) 7.11.1.20160702-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=aarch64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./out/kernel/build/vmlinux...done.
(gdb) list *regulator_pmc_voltage_init+0x2c
0xffffffc010a2ee48 is in regulator_pmc_voltage_init (/home1/weidonghui/workspace/bsp/longan/kernel/linux-5.4/drivers/regulator/pmc.c:8).
3       #include <linux/kernel.h>
4
5       static void creat_oops(void)
6       {
    
    
7               printk("******start*****\n");
8               *(int *)0 = 0;
9               printk("******end*****\n");
10
11      }
12
(gdb)

Cuando no hay una tabla de símbolos, se puede usar decodecode para el análisis:

Para archivos binarios sin una tabla de símbolos compilada, el kernel proporciona un script muy útil que puede ayudar a localizar rápidamente el problema. El script se encuentra en scripts/decodecode en el directorio de código del kernel de Linux. Primero, guarde el registro de errores en un archivo txt.

$ ARCH=arm64 CROSS_COMPILE=~/longan/out/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu- ./scripts/decodecode < ./temp.txt
[ 1.262428] Code: f0fff900 9126e800 97f3ffbc d2800000 (b900001f)
All code
========
   0:   f0fff900        adrp    x0, 0xfffffffffff23000
   4:   9126e800        add     x0, x0, #0x9ba
   8:   97f3ffbc        bl      0xffffffffffcffef8
   c:   d2800000        mov     x0, #0x0                        // #0
  10:*  b900001f        str     wzr, [x0]               <-- trapping instruction

Code starting with the faulting instruction
===========================================
   0:   b900001f        str     wzr, [x0]
$

El script decodecode convierte la información de registro de oops incorrecta en un código ensamblador intuitivo y útil, e indica en qué instrucción de ensamblado se encuentra el error, lo cual es muy útil para analizar errores de oops sin código fuente.

problema de interbloqueo

Interbloqueo se refiere al fenómeno de que dos o más procesos esperan el uno al otro debido a la competencia por los recursos. Por ejemplo, el proceso A necesita el recurso X, el proceso B necesita el recurso Y y ambas partes tienen los recursos que necesita la otra parte y no los liberan, lo que conducirá a un punto muerto. En el desarrollo del kernel, a menudo se considera el diseño de concurrencia, incluso si se adoptan las ideas de programación correctas, inevitablemente se producirán interbloqueos. En el kernel de Linux, existen dos interbloqueos comunes de la siguiente manera: Interbloqueo recursivo: por ejemplo, los bloqueos se utilizan en operaciones retrasadas, como interrupciones, y los bloqueos externos constituyen interbloqueos recursivos. Punto muerto AB-BA: varios bloqueos provocan un punto muerto debido a un manejo inadecuado, y el orden de procesamiento inconsistente de los bloqueos en varias rutas del núcleo también puede causar un punto muerto. El kernel de Linux introdujo el módulo de depuración de interbloqueos Lockdep en 2006. Después de años de desarrollo, Lockdep proporciona comodidad para que los desarrolladores del kernel y los desarrolladores de controladores descubran los interbloqueos con anticipación. Lockdep rastrea el estado de cada bloqueo y las dependencias entre cada bloqueo, y pasa por una serie de reglas de verificación para garantizar que las dependencias entre bloqueos sean correctas. Habilitar Lockdep Para usar la función Lockdep en el kernel de Linux, debe habilitar las siguientes opciones:

CONFIG_LOCK_STAT=s
CONFIG_PROVE_LOCKING=s
CONFIG_DEBUG_LOCKDEP=s

Ejemplo de interbloqueo AB-BA (basado en linux-5.4)

#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

static DEFINE_SPINLOCK(hack_spinA);
static DEFINE_SPINLOCK(hack_spinB);


void hack_spinAB(void)
{
    
    
	printk("\nhack_lockdep:A-->B\n");
	spin_lock(&hack_spinA);
	spin_lock(&hack_spinB);
}


void hack_spinBA(void)
{
    
    
	printk("\nhack_lockdep:B-->A\n");
	spin_lock(&hack_spinB);
}


static int __init lockdep_test_init(void)
{
    
    
	printk("\nfigo: my lockdep module init\n");
	hack_spinAB();
	hack_spinBA();
	return 0;
}

static void __exit lockdep_test_exit(void)
{
    
    
	printk("\ngoodbye\n");
}

MODULE_LICENSE("GPL");
module_init(lockdep_test_init);
module_exit(lockdep_test_exit);

El ejemplo de interbloqueo anterior inicializa dos spinlocks, donde la función hack_spinAB() se aplica para el bloqueo hack_spinA y el bloqueo hack_spinB respectivamente, y la función hack_spinBA() se aplica para el bloqueo hack_spinB. Debido a que el bloqueo hack_spinB se adquirió con éxito y no se ha liberado en este momento, esperará para siempre y también está bloqueado en la sección crítica de hack_spinA. Después de volver a compilar el núcleo, habrá nodos de archivo lockdep, lockdep_chains y lockdep_stats en el directorio proc, lo que indica que el módulo lockdep ha entrado en vigor. La operación produce el siguiente registro:

[    3.010121] sunxi_sid_init()485 - insmod ok
[    3.010191]
[    3.010191] figo: my lockdep module init
[    3.014149]
[    3.014149] hack_lockdep:A-->B
[    3.018919]
[    3.018919] hack_lockdep:B-->A
[    3.023168]
[    3.024541] ============================================
[    3.029827] WARNING: possible recursive locking detected
[    3.035117] 5.4.99-00006-g02e5b77f5cd8-dirty #7 Not tainted
[    3.040661] --------------------------------------------
[    3.045948] swapper/0/1 is trying to acquire lock:
[    3.050715] ffffffc01120e668 (hack_spinB){
    
    +.+.}, at: hack_spinBA+0x2c/0x34
[    3.057561]
[    3.057561] but task is already holding lock:
[    3.063367] ffffffc01120e668 (hack_spinB){
    
    +.+.}, at: hack_spinAB+0x38/0x44
[    3.070214]
[    3.070214] other info that might help us debug this:
[    3.076714]  Possible unsafe locking scenario:
[    3.076714]
[    3.082607]        CPU0
[    3.085034]        ----
[    3.087460]   lock(hack_spinB);
[    3.090580]   lock(hack_spinB);
[    3.093700]
[    3.093700]  *** DEADLOCK ***
[    3.093700]
[    3.099594]  May be due to missing lock nesting notation
[    3.099594]
[    3.106356] 2 locks held by swapper/0/1:
[    3.110254]  #0: ffffffc01120e620 (hack_spinA){
    
    +.+.}, at: hack_spinAB+0x30/0x44
[    3.117534]  #1: ffffffc01120e668 (hack_spinB){
    
    +.+.}, at: hack_spinAB+0x38/0x44
[    3.124814]
[    3.124814] stack backtrace:
[    3.129153] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.4.99-00006-g02e5b77f5cd8-dirty #7
[    3.137294] Hardware name: sun50iw10 (DT)
[    3.141281] Call trace:
[    3.143713]  dump_backtrace+0x0/0x16c
[    3.147350]  show_stack+0x24/0x30
[    3.150645]  dump_stack+0xd0/0x118
[    3.154025]  __lock_acquire+0xe04/0xe9c
[    3.157836]  lock_acquire+0x14c/0x1b8
[    3.161478]  _raw_spin_lock+0x4c/0x88
[    3.165116]  hack_spinBA+0x2c/0x34
[    3.168499]  lockdep_test_init+0x24/0x30
[    3.172398]  do_one_initcall+0x110/0x2c8
[    3.176299]  kernel_init_freeable+0x158/0x1f8
[    3.180629]  kernel_init+0x18/0x108
[    3.184097]  ret_from_fork+0x10/0x18
  • lockdep ha mostrado claramente la ruta donde ocurrió el interbloqueo y la información de la pila de la función cuando ocurrió. La combinación con gdb puede localizar y resolver problemas rápidamente.
$ ./out/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gdb ./out/kernel/build/vmlinux
GNU gdb (Linaro_GDB-2016.05) 7.11.1.20160702-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-unknown-linux-gnu --target=aarch64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./out/kernel/build/vmlinux...done.
(gdb) list *hack_spinAB+0x30
0xffffffc010402908 is in hack_spinAB (/home1/weidonghui/workspace/bsp/longan/kernel/linux-5.4/include/linux/spinlock.h:338).
333             raw_spin_lock_init(&(_lock)->rlock);            \
334     } while (0)
335
336     static __always_inline void spin_lock(spinlock_t *lock)
337     {
    
    
338             raw_spin_lock(&lock->rlock);
339     }
340
341     static __always_inline void spin_lock_bh(spinlock_t *lock)
342     {
    
    
(gdb) list *hack_spinAB+0x38
0xffffffc010402910 is in hack_spinAB (/home1/weidonghui/workspace/bsp/longan/kernel/linux-5.4/drivers/regulator/lock_test_1.c:14).
9       void hack_spinAB(void)
10      {
    
    
11              printk("\nhack_lockdep:A-->B\n");
12              spin_lock(&hack_spinA);
13              spin_lock(&hack_spinB);
14      }
15
16
17      void hack_spinBA(void)
18      {
    
    
(gdb)
  • Ejemplo de problema de interbloqueo recursivo (basado en linux-4.9)
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/mutex.h>
#include <linux/delay.h>


static DEFINE_MUTEX(mutex_a);
static struct delayed_work delay_task;
static void lockdep_timefunc(unsigned long);
static DEFINE_TIMER(lockdep_timer, lockdep_timefunc, 0, 0);

static void lockdep_timefunc(unsigned long dummy)
{
    
    
	schedule_delayed_work(&delay_task, 10);
	mod_timer(&lockdep_timer, jiffies + msecs_to_jiffies(100));
}


static void lockdep_test_worker(struct work_struct *work)
{
    
    
	mutex_lock(&mutex_a);
	mdelay(300);		//处理一些事情,这里用mdelay代替
	mutex_unlock(&mutex_a);
}


static int lockdep_thread(void *nothing)
{
    
    
	set_freezable();
	set_user_nice(current, 0);
	while (!kthread_should_stop()) {
    
    
		mdelay(500);	//处理一些事情,这里用mdelay代替
		
		//遇到某些特殊情况,需要取消delay_task
		mutex_lock(&mutex_a);
		cancel_delayed_work_sync(&delay_task);
		mutex_unlock(&mutex_a);
	}
	return 0;
}


static int __init lockdep_test_init(void)
{
    
    
	struct task_struct *lock_thread;
	printk("figo: my lockdep module init\n");

	/*创建一个线程来处理某些事情*/
	lock_thread = kthread_run(lockdep_thread, NULL, "lockdep_test");

	/*创建一个delay worker*/
	INIT_DELAYED_WORK(&delay_task, lockdep_test_worker);

	/*创建一个定时器来模拟某些异步事件,比如中断等*/
	lockdep_timer.expires = jiffies + msecs_to_jiffies(500);
	add_timer(&lockdep_timer);
	return 0;
}

static void __exit lockdep_test_exit(void)
{
    
    
	printk("goodbye\n");
}

MODULE_LICENSE("GPL");
module_init(lockdep_test_init);
module_exit(lockdep_test_exit);
  • Primero cree un hilo de kernel lockdep_thread para procesar algunas cosas periódicamente, cree un kworker para manejar algunas operaciones retrasadas como la mitad inferior de las interrupciones y finalmente use un temporizador para simular eventos asincrónicos (como interrupciones). En el subproceso del núcleo lockdep_thread, a menudo es necesario cancelar kworker en algunos casos especiales. En el código, primero se aplica un bloqueo mutex mutex_a y luego se llama a la función cancel_delayed_work_sync() para cancelar kworker. Por otro lado, el temporizador llama a kworker regularmente y aplica el bloqueo mutex mutex_a en la función de devolución de llamada lockdep_test_worker(). El registro es el siguiente:
[    3.229887] ======================================================
[    3.229889] [ INFO: possible circular locking dependency detected ]
[    3.229893] 4.9.191 #2 Not tainted
[    3.229895] -------------------------------------------------------
[    3.229898] kworker/0:1/32 is trying to acquire lock:
[    3.229919]  (mutex_a){
    
    +.+...}, at: [<ffffff80083040f4>] lockdep_test_worker+0x30/0x60
[    3.229921]
[    3.229921] but task is already holding lock:
[    3.229933]  ((&(&delay_task)->work)){
    
    +.+...}, at: [<ffffff80080b4858>] process_one_work+0x1a4/0x354
[    3.229935]
[    3.229935] which lock already depends on the new lock.
[    3.229935]
[    3.229937]
[    3.229937] the existing dependency chain (in reverse order) is:
[    3.229945]
[    3.229945] -> #1 ((&(&delay_task)->work)){
    
    +.+...}:
[    3.229953]        __lock_acquire+0x13a0/0x16f4
[    3.229958]        lock_acquire+0x8c/0xb4
[    3.229962]        flush_work+0x5c/0x224
[    3.229967]        __cancel_work_timer+0x128/0x1a0
[    3.229973]        cancel_delayed_work_sync+0x10/0x18
[    3.229977]        lockdep_thread+0x70/0x90
[    3.229982]        kthread+0xd4/0xdc
[    3.229988]        ret_from_fork+0x10/0x50
[    3.229995]
[    3.229995] -> #0 (mutex_a){
    
    +.+...}:
[    3.230000]        print_circular_bug+0x60/0x2b8
[    3.230004]        __lock_acquire+0x1098/0x16f4
[    3.230008]        lock_acquire+0x8c/0xb4
[    3.230016]        mutex_lock_nested+0x5c/0x390
[    3.230020]        lockdep_test_worker+0x30/0x60
[    3.230025]        process_one_work+0x210/0x354
[    3.230030]        worker_thread+0x288/0x3a8
[    3.230034]        kthread+0xd4/0xdc
[    3.230038]        ret_from_fork+0x10/0x50
[    3.230040]
[    3.230040] other info that might help us debug this:
[    3.230040]
[    3.230043]  Possible unsafe locking scenario:
[    3.230043]
[    3.230045]        CPU0                    CPU1
[    3.230046]        ----                    ----
[    3.230051]   lock((&(&delay_task)->work));
[    3.230056]                                lock(mutex_a);
[    3.230060]                                lock((&(&delay_task)->work));
[    3.230064]   lock(mutex_a);
[    3.230066]
[    3.230066]  *** DEADLOCK ***
[    3.230066]
[    3.230069] 2 locks held by kworker/0:1/32:
[    3.230081]  #0:  ("events"){
    
    .+.+..}, at: [<ffffff80080b4858>] process_one_work+0x1a4/0x354
[    3.230093]  #1:  ((&(&delay_task)->work)){
    
    +.+...}, at: [<ffffff80080b4858>] process_one_work+0x1a4/0x354
[    3.230095]
[    3.230095] stack backtrace:
[    3.230100] CPU: 0 PID: 32 Comm: kworker/0:1 Not tainted 4.9.191 #2
[    3.230103] Hardware name: sun50iw10 (DT)
[    3.230112] Workqueue: events lockdep_test_worker
[    3.230115] Call trace:
[    3.230122] [<ffffff8008089004>] dump_backtrace+0x0/0x240
[    3.230128] [<ffffff8008089258>] show_stack+0x14/0x1c
[    3.230134] [<ffffff80082b257c>] dump_stack+0xb0/0xe8
[    3.230139] [<ffffff80080e2ad0>] print_circular_bug+0x29c/0x2b8
[    3.230144] [<ffffff80080e50dc>] __lock_acquire+0x1098/0x16f4
[    3.230148] [<ffffff80080e5c00>] lock_acquire+0x8c/0xb4
[    3.230154] [<ffffff80085539cc>] mutex_lock_nested+0x5c/0x390
[    3.230159] [<ffffff80083040f4>] lockdep_test_worker+0x30/0x60
[    3.230165] [<ffffff80080b48c4>] process_one_work+0x210/0x354
[    3.230170] [<ffffff80080b5858>] worker_thread+0x288/0x3a8
[    3.230175] [<ffffff80080bae78>] kthread+0xd4/0xdc
[    3.230179] [<ffffff8008083180>] ret_from_fork+0x10/0x50
  • La información de bloqueo primero indica que puede ocurrir un interbloqueo recursivo (INFORMACIÓN: se detectó una posible dependencia de bloqueo circular)
  • A continuación, se solicita al subproceso "kworker/0:1/32" que intente adquirir el bloqueo mutex mutex_a, pero el bloqueo ya está en manos de otros procesos, y el proceso que mantiene el bloqueo está en &delay_task->work. La siguiente pila de llamadas de función muestra la ruta de llamada de los dos intentos anteriores para adquirir el bloqueo mutex_a. (1) El subproceso del kernel lockdep_thread primero adquiere con éxito el bloqueo mutex mutex_a y luego llama a la función cancel_delayed_work_sync() para cancelar kworker. Tenga en cuenta que la función cancel_delayed_work_sync() llamará a la operación de descarga y esperará a que se completen todas las funciones de devolución de llamada de kworker antes de llamar a mutex_unlock(&mutex_a) para liberar el bloqueo.
[    3.229945] -> #1 ((&(&delay_task)->work)){
    
    +.+...}:
[    3.229953]        __lock_acquire+0x13a0/0x16f4
[    3.229958]        lock_acquire+0x8c/0xb4
[    3.229962]        flush_work+0x5c/0x224
[    3.229967]        __cancel_work_timer+0x128/0x1a0
[    3.229973]        cancel_delayed_work_sync+0x10/0x18
[    3.229977]        lockdep_thread+0x70/0x90
[    3.229982]        kthread+0xd4/0xdc
[    3.229988]        ret_from_fork+0x10/0x50

(2) La función de devolución de llamada de kworker lockdep_test_worker() primero intentará adquirir el bloqueo mutex mutex_a Tenga en cuenta que el subproceso del kernel lockdep_thread ha adquirido el bloqueo mutex_a mutex en este momento y ha estado esperando que se complete la ejecución de la función de devolución de llamada actual de kworker , por lo que se produce un interbloqueo.

[    3.229995] -> #0 (mutex_a){
    
    +.+...}:
[    3.230000]        print_circular_bug+0x60/0x2b8
[    3.230004]        __lock_acquire+0x1098/0x16f4
[    3.230008]        lock_acquire+0x8c/0xb4
[    3.230016]        mutex_lock_nested+0x5c/0x390
[    3.230020]        lockdep_test_worker+0x30/0x60
[    3.230025]        process_one_work+0x210/0x354
[    3.230030]        worker_thread+0x288/0x3a8
[    3.230034]        kthread+0xd4/0xdc
[    3.230038]        ret_from_fork+0x10/0x50

El diagrama de llamadas de CPU del escenario de punto muerto se dibuja a continuación, que es claro de un vistazo
inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_21688871/article/details/131114564
Recomendado
Clasificación