← Sistemas de Archivos y E/SBloque 9 · Montaje y la capa virtual · Tema 31 de 50

Tema 31

El VFS y los sistemas de archivos especiales

Las mismas llamadas pueden leer un documento, consultar el kernel o acceder a un dispositivo. Estudiaremos cómo el VFS coordina esas operaciones y qué distingue a procfs, sysfs, tmpfs, devtmpfs y OverlayFS. Dos programas en C, consultas acotadas, prácticas con montajes propios y dos simuladores permitirán separar interfaz común, contenido generado, almacenamiento temporal y vistas de capas.

1. Una interfaz común no implica datos iguales

En el tema 30 conectamos un ext4 al árbol mediante un montaje. Ahora veremos por qué un programa también puede abrir una ruta bajo /proc o /sys sin cambiar todas sus llamadas. El kernel ofrece una interfaz común y cada implementación define cómo atiende las operaciones.

VFS: capa del kernel que organiza la interfaz de sistemas de archivos y permite que implementaciones diferentes convivan en el mismo espacio de rutas. Compartir open y read no obliga a compartir almacenamiento, persistencia ni todas las operaciones posibles.

misma forma de llamada · proveedores diferentes
open("nota.txt", O_RDONLY)          → contenido de un regular
open("/proc/uptime", O_RDONLY)      → información generada por el kernel
open("/sys/class/net/lo/mtu", ...)  → atributo de un objeto del kernel
open("/dev/null", O_RDONLY)         → dispositivo de caracteres

Cada apertura devuelve un descriptor o un error.
Lo que hace read depende del objeto y de su implementación.

La idea de «todo es un archivo» resulta útil como orientación, pero no significa que cualquier recurso sea un archivo de disco ni que admita búsqueda, truncado, mapeo o escritura arbitraria.

2. Del descriptor a las operaciones de la implementación

Al abrir una ruta, el VFS participa en la resolución de nombres, atraviesa los montajes que correspondan y aplica las comprobaciones pertinentes. La implementación concreta aporta operaciones para localizar y manejar sus objetos.

Recorrido de una operación a través del VFSUn programa utiliza open y read. El VFS coordina referencias y dirige la operación a ext4, procfs, tmpfs u otro proveedor.Programa: open, fstat, read, closeVFS: nombres, montajes y referenciasoperaciones y comprobaciones comunesext4procfstmpfsotros
Esquema conceptual: no todas las operaciones recorren exactamente las mismas funciones internas.

Después de abrir, read(fd, ...) utiliza la referencia guardada para esa apertura, no empieza de nuevo por la ruta original. Las operaciones concretas pueden producir bytes a partir de un estado interno, recuperar páginas de memoria o consultar un almacenamiento.

La documentación del VFS del kernel describe esta organización. Los nombres internos sirven para comprender responsabilidades; sus estructuras no son una API estable para programas de usuario.

3. Superbloque, inodo, dentry y archivo abierto

Objeto conceptualResponsabilidadNo confundir con
SuperbloqueRepresenta una instancia de sistema de archivos y sus operaciones generales.Una sola carpeta o un descriptor de proceso.
InodoRepresenta un objeto y sus atributos y operaciones.El nombre de la ruta.
DentryRelaciona un nombre dentro de un directorio con el resultado de su búsqueda.Una copia permanente de todos los bytes del archivo.
Archivo abiertoEstado asociado a una apertura, como posición y opciones pertinentes.El inodo compartido por varias aperturas.
MontajeConexión de una raíz de sistema de archivos al árbol visible.Una instancia necesariamente distinta para cada conexión.

Dos enlaces duros pueden conducir al mismo inodo. Dos aperturas independientes de un archivo pueden tener posiciones independientes; un descriptor duplicado comparte la descripción abierta correspondiente. La caché de nombres también puede recordar búsquedas negativas.

Un inodo de procfs no tiene que tener una representación persistente equivalente en un disco. La abstracción de objeto es más amplia que el caso de un formato de bloques. Tampoco un bind mount exige crear otro sistema de archivos de almacenamiento.

4. Qué distingue a estos sistemas de archivos

