¿Cómo diferencia Linux entre archivos reales e inexistentes (por ejemplo, dispositivos)?

28

Esta es una pregunta de bajo nivel, y entiendo que podría no ser el mejor lugar para preguntar. Pero, parecía más apropiado que cualquier otro sitio de SE, así que aquí va.

Sé que en el sistema de archivos de Linux, algunos archivos realmente existen , por ejemplo: /usr/bin/bashes uno que existe. Sin embargo, (por lo que yo entiendo), algunos también no existen realmente como tales y son más virtuales archivos, por ejemplo: /dev/sda, /proc/cpuinfo, etc. Mis preguntas son (son dos, pero demasiado estrechamente relacionados que ser preguntas separadas):

  • ¿Cómo funciona el kernel de Linux si estos archivos son reales (y, por lo tanto, los leen del disco) o no cuando se emite un comando de lectura (o tal)?
  • Si el archivo no es real: como ejemplo, una lectura de /dev/randomdevolverá datos aleatorios, y una lectura de /dev/nulldevolverá EOF. ¿Cómo funciona qué datos leer de este archivo virtual? o incluso para el directorio virtual en sí? Entonces, una entrada para /dev/nullsimplemente podría devolver un EOF.
Joe
fuente
1
Cuando se crea el archivo, el núcleo registra su tipo. Los archivos de disco normales se tratan de manera diferente a los enlaces simbólicos, dispositivos de bloque, dispositivos de caracteres, directorios, sockets, FIFO, etc. Es el trabajo del núcleo saberlo.
Jonathan Leffler
ver el hombre pge para mknod
Jasen
Esto es como preguntar "¿cómo sabe un interruptor de luz si la luz está encendida?" El interruptor de la luz se encarga de decidir si la luz está encendida.
ligereza corre con Mónica el

Respuestas:

25

Así que aquí hay básicamente dos tipos diferentes de cosas:

  1. Sistemas de archivos normales, que contienen archivos en directorios con datos y metadatos, de manera familiar (incluidos enlaces blandos, enlaces duros, etc.). A menudo, pero no siempre, están respaldados por un dispositivo de bloque para almacenamiento persistente (un tmpfs vive solo en la RAM, pero por lo demás es idéntico a un sistema de archivos normal). La semántica de estos es familiar; leer, escribir, renombrar, etc., todo funciona de la manera esperada.
  2. Sistemas de archivos virtuales, de varios tipos. /procy /sysson ejemplos aquí, como son los sistemas de archivos personalizados FUSE como sshfso ifuse. Hay mucha más diversidad en estos, porque en realidad solo se refieren a un sistema de archivos con semántica que en cierto sentido son "personalizados". Por lo tanto, cuando lee de un archivo debajo /proc, en realidad no está accediendo a un dato específico que ha sido almacenado por otra cosa que lo escribió anteriormente, como en un sistema de archivos normal. Básicamente, está haciendo una llamada de kernel, solicitando información que se genera sobre la marcha. Y este código puede hacer lo que quiera, ya que es solo una función en algún lugar que implementa readsemántica. Por lo tanto, tiene el comportamiento extraño de los archivos /proc, como por ejemplo pretender ser enlaces simbólicos cuando no están

La clave es que /dev, en realidad, suele ser una de las primeras. Es normal en las distribuciones modernas tener /devalgo así como un tmpfs, pero en los sistemas más antiguos, era normal tener un directorio plano en el disco, sin ningún atributo especial. La clave es que los archivos bajo/dev encuentran son nodos de dispositivo, un tipo de archivo especial similar a los sockets FIFO o Unix; un nodo de dispositivo tiene un número mayor y menor, y leerlos o escribirlos está llamando a un controlador de kernel, al igual que leer o escribir un FIFO está llamando al kernel para almacenar su salida en una tubería. Este controlador puede hacer lo que quiera, pero generalmente toca el hardware de alguna manera, por ejemplo, para acceder a un disco duro o reproducir sonido en los altavoces.

Para responder las preguntas originales:

  1. Hay dos preguntas relevantes sobre si el 'archivo existe' o no; estos son si el archivo de nodo del dispositivo existe literalmente y si el código del núcleo que lo respalda es significativo. El primero se resuelve como cualquier cosa en un sistema de archivos normal. Los sistemas modernos usan udevo algo similar para observar eventos de hardware y crear y destruir automáticamente los nodos del dispositivo en /devconsecuencia. Pero los sistemas más antiguos, o las compilaciones personalizadas livianas, pueden tener todos sus nodos de dispositivo literalmente en el disco, creados con anticipación. Mientras tanto, cuando lee estos archivos, está haciendo una llamada al código del núcleo que está determinado por los números de dispositivo mayor y menor; Si no son razonables (por ejemplo, está tratando de leer un dispositivo de bloqueo que no existe), obtendrá algún tipo de error de E / S.

  2. La forma en que funciona qué código del kernel llamar para qué archivo de dispositivo varía. Para sistemas de archivos virtuales como /proc, implementan sus propios ready writefunciones; el núcleo solo llama a ese código según el punto de montaje en el que se encuentre, y la implementación del sistema de archivos se encarga del resto. Para los archivos del dispositivo, se envía en función de los números de dispositivo mayor y menor.

