← Sistemas de Archivos y E/S Bloque 1 · Archivos y sistemas de archivos · Tema 1 de 50

Tema 1

Qué es un sistema de archivos

Guardas un informe, apagas el equipo y al día siguiente el informe sigue ahí, con su nombre, dentro de su carpeta. Esa comodidad no la da el disco: un disco solo sabe leer y escribir bloques identificados por un número. Convertir ese arreglo de bloques en archivos con nombre, en carpetas, con dueños y permisos, y hacerlo de manera que los datos sobrevivan a un corte de luz, es el trabajo del sistema de archivos. En este tema verás qué ofrece realmente un dispositivo de almacenamiento, escribirás a mano en un «disco» sin sistema de archivos, programarás en C uno mínimo de unas 130 líneas, inspeccionarás un volumen ext4 real sin permisos de administrador y medirás con un simulador por qué el tamaño del bloque importa. Es el mapa de todo el curso.

1. Por qué existe: los datos tienen que sobrevivir

La memoria principal es rápida pero volátil: al apagar el equipo, o simplemente cuando un proceso termina, todo lo que contenía desaparece. Un programa que calculó durante horas, un documento, una base de datos, el propio sistema operativo: nada de eso puede vivir solo en la RAM. Hace falta un lugar donde los datos permanezcan, y ese lugar es el almacenamiento secundario: discos magnéticos, unidades de estado sólido, memorias USB.

Ese almacenamiento tiene tres características que lo distinguen de la RAM y que condicionan todo lo que verás en el curso:

Un sistema de archivos es la parte del sistema operativo (y la estructura de datos que deja grabada en el dispositivo) que organiza el almacenamiento persistente en archivos con nombre agrupados en directorios, controla quién puede acceder a ellos y hace que su contenido sobreviva a reinicios y fallos.

La palabra «sistema de archivos» se usa con dos sentidos que conviene distinguir desde el principio: el software del núcleo que implementa las operaciones (por ejemplo, el controlador de ext4) y el formato grabado en un volumen concreto (ese disco «está formateado en ext4»). El primero lee y escribe el segundo.

2. Qué ofrece un dispositivo de almacenamiento

Para entender qué tiene que construir el sistema de archivos, hay que saber qué recibe de partida. Un dispositivo de almacenamiento se presenta al sistema operativo como una sucesión de bloques de tamaño fijo numerados desde 0, y sus operaciones son solo dos: leer el bloque número N y escribir el bloque número N. La unidad mínima de transferencia es el sector: 512 bytes en los discos clásicos, 4096 bytes en los discos modernos de «formato avanzado». No existe la operación «leer 10 bytes desde la posición 3»: se lee el sector entero.

Disco duro (HDD)SSD SATASSD NVMe
Cómo guardaPlatos magnéticos que giran; un cabezal se mueve sobre ellosMemoria flash sin partes móviles, interfaz SATAMemoria flash sin partes móviles, conectada al bus PCIe
Acceso aleatorio (orden de magnitud)5–10 ms50–100 µs20–100 µs
Transferencia secuencial (orden de magnitud)100–250 MB/sunos 500 MB/s2–7 GB/s
Lo que ve el sistemaSectores de 512 B o 4 KiBSectores de 512 B o 4 KiBSectores de 512 B o 4 KiB

Las cifras de la tabla son órdenes de magnitud y varían según el modelo, pero la comparación con la RAM (unos 100 nanosegundos por acceso) es instructiva: un acceso aleatorio a un disco duro cuesta del orden de 100.000 veces más que uno a la memoria, y uno a un SSD, unas 1.000 veces más. Lo que cambia entre las tres tecnologías es el rendimiento y las estrategias que conviene usar (temas 41 al 44), no la interfaz: los tres se ven como un arreglo de sectores, y por eso un mismo sistema de archivos funciona sobre todos.

Linux muestra los dispositivos de bloque con lsblk. Las columnas PHY-SEC y LOG-SEC son el tamaño físico y el lógico del sector:

terminal · los dispositivos de bloque del equipo
$ lsblk -d -o NAME,SIZE,PHY-SEC,LOG-SEC
NAME   SIZE PHY-SEC LOG-SEC
sda  388.4M     512     512
sdb    186M     512     512
sdc      4G    4096     512
sdd      1T    4096     512
$ cat /sys/block/sda/queue/rotational
1

