Born to be geek!

sábado, agosto 28, 2004

Mi primer parche (chapuza) para el kernel de FreeBSD 5.x

El demonio de BSD Anteayer me dio por probar la nueva versión 6.0 de FreeBSD (que es en realidad la primera beta de la versión 5.3). Todo fue muy bonito. El kernel se actualizó sin problemas, pero en el primer arranque empecé a ver varios mensajes extraños, incluyendo mensajes de depuración de ACPI. Todo hacía presagiar que ACPI no iba a funcionar correctamente. Así que me dispuse a examinar la salida del comando sysctl hw.acpi. La primera sorpresa fue comprobar que de nuevo el throttling funcionaba (en mi última actualización a una snapshot del mes de julio, dejó de funcionar). Aparentemente todo estaba correcto.

Sin embargo, tras suspender el ordenador, en (frecuentes) ocasiones obtenía mensajes como este:

ad0: WARNING - WRITE_DMA interrupt was seen but timeout fired LBA=59203789

Después de cinco o seis mensajes como este (tiempo durante el cual el sistema respondía perfectamente, incluyendo la lectura y escritura en el disco ad0), se lanzaba un kernel panic, y a tomar viento todo.

Buscando por Internet (Google es tu amigo) encontré varios mensajes en las listas de correo de FreeBSD que decían que el problema se debía a fallos en los drivers de diversas tarjetas de red, que no respondían correctamente cuando se volvía de la suspensión. Esto afectaba al driver ATA (el de los discos duros), que no era informado a tiempo de que el disco duro debía despertarse. La solución que daban era compilar el kernel con todas las opciones de depuración, para que el funcionamiento fuera más lento, y así se diera tiempo a que todo se hiciera correctamente (pues vaya solución, pensé). Otra genial solución era eliminar todos los drivers de tarjeta de red del kernel, pero entonces no puedes usar la tarjeta de red (otra genial solución).

Como la primera solución era una señora chapuza (y además no funcionó, seguro que el que lo puso se estaba quedando con el personal), y la segunda no funcionó (compilé el kernel para que sólo soportara la Realtek 8139, pero nada), me puse a indagar por las fuentes del kernel. Descubrí que ese mensaje se lanzaba en la función ata_timeout(struct ata_request *request) en el fichero /usr/src/sys/dev/ata/ata-queue.c. Había un contador, con el número de intentos. Cuando el número de intentos llegaba a cero, se lanzaba el kernel panic. Como yo había comprobado que el sistema (incluido el disco duro) funcionaba normalmente mientras salían esos mensajes, en cada iteración, le añado uno al número de intentos, de modo que nunca se lanza el kernel panic.

Ya sé que mi solución es una chapuza. Pero funciona. Se puede suspender todas las veces que quieras el ordenador, y nunca deja de responder. El único inconveniente es que el mensaje se lanza cada dos por tres, y te llena el histórico /var/log/messages. Voy a retocarlo, para que no lance el mensaje.

Para los que les interes, aquí tienen el parche, y aquí la configuración de mi kernel.

Ups, me acabo de dar cuenta que la versión del cvs del fichero /usr/src/sys/dev/ata/ata-queue.c, disponible aquí, tiene solucionado este problema. Así que a recompilar el kernel con este ficherito, a ver qué pasa. En cuanto recompile el kernel y lo pruebe, actualizaré este post.

ACTUALIZACIÓN (antes de recompilar el kernel)

El parche está mal generado, así que aquí dejo el fichero modificado por mí. Simplemente hay que copiarlo en /usr/src/sys/dev/ata y recompilar el kernel.

ACTUALIZACIÓN (después de recompilar el kernel)

Todo funciona usando el fichero del CVS. Así que todo va bien ya. En realidad, se puede actualizar directamente al kernel del CVS, a la versión 5.3 Beta 2, o a cualquiera posterior al 27 de agosto. Funciona perfectamente (por lo menos, en mi máquina).