TipoQué presentaRelación con persistencia
procfsInformación de procesos, kernel y algunas interfaces de control.Consultar no equivale a recuperar un documento guardado.
sysfsObjetos del kernel, sus relaciones y atributos.Los atributos reflejan el objeto y su controlador.
tmpfsArchivos normales almacenados en memoria virtual.Su contenido no sobrevive a la destrucción de la instancia.
devtmpfsNodos de dispositivos administrados por el kernel.El nodo no contiene una copia de los datos del dispositivo.
OverlayFSUna vista combinada de capas de otros sistemas.Depende del almacenamiento que respalda sus capas.

«Virtual», «en memoria» y «especial» no son sinónimos perfectos. tmpfs sí guarda los bytes que escribes; procfs suele generarlos al consultar; OverlayFS puede apoyarse en sistemas persistentes o temporales.

5. procfs: procesos e información del kernel

/proc es el punto de montaje habitual de procfs. Hay rutas generales, como /proc/uptime, y directorios asociados a procesos. /proc/self identifica al proceso que realiza el acceso: si usas cat, corresponde a cat, no automáticamente al shell que lo lanzó.

terminal · consultas de lectura
$ findmnt --target /proc --output TARGET,SOURCE,FSTYPE,OPTIONS
$ cat /proc/uptime
$ sed -n '1,12p' /proc/self/status
$ head -n 5 /proc/self/mountinfo

Los datos visibles dependen del proceso, los espacios de nombres y las políticas de acceso. Un PID puede desaparecer entre una enumeración y la consulta siguiente. Algunas entradas permiten escritura para modificar parámetros; no son documentos de configuración que deban editarse indiscriminadamente. Véase proc(5).

Status presenta campos como identidad y estado; los detalles se describen en proc_pid_status(5). Una aplicación debe interpretar los campos que necesita y tolerar los que no conoce.

6. Un tamaño aparente no determina los bytes disponibles

Algunas entradas de procfs tienen st_size igual a cero y aun así devuelven contenido. En sysfs el tamaño informado de un atributo también puede ser una cota o convención diferente de la cantidad de texto actual. Asignar un buffer de st_size bytes y decidir que cero significa «no leer» es un error.

lectura acotada · usar el retorno de read
unsigned char buffer[64];
ssize_t n = read(fd, buffer, sizeof buffer);
/* n > 0: usar exactamente n bytes; n == 0: fin para esa lectura. */
/* n == -1: interpretar errno; EINTR puede requerir reintento. */

Leer hasta EOF sin límite tampoco es adecuado para todo recurso: /dev/zero puede seguir entregando bytes. Para información de tamaño variable se decide un límite, se leen los bloques necesarios y se maneja el truncado deliberadamente.

La posibilidad de seek y el significado de releer dependen de la interfaz concreta. Varias lecturas de un recurso generado no constituyen necesariamente una instantánea coherente del sistema. El descriptor conserva la referencia, como en el tema 29, pero no congela el estado consultado.

7. sysfs: objetos, relaciones y atributos

sysfs suele estar montado en /sys. Exporta objetos del kernel, sus atributos y enlaces que permiten ver relaciones entre subsistemas. No es un listado de todos los procesos ni un almacén de documentos ordinarios.

terminal · observar un atributo conocido de loopback
$ findmnt --target /sys --output TARGET,SOURCE,FSTYPE,OPTIONS
$ ls /sys/class/net
$ readlink -f /sys/class/net/lo
$ cat /sys/class/net/lo/mtu

El ejemplo depende de que la interfaz lo y ese atributo estén disponibles en el entorno. Muchos atributos textuales se diseñan para expresar un valor simple por archivo, aunque existen interfaces binarias y excepciones. Escribir un atributo habilitado invoca el comportamiento del controlador; una escritura parcial o un formato incorrecto puede ser rechazado.

El laboratorio solo consulta atributos conocidos. Las convenciones de atributos y su relación con objetos se describen en la documentación de sysfs; para una interfaz concreta debe consultarse además su ABI.

8. devtmpfs, udev y nodos de dispositivo

devtmpfs mantiene nodos para dispositivos registrados con números major/minor. Es habitual que respalde /dev, pero algunos entornos usan otro montaje y nodos proporcionados de otra forma. Se comprueba con findmnt en vez de inferirlo por el nombre del directorio.