La salida es de una instalación de Linux sobre WSL, cuyos discos son virtuales. Muestra un caso frecuente: sdc y sdd tienen sectores físicos de 4096 bytes pero se presentan con sectores lógicos de 512 («512e»), para ser compatibles con software antiguo. El archivo rotational vale 1 en discos magnéticos y 0 en SSD; WSL declara 1 para sus discos virtuales aunque por debajo haya flash, así que en un equipo real el valor es el que cuenta. Los bloques de lsblk se estudian en el tema 45.

3. Experimento: un disco sin sistema de archivos

Para sentir lo que significa trabajar solo con bloques no hace falta un disco de verdad: Linux permite usar un archivo normal como si fuera un dispositivo. Creamos una imagen de 1 MiB, es decir, 2048 sectores de 512 bytes, llena de ceros, con dd (una herramienta que copia bloques de tamaño exacto):

terminal · escribir y leer un sector por su número
$ dd if=/dev/zero of=disco.img bs=512 count=2048
2048+0 records in
2048+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied
$ printf 'informe de ventas: 1200 unidades\n' | dd of=disco.img bs=512 seek=100 conv=notrunc
0+1 records in
0+1 records out
33 bytes copied
$ dd if=disco.img bs=512 skip=100 count=1 2>/dev/null | head -c 33
informe de ventas: 1200 unidades
$ dd if=disco.img bs=512 skip=100 count=1 2>/dev/null | xxd | head -3
00000000: 696e 666f 726d 6520 6465 2076 656e 7461  informe de venta
00000010: 733a 2031 3230 3020 756e 6964 6164 6573  s: 1200 unidades
00000020: 0a00 0000 0000 0000 0000 0000 0000 0000  ................
$ dd if=disco.img bs=512 skip=101 count=1 2>/dev/null | xxd | head -2
00000000: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................

seek=100 salta 100 bloques de salida y skip=100 salta 100 de entrada; conv=notrunc evita que dd acorte la imagen. El informe se grabó con éxito y se recuperó. Mira, sin embargo, lo que falta:

Todo eso es información que alguien tiene que guardar en el propio disco, junto a los datos, para que sobreviva. Esa información sobre los datos se llama metadatos, y organizarla es el núcleo de un sistema de archivos.

4. Qué le pedimos a un sistema de archivos

Del experimento salen las responsabilidades básicas. Cada una será un bloque de este curso:

ResponsabilidadLa pregunta que resuelveDónde se estudia
Nombres y jerarquía¿Cómo se encuentra «el informe» sin recordar números de bloque? ¿Cómo se agrupan los archivos en carpetas?Temas 2, 3 y 20–22
Asignación de espacio¿Qué bloques usa cada archivo, cuáles están libres, cómo crece un archivo?Temas 17–19
Metadatos¿Dónde se guardan tamaño, fechas, propietario y la lista de bloques?Temas 2, 17 y 18
Interfaz de programación¿Qué operaciones ofrece a los programas: abrir, leer, escribir, cerrar?Temas 4–11
Protección¿Quién puede leer, escribir o ejecutar cada archivo?Temas 26–29
Rendimiento¿Cómo evitar esperar al disco en cada operación? Caché, lectura anticipada, orden de las peticionesTemas 12–16 y 41–44
Consistencia y fiabilidad¿Qué pasa si se corta la luz a mitad de una escritura?Temas 33–35
Variedad de dispositivos¿Cómo se usan a la vez volúmenes ext4, NTFS, FAT o de red bajo un solo árbol?Temas 30–32 y 36–40

Estas responsabilidades se contradicen a veces. Un sistema muy cuidadoso con la consistencia escribe más veces y más despacio. Una caché agresiva da velocidad y arriesga datos si se corta la energía. Un bloque grande reduce el trabajo de gestión y desperdicia espacio. Cada sistema de archivos real es un equilibrio entre estas fuerzas, y por eso existen varios.

5. Experimento: el sistema de archivos más pequeño

La mejor forma de entender estas piezas es construir las mínimas. El programa siguiente, minifs.c, convierte una imagen de disco en un sistema de archivos con tres reglas muy simples:

Las operaciones son formatear, guardar, listar y leer. Usa pread y pwrite para leer y escribir en una posición exacta del archivo sin mover el desplazamiento; las verás con detalle en el tema 7.