Tom Hunt
fuente
Entonces, si, digamos, un sistema antiguo se desconectara, los archivos /devaún estarían allí, pero supongo que se borrarían cuando se inicie el sistema.
Joe
2
Si un sistema antiguo (uno sin creación dinámica de dispositivos) se apagara, normal o anormalmente, los nodos del dispositivo permanecerían en el disco como cualquier archivo. Luego, cuando ocurriera el próximo arranque, también permanecerían en el disco, y usted podría usarlos normalmente. Solo en los sistemas modernos sucede algo especial cuando se crean y destruyen nodos de dispositivos.
Tom Hunt
Entonces, un sistema más moderno que no use a tmpfslos crearía y eliminaría dinámicamente según sea necesario, por ejemplo: ¿arranque y apagado?
Joe
3
devtmpfs, el /devsistema de archivos en Linux moderno, es similar a a tmpfs, pero tiene algunas diferencias que soportar udev. (El kernel crea algunos nodos automatizados por sí solo antes de entregarlos udev, para que el arranque sea menos complicado). En todos estos casos, los nodos de dispositivos viven solo en la RAM y se crean y destruyen dinámicamente según lo requiera el hardware. Presumiblemente, también podría usarlo udeven un disco ordinario /dev, pero nunca he visto esto hecho y no parece haber buenas razones para hacerlo.
Tom Hunt
17

Aquí hay una lista de archivos de /dev/sda1mi servidor Arch Linux casi actualizado:

% ls -li /dev/sda1
1294 brw-rw---- 1 root disk 8, 1 Nov  9 13:26 /dev/sda1

Entonces, la entrada del directorio /dev/parasda tiene un número de inodo, 1294. Es un archivo real en el disco.

Mire dónde aparece generalmente el tamaño del archivo. "8, 1" aparece en su lugar. Este es un número de dispositivo mayor y menor. También tenga en cuenta la 'b' en los permisos de archivo.

El archivo /usr/include/ext2fs/ext2_fs.hcontiene esta estructura (fragmento) C:

/*
 * Structure of an inode on the disk
 */
