Red de conocimiento informático - Material del sitio web - Cómo reportar problemas en el kernel de Linux

Cómo reportar problemas en el kernel de Linux

Error del kernel de Linux: Análisis bloqueado de Softlock CPU #1

Registro de errores del kernel en línea.

Kernel: ¡El incremento es demasiado grande! 18428729675200069867 ts = 18446743954022816244 escribir sello = 18014278822746377

Kernel: - [cortar aquí] -

kernel: ADVERTENCIA: en kernel/trace/ring_buffer c: 1988 Rb_ reserve _ next _ event. 0x2ce/0x 370() (no infectado)

Kernel: Nombre del hardware: ProLiant DL360 G7

Kernel: Vinculado en el módulo: fuse ipv6 power_meter bnx2 sg micro código serio_raw iTCO_wd titco_vendor_support HP ILO HP wdt i7 core_edac edac_core shpchp ext 4m bcache jbd 2 SD_mod CRC_t 10 dif hpsa radeon TTM DRM_kms_helper DRM I2C_algo_ bit I2C_coredm_mirror DM_region_hash DM_log DM_mod[Última desinstalación: scsi_wait_scan]

Núcleo: Pid 5483 , Comunicaciones: Host no infectado 2.6.32-220.el6 .x86_64 #1

Kernel: rastreo de llamadas:

Kernel: [lt;ffffffff 81069 b77 gt;] ?warn_slowpath_common 0x87/0xc0

Kernel: [lt ;ffffffff 81069 BCA gt;] ?warn_slow path_null 0x 1a/0x 20

Kernel: [lt;ffffffff 810 ea8ae gt;] ?Rb_reserve_next_event 0x2ce/0x 370

Núcleo: [lt;ffffffff 810 eab 02 gt;] ?ring_buffer_lock_reserve 0x a2/0x 160

Núcleo: [lt;ffffffff 810ec 97c gt;] ?trace_buffer_lock_reserve 0x2c/0x 70

Kernel: [lt;ffffffff 810 ECB 16gt;] ?trace_current_buffer_lock_reserve 0x 16/0x 20

Kernel: [lt;ffffffff 8107 AE 1e gt;] ?ftrace_raw_event_HR timer_cancel 0x4e/0xb 0

Kernel: [lt;ffffffff 81095 e7a gt;] ?HR timer _ intenta _ cancelar 0x ba/0xd 0

Kernel: [lt;ffffffff 8106 f634 gt;] ?do_setimer 0xd4 /0x220

Kernel: [lt;ffffffff 8106 f88a gt;

] ?alarm_setimer 0x3a/0x60

Kernel: [lt;ffffffff 8107 c27e gt;] ?sys_alarm 0xe/0x20

Kernel: [lt;ffffffff 8100 b308 gt;] ?tracesys 0xd9 /0xde

Kernel: -[end trace 4d 0a 1 e F2 e 62 CB 1 a2]-

abrt-dump-oops: 1 OOP del kernel informado a abrt

p>

Kernel: ERROR: bloqueo suave: CPU n.° 11 atascada 4278190091s. [qmgr:5492]

Kernel: Vinculado en módulos: fusible ipv6 power_meter bnx2 sg microcódigo serio _ raw iTCO _ wd titco _ proveedor _ soporte HP ILO HP wdt i7 core _ edac edac _ core shpchp ext 4m bcache jbd 2 SD _ mod CRC _ t 10 dif hpsa radeon TTM DRM _ kms _ helper DRM I2C _ algo _ bit I2C _ coredm _ mirror DM _ region _ hash DM _ log DM _ mod[Última desinstalación: scsi_wait_scan]

Núcleo: CPU 11

Núcleo: Módulo vinculado: fusible ipv6 power_meter bnx2 sg microcódigo serio _ raw iTCO _ wd titco _ proveedor _ soporte HP ILO HP wdt i7 core _ edac edac_core shpchp ext 4m bcache jbd 2 SD_mod CRC_t 10 dif hpsa radeon TTM DRM_kms_helper DRM I2C_algo_bit I2C_coredm_mirror DM_region_hash DM_log DM_mod[última desinstalación: scsi_wait_scan]