minifs.c
#define _POSIX_C_SOURCE 200809L
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define BLOQUE   512
#define ENTRADAS 8                      /* 8 entradas de 64 bytes = el bloque 0 completo */

struct entrada {
    char     nombre[40];                /* nombre[0] == 0 significa entrada libre */
    uint32_t inicio;                    /* número del primer bloque de datos */
    uint32_t longitud;                  /* tamaño del archivo en bytes */
    char     reservado[16];
};

_Static_assert(sizeof(struct entrada) * ENTRADAS == BLOQUE, "el catálogo debe ocupar un bloque");

static void fallo(const char *msg)
{
    perror(msg);
    exit(1);
}

static uint32_t bloques_de(uint32_t bytes)
{
    return (bytes + BLOQUE - 1) / BLOQUE;
}

static void leer_catalogo(int fd, struct entrada *t)
{
    if (pread(fd, t, BLOQUE, 0) != BLOQUE)
        fallo("pread del catálogo");
}

static void escribir_catalogo(int fd, const struct entrada *t)
{
    if (pwrite(fd, t, BLOQUE, 0) != BLOQUE)
        fallo("pwrite del catálogo");
}

int main(int argc, char *argv[])
{
    if (argc < 3) {
        fprintf(stderr, "uso: %s imagen formatear | listar | leer NOMBRE | guardar NOMBRE TEXTO\n", argv[0]);
        return 1;
    }
    int fd = open(argv[1], O_RDWR);
    if (fd == -1)
        fallo(argv[1]);

    struct entrada tabla[ENTRADAS];
    const char *orden = argv[2];

    if (strcmp(orden, "formatear") == 0) {
        memset(tabla, 0, sizeof tabla);
        escribir_catalogo(fd, tabla);
        printf("catálogo vacío escrito en el bloque 0\n");
    } else if (strcmp(orden, "listar") == 0) {
        leer_catalogo(fd, tabla);
        printf("%-16s %6s %9s %7s\n", "nombre", "inicio", "longitud", "bloques");
        for (int i = 0; i < ENTRADAS; i++)
            if (tabla[i].nombre[0] != '\0')
                printf("%-16s %6u %9u %7u\n", tabla[i].nombre, tabla[i].inicio,
                       tabla[i].longitud, bloques_de(tabla[i].longitud));
    } else if (strcmp(orden, "leer") == 0 && argc == 4) {
        leer_catalogo(fd, tabla);
        for (int i = 0; i < ENTRADAS; i++) {
            if (strcmp(tabla[i].nombre, argv[3]) == 0) {
                char *datos = malloc(tabla[i].longitud);
                if (datos == NULL)
                    fallo("malloc");
                if (pread(fd, datos, tabla[i].longitud, (off_t)tabla[i].inicio * BLOQUE)
                        != (ssize_t)tabla[i].longitud)
                    fallo("pread de los datos");
                fwrite(datos, 1, tabla[i].longitud, stdout);
                free(datos);
                return 0;
            }
        }
        fprintf(stderr, "%s: no existe\n", argv[3]);
        return 1;
    } else if (strcmp(orden, "guardar") == 0 && argc == 5) {
        leer_catalogo(fd, tabla);

        int libre = -1;
        uint32_t siguiente = 1;                       /* el bloque 0 es el catálogo */
        for (int i = 0; i < ENTRADAS; i++) {
            if (tabla[i].nombre[0] == '\0') {
                if (libre == -1)
                    libre = i;
            } else {
                uint32_t fin = tabla[i].inicio + bloques_de(tabla[i].longitud);
                if (fin > siguiente)
                    siguiente = fin;                  /* primer bloque después del último archivo */
            }
        }
        if (libre == -1 || strlen(argv[3]) >= sizeof tabla[0].nombre) {
            fprintf(stderr, "catálogo lleno o nombre demasiado largo\n");
            return 1;
        }

        uint32_t longitud = (uint32_t)strlen(argv[4]);
        uint32_t nb = bloques_de(longitud);
        struct stat st;
        if (fstat(fd, &st) == -1)
            fallo("fstat");
        if ((off_t)(siguiente + nb) * BLOQUE > st.st_size) {
            fprintf(stderr, "disco lleno\n");
            return 1;
        }

        char *bloques = calloc(nb ? nb : 1, BLOQUE);  /* se rellena de ceros hasta completar el bloque */
        if (bloques == NULL)
            fallo("calloc");
        memcpy(bloques, argv[4], longitud);
        if (pwrite(fd, bloques, (size_t)nb * BLOQUE, (off_t)siguiente * BLOQUE) != (ssize_t)nb * BLOQUE)
            fallo("pwrite de los datos");
        free(bloques);

        memset(&tabla[libre], 0, sizeof tabla[libre]);
        strcpy(tabla[libre].nombre, argv[3]);
        tabla[libre].inicio = siguiente;
        tabla[libre].longitud = longitud;
        escribir_catalogo(fd, tabla);
        printf("%s guardado: %u bytes en %u bloque(s) desde el bloque %u\n",
               argv[3], longitud, nb, siguiente);
    } else {
        fprintf(stderr, "orden desconocida o argumentos incorrectos\n");
        return 1;
    }
    close(fd);
    return 0;
}