El kernel mantiene los nodos básicos; la gestión en espacio de usuario puede aplicar permisos y crear enlaces descriptivos. La opción DEVTMPFS del kernel describe el mecanismo básico, y udev(7) explica reglas y eventos.

terminal · distinguir nodo y almacenamiento del nodo
$ findmnt --target /dev --output TARGET,SOURCE,FSTYPE,OPTIONS
$ ls -l /dev/null /dev/zero
$ stat -c 'nombre=%n tipo=%F major=%t minor=%T' /dev/null /dev/zero

/dev/null devuelve EOF al leer; /dev/zero entrega bytes cero. Se estudian en null(4). El almacenamiento del nodo no determina el almacenamiento de los datos: un nodo de bloques puede dar acceso a un disco persistente, aunque el nodo viva en devtmpfs.

Abrir un dispositivo arbitrario puede tener efectos propios. Los ejemplos se limitan a null y zero en modo lectura; no trasladan su comportamiento a discos, terminales u otros controladores.

9. tmpfs: bytes almacenados en memoria virtual

tmpfs permite crear directorios y archivos, escribir bytes y volver a leerlos. Su capacidad se asigna según el uso y las restricciones del sistema; un límite size no reserva de inmediato toda esa memoria.

Las páginas pueden usar swap cuando está disponible y permitida. Por tanto, «tmpfs» no equivale a prometer que ningún byte llegará a un medio de intercambio. La instancia es temporal: al destruirla se pierde su contenido. Un desmontaje normal de la última vista de una instancia aislada como la del laboratorio no convierte sus archivos en persistentes.

terminal · consultar sin asumir el tipo por el nombre
$ findmnt --target /dev/shm --output TARGET,SOURCE,FSTYPE,OPTIONS
$ findmnt --target /tmp --output TARGET,SOURCE,FSTYPE,OPTIONS

/tmp no tiene que ser tmpfs, y /dev/shm debe verificarse en el entorno. Además del límite de bytes pueden intervenir límites de inodos y la presión de memoria. Los permisos siguen siendo relevantes. Véase tmpfs(5).

tmpfs no necesita formatear un archivo ni asociar un loop: su implementación administra directamente los archivos. La documentación del kernel sobre tmpfs contrasta ese diseño con un disco RAM de bloques y con ramfs.

10. OverlayFS: una vista de varias capas

OverlayFS combina un árbol inferior, lowerdir, con una capa superior escribible, upperdir, y presenta una vista merged. Si un nombre está en la capa superior, su objeto puede ocultar el inferior. Los directorios pueden combinar entradas de ambas capas.

ejemplo conceptual · vista antes y después de escribir
lower/nota.txt = "base"
upper/        = vacío
merged/nota.txt → "base"

Escritura mediante merged:
    puede requerir copy-up del objeto a upper
    lower/nota.txt sigue con "base"
    merged/nota.txt usa la versión superior

Borrar una entrada inferior desde merged puede crear una marca de ocultación.
Esa marca evita que reaparezca la entrada de lower en la vista combinada.

Un whiteout es una marca con semántica del overlay, no un archivo de usuario que deba crearse o copiarse manualmente. Los directorios opacos permiten ocultar contenido inferior de un directorio. La representación y las optimizaciones dependen de configuración y soporte.

workdir debe estar en el mismo sistema de archivos que upperdir y prepararse vacío para un montaje nuevo. Se accede a los cambios mediante merged; no se alteran las capas por detrás mientras están en uso. Véase la documentación de OverlayFS.

La persistencia depende de las capas: un upperdir en tmpfs es temporal. Un descriptor que ya estaba abierto puede seguir conectado a un objeto anterior durante cambios de capa; no debe suponerse que toda referencia cambia automáticamente a la versión nueva.

11. Consultar el proveedor real y acotar el contrato

ConsultaQué informaQué no demuestra
findmnt -T rutaMontaje que contiene la ruta en la vista actual.Todos los efectos que admite el objeto final.
fstat(fd)Tipo y atributos del objeto abierto.Que st_size sea la cantidad total de texto generado.
fstatfs(fd)Datos del sistema de archivos, incluido f_type en Linux.Que cualquier objeto de ese sistema tenga idéntica semántica.
read(fd, buffer, límite)Bytes de esa lectura o su error.Una instantánea de todo el kernel ni persistencia futura.

