¿Cómo puedo encontrar las implementaciones de las llamadas al sistema kernel de Linux?


375

Estoy tratando de entender cómo funciona una función, por ejemplo mkdir, mirando la fuente del núcleo. Este es un intento de comprender las partes internas del núcleo y navegar entre varias funciones. Sé que mkdirse define en sys/stat.h. Encontré el prototipo:

/* Create a new directory named PATH, with permission bits MODE.  */
extern int mkdir (__const char *__path, __mode_t __mode)
     __THROW __nonnull ((1));

Ahora necesito ver en qué archivo C se implementa esta función. Desde el directorio fuente, intenté

ack "int mkdir"

que se muestra

security/inode.c
103:static int mkdir(struct inode *dir, struct dentry *dentry, int mode)

tools/perf/util/util.c
4:int mkdir_p(char *path, mode_t mode)

tools/perf/util/util.h
259:int mkdir_p(char *path, mode_t mode);

Pero ninguno de ellos coincide con la definición en sys/stat.h.

Preguntas

  1. ¿Qué archivo tiene la mkdirimplementación?
  2. Con una definición de función como la anterior, ¿cómo puedo averiguar qué archivo tiene la implementación? ¿Hay algún patrón que el núcleo siga para definir e implementar métodos?

NOTA: Estoy usando el kernel 2.6.36-rc1 .


2
Por cierto, mira esto: voinici.ceata.org/~tct/resurse/utlk.pdf
Tom Brito

Respuestas:


386

Las llamadas al sistema no se manejan como llamadas a funciones regulares. Se necesita un código especial para hacer la transición del espacio del usuario al espacio del núcleo, básicamente un poco de código de ensamblaje en línea inyectado en su programa en el sitio de la llamada. El código del lado del kernel que "atrapa" la llamada del sistema también es algo de bajo nivel que probablemente no necesite comprender profundamente, al menos al principio.

En include/linux/syscalls.hdebajo de su directorio de origen del núcleo, encontrará esto:

asmlinkage long sys_mkdir(const char __user *pathname, int mode);

Luego en /usr/include/asm*/unistd.h, encuentras esto:

#define __NR_mkdir                              83
__SYSCALL(__NR_mkdir, sys_mkdir)

Este código dice que mkdir(2)es la llamada al sistema # 83. Es decir, las llamadas al sistema se llaman por número, no por dirección como con una llamada de función normal dentro de su propio programa o a una función en una biblioteca vinculada a su programa. El código de cola de ensamblaje en línea que mencioné anteriormente usa esto para hacer la transición del usuario al espacio del núcleo, tomando sus parámetros junto con él.

Otra evidencia de que las cosas son un poco raras aquí es que no siempre hay una lista estricta de parámetros para las llamadas al sistema: open(2)por ejemplo, puede tomar 2 o 3 parámetros. Eso significa que open(2)está sobrecargado , una característica de C ++, no C, pero la interfaz syscall es compatible con C. (Esto no es lo mismo que la función varargs de C , que permite que una sola función tome un número variable de argumentos).

Para responder a su primera pregunta, no existe un archivo único donde mkdir()exista. Linux admite muchos sistemas de archivos diferentes y cada uno tiene su propia implementación de la operación "mkdir". La capa de abstracción que permite que el núcleo oculte todo eso detrás de una sola llamada al sistema se llama VFS . Entonces, probablemente quieras comenzar a cavar fs/namei.c, con vfs_mkdir(). Las implementaciones reales del código de modificación del sistema de archivos de bajo nivel están en otra parte. Por ejemplo, se llama a la implementación ext4 ext4_mkdir(), definida en fs/ext4/namei.c.

En cuanto a su segunda pregunta, sí, hay patrones para todo esto, pero no hay una sola regla. Lo que realmente necesita es una comprensión bastante amplia de cómo funciona el núcleo para averiguar dónde debe buscar cualquier llamada de sistema en particular. No todas las llamadas al sistema involucran el VFS, por lo que sus cadenas de llamadas del lado del kernel no comienzan todas fs/namei.c. mmap(2), por ejemplo, comienza en mm/mmap.c, porque es parte del subsistema de gestión de memoria ("mm") del núcleo.

Le recomiendo que obtenga una copia de " Comprender el kernel de Linux " de Bovet y Cesati.


Muy buena respuesta. Un punto sobre el libro que menciona, "Comprender el kernel de Linux". No lo tengo, pero desde la fecha de lanzamiento (2000) y TOC (en el sitio de oreilly) me parece que son aproximadamente 2.2 núcleos más algunas ideas de 2.4 núcleos (pero me equivoco). Mi pregunta es: ¿hay un libro equivalente que cubra 2.6 núcleos internos? (o incluso mejor que cubren 2.2, 2.4 y 2.6)?
DavAlPi

2
@DavAlPi: Hasta donde yo sé, Bovet & Cesati sigue siendo el mejor libro individual sobre este tema. Cuando necesito complementarlo con material más actualizado, busco en el Documentationsubdirectorio del árbol de origen del núcleo con el que estoy trabajando.
Warren Young

1
De hecho, open (2) es una función varargs. Solo hay dos formas de llamarlo, por lo que la página de manual lo documenta de esta manera, el prototipo real tiene ...como función varargs. Por supuesto, esto se implementa a nivel de libc. Puede pasar 0 o un valor basura al núcleo ABI cuando no se utiliza el tercer parámetro.
Random832

"Es algo que no necesitas entender". El mundo sería un lugar mejor si este tipo de oración no se encontrara en ninguna parte de la red stackexchange.
Petr

84

Probablemente esto no responda su pregunta directamente, pero he encontrado straceque es realmente genial cuando trato de entender las llamadas subyacentes del sistema, en acción, que están hechas incluso para los comandos de shell más simples. p.ej