Lo compilamos y lo probamos sobre la imagen de 1 MiB del experimento anterior. Se guardan tres archivos, uno de ellos de 700 bytes (dos bloques):

terminal · usar minifs
$ gcc -std=c17 -Wall -Wextra -o minifs minifs.c
$ ./minifs disco.img formatear
catálogo vacío escrito en el bloque 0
$ ./minifs disco.img guardar notas.txt "comprar pan y leche"
notas.txt guardado: 19 bytes en 1 bloque(s) desde el bloque 1
$ ./minifs disco.img guardar informe.txt "informe de ventas: 1200 unidades"
informe.txt guardado: 32 bytes en 1 bloque(s) desde el bloque 2
$ ./minifs disco.img guardar largo.txt "$(head -c 700 /dev/zero | tr '\0' 'x')"
largo.txt guardado: 700 bytes en 2 bloque(s) desde el bloque 3
$ ./minifs disco.img listar
nombre           inicio  longitud bloques
notas.txt             1        19       1
informe.txt           2        32       1
largo.txt             3       700       2
$ ./minifs disco.img leer informe.txt
informe de ventas: 1200 unidades
$ ./minifs disco.img leer fantasma
fantasma: no existe

Ahora los nombres funcionan: ya no hace falta recordar números de bloque. Y como el catálogo está en el disco, el sistema de archivos persiste: si copias disco.img a otro equipo, listar muestra los mismos archivos. Mirar el interior de la imagen lo confirma:

terminal · el catálogo, tal como quedó grabado en el bloque 0
$ dd if=disco.img bs=512 count=1 2>/dev/null | xxd | head -9
00000000: 6e6f 7461 732e 7478 7400 0000 0000 0000  notas.txt.......
00000010: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000020: 0000 0000 0000 0000 0100 0000 1300 0000  ................
00000030: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000040: 696e 666f 726d 652e 7478 7400 0000 0000  informe.txt.....
00000050: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000060: 0000 0000 0000 0000 0200 0000 2000 0000  ............ ...
00000070: 0000 0000 0000 0000 0000 0000 0000 0000  ................
00000080: 6c61 7267 6f2e 7478 7400 0000 0000 0000  largo.txt.......

En el desplazamiento 0x28 (el byte 40, justo después de los 40 bytes del nombre) aparece 0100 0000: el campo inicio de notas.txt, un entero de 32 bits en orden little-endian que vale 1. Le sigue 1300 0000, que es 0x13 = 19: la longitud. Cada entrada ocupa 64 bytes, de modo que la siguiente (informe.txt) empieza en el desplazamiento 0x40, con inicio 2 y longitud 0x20 = 32. Esto es un sistema de archivos: nombres, ubicación y tamaño grabados donde sobreviven.

Lo que este sistema de archivos no resuelve

Funciona, pero aunque sea diminuto sus límites enseñan por qué los reales son más complejos:

Al final del curso (tema 48) construirás una versión mucho más completa que resuelve casi todo esto.

6. Un volumen ext4 real, por dentro

Veamos cómo resuelve las mismas cuestiones un sistema de archivos real. Crear un volumen ext4 normalmente exige un disco o una partición y permisos de administrador, pero mke2fs puede formatear un archivo de imagen sin privilegios, y con la opción -d lo rellena con el contenido de una carpeta. Preparamos una carpeta con dos archivos, uno de 16 bytes y otro de 10.000, y formateamos una imagen de 16 MiB:

terminal · crear un volumen ext4 dentro de un archivo, sin ser administrador
$ mkdir raiz
$ printf 'hola desde ext4\n' > raiz/notas.txt
$ head -c 10000 /dev/zero | tr '\0' 'a' > raiz/datos.bin
$ dd if=/dev/zero of=ext4.img bs=1M count=16 2>/dev/null
$ mke2fs -q -t ext4 -d raiz -F ext4.img
$ dumpe2fs -h ext4.img 2>/dev/null | grep -E 'magic|Block size|Block count|Inode count|Inode size'
Filesystem magic number:  0xEF53
Inode count:              4096
Block count:              4096
Inode size:               256
Block size:               4096
$ debugfs -R 'ls -l /' ext4.img 2>/dev/null
      2   40755 (2)      0      0    4096 18-Oct-2026 16:37 .
      2   40755 (2)      0      0    4096 18-Oct-2026 16:37 ..
     11   40700 (2)      0      0   16384 18-Oct-2026 16:37 lost+found
     13  100644 (1)   1000   1000   10000 18-Oct-2026 16:37 datos.bin
     14  100644 (1)   1000   1000      16 18-Oct-2026 16:37 notas.txt
$ debugfs -R 'stat /notas.txt' ext4.img 2>/dev/null | grep -E 'User:|Blockcount|^[(]'
User:  1000   Group:  1000   Project:     0   Size: 16
Links: 1   Blockcount: 8
(0):1326
$ debugfs -R 'stat /datos.bin' ext4.img 2>/dev/null | grep -E 'User:|Blockcount|^[(]'
User:  1000   Group:  1000   Project:     0   Size: 10000
Links: 1   Blockcount: 24
(0-2):1323-1325

Cada línea corresponde a una pieza de las que echaste en falta en el experimento con dd:

Dos tamaños que no son lo mismo

El tamaño de un archivo (Size: 10000) es cuántos bytes tiene; el espacio que ocupa (Blockcount: 24, es decir, 12.288 bytes) es cuántos bloques enteros se reservaron. Por eso ls -l y du pueden mostrar cifras distintas para el mismo archivo. Lo exploraremos en el tema 3.

7. Dónde está cada capa

Cuando un programa llama a read, la petición atraviesa varias capas del sistema operativo antes de llegar a un sector. Conocer el orden ayuda a ubicar cada tema del curso:

Capas del almacenamiento en Linux, de arriba abajo: programa, llamadas al sistema, sistema de archivos virtual, sistema de archivos concreto, caché de bloques y planificador, y dispositivo. Arriba se habla de archivos y nombres; abajo, de bloques numerados Programa (C, Bash) cat notas.txt · fd = open("notas.txt", O_RDONLY) Llamadas al sistema open · read · write · close Sistema de archivos virtual (VFS) una interfaz común para todos los formatos Sistema de archivos concreto ext4 · NTFS · FAT · inodos, directorios, journal Caché de bloques y planificador de E/S memoria intermedia, orden de las peticiones Dispositivo de almacenamiento HDD · SSD · NVMe: sectores numerados archivos, nombres, descriptores bloques numerados y sectores
Una petición de lectura baja por las capas: arriba se habla de archivos y nombres; el sistema de archivos los traduce a números de bloque, y el dispositivo solo entiende esos números.

El tema 4 empieza por la capa de arriba (descriptores de archivo y llamadas al sistema), el bloque 4 estudia la caché, los bloques 5 al 8 la estructura interna del sistema de archivos concreto, el bloque 9 el VFS, y los bloques 12 y 13 el planificador y el dispositivo. Para seguir un ejemplo concreto: un read de 100 bytes del archivo notas.txt pregunta al sistema de archivos en qué bloque del disco está el byte pedido (el trabajo de los extents que viste arriba), busca ese bloque en la caché y, solo si no está, lo pide al dispositivo, que entrega 4096 bytes de los que el programa recibe 100.

8. Probar con un simulador