Kernel:

Kernel: Pid: 5492, Comunicaciones: qmgr Taint: G W-2.6.32-220.el6.x86_64#1 HP proliant dl 360 G7

Núcleo: RIP: 0010: [lt;ffffffff 8106 f730 gt;][lt;ffffffff 8106 f730 gt;] do_setimer 0x 1d 0/0x 220

Kernel: RSP: 0018: ffff 88080 a 661e F8 e flags: 00000286

Kernel: RAX: ffff 88080 b 175a 08 RBX: ffff 88080 a 661f 18 RCX: 0000000000000

Kernel :RDX: 000000000000000 RSI: 00000000000082 RDI: ffff 88080 c8c 40

Kernel: RBP: ffffffff 8100 bc0e R08:

0000000000000 R09: 0099d 7270 e 01c3f 1

Núcleo: r 10: 00000000000000 r 11: 00000000000246 r 12: ffffffff 810e F9 a 3

Núcleo: r 13: ffff 88080 a 661e 88 r 14: 0000000000000 r 15: ffff 88080 a 65a 544

Kernel: FS: 00007 f 10b 245 f 7c 0(0000)GS: ffff 88083 C4 a 0000(0000)knlGS: 0000

Core: CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003 B

Core: CR2: 00007 FF 955977380 CR3: 000000100 A80B 000 CR4: 00000000000006 E0

Core: DR0: 000000000000000 dr 1: 000000000000000 DR2: 0000000000000

Kernel: DR3

Kernel: proceso qmgr (pid: 5492, threadinfo ffff88080a660000, tarea ffff880809577500 )

Núcleo :stack:

Núcleo: 00007 f 10b 323 def 0 00007 f 10b 248 EAD 0 00007 f 10b 26 d0f 78 00007 f 10b 248 ede 0

Núcleo: lt0 gtffff 88080 a 661f 68 ffffffff 8106 f88a 000000000000000000000000000000

Núcleo: lt0 gt0000000000000014c 000000000000000000000000000000000000000 000 0000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000000000000000 Núcleo: [lt;ffffffff 8106 f88a gt;]? alarm_setimer 0x3a /0x60

Kernel: [lt;ffffffff 8107 c27e gt;] ?sys_alarm 0xe/0x20

Kernel: [lt;ffffffff 8100 b308 gt;] ?tracesys 0xd9/0xde

Núcleo: Código: 89 ef E8 74 66 02 00 83 3d 15 69 b5 00 00 75 37 49 8b 84 24 70 07 00 00 48 0508 08 00 00 66 ff 00 66 66 90 FB 66 0f 1f 44 00 00 lt; 31 gt; c0 e9 64 Fe ff ff49 8b 84 24 68 07 00 00 48 C7 80 d0 00 00

Kernel: seguimiento de llamadas:

Kernel: [

lt;ffffffff 8106 f769 gt;] ?do_setimer 0x209/0x220

Kernel: [ lt;ffffffff 8106 f88a gt;] ?alarm_setimer 0x3a/0x60

Kernel: [ lt;ffffffff 8107 c27e gt;] ?sys_alarm 0xe/0x20

kernel: [lt;ffffffff 8100 b308 gt;] ?tracesys 0xd9/0xde

abrt-dump-oops: 1 informado a abrt Kernel OOP

2. Análisis de las causas del error del bloqueo suave del kernel.

Explicación del nombre del bloqueo suave: el llamado bloqueo suave significa que el error no bloquea completamente el sistema, sino que bloquea varios procesos (o subprocesos del kernel) en un estado determinado (generalmente en el área del kernel). En muchos casos esto se debe al uso de bloqueos del kernel.