strace -o trace.txt mkdir mynewdir

El sistema solicita el comando mkdir mynewdirse volcará a trace.txt para su placer visual.


55
+1 ¡Truco genial! No lo había usado antes
David Oneill el

3
Mejor aún, haga que el archivo de salida trace.strace y ábralo en VIM. VIM lo resaltará, haciendo que leerlo sea mucho más fácil.
Marcin

55

Un buen lugar para leer la fuente del kernel de Linux es la referencia cruzada de Linux (LXR) ¹. Las búsquedas devuelven coincidencias escritas (prototipos de funciones, declaraciones de variables, etc.) además de los resultados de búsqueda de texto libre, por lo que es más práctico que un simple grep (y también más rápido).

LXR no expande las definiciones de preprocesador. Las llamadas al sistema tienen su nombre destrozado por el preprocesador en todo el lugar. Sin embargo, la mayoría de las llamadas al sistema (¿todas?) Se definen con una de las SYSCALL_DEFINExfamilias de macros. Como mkdirtoma dos argumentos, una búsqueda de SYSCALL_DEFINE2(mkdirconduce a la declaración de la mkdirllamada al sistema :

SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)
{
    return sys_mkdirat(AT_FDCWD, pathname, mode);
}

ok, sys_mkdiratsignifica que es la mkdiratllamada al sistema, por lo que hacer clic en él solo te lleva a la declaración include/linux/syscalls.h, pero la definición está justo arriba.

El trabajo principal de mkdirates llamar vfs_mkdir(VFS es la capa genérica del sistema de archivos). Al hacer clic en eso, se muestran dos resultados de búsqueda: la declaración en include/linux/fs.hy la definición algunas líneas arriba. La tarea principal de vfs_mkdires llamar a la implementación del sistema de ficheros específicos: dir->i_op->mkdir. Para saber cómo esto se lleva a cabo, hay que girar a la aplicación del sistema de archivos individuales, y no hay regla dura y rápida - que incluso podría ser un módulo fuera del árbol del núcleo.

¹ LXR es un programa de indexación. Hay varios sitios web que proporcionan una interfaz para LXR, con conjuntos ligeramente diferentes de versiones conocidas e interfaces web ligeramente diferentes. Tienden a ir y venir, por lo que si el que estás acostumbrado no está disponible, realiza una búsqueda web de "referencia cruzada de Linux" para encontrar otro.


Ese es un gran recurso. Gran respuesta.
Stabledog

"Error interno del servidor" en el enlace de linux.no .
Fredrick Gauss

@FredrickGauss Durante un tiempo, lxr.linux.no fue la mejor interfaz para LXR, pero tuvo tiempos de inactividad frecuentes. Ahora creo que se ha ido para siempre. Reemplacé el primer enlace a otra interfaz LXR.
Gilles

21

Las llamadas al sistema generalmente se envuelven en la SYSCALL_DEFINEx()macro, por lo que un simple grepno las encuentra:

fs/namei.c:SYSCALL_DEFINE2(mkdir, const char __user *, pathname, int, mode)

El nombre de la función final después de que se expande la macro termina siendo sys_mkdir. La SYSCALL_DEFINEx()macro agrega elementos repetitivos como el código de seguimiento que cada definición de syscall debe tener.


17

Nota: el archivo .h no define la función. Se declara en ese archivo .h y se define (implementa) en otro lugar. Esto permite que el compilador incluya información sobre la firma de la función (prototipo) para permitir la verificación de tipo de argumentos y hacer coincidir los tipos de retorno con cualquier contexto de llamada en su código.

En general, los archivos .h (encabezado) en C se utilizan para declarar funciones y definir macros.

mkdiren particular es una llamada al sistema. Puede haber un contenedor de libc de GNU alrededor de esa llamada al sistema (de hecho es casi seguro). La verdadera implementación del kernel mkdirse puede encontrar buscando las fuentes del kernel y las llamadas del sistema en particular.

Tenga en cuenta que también habrá una implementación de algún tipo de código de creación de directorio para cada sistema de archivos. La capa VFS (sistema de archivos virtual) proporciona una API común a la que puede llamar la capa de llamada del sistema. Cada sistema de archivos debe registrar funciones para que la capa VFS llame. Esto permite que diferentes sistemas de archivos implementen su propia semántica de cómo se estructuran los directorios (por ejemplo, si se almacenan utilizando algún tipo de esquema de hash para que la búsqueda de entradas específicas sea más eficiente). Menciono esto porque es probable que se tropiece con estas funciones de creación de directorios específicas del sistema de archivos si está buscando en el árbol de fuentes del kernel de Linux.


8

Ninguna de las implementaciones que encontró coincide con el prototipo en sys / stat.h ¿Quizás la búsqueda de una declaración de inclusión con este archivo de encabezado sería más exitosa?


1
La implementación (como se describe en sys / stat.h) es asunto de userland y libc. El material interno del núcleo (cómo se hace realmente ) es un negocio interno del núcleo. Para todos los hackers del núcleo, la función interna podría llamarse xyzzy y tomar 5 parámetros. Es el trabajo de libc tomar la llamada de usuario, traducirla a los encantamientos del núcleo que se requieran, enviarla y recopilar los resultados.
vonbrand

6

Aquí hay un par de publicaciones de blog realmente geniales que describen varias técnicas para buscar el código fuente de kernel de bajo nivel.


12
No publique solo enlaces a blogs o foros, resuma sus contenidos para que los lectores puedan ver de qué se tratan y que les quede algo si los sitios desaparecen. Además, su primer enlace es sobre libc, que está fuera de tema para esta pregunta.
Gilles
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.