Códigos de error y su propagación
El vocabulario de errores del kernel: los -errno más comunes, qué significa cada uno, y la disciplina de propagarlos sin perder información.
Elegir el código de error correcto no es un detalle: es lo que ve el usuario cuando algo falla (como el mensaje “Permission denied” o “No such device”). El kernel tiene un vocabulario preciso de errores, y usarlo bien hace que los fallos sean diagnosticables.
- Los códigos de error más comunes.
- Elegir el correcto para cada situación.
- Propagar sin perder información.
- De -errno a mensaje de usuario.
El vocabulario de errores
Los códigos viven en include/uapi/asm-generic/errno-base.h y errno.h. Los que más usarás:
| Código | Significado |
|---|---|
-EINVAL |
argumento inválido |
-ENOMEM |
sin memoria |
-ENODEV |
no existe el dispositivo |
-EBUSY |
recurso ocupado |
-EPERM / -EACCES |
sin permiso / acceso denegado |
-EFAULT |
dirección de memoria inválida (frontera user, nivel 12) |
-EAGAIN |
inténtalo de nuevo (recurso temporalmente no disponible) |
-ENOSYS |
no implementado |
-EIO |
error de entrada/salida |
Elegir el correcto
Un error mal elegido confunde a quien depura; uno bien elegido guía directo al problema. El código que devuelves cruza la frontera al usuario: la libc lo convierte en el errno que ve el programa, y en el mensaje que lee la persona (“Cannot allocate memory”, “Device or resource busy”). Por eso importa ser preciso: -EINVAL si el usuario pasó basura, -ENOMEM si te quedaste sin memoria, -EBUSY si el recurso está en uso, -EPERM si no tiene permiso. Devolver -EINVAL para todo es como escribir “algo falló” en cada error de un programa: técnicamente informa, pero desperdicia la oportunidad de comunicar qué falló. Los códigos de error son parte del contrato de tu driver con el mundo. Trátalos con el mismo cuidado que el resto de la API.
Propagar sin perder información
La disciplina: cuando una función que llamas falla, propaga su código hacia arriba, no lo aplastes con uno genérico:
ret = operacion_que_puede_fallar();
if (ret)
return ret; /* propaga el error ORIGINAL, no un -EINVAL genérico */
Así el error específico (p. ej. -ENOMEM de un kmalloc profundo) llega intacto hasta arriba, y el diagnóstico es posible. Aplastarlo a -EINVAL en cada capa destruye la información justo cuando más la necesitas.
Recuerda el círculo completo: tu -ENOMEM en el kernel se convierte, tras la syscall, en errno = ENOMEM en el programa de usuario, que perror() imprime como “Cannot allocate memory”. Cuando elijas un código, imagina ese mensaje final. Es la diferencia entre un usuario que entiende qué pasó y uno perdido ante un “Invalid argument” que no explica nada.
- Para cada caso, elige el -errno: (a) puntero de usuario inválido, (b) sin memoria, (c) dispositivo en uso, (d) el usuario pasó un tamaño negativo.
- Escribe una cadena de funciones donde el error de la más profunda se propague intacto hasta arriba.
- Desde userspace, provoca un error de una syscall y mira
errnoconperror. - Explora
errno-base.hen el árbol del kernel.