Un nodo de dispositivo encontrado dentro de un montaje tmpfs sigue siendo un dispositivo. Conviene distinguir el tipo del contenedor del tipo de objeto y su proveedor de operaciones.

El siguiente programa de creación usa fstatfs únicamente para reconocer tmpfs en Linux. El tema 32 utilizará statvfs para estadísticas de volumen con una interfaz más portable. Véase statfs(2).

12. Programa en C: una lectura acotada sobre proveedores distintos

Guarda muestra-vfs.c. El programa consulta metadatos y pide hasta 64 bytes sin calcular el buffer a partir de st_size. Muestra los bytes en hexadecimal para no confundir un cero binario con el terminador de una cadena.

muestra-vfs.c · ejecutar con las rutas conocidas del laboratorio
#define _POSIX_C_SOURCE 200809L
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <inttypes.h>
#include <errno.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    if (argc != 2) {
        fprintf(stderr, "Uso: %s ruta-de-lectura-conocida\n", argv[0]); return 2;
    }
    int fd = open(argv[1], O_RDONLY | O_CLOEXEC | O_NONBLOCK);
    if (fd == -1) { perror("open"); return 1; }
    int resultado = 1;
    struct stat st;
    if (fstat(fd, &st) == -1) { perror("fstat"); goto fin; }
    const char *tipo = S_ISREG(st.st_mode) ? "regular" :
                       S_ISCHR(st.st_mode) ? "caracter" : "otro";
    if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
        fprintf(stderr, "El ejemplo acepta regulares o dispositivos de caracteres conocidos\n");
        goto fin;
    }
    printf("TIPO=%s\nST_SIZE=%jd\n", tipo, (intmax_t)st.st_size);
    unsigned char datos[64];
    ssize_t n;
    do { n = read(fd, datos, sizeof datos); } while (n == -1 && errno == EINTR);
    if (n == -1) { perror("read"); goto fin; }
    printf("LEIDOS=%zd\nHEX=", n);
    for (ssize_t i = 0; i < n; ++i) printf("%02x", (unsigned int)datos[i]);
    putchar('\n');
    resultado = 0;
fin:
    if (close(fd) == -1) { perror("close"); resultado = 1; }
    return resultado;
}

Esta es una muestra de una sola lectura, no un copiador completo. read puede devolver menos de 64 bytes sin error. O_NONBLOCK no garantiza que todos los proveedores respondan instantáneamente; EAGAIN, EIO y otros errores se tratan como fallos del ensayo, no como EOF.

El programa sigue enlaces y permite dispositivos de caracteres conocidos. La comprobación posterior de tipo no evita efectos que una apertura de otro dispositivo pudiera producir. Por eso el contrato de uso limita las rutas y no propone leer indiscriminadamente todo /dev.

13. Programa en C: crear un archivo solo si la base es tmpfs

Guarda crear-en-tmpfs.c. Abre una base propia, identifica su sistema con fstatfs y crea un nombre nuevo mediante openat con O_EXCL. Si la base no es tmpfs, termina sin crear ese archivo. El programa conserva un eventual archivo parcial si una escritura falla.

crear-en-tmpfs.c · Linux y referencia por descriptor
#define _POSIX_C_SOURCE 200809L
#include <sys/stat.h>
#include <sys/vfs.h>
#include <linux/magic.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    if (argc != 2) {
        fprintf(stderr, "Uso: %s directorio-propio-en-tmpfs\n", argv[0]); return 2;
    }
    int base = open(argv[1], O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
    if (base == -1) { perror("open directorio"); return 1; }
    int fd = -1, resultado = 1;
    struct statfs sistema;
    if (fstatfs(base, &sistema) == -1) { perror("fstatfs"); goto fin; }
    if ((unsigned long)sistema.f_type != (unsigned long)TMPFS_MAGIC) {
        fprintf(stderr, "Se requiere tmpfs; no se creó ningún archivo\n"); goto fin;
    }
    fd = openat(base, "nota-c.txt", O_WRONLY | O_CREAT | O_EXCL | O_CLOEXEC, 0600);
    if (fd == -1) { perror("openat nuevo"); goto fin; }
    const char texto[] = "datos en tmpfs\n";
    size_t escritos = 0, total = sizeof texto - 1;
    while (escritos < total) {
        ssize_t n = write(fd, texto + escritos, total - escritos);
        if (n == -1 && errno == EINTR) continue;
        if (n <= 0) {
            if (n == -1) perror("write");
            else fprintf(stderr, "write no avanzó\n");
            goto fin;
        }
        escritos += (size_t)n;
    }
    printf("ESCRITOS=%zu\n", escritos);
    resultado = 0;
fin:
    if (fd != -1 && close(fd) == -1) { perror("close archivo"); resultado = 1; }
    if (close(base) == -1) { perror("close directorio"); resultado = 1; }
    return resultado;
}