struct ext2_inode {
    __u16   i_mode;     /* File mode */

Esa estructura nos muestra la estructura en disco del inodo de un archivo. Hay muchas cosas interesantes en esa estructura; échale un vistazo largo.

El i_modeelemento de struct ext2_inodetiene 16 bits, y usa solo 9 para los permisos de usuario / grupo / otro, lectura / escritura / ejecución, y otros 3 para setuid, setgid y sticky. Tiene 4 bits para diferenciar entre tipos como "archivo plano", "enlace", "directorio", "canalización con nombre", "socket de la familia Unix" y "dispositivo de bloque".

El kernel de Linux puede seguir el algoritmo de búsqueda de directorio habitual, luego tomar una decisión basada en los permisos y las marcas en el i_modeelemento. Para 'b', bloquear archivos de dispositivo, puede encontrar los números de dispositivo mayor y menor, y tradicionalmente, usar el número de dispositivo principal para buscar un puntero a alguna función del núcleo (un controlador de dispositivo) que se ocupa de discos. El número de dispositivo menor generalmente se usa como, por ejemplo, el número de dispositivo del bus SCSI, o el número de dispositivo EIDE o algo así.

Algunas otras decisiones sobre cómo tratar un archivo como /proc/cpuinfose toman en función del tipo de sistema de archivos. Si haces un:

% mount | grep proc 
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

puede ver que /proctiene un tipo de sistema de archivos de "proc". La lectura de un archivo /prochace que el kernel haga algo diferente según el tipo de sistema de archivos, al igual que abrir un archivo en un sistema de archivos ReiserFS o DOS podría hacer que el kernel use diferentes funciones para ubicar archivos y localizar datos del archivos

Bruce Ediger
fuente
¿Está seguro de que solo se muestran los "archivos reales en el disco" con un número de inodo? Entiendo 4026531975 -r--r--r-- 1 root root 0 Nov 14 18:41 /proc/mdstatque claramente no es un "archivo real".
Guntbert
7

Al final del día, todos son archivos para Unix, esa es la belleza de la abstracción.

La forma en que el núcleo maneja los archivos, ahora que es una historia diferente.

/ proc y hoy en día / dev y / run (también conocido como / var / run) son sistemas de archivos virtuales en RAM. / proc es una interfaz / windows para kernel variables y estructuras.

Recomiendo leer The Linux Kernel http://tldp.org/LDP/tlk/tlk.html y controladores de dispositivos Linux, tercera edición https://lwn.net/Kernel/LDD3/ .

También disfruté el diseño e implementación del sistema operativo FreeBSD http://www.amazon.com/Design-Implementation-FreeBSD-Operating-System/dp/0321968972/ref=sr_1_1

Eche un vistazo a la página relevante que pertenece a su pregunta.

http://www.tldp.org/LDP/tlk/dd/drivers.html

Rui F Ribeiro
fuente
gracias, cambié ligeramente la primera pregunta después de que comentaras eso.
Joe
Lee el último comentario por favor.
Rui F Ribeiro
5

Además de las respuestas de @ RuiFRibeiro y @ BruceEdiger, la distinción que usted hace no es exactamente la distinción que hace el núcleo. En realidad, tiene varios tipos de archivos: archivos normales, directorios, enlaces simbólicos, dispositivos, sockets (y siempre olvido algunos, así que no intentaré hacer una lista completa). Puede tener la información sobre el tipo de archivo con ls: es el primer carácter de la línea. Por ejemplo:

$ls -la /dev/sda
brw-rw---- 1 root disk 8, 0 17 nov.  08:29 /dev/sda

La 'b' al principio indica que este archivo es un dispositivo de bloque. Un guión significa un archivo normal, 'l', un enlace simbólico, etc. Esta información se almacena en los metadatos del archivo y es accesible a través de la llamada del sistemastat por ejemplo, se puede , por lo que el núcleo puede leer de manera diferente un archivo y un enlace simbólico, por ejemplo.

Luego, hace otra distinción entre "archivos reales" /bin/bashy "archivos virtuales", /proc/cpuinfopero lsinforma ambos como archivos normales, por lo que la diferencia es de otro tipo:

ls -la /proc/cpuinfo /bin/bash
-rwxr-xr-x 1 root root  829792 24 août  10:58 /bin/bash
-r--r--r-- 1 root wheel      0 20 nov.  16:50 /proc/cpuinfo

Lo que sucede es que pertenecen a diferentes sistemas de archivos. /proces el punto de montaje de un pseudo-sistema de archivos procfsmientras /bin/bashestá en un sistema de archivos de disco normal. Cuando Linux abre un archivo (lo hace de manera diferente según el sistema de archivos), llena una estructura de datos fileque tiene, entre otros atributos, una estructura de varios punteros de función que describen cómo usar este archivo. Por lo tanto, puede implementar comportamientos distintos para diferentes tipos de archivos.

Por ejemplo, estas son las operaciones anunciadas por /proc/meminfo:

static int meminfo_proc_open(struct inode *inode, struct file *file)
{
    return single_open(file, meminfo_proc_show, NULL);
}

static const struct file_operations meminfo_proc_fops = {
    .open       = meminfo_proc_open,
    .read       = seq_read,
    .llseek     = seq_lseek,
    .release    = single_release,
};

Si observa la definición de meminfo_proc_open, puede ver que esta función llena un búfer en la memoria con la información devuelta por la función meminfo_proc_show, cuya tarea es recopilar datos sobre el uso de la memoria. Esta información se puede leer normalmente. Cada vez que abre el archivo, meminfo_proc_opense llama a la función y se actualiza la información sobre la memoria.

lgeorget
fuente
3

Todos los archivos en un sistema de archivos son "reales" en el sentido de que permiten E / S de archivos. Cuando abre un archivo, el núcleo crea un descriptor de archivo, que es un objeto (en el sentido de la programación orientada a objetos) que actúa como un archivo. Si lee el archivo, el descriptor de archivo ejecuta su método de lectura, que a su vez solicitará al sistema de archivos (sysfs, ext4, nfs, etc.) datos del archivo. Los sistemas de archivos presentan una interfaz uniforme para el espacio de usuario y saben qué hacer para manejar lecturas y escrituras. Los sistemas de archivos a su vez solicitan a otras capas que manejen sus solicitudes. Para un archivo normal en digamos un sistema de archivos ext4, esto implicará búsquedas en las estructuras de datos del sistema de archivos (que pueden incluir lecturas de disco) y, finalmente, una lectura del disco (o caché) para copiar datos en el búfer de lectura. Para un archivo en say sysfs, generalmente solo sprintf () s algo al búfer. Para un nodo de desarrollo de bloque, le pedirá al controlador de disco que lea algunos bloques y los copie en el búfer (los números mayor y menor le indican al sistema de archivos a qué controlador debe realizar las solicitudes).

jpkotta
fuente