El tamaño de bloque es la decisión de diseño más sencilla de ver. Con bloques grandes, un archivo necesita pocos bloques y pocas entradas en sus metadatos, y el disco transfiere más datos por operación. Pero el último bloque de cada archivo queda casi siempre a medias, y ese espacio no lo puede usar nadie más. Indica los tamaños de varios archivos, en bytes (se admite el sufijo k para KiB y m para MiB), separados por comas, y elige un tamaño de bloque. Los valores iniciales son los de los archivos del experimento con ext4 más dos archivos más.

Simulador · cuánto espacio se pierde según el tamaño de bloque

Espacio reservado: datos (azul) y desperdicio (ámbar)

ArchivoTamañoBloquesReservadoDesperdiciado
Total

Prueba tres cosas. Con 4 KiB, comprueba que los tamaños 16 y 10000 dan los mismos bloques que debugfs mostró: 1 y 3. Cambia a 512 B y mira cómo el desperdicio casi desaparece, pero los archivos necesitan ocho veces más bloques (cada uno es una entrada que gestionar y una unidad de transferencia). Después pasa a 64 KiB con muchos archivos pequeños: el desperdicio supera la mitad del espacio. Por eso los sistemas modernos eligen 4 KiB, que coincide además con el tamaño de página de memoria (4096) y de sector físico de los discos actuales.

9. El mapa del curso

Los 50 temas siguen el camino de un dato, desde el programa que lo escribe hasta el sector donde queda:

BloqueTemasLa pregunta que responde
1. Archivos y sistemas de archivos1–3¿Qué es un archivo y cómo se inspecciona?
2. Descriptores de archivo4–7¿Cómo abre, lee y escribe un programa?
3. E/S con llamadas al sistema8–11¿Cómo se copian archivos bien, y cuánto cuesta cada llamada?
4. El búfer y la caché de disco12–16¿Cuándo llega realmente un dato al disco?
5. Inodos y estructura en disco17–19¿Cómo se guarda un archivo dentro del volumen?
6. Directorios20–22¿Cómo se convierte un nombre en un inodo?
7. Enlaces duros y simbólicos23–25¿Qué es un nombre y qué significa borrar?
8. Permisos y protección26–29¿Quién puede hacer qué con cada archivo?
9. Montaje y la capa virtual30–32¿Cómo conviven varios volúmenes bajo un árbol?
10. Consistencia y journaling33–35¿Cómo sobrevive un volumen a un corte de energía?
11. Sistemas de archivos reales36–40¿En qué se diferencian FAT, ext4 y NTFS?
12. Planificación de disco41–44¿En qué orden conviene atender las peticiones?
13. Dispositivos de bloque y de caracteres45–47¿Cómo se accede al dispositivo en sí?
14. Integración y cierre48–50¿Cómo se combina todo en programas completos?

Los programas en C se compilan con gcc -std=c17 -Wall -Wextra y los scripts son de Bash; todo se prueba en Linux. Se da por sabido el C de Programación en C para Sistemas Operativos, en especial punteros y cadenas, y lo básico de Automatización con Scripts en Bash. Siempre que el ejemplo necesite un volumen se usa una imagen dentro de un archivo, así que nada de lo que hagas pone en riesgo tus datos reales ni exige ser administrador, salvo el tema de montaje, donde se avisa.

Los números cambiarán

Los números de inodo, los bloques asignados, las fechas y los dispositivos de lsblk dependen de la máquina y de cada ejecución. Con otro mke2fs los extents caerán en otros bloques. Lo que debe repetirse es el patrón: un archivo pequeño ocupa un bloque entero, Blockcount supera al tamaño y los nombres de un directorio apuntan a inodos.

10. Resumen

11. Preguntas de repaso

Intenta responder cada una antes de abrir la respuesta.

1. ¿Por qué no basta con guardar los datos en la RAM?

Porque la RAM es volátil: su contenido se pierde al apagar el equipo y también cuando termina el proceso que la usaba. Los datos que deben sobrevivir necesitan un almacenamiento persistente, como un disco.

2. ¿Qué operaciones ofrece un dispositivo de bloque y cuál es su unidad mínima de transferencia?

Solo leer y escribir un bloque (sector) identificado por su número. La unidad mínima es el sector: 512 bytes en discos clásicos y 4096 en los de formato avanzado. No se puede leer o escribir un byte suelto sin transferir el sector que lo contiene.

3. En el experimento con dd, ¿qué información faltaba para poder usar el disco con comodidad?

Los nombres (había que recordar el bloque 100), la longitud exacta del informe, el registro de qué bloques están libres o en uso, y la lista de bloques de los archivos que ocupan más de uno. Todo eso son metadatos que deben guardarse en el propio disco.

4. ¿Qué papel cumple el bloque 0 en minifs y qué pasaría si se perdiera?

Contiene el catálogo: nombre, bloque inicial y longitud de cada archivo. Si se perdiera, los datos seguirían en los bloques siguientes, pero no habría forma de saber dónde empieza cada archivo ni cómo se llama: sin los metadatos, los datos son inaccesibles en la práctica.

5. En minifs, ¿en qué bloque se guardaría un cuarto archivo de 100 bytes tras los tres del ejemplo?

En el bloque 5. largo.txt empieza en el 3 y ocupa dos bloques (3 y 4), de modo que el primer bloque libre a continuación del último archivo es el 5.

6. ¿Por qué notas.txt tiene 16 bytes pero Blockcount: 8?

Blockcount cuenta en sectores de 512 bytes y el sistema reserva bloques enteros de 4096 bytes: 4096 / 512 = 8. El archivo ocupa un bloque completo aunque solo use 16 bytes; el resto es fragmentación interna.

7. ¿Qué indica la línea (0-2):1323-1325 de debugfs?

Que los bloques lógicos 0 a 2 del archivo (sus tres primeros bloques) están almacenados en los bloques físicos 1323 a 1325 del volumen, consecutivos. Es un extent: un rango continuo descrito con un solo registro.

8. Un archivo de 10.000 bytes en un sistema con bloques de 4 KiB, ¿cuántos bloques ocupa y cuánto espacio se desperdicia?

Ocupa ⌈10000 / 4096⌉ = 3 bloques, es decir, 12.288 bytes, de modo que se desperdician 12.288 − 10.000 = 2.288 bytes. Con bloques de 512 serían 20 bloques (10.240 bytes) y se perderían solo 240.

9. ¿Por qué un mismo sistema de archivos puede usarse sobre un HDD, un SSD y un NVMe?

Porque los tres se presentan al sistema operativo con la misma interfaz: un arreglo de bloques numerados que se leen y escriben. Lo que cambia es el rendimiento (latencia y ancho de banda) y las estrategias óptimas de acceso, no el contrato con el sistema de archivos.

10. Cita tres responsabilidades de un sistema de archivos que minifs no cumple.

Por ejemplo: directorios y jerarquía (solo hay un catálogo plano de 8 entradas), permisos y propietario, consistencia ante cortes de energía, reutilización del espacio de archivos borrados, crecimiento de archivos y caché para mejorar el rendimiento.

Para practicar

  1. Repite el experimento con dd: escribe dos textos distintos en los bloques 10 y 11, léelos y comprueba con xxd que el resto de cada bloque son ceros. Después escribe 600 bytes en el bloque 10 con dd y comprueba qué hay en el bloque 11: ¿qué le ocurre al disco cuando el dato no cabe en un solo bloque?
  2. Ejecuta minifs hasta llenar las 8 entradas del catálogo y comprueba el mensaje de error del noveno archivo. Después crea una imagen de 4 KiB con truncate -s 4096 chica.img y descubre cuántos archivos de 100 bytes caben.
  3. Añade a minifs la orden borrar NOMBRE, que pone a cero el primer byte del nombre de la entrada. Guarda tres archivos, borra el segundo y guarda uno nuevo. ¿Se reutiliza el bloque liberado? Piensa cómo cambiarías la regla de colocación para que sí.
  4. Haz que listar muestre también el espacio desperdiciado de cada archivo (bloques × 512 − longitud) y su total.
  5. Crea otra carpeta con cinco archivos de tamaños distintos, formatea una imagen con mke2fs -d y usa debugfs -R 'stat /archivo' para comparar Size y Blockcount de cada uno. ¿Coincide el número de bloques con el que predice el simulador para 4 KiB?
  6. Repite el paso anterior con mke2fs -b 1024 y con -b 2048 (bloques de 1 y 2 KiB) y mide cuántos bloques ocupa el archivo de 10.000 bytes.
  7. Ejecuta lsblk -d -o NAME,SIZE,PHY-SEC,LOG-SEC,ROTA en tu equipo y averigua si tu disco es magnético o de estado sólido, y si usa sectores de 512 o de 4096 bytes.