La comprobación se hace sobre el descriptor de la base. Los componentes previos de la ruta para obtenerla deben ser de confianza. El nombre de salida es fijo, de un solo componente y debe ser nuevo: repetir la ejecución no sobrescribe el resultado anterior.

Una escritura satisfactoria y close no prometen persistencia tras destruir tmpfs. Incluso añadir una sincronización no convertiría esa instancia temporal en un sistema de archivos persistente.

14. Laboratorio sin modificar interfaces del kernel

Usa Bash en Linux con una cuenta ordinaria, compilador C y Python 3. Guarda los programas anteriores en un directorio nuevo. Estas primeras consultas no necesitan montar nada ni escribir en /proc, /sys o dispositivos.

terminal · preparación y compilación
$ LAB31=$(mktemp -d "$HOME/tema31.XXXXXX")
$ cd -- "$LAB31"
$ cc -std=c11 -Wall -Wextra -Wpedantic -O2 muestra-vfs.c -o muestra-vfs
$ cc -std=c11 -Wall -Wextra -Wpedantic -O2 crear-en-tmpfs.c -o crear-en-tmpfs
$ ./muestra-vfs /proc/uptime
$ ./muestra-vfs /proc/self/status
$ ./muestra-vfs /dev/null
$ ./muestra-vfs /dev/zero

En uptime se espera ST_SIZE=0 y una lectura no vacía. Null devuelve LEIDOS=0; zero devuelve 64 bytes cero. En self/status la consulta corresponde a muestra-vfs, porque es el proceso que abre la ruta. No se comparan entre sí valores dinámicos de uptime o PID.

terminal · atributo opcional y directorio propio en un tmpfs existente
$ if test -r /sys/class/net/lo/mtu; then ./muestra-vfs /sys/class/net/lo/mtu; fi
$ findmnt --target /dev/shm --output TARGET,SOURCE,FSTYPE,OPTIONS
# Continuar aquí solo si /dev/shm es tmpfs y permite crear el directorio propio.
$ TMP31=$(mktemp -d /dev/shm/curso31.XXXXXX)
$ (umask 077; ./crear-en-tmpfs "$TMP31")
$ cat -- "$TMP31/nota-c.txt"

Si /dev/shm no es utilizable, puedes realizar la sección siguiente de montaje propio y usar su directorio como TMP31. No debes elegir un destino de otro tipo para eludir la comprobación del programa.

Guarda verificar-tema31.py y ejecútalo una vez sobre ese TMP31 después de crear nota-c.txt. El verificador crea otro nombre exclusivo, por lo que repetirlo requiere un directorio de casos nuevo.

verificar-tema31.py · comprobar bytes y retornos
from pathlib import Path
import os
import subprocess
import sys

if len(sys.argv) != 2:
    raise SystemExit("Uso: python3 verificar-tema31.py directorio-propio-en-tmpfs")
tmp = Path(sys.argv[1]).resolve(strict=True)
lector = Path("muestra-vfs").resolve(strict=True)
creador = Path("crear-en-tmpfs").resolve(strict=True)

def muestra(ruta):
    p = subprocess.run([str(lector), str(ruta)], capture_output=True,
                       text=True, timeout=5, check=True)
    campos = dict(linea.split("=", 1) for linea in p.stdout.splitlines())
    datos = bytes.fromhex(campos["HEX"])
    assert len(datos) == int(campos["LEIDOS"]) <= 64
    return campos, datos