El kernel de Linux tiene un proceso de monitorización para cada CPU, lo que en el ámbito técnico se denomina watchdog. Desde ps -ef | grep watchdog, podemos ver que el nombre del proceso probablemente sea watchdog/X (número: número lógico de la CPU 1/2/3/4, etc.). Este proceso o subproceso se ejecuta una vez por segundo; de lo contrario, se suspende y permanece inactivo. Este proceso recopilará datos de uso de tiempo para cada CPU y los almacenará en su propia estructura de datos del kernel. Hay muchas funciones de interrupción específicas en el kernel. Estas funciones de interrupción llaman al recuento de bloqueo suave, que compara la marca de tiempo actual con el tiempo almacenado en una estructura de datos del núcleo de la CPU específica (correspondiente). Si encuentra que la marca de tiempo actual es más larga que el tiempo de ahorro de CPU correspondiente, asume que el proceso de monitoreo o el subproceso de vigilancia no se ha ejecutado durante mucho tiempo. ¿Por qué y cómo se produce el bloqueo suave de la CPU? Si el kernel de Linux está cuidadosamente diseñado y organizado para que la CPU pueda acceder a él, ¿cómo puede ocurrir un punto muerto suave de la CPU? Entonces solo podemos decir que debido al desarrollo del usuario o la introducción de software de terceros, la razón por la que el kernel de nuestro servidor falla es el proceso qmgr. Porque siempre hay un proceso de ejecución de CPU para cada bucle infinito (el proceso qmgr muestra un proceso de servicio de cola de mensajes de correo en segundo plano) y tiene una cierta prioridad. El programador de la CPU programa la ejecución de un controlador. Si hay un problema con el controlador y no se detecta, el controlador puede usar temporalmente la CPU durante un período prolongado. Según la descripción anterior, el proceso de vigilancia detectará esto y arrojará un error de interbloqueo suave. Un punto muerto suave bloqueará la CPU y dejará el sistema inutilizable.

Si el problema es causado por un proceso o subproceso en el espacio del usuario, el rastreo no tendrá contenido. Si hay un subproceso del núcleo involucrado, la información de rastreo se mostrará en el mensaje de bloqueo suave.

3. Analizar los errores según el código fuente del kernel de Linux

Analizar los motivos específicos según el mensaje de error arrojado por nuestra primera parte del kernel y llamar al seguimiento (el subsistema de seguimiento de el kernel de Linux).

Primero instale el código fuente del kernel de Linux correspondiente de acuerdo con nuestra versión centos. Los pasos específicos son los siguientes:

(1) Descargue el paquete rpm del código fuente kernel-2. 32-220.17 .1 .el6 rpm.

(2) Utilice el comando para instalar la biblioteca dependiente correspondiente: yum Install rpm-build red hat-rpm-config ascii doc newt-devel.

(3) Instale el paquete fuente: rpm-Iker nel-2 6 .

(4) Ingrese el directorio donde se creó el código fuente: cd~/rpmbuild/SPECS.

(5) Cree el directorio del código fuente generado: rpmbuild-BP-target = `uname-m` kernel spec.

Comenzamos a analizar el código fuente según el registro de errores del kernel:

(1) Análisis del registro de errores del kernel de la primera etapa (análisis del código de salida del registro el 4 de diciembre a las 14:03:34 De hecho, algunos códigos no causarán un punto muerto suave de la CPU, principalmente porque el registro de errores de la segunda etapa muestra que causará un punto muerto suave de la CPU).

Primero localizamos el código fuente relevante a través del registro: mire el siguiente registro: dec 414:03:34bp-YZH-1-xxxx kernel: advertencia: en kernel/trace/ring_buffer c: 1988. Rb _reserve_next_event 0x2ce.

Según el contenido del registro, podemos localizar fácilmente la línea de código número 1988 en el archivo kernel/trace/ring_buffer.c de la siguiente manera: WARN_ON(1).

Primero explique brevemente la función de WARN_ON: WARN_ON solo imprime la información de la pila actual y no falla. Entonces verá mucha información de la pila detrás de él. La macro se define de la siguiente manera:

#ifndef WARN_ON

#defineWARN_ON(condición) ({ \

int __ret_warn_on =!!(condición); \

if (improbable(__ret_warn_on)) \

_ _ WARN();\

Improbable(_ _ ret _ warn _ on); >

})

#endif

Esta macro simplemente garantiza que el valor de condición pasado sea 0 o 1 (el resultado de dos operaciones lógicas NOT), y luego usa la Tecnología de predicción de ramas (para garantizar que las ramas con alta probabilidad de ejecución estén al lado de las instrucciones anteriores) para determinar si es necesario llamar a la definición de macro de __WARN (). Si la definición de macro de __WARN() se ejecuta cuando se cumplen las condiciones, se ejecutará una instrucción vacía. . La macro anterior llamada WARN_ON es 1, por lo que se ejecutará __WARN(). Sigamos mirando la definición de la macro __WARN(), de la siguiente manera:

#define _ _ WARN()WARN _ slow path _ null(_ _ FILE _ _, __LINE__)

A partir de la información de seguimiento de llamadas a continuación, encontramos que se llamó a la función warn_slowpath_null. Al buscar la implementación de esta función en el código fuente del kernel de Linux, encontramos que está implementada en pánico.c (la implementación de funciones relacionadas en el kernel pánico), de la siguiente manera:

void warn _ slow ruta _ null(const char * archivo, int línea)

{

warn_slowpath_common(archivo, línea, __builtin_return_address(0),

TAINT_WARN, NULL);

}

EXPORT _ SYMBOL(warn _ slow path _ null); //Muestra este símbolo para que otros módulos puedan usar esta función.

De manera similar, vimos la función warn_slowpath_common, y esta función se imprimió antes de llamar a la función warn_slowpath_null en el seguimiento, lo que una vez más confirmó que este proceso es correcto.

También en el archivo pánico.c, encontré que la función de warn_slowpath_common se implementa de esta manera:

Static void warn_slow path_common(const char * file, int line, void *caller,

Contaminación sin firmar, estructura slowpath_args *args)

{

const char * board

printk(KERN_WARNING " - [cortar aquí]- \n ");

printk(KERN_WARNING "Advertencia: en s:d pS()(s)\n ",

archivo, línea, llamador, print_tincted()

<); p>board = DMI _ get _ system _ info (DMI _ product _ name); //Obtener información del sistema dmi

IF (placa de circuito)

printk(KERN_WARNING "Nombre del hardware) : s\n ", board); //A través de nuestra información de registro, podemos encontrar que nuestro nombre de hardware es ProLiant DL360 G7.

if (parámetro)

vprintk(args- gt; fmt, args- gt; args);

print_modules() // sistema de impresión Información del módulo

dump _ stack(); //Volcar la salida de información (se inicia el seguimiento de llamadas)

print _ oops _ end _marker() // Imprimir fin oops<; p>add_taint(taint);

}

Al analizar la implementación de esta función, no es difícil encontrar que gran parte de nuestra información de registro se genera desde aquí, incluida la impresión de parte. información del sistema, no continuaremos con más análisis (consulte los comentarios del código, que llaman a funciones relevantes para imprimir la información correspondiente. A través de mi análisis, la implementación de estas funciones puede corresponder completamente a nuestra información de registro, entre las cuales dump_stack está relacionado con el Arquitectura de CPU. El servidor debe pertenecer a la arquitectura x86). Aquí continuamos analizando la implementación de la función dump_stack, porque esta función está relacionada con la arquitectura de la CPU y esta función refleja directamente los procesos relacionados que hacen que el kernel falle. Esta función se implementa de la siguiente manera:

/*

*dump_stackgenerator independiente de la arquitectura

*/

void dump_stack(void)

{

Pila larga sin firmar;

printk("Pid: d, comm: .20s s s.*s\n ",

current->pid, current->comm, print_tainted(),

init_utsname()->release,

(int