regular = tmp / "regular-verificador.txt"
fd = os.open(regular, os.O_CREAT | os.O_EXCL | os.O_WRONLY, 0o600)
with os.fdopen(fd, "wb") as f:
    f.write(b"abc\n")
c, b = muestra(regular)
assert c["TIPO"] == "regular" and int(c["ST_SIZE"]) == 4 and b == b"abc\n"
c, b = muestra("/proc/uptime")
assert c["TIPO"] == "regular" and int(c["ST_SIZE"]) == 0 and len(b) > 0
c, b = muestra("/dev/null")
assert c["TIPO"] == "caracter" and b == b""
c, b = muestra("/dev/zero")
assert c["TIPO"] == "caracter" and b == bytes(64)
sysfs = Path("/sys/class/net/lo/mtu")
if sysfs.is_file() and os.access(sysfs, os.R_OK):
    _, b = muestra(sysfs)
    assert b.strip().isdigit()
else:
    print("Omitida consulta opcional: atributo sysfs no disponible")
nota = tmp / "nota-c.txt"
assert nota.read_bytes() == b"datos en tmpfs\n"
p = subprocess.run([str(creador), str(tmp)], capture_output=True, text=True, timeout=5)
assert p.returncode == 1, "O_EXCL debe rechazar repetir el nombre"
assert nota.read_bytes() == b"datos en tmpfs\n"
print("Correctos: regular, proc con tamaño cero, dispositivos y creación exclusiva en tmpfs")
print("Directorio temporal conservado:", tmp)
terminal · ejecutar las comprobaciones
$ python3 verificar-tema31.py "$TMP31"
$ printf 'Laboratorio: %s\nDirectorio en tmpfs: %s\n' "$LAB31" "$TMP31"

La prueba no exige un valor concreto de MTU ni un PID estable. Si procfs, null o zero no están disponibles por la configuración del entorno, el fallo se interpreta como una precondición no satisfecha; no se inventa una salida equivalente.

15. Prácticas opcionales con montajes propios

Estas etapas requieren autorización de montaje y soporte del kernel, como en el tema 30. Utilizan destinos nuevos del laboratorio; no reemplazan los montajes del sistema en /proc, /sys o /dev. Se comprueba cada retorno antes de continuar.

Instancia tmpfs pequeña y vacía al recrearla

terminal · montar 8 MiB como límite, no como reserva inmediata
$ mkdir -- "$LAB31/memoria"
$ TMP31="$LAB31/memoria"
$ sudo mount -t tmpfs -o "size=8M,mode=0700,uid=$(id -u),gid=$(id -g),nodev,nosuid,noexec" tmpfs "$TMP31"
$ findmnt --mountpoint "$TMP31" --output TARGET,SOURCE,FSTYPE,OPTIONS
$ (umask 077; ./crear-en-tmpfs "$TMP31")
$ cat -- "$TMP31/nota-c.txt"
$ cd -- "$LAB31"
$ sudo umount "$TMP31"
$ sudo mount -t tmpfs -o "size=8M,mode=0700,uid=$(id -u),gid=$(id -g),nodev,nosuid,noexec" tmpfs "$TMP31"
$ ls -la -- "$TMP31"
$ sudo umount "$TMP31"

El segundo montaje crea una instancia nueva: nota-c.txt no debe estar. Esta prueba presupone que no se conservan otras vistas o referencias que mantengan viva la instancia anterior. Si umount indica ocupado, primero se cierran los recursos y se repite el desmontaje normal.

Vista OverlayFS de archivos del propio ensayo

terminal · preparar capas nuevas en el mismo sistema de archivos
$ LOWER31="$LAB31/lower"
$ UPPER31="$LAB31/upper"
$ WORK31="$LAB31/work"
$ MERGED31="$LAB31/merged"
$ mkdir -- "$LOWER31" "$UPPER31" "$WORK31" "$MERGED31"
$ printf 'base original\n' > "$LOWER31/base.txt"
$ printf 'conservar\n' > "$LOWER31/conservar.txt"
$ printf 'inferior\n' > "$LOWER31/borrar.txt"
$ sudo mount -t overlay overlay -o "lowerdir=$LOWER31,upperdir=$UPPER31,workdir=$WORK31,nodev,nosuid,noexec" "$MERGED31"
$ findmnt --mountpoint "$MERGED31" --output TARGET,SOURCE,FSTYPE,OPTIONS

Para esta sintaxis simple, las rutas de las capas no deben contener comas, dos puntos ni barras inversas, que tienen significado en las opciones de OverlayFS. Si el directorio del usuario los contiene, prepara el laboratorio en una ruta de práctica adecuada. La implementación superior debe soportar los requisitos de OverlayFS; que ext4 o tmpfs exista no prueba por sí solo que overlay esté autorizado en el entorno.

terminal · escribir y eliminar solo por la vista combinada
$ cat -- "$MERGED31/base.txt"
$ printf 'version superior\n' > "$MERGED31/base.txt"
$ cat -- "$LOWER31/base.txt" "$UPPER31/base.txt" "$MERGED31/base.txt"
$ rm -- "$MERGED31/borrar.txt"
$ test -f "$LOWER31/borrar.txt" && test ! -e "$MERGED31/borrar.txt"
$ ls -la -- "$UPPER31"
$ cd -- "$LAB31"
$ sudo umount "$MERGED31"

Lower conserva base original y borrar.txt; la vista muestra la versión superior y oculta el nombre borrado. No se exige una representación textual concreta del whiteout. Tampoco se modifican directamente las capas mientras están montadas.

terminal · volver a conectar las mismas capas para verificar la vista
$ sudo mount -t overlay overlay -o "lowerdir=$LOWER31,upperdir=$UPPER31,workdir=$WORK31,nodev,nosuid,noexec" "$MERGED31"
$ cat -- "$MERGED31/base.txt" "$MERGED31/conservar.txt"
$ test ! -e "$MERGED31/borrar.txt"
$ sudo umount "$MERGED31"

Las capas se conservan para inspección. Antes de limpiar, comprueba que no quedan montajes propios activos. No se borra un destino suponiendo que umount tuvo éxito.

16. Simuladores de lectura y capas

La misma petición read sobre fuentes diferentes

Estos son datos ilustrativos, fijos para una apertura del modelo; no son consultas a tu kernel. El tamaño mostrado no se usa para decidir el buffer. Cada lectura pide entre 1 y 128 bytes. Reabrir reinicia la muestra; no representa una garantía de instantánea en procfs o sysfs reales.

Misma interfaz, distinto proveedor

metadatos y bytes entregados por esta apertura del modelo
última lectura en hexadecimal

Copy-up, prioridad superior y ocultación

Modelo de regulares con nombres fijos, una capa inferior que no cambia, una superior y marcas de ocultación. Omite directorios, metadatos, enlaces, descriptores abiertos y optimizaciones como metacopy. La marca se representa conceptualmente, no como una instrucción para editar whiteouts reales.

Vista combinada de dos capas

NombreLowerUpperOcultaciónVista merged

Prueba escribir config.txt: lower debe conservar su texto. Después bórralo y observa la marca. Escribir de nuevo ese nombre debe hacer visible la nueva versión superior. Para nuevo.txt, que nunca existió en lower, borrar su única versión no necesita ocultar un objeto inferior.

17. Diagnóstico y resumen

ObservaciónInterpretación a comprobar
st_size es cero, pero cat muestra datos.Puede tratarse de una interfaz que genera contenido; usar lecturas acotadas y su retorno.
Una ruta de /proc desapareció.El proceso pudo terminar o cambiar la visibilidad; no es un documento estable.
Un atributo de /sys rechaza un formato.Su ABI y controlador definen valores, permisos y escritura admitida.
/dev no figura como devtmpfs.El entorno puede presentar otro montaje; inspeccionar origen y tipos de nodo.
tmpfs indica falta de espacio.Revisar límites de bytes, inodos y restricciones del entorno.
Un archivo inferior existe, pero merged no lo muestra.Puede haber prioridad superior, whiteout o un directorio opaco.
OverlayFS no monta.Revisar autorización, soporte, rutas de capas, requisitos de upper y ubicación de work.

18. Preguntas de repaso y práctica

1. ¿Qué aporta el VFS?

Una capa común que organiza la interfaz y permite coexistir a diferentes implementaciones de sistemas de archivos.

2. ¿open exitoso garantiza que el recurso proviene de un disco?

No. Puede abrir una interfaz generada, memoria virtual o un dispositivo, entre otros casos.

3. ¿Inodo y dentry son lo mismo?

No. El inodo representa un objeto; la dentry participa en la relación entre nombres y resultados de búsqueda.

4. ¿Dos aperturas siempre comparten posición?

No. Dos aperturas independientes pueden tener posiciones independientes; los descriptores duplicados comparten la descripción abierta correspondiente.

5. ¿Todo lo que está bajo /proc es de solo lectura?

No. Existen interfaces de control escribibles con reglas concretas. El laboratorio no las modifica.

6. ¿A qué proceso se refiere /proc/self/status al usar muestra-vfs?

Al proceso muestra-vfs que abre esa ruta, no al shell padre.

7. ¿st_size cero prueba que read devolverá cero?

No. Una entrada como /proc/uptime puede informar tamaño cero y producir bytes.

8. ¿Leer hasta EOF siempre termina?

No. Un proveedor como /dev/zero puede seguir produciendo bytes; hay que establecer límites.

9. ¿sysfs es una base de archivos de configuración ordinarios?

No. Expone objetos y atributos del kernel, cuyos controladores definen los efectos de acceso.

10. ¿Qué diferencia hay entre devtmpfs y udev?

El kernel mantiene nodos básicos en devtmpfs; udev recibe eventos y puede gestionar permisos y enlaces en espacio de usuario.

11. ¿El nodo /dev/null contiene una copia de lo escrito?

No. Ese dispositivo descarta escrituras y devuelve EOF al leer.

12. ¿Todos los bytes de tmpfs permanecen obligatoriamente en RAM?

No. Las páginas pueden usar swap si está disponible y permitido.

13. ¿size=8M reserva inmediatamente 8 MiB?

No. Expresa un límite de la instancia; el consumo se produce según el uso.

14. ¿/tmp siempre es tmpfs?

No. Se consulta el montaje real del entorno.

15. ¿Sincronizar tmpfs garantiza persistencia al destruirlo?

No. La sincronización no cambia su naturaleza temporal.

16. ¿Escribir por merged modifica necesariamente lower?

No. El diseño del ensayo conserva lower y lleva la versión modificada a upper.

17. ¿Por qué borrar un nombre de lower puede necesitar una marca?

Porque, sin ocultación, la entrada inferior volvería a ser visible al desaparecer la versión superior.

18. ¿workdir puede estar en cualquier volumen?

No. En este montaje debe estar en el mismo sistema de archivos que upperdir y prepararse vacío para el montaje nuevo.

19. ¿OverlayFS es siempre persistente?

Depende de sus capas. Una capa superior en tmpfs se pierde al destruir esa instancia.

20. ¿Por qué crear-en-tmpfs conserva un descriptor de la base?

Para consultar y crear respecto del mismo directorio abierto, sin resolver otra vez su ruta para cada operación.

Para practicar

  1. Identifica el tipo de montaje de /proc, /sys, /dev, /dev/shm y /tmp en tu entorno.
  2. Relaciona el VFS con los descriptores estables que estudiaste en el tema 29.
  3. Ejecuta muestra-vfs sobre un regular vacío y sobre /proc/uptime; compara ST_SIZE y LEIDOS.
  4. Explica por qué una lectura de /dev/zero debe tener límite.
  5. Busca en la documentación la ABI de un atributo que puedas consultar sin modificarlo.
  6. Comprueba que crear-en-tmpfs rechaza una base de otro tipo antes de crear nota-c.txt.
  7. Observa en el simulador que varias lecturas consumen la muestra finita y zero sigue generando bytes.
  8. Completa el ciclo de una instancia tmpfs propia y verifica que la nueva está vacía.
  9. Escribe, borra y recrea un nombre inferior en el simulador de overlay.
  10. Comprueba que los archivos lower del laboratorio no cambian tras escribir por merged.
  11. Distingue permanencia de las capas y permanencia de una conexión de montaje.
  12. Diseña una función de lectura con límite que trate lectura corta, EOF y error como resultados distintos.

En el tema 32 estudiaremos estadísticas del volumen en C con statvfs, construiremos un df propio y analizaremos qué significa consultar espacio disponible antes de escribir.