1. Dos recursos que pueden agotarse por separado
En el tema 17 distinguimos nombre, inodo y contenido; en el 18 recorrimos el mapa de bloques. Esa separación explica un problema real: una aplicación puede recibir «No space left on device» aunque todavía vea gigabytes libres. Crear un objeto y almacenar sus bytes requieren recursos diferentes.
Agotar inodos: no disponer de las estructuras de identificación y metadatos necesarias para crear otro objeto en el sistema de archivos, aunque quede capacidad para contenido. Agotar bloques: no disponer de las unidades de asignación necesarias para datos o metadatos.
Un archivo regular vacío sigue necesitando un inodo y una entrada en su directorio. En una representación habitual no necesita bloques de contenido, pero el directorio puede crecer y requerir bloques propios. Un millón de archivos vacíos no equivale a un único archivo vacío.
Disponible: 10000 bloques de datos y 4 inodos
Crear a, b, c y d vacíos: quedan 10000 bloques de datos y 0 inodos
Crear e: falla por falta de inodos
Ampliar a en 1 bloque: puede funcionar sin crear otro inodoEl último paso depende de que también pueda actualizarse el mapa y demás metadatos. El ejemplo aísla dos contadores; un formato real tiene más condiciones. No interpreta cualquier fallo de creación como agotamiento de inodos.
| Carga | Recurso que puede agotarse primero | Por qué |
|---|---|---|
| Muchísimos archivos pequeños | Inodos. | Cada objeto necesita metadatos, aunque tenga pocos bytes. |
| Pocos archivos densos grandes | Bloques. | El contenido consume mucha capacidad con pocos objetos. |
| Archivos dispersos de gran longitud | Depende de la asignación efectiva. | La longitud no obliga a respaldar cada bloque lógico. |
| Muchos directorios vacíos | Inodos y bloques de directorio. | Son objetos con metadatos y representación propia. |
En ext2/ext3/ext4 los inodos se organizan en tablas cuya capacidad se establece al crear el sistema de archivos; ampliar el volumen puede incorporar grupos e inodos. Otros formatos asignan sus estructuras de manera diferente. No hay que generalizar una cantidad fija de inodos a todos los sistemas.
2. Consultar el sistema correcto con df y df -i
Antes de contar, identifica el montaje que contiene la ruta problemática. El espacio libre de /home no sirve para escribir en un /var montado por separado. En contenedores puede intervenir una capa escribible distinta del almacenamiento visible desde el anfitrión.
$ ruta=/var/tmp
$ findmnt -T "$ruta"
$ df -h -- "$ruta"
$ df -i -- "$ruta"
$ df -B1 --output=source,fstype,size,used,avail,pcent,target -- "$ruta"Si el archivo que falla todavía no existe, consulta su directorio padre existente. df informa estadísticas del sistema de archivos que contiene la ruta, no el consumo exclusivo de ese directorio. -h redondea en unidades legibles; -B1 permite comparar bytes sin ese redondeo.
| Vista | Campos centrales | Pregunta que responde |
|---|---|---|
df -h | Size, Used, Avail, Use% | ¿Qué capacidad y disponibilidad de bloques informa el montaje? |
df -i | Inodes, IUsed, IFree, IUse% | ¿Qué disponibilidad de inodos informa ese sistema? |
findmnt -T | Origen, destino, tipo y opciones | ¿Qué montaje contiene la ruta? |
df -h: Size=10G Used=2G Avail=8G Use%=20%
df -i: Inodes=100000 IUsed=100000 IFree=0 IUse%=100%
Hay capacidad de datos, pero no inodos libres informados.Las columnas pueden variar con el idioma y las opciones. Algunos sistemas no exponen un límite de inodos comparable; un guion, cero o un contador sintético debe interpretarse según el formato. La documentación de GNU df detalla sus unidades y campos.
3. Interpretar ENOSPC y otros errores
ENOSPC identifica falta de espacio para la operación; no especifica por sí solo qué recurso se agotó. Al crear puede faltar capacidad para el nuevo objeto. Durante una escritura o sincronización puede no completarse la asignación de datos o metadatos.
| Error | Interpretación inicial | Qué comprobar |
|---|---|---|
ENOSPC | No hay capacidad requerida. | Bloques, inodos, metadatos y montaje de la ruta. |
EDQUOT | Se alcanzó una cuota aplicable. | Cuotas de bloques o inodos por usuario, grupo o proyecto. |
EACCES | Falta permiso para el acceso. | Permisos de archivo y directorios, ACL y políticas. |
EROFS | Sistema de archivos de solo lectura. | Opciones y estado del montaje. |
EFBIG | Se supera un límite de tamaño. | Límites de archivo, proceso o implementación. |
EMFILE / ENFILE | Límite de descriptores del proceso o de archivos abiertos del sistema. | Descriptores abiertos; mirar solo inodos libres no resuelve el problema. |
La referencia de open(2) distingue estos errores. Guarda errno inmediatamente después del fallo si vas a llamar a otras funciones antes de interpretarlo; solo tiene sentido consultarlo cuando el resultado indica error.
Una escritura aceptada en caché puede fallar durante la escritura diferida. Comprueba escrituras parciales y errores de fsync y close. La referencia de fsync(2) incluye errores de espacio y cuota. Un df favorable anterior no reserva capacidad.
4. Reservas, cuotas y metadatos
«Libre» y «disponible para este proceso» no siempre coinciden. ext puede reservar bloques para usos privilegiados; las cuotas limitan a ciertos usuarios o proyectos; los metadatos también requieren espacio. La diferencia entre capacidad total y suma de usado más disponible puede reflejar reservas, según el sistema y la contabilidad.
Por ejemplo, si quedan 1000 bloques libres y 200 están reservados, un proceso sin acceso a esa reserva podría disponer de 800. Esa resta es ilustrativa: no reemplaza la interpretación de los contadores reales ni de las cuotas. El valor habitual de Avail no garantiza la capacidad que una cuota particular permite consumir.
Una escritura de pocos bytes puede necesitar un bloque completo, índices o estructuras de copy-on-write. Crear un nombre puede exigir ampliar un directorio. Un dispositivo subyacente con aprovisionamiento fino también puede quedarse sin capacidad aunque la vista superior parezca tener espacio.
Planificar muchos archivos pequeños
Cuenta objetos además de bytes: archivos, directorios y margen de crecimiento. En formatos ext, mke2fs -i configura una relación de bytes por inodo y -N solicita una cantidad de inodos, sujeta a la geometría. Una relación menor puede provisionar más inodos y dedicar más espacio a sus tablas. No cambia el tamaño de bloque de contenido. Son opciones de creación; consulta mke2fs(8).
La acción correctiva depende del diagnóstico: retirar datos prescindibles de la ruta correcta, revisar retención y cantidad de objetos, ajustar una cuota autorizada o redimensionar el almacenamiento. Cambiar reservas o reformatear no son pasos iniciales de diagnóstico.
5. Qué mide du y por qué no coincide siempre con df
du recorre nombres y suma el uso atribuido a los objetos que encuentra. df consulta la contabilidad global del montaje. No son dos implementaciones del mismo cálculo.
$ du -x -B1 --max-depth=1 -- /var/tmp
$ du -x --inodes --max-depth=1 -- /var/tmp
$ du -B1 -- archivo.bin
$ du --apparent-size -B1 -- archivo.bin-x evita cruzar a otros sistemas de archivos durante el recorrido. --inodes ayuda a localizar árboles con muchos objetos; no muestra la capacidad libre del montaje. No combines ese modo con opciones de bytes esperando medir ambas cosas a la vez. En GNU du, -b equivale a --apparent-size --block-size=1, por lo que no significa «asignación expresada en bytes».
- Alcance: sumar una carpeta no incluye todo el montaje ni los metadatos globales.
- Permisos: un recorrido incompleto produce diagnósticos y no una suma completa. Conserva los errores.
- Enlaces duros: GNU du cuenta normalmente una vez cada archivo con varios enlaces dentro de una ejecución;
--count-linkscambia esa política. - Objetos sin nombre: un archivo eliminado pero todavía abierto puede retener espacio que no aparece en el recorrido. Se estudiará en el tema 25.
- Cambios concurrentes: crear, borrar o escribir durante el recorrido hace que las mediciones no sean una instantánea común.
- Compartición: snapshots, reflinks y compresión pueden impedir interpretar la suma como bytes exclusivos recuperables al borrar.
La referencia de GNU du describe sus modos de tamaño aparente, inodos y enlaces. Registra opciones, ruta, permisos y momento antes de comparar resultados.
6. Longitud lógica y asignación
La longitud lógica delimita qué posiciones se pueden leer antes del fin del archivo. La asignación describe recursos atribuidos al objeto. Un archivo puede ser largo y tener poca asignación, o muy corto y consumir un bloque completo.
$ stat -c 'nombre=%n longitud=%s bloques=%b unidad=%B io_preferida=%o' -- archivo.bin
$ du -B1 -- archivo.bin
$ du --apparent-size -B1 -- archivo.bin| Dato | Significado | Precaución |
|---|---|---|
st_size / %s | Longitud lógica en bytes de un archivo regular. | No mide bytes asignados. |
st_blocks / %b | Unidades de almacenamiento atribuidas al archivo. | En Linux, cada unidad de st_blocks representa 512 bytes. |
%B | Bytes por unidad de la cifra %b de GNU stat. | Permite interpretar su producto sin confundirlo con %o. |
st_blksize / %o | Tamaño de transferencia preferido informado. | No es el factor para convertir st_blocks a bytes. |
Archivo corto: st_size=1, st_blocks=8
Asignación informada = 8 × 512 = 4096 bytes
Archivo disperso: st_size=16777216, st_blocks=16
Asignación informada = 16 × 512 = 8192 bytes
st_blksize podría ser 4096; no se usa para multiplicar st_blocks.Los números exactos dependen del sistema. st_blocks × 512 es contabilidad informada por Linux, no una medida universal del costo exclusivo del archivo ni de toda su participación en metadatos. La referencia inode(7) especifica estas unidades. Aquí nos referimos a archivos regulares; el tamaño de un directorio no suma los tamaños de sus hijos.
7. Archivos dispersos y huecos
Archivo disperso o sparse: archivo cuyo espacio lógico contiene regiones sin bloques de datos asignados. Al leer esos huecos antes del fin del archivo se obtienen bytes de valor cero.
Un byte cero es un valor del contenido; un hueco es una propiedad de su representación. Escribir un millón de ceros puede asignar bloques. Leer un millón de ceros no demuestra que exista un hueco: podrían provenir de datos escritos, de una región preasignada sin escribir o de otra representación.
Longitud lógica: 16384 bytes = 4 posiciones de bloque
Escrituras: byte 0 = 'A'; byte 16383 = 'Z'
Lógico: [0] [1] [2] [3]
Contenido: A... ceros ceros ...Z
Asignación: dato hueco hueco dato
Datos asignados en este modelo: 2 × 4096 = 8192 bytes
Bytes explícitamente escritos: 2
Inodos del archivo: 1El espacio no escrito dentro de un bloque asignado no se convierte por ello en otro bloque libre. Además pueden necesitarse índices para alcanzar posiciones lejanas. En el tema 18 ya observamos que asignar un bloque distante no obliga a asignar todos sus antecesores lógicos.
Una longitud dispersa enorme puede alcanzarse con pocos bloques, pero rellenar después sus huecos requiere capacidad. Esta propiedad resulta útil para imágenes y archivos con regiones vacías; no es una reserva del tamaño lógico.
8. Extender, preasignar y copiar
lseek puede desplazar el offset más allá del final sin cambiar la longitud. La escritura posterior amplía el archivo y el intervalo intermedio se lee como ceros. ftruncate puede ampliar directamente la longitud; la zona añadida también se lee como ceros. La representación dispersa concreta depende del sistema de archivos.
$ (set -o noclobber; : > huecos.bin) && truncate -s 16M -- huecos.bin
$ stat -c 'longitud=%s bloques=%b unidad=%B' -- huecos.bin
$ du -B1 -- huecos.bin
$ du --apparent-size -B1 -- huecos.binEjecuta los ejemplos en Bash dentro de un directorio nuevo. La creación con noclobber evita sustituir un nombre existente. truncate no escribe 16 MiB de contenido ni promete que futuras escrituras vayan a caber. Al reducir la longitud elimina el contenido posterior al nuevo fin. La referencia de truncate(2) explica la extensión y sus restricciones.
Preasignación y huecos son decisiones distintas
posix_fallocate solicita espacio para un intervalo y devuelve un código de error directamente. La preasignación puede usar regiones sin escribir que se leen como ceros, pero ya tienen espacio reservado. En Linux, ciertas modalidades de fallocate permiten perforar huecos manteniendo la longitud, con restricciones de soporte y alineación. No se puede concluir «sin asignación» a partir de ceros leídos.
Una copia puede cambiar la asignación
$ cp --no-clobber --reflink=never --sparse=always -- huecos.bin copia-dispersa.bin
$ cp --no-clobber --reflink=never --sparse=never -- huecos.bin copia-densa.bin
$ cmp -- huecos.bin copia-dispersa.bin
$ cmp -- huecos.bin copia-densa.bin
$ du -B1 -- huecos.bin copia-dispersa.bin copia-densa.bin
$ du --apparent-size -B1 -- huecos.bin copia-dispersa.bin copia-densa.binLas copias pueden tener el mismo contenido y longitud con asignaciones distintas. --reflink=never evita que la compartición mediante clonación oculte el propósito de la comparación. La compresión y otras optimizaciones todavía pueden cambiar las cifras. Un archivo de ceros copiado con --sparse=always puede adquirir huecos que el original no tenía. La documentación de cp describe ambas opciones.
SEEK_DATA y SEEK_HOLE permiten consultar regiones cuando están disponibles, pero el sistema puede informar todo el archivo como datos y el final como hueco. No son un detector universal de bloques con ceros. Consulta lseek(2); FIEMAP, visto en el tema anterior, también requiere interpretar sus banderas.
9. Programa en C: medir el espacio
El siguiente programa consulta archivos regulares en Linux, expresa claramente las unidades y devuelve estado distinto de cero si alguna consulta falla. stat sigue enlaces simbólicos: si recibe uno, mide su destino. Todavía no recorre directorios; construiremos herramientas de recorrido en el tema 21.
#define _POSIX_C_SOURCE 200809L
#define _FILE_OFFSET_BITS 64
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
if (argc < 2) {
fprintf(stderr, "Uso: %s ARCHIVO...\n", argv[0]);
return 1;
}
int estado = 0;
for (int i = 1; i < argc; ++i) {
struct stat s;
if (stat(argv[i], &s) == -1) {
perror(argv[i]);
estado = 1;
continue;
}
if (!S_ISREG(s.st_mode)) {
fprintf(stderr, "%s: se requiere un archivo regular\n", argv[i]);
estado = 1;
continue;
}
if (s.st_blocks < 0 || (uintmax_t)s.st_blocks > UINTMAX_MAX / 512) {
fprintf(stderr, "%s: asignación no representable\n", argv[i]);
estado = 1;
continue;
}
uintmax_t asignados = (uintmax_t)s.st_blocks * 512;
printf("%s: longitud=%jd bloques512=%jd asignados=%ju io=%jd\n",
argv[i], (intmax_t)s.st_size, (intmax_t)s.st_blocks,
asignados, (intmax_t)s.st_blksize);
}
return estado;
}$ gcc -std=c11 -Wall -Wextra -Wpedantic -O2 medir-espacio.c -o medir-espacio
$ ./medir-espacio huecos.bin copia-dispersa.bin copia-densa.binLa columna asignados debería corresponder al uso que GNU du -B1 informa para cada archivo aislado y sin cambios concurrentes. No es una promesa de bytes recuperables al borrar. Si dos consultas discrepan, comprueba momento, enlaces, alcance y características del sistema antes de deducir un error.
10. Programa en C: crear un archivo disperso
Crearemos un archivo de 16 MiB lógicos y escribiremos solamente sus bytes extremos. O_EXCL impide reutilizar un nombre existente. Las operaciones se realizan sobre el descriptor obtenido y se comprueban sus errores. Una interrupción se reintenta en las transferencias; un fallo de close se informa sin reintentar el descriptor.
#define _POSIX_C_SOURCE 200809L
#define _FILE_OFFSET_BITS 64
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
static int escribir_byte(int fd, off_t posicion, char valor)
{
ssize_t n;
do {
n = pwrite(fd, &valor, 1, posicion);
} while (n == -1 && errno == EINTR);
if (n == 1) return 0;
if (n == 0) errno = EIO;
return -1;
}
int main(int argc, char **argv)
{
if (argc != 2) {
fprintf(stderr, "Uso: %s ARCHIVO_NUEVO\n", argv[0]);
return 1;
}
const off_t longitud = (off_t)16 * 1024 * 1024;
int fd = open(argv[1], O_RDWR | O_CREAT | O_EXCL, 0600);
if (fd == -1) { perror("open"); return 1; }
int estado = 1;
if (ftruncate(fd, longitud) == -1) { perror("ftruncate"); goto fin; }
if (escribir_byte(fd, 0, 'A') == -1 ||
escribir_byte(fd, longitud - 1, 'Z') == -1) {
perror("pwrite");
goto fin;
}
char c;
ssize_t n;
do {
n = pread(fd, &c, 1, longitud / 2);
} while (n == -1 && errno == EINTR);
if (n == -1) { perror("pread"); goto fin; }
if (n != 1 || c != '\0') {
fprintf(stderr, "El byte intermedio no es el cero esperado\n");
goto fin;
}
if (fsync(fd) == -1) { perror("fsync"); goto fin; }
estado = 0;
fin:
if (close(fd) == -1) { perror("close"); estado = 1; }
if (estado != 0)
fprintf(stderr, "Se conserva el archivo para inspeccionar el fallo\n");
return estado;
}$ gcc -std=c11 -Wall -Wextra -Wpedantic -O2 crear-disperso.c -o crear-disperso
$ ./crear-disperso extremos.bin
$ ./medir-espacio extremos.bin
$ du -B1 -- extremos.bin
$ du --apparent-size -B1 -- extremos.binEn un sistema que admita huecos, la asignación debería ser mucho menor que 16777216 bytes; no impongas 8192 como valor universal porque pueden intervenir índices y otras reglas. La lectura central verifica un cero del contenido; la consulta de asignación aporta evidencia diferente sobre la representación.
El ejemplo sincroniza el archivo para detectar errores de escritura diferida y hacer más comparable la medición. No demuestra por sí solo la persistencia del nombre después de un corte de energía: la sincronización del directorio y las actualizaciones resistentes a fallos se estudiarán en el tema 35.
11. Laboratorio de tamaños y copias
Usa Linux o WSL sobre un sistema Linux que admita archivos dispersos; en WSL es preferible trabajar dentro de su directorio personal y registrar el montaje. Necesitas GCC, Python 3 y GNU Coreutils. Los archivos de este ensayo tienen como máximo 16 MiB lógicos cada uno; no se intenta llenar el sistema anfitrión.
$ LAB19=$(mktemp -d "$HOME/tema19.XXXXXX")
$ cd -- "$LAB19"
$ findmnt -T .
$ df -h .
$ df -i .Guarda aquí los dos fuentes anteriores y compílalos. Ejecuta después los apartados de huecos.bin, sus dos copias y extremos.bin. Mantén nombres nuevos: si ya existen, crea otro directorio con mktemp.
Contrastar con un archivo escrito de principio a fin
$ python3 - <<'PY'
import os
with open("denso.bin", "xb") as f:
for _ in range(16):
f.write(os.urandom(1024 * 1024))
f.flush()
os.fsync(f.fileno())
PY
$ ./medir-espacio huecos.bin extremos.bin denso.bin
$ du -B1 -- huecos.bin extremos.bin denso.bin
$ du --apparent-size -B1 -- huecos.bin extremos.bin denso.binLos tres tienen 16 MiB lógicos, pero contenidos distintos. El archivo aleatorio sirve para contrastar una escritura densa; no se espera que cmp lo considere igual a los otros.
$ python3 - <<'PY'
import os
assert os.stat("extremos.bin").st_size == 16 * 1024 * 1024
with open("extremos.bin", "rb") as f:
assert f.read(1) == b"A"
f.seek(-1, os.SEEK_END)
assert f.read(1) == b"Z"
f.seek(1)
restantes = 16 * 1024 * 1024 - 2
while restantes:
parte = f.read(min(restantes, 65536))
assert parte and not any(parte)
restantes -= len(parte)
print("Longitud, extremos y región intermedia correctos")
PYRegistra para cada archivo longitud, st_blocks, unidad, asignación y resultado de comparación cuando corresponda. Si el sistema no conserva huecos, describe esa limitación y no sustituyas las cifras por las del modelo. Prueba además ejecutar de nuevo el creador sobre extremos.bin: debe fallar en open sin modificarlo.
12. Agotar inodos dentro de una imagen ext2
Este ensayo crea una imagen nueva de 16 MiB y solicita pocos inodos para agotarlos con una cantidad acotada de archivos vacíos. Usa e2fsprogs y no requiere montaje ni privilegios. debugfs -w modificará únicamente inodos.ext2 dentro del directorio nuevo del laboratorio; nunca sustituyas esa ruta por un dispositivo o una imagen ajena.
$ command -v mke2fs dumpe2fs debugfs
$ python3 - <<'PY'
with open("inodos.ext2", "xb") as f:
f.truncate(16 * 1024 * 1024)
with open("vacio", "xb"):
pass
PY
$ mke2fs -q -t ext2 -b 1024 -I 256 -N 128 -m 0 inodos.ext2
$ LC_ALL=C dumpe2fs -h inodos.ext2 > antes.txt
$ cat antes.txtComprueba Inode count, Free inodes y Free blocks. El total solicitado puede ajustarse a la geometría. Ya existen inodos reservados y objetos del formato, por lo que no se esperan exactamente 128 archivos nuevos. Si el total efectivo supera 256, omite el llenado y revisa la creación: el lote siguiente está deliberadamente limitado.
$ python3 - <<'PY'
with open("crear.cmd", "x") as f:
for i in range(256):
f.write(f"write vacio /f{i:03d}\n")
PY
$ LC_ALL=C debugfs -w -f crear.cmd inodos.ext2 > creacion.log 2>&1
$ LC_ALL=C dumpe2fs -h inodos.ext2 > despues.txt
$ cat despues.txt
$ tail -n 20 creacion.logLa evidencia esperada es Free inodes: 0, bloques todavía libres y diagnósticos de que no se pudo asignar otro inodo. El directorio raíz crece al añadir nombres y puede consumir bloques, aunque el contenido de cada archivo sea vacío. No esperes que Free blocks permanezca exactamente igual.
df -i inodos.ext2 consulta el sistema anfitrión que contiene el archivo de imagen. Como el interior no está montado, para sus contadores usamos dumpe2fs. El agotamiento interior no agota los inodos del anfitrión.
Liberar uno y comprobar que se puede crear otro
$ LC_ALL=C debugfs -w -R 'rm /f000' inodos.ext2
$ LC_ALL=C dumpe2fs -h inodos.ext2 > liberado.txt
$ LC_ALL=C debugfs -w -R 'write vacio /repuesto' inodos.ext2
$ LC_ALL=C debugfs -R 'stat /repuesto' inodos.ext2
$ LC_ALL=C dumpe2fs -h inodos.ext2 > repuesto.txt
$ cat liberado.txt repuesto.txtDespués de retirar /f000 debe aparecer un inodo libre y después de crear /repuesto debe volver a consumirse. Comprueba la existencia del nuevo archivo con stat de debugfs. Su interfaz de depuración no es una llamada open del kernel: conserva diagnósticos y contadores; no uses solamente su estado de salida como prueba de que todas las órdenes del lote tuvieron éxito.
La referencia de debugfs documenta -w, los lotes y las órdenes de archivos. El ensayo demuestra la contabilidad del formato en una imagen; no mide concurrencia, fallos de energía ni el comportamiento exacto de un montaje en producción. Para el agotamiento de bloques usaremos el simulador siguiente, sin llenar el disco real.
13. Simuladores de recursos y asignación
Crear, ampliar y eliminar objetos
El volumen didáctico dispone inicialmente de 64 bloques de datos y 8 inodos. Cada archivo nuevo consume un inodo. Se omiten directorios, índices, reservas, cuotas, aperturas y enlaces adicionales; las operaciones son completas o no cambian el estado. La ampliación afecta al último archivo.
Bloques e inodos independientes
Crea ocho archivos con cero bloques e intenta crear un noveno: faltan inodos y sobran bloques. Después cambia la cantidad a uno y amplía el último: no necesita otro inodo. Reinicia, crea un archivo de 64 bloques e intenta crear uno de un bloque: faltan datos aunque queden inodos. Un archivo de cero bloques todavía cabe en este modelo simplificado.
Una escritura sobre un archivo inicialmente sin datos asignados
El segundo modelo parte cada vez de un archivo extendido a la longitud inicial y sin bloques de datos. Una única escritura asigna todos los bloques que toca. Usa intervalos semiabiertos: el byte del extremo final queda fuera de la escritura.
Longitud, bloques tocados y huecos
fin = X + C
longitud_final = max(longitud_inicial, fin)
primer_bloque = floor(X / B)
ultimo_bloque = floor((fin - 1) / B)
asignados = ultimo_bloque - primer_bloque + 1
bytes_de_datos_asignados = asignados × BPrueba B=4096, longitud inicial 0, offset 4095 y dos bytes: se tocan dos bloques, la longitud queda en 4097 y la asignación de datos es 8192 bytes. La asignación puede superar la longitud por la parte no utilizada de los bloques. El modelo no acumula escrituras entre cálculos, no consulta archivos reales y no calcula el costo de índices.
14. Un procedimiento de diagnóstico
- Registra la operación que falló. Crear, ampliar, sincronizar o cerrar; conserva mensaje y código de error.
- Identifica la ruta y su montaje. Consulta el directorio existente con
findmnt -T. - Consulta ambas disponibilidades.
df -hydf -i; fija unidades para comparar cifras. - Examina restricciones adicionales. Cuotas, reservas, solo lectura y capacidad de las capas inferiores según el entorno.
- Acota el recorrido. Usa
du -xpara bytes ydu --inodespara localizar muchos objetos; revisa errores de permisos. - Distingue longitud de asignación. Consulta
staty los dos modos dedusi aparecen archivos grandes con poco uso. - Explica discrepancias. Verifica archivos abiertos sin nombre, enlaces, snapshots, metadatos y actividad concurrente.
- Comprueba el resultado de la intervención. Repite los contadores y la operación original; no basta con que haya bajado una cifra.
Una comprobación previa es una observación de ese instante. Otro proceso puede consumir los recursos antes de la escritura, y los metadatos pueden requerir más de lo estimado. Los programas deben manejar el fallo real aunque sus comprobaciones previas fueran favorables. El tema 32 profundizará en statvfs y las estadísticas del volumen desde C.
15. Resumen
- Crear un objeto necesita inodo y nombre; almacenar contenido y metadatos necesita capacidad de asignación.
dfydf -iconsultan recursos distintos del montaje que contiene una ruta.ENOSPCno identifica por sí solo si faltan bloques, inodos u otros recursos necesarios.- Cuotas, reservas, permisos y estado del montaje requieren interpretaciones diferentes.
durecorre objetos visibles; no reproduce toda la contabilidad global dedf.- En Linux, longitud es
st_sizey asignación informada esst_blocks × 512. - Los huecos se leen como ceros; los ceros leídos no prueban que existan huecos.
- Extender longitud no garantiza capacidad para rellenar después el archivo.
- Copiar puede conservar bytes y longitud mientras cambia la asignación.
- Las escrituras, sincronización y cierre deben comprobarse, aunque antes hubiera recursos libres.
16. Preguntas de repaso y práctica
1. ¿Puede un archivo vacío contribuir al agotamiento de inodos?
Sí. Su objeto requiere un inodo y una entrada de directorio aunque no tenga bloques de contenido. Muchos archivos vacíos pueden agotar ese recurso.
2. ¿Qué consulta df -i /var/tmp?
Los contadores de inodos del sistema de archivos que contiene esa ruta, no solo los objetos de /var/tmp.
3. ¿ENOSPC significa necesariamente cero bytes libres?
No. Puede faltar capacidad para crear un objeto o asignar datos o metadatos. Hay que consultar bloques, inodos y condiciones del montaje.
4. ¿Por qué una cuota puede detener escrituras con espacio global libre?
Porque limita el consumo de un usuario, grupo o proyecto. Puede afectar bloques o inodos; la capacidad global no elimina ese límite.
5. ¿Es st_blksize el factor de conversión de st_blocks?
No. En Linux st_blocks se expresa en unidades de 512 bytes. st_blksize informa un tamaño preferido de E/S.
6. ¿Cuánto informa st_blocks=24 en Linux?
24 × 512 = 12288 bytes de asignación atribuida al objeto. No representa necesariamente bytes exclusivos recuperables al eliminarlo.
7. ¿Por qué du -b no sirve para medir asignación en bytes?
En GNU du equivale a --apparent-size --block-size=1: mide tamaño aparente. Para uso atribuido expresado en bytes se usa du -B1.
8. ¿Leer ceros demuestra que hay un hueco?
No. También pueden ser ceros escritos o una región preasignada sin escribir. Contenido y representación necesitan evidencias diferentes.
9. ¿Mover el offset con lseek amplía un archivo?
No. La escritura posterior puede ampliarlo. ftruncate sí puede cambiar directamente su longitud.
10. ¿Un archivo disperso grande reserva capacidad para futuras escrituras?
No. Al rellenar huecos pueden faltar bloques o metadatos y fallar la escritura o su sincronización.
11. ¿Qué cambia al escribir dos bytes desde el offset 4095 con B=4096?
En el modelo se tocan los bloques 0 y 1. Desde longitud inicial cero queda longitud 4097 y 8192 bytes de datos asignados.
12. ¿Dos archivos idénticos deben tener igual st_blocks?
No. Pueden diferir en huecos, preasignación, compresión, compartición u organización de metadatos.
13. ¿Por qué un archivo borrado puede seguir usando espacio?
Porque puede permanecer abierto u otra referencia puede retenerlo. Su nombre desaparece del recorrido, pero la asignación puede seguir existiendo.
14. ¿Qué consulta df -i inodos.ext2 en el laboratorio?
El sistema anfitrión que contiene el archivo de imagen. Para la contabilidad del interior sin montar se utiliza dumpe2fs.
15. ¿El laboratorio debe crear exactamente 128 archivos?
No. La geometría puede ajustar la cantidad solicitada y ya hay inodos reservados u ocupados por objetos del formato. Se comprueban los contadores efectivos.
16. ¿Por qué se conserva el log de debugfs?
Porque los fallos de órdenes del lote requieren revisar diagnósticos y estado interior. Su código de salida por sí solo no certifica todas las operaciones.
17. ¿Una escritura que devuelve éxito garantiza persistencia?
No. Puede haberse aceptado en caché y aparecer un error posterior. Se comprueban fsync y close; la persistencia del nombre requiere considerar el directorio.
18. ¿Puede ampliarse un archivo cuando no quedan inodos?
Puede, porque el objeto ya tiene su inodo, siempre que haya recursos para los nuevos datos y metadatos y se cumplan las demás restricciones.
Para practicar
- Describe una carga que agote primero inodos y otra que agote primero bloques. Incluye el costo de los directorios.
- Identifica el montaje de tu laboratorio y conserva las dos salidas de df con fecha y opciones.
- Convierte st_blocks=0, 8 y 40 a bytes sin usar st_blksize.
- Compara du -B1, du -b y stat sobre un archivo vacío, uno de un byte y uno disperso.
- Ejecuta los dos programas y comprueba el rechazo de un nombre existente y de una ruta inexistente.
- Contrasta copias densas y dispersas: compara contenido, longitud y asignación por separado.
- Repite el simulador con una escritura que termina justo en una frontera de bloque y otra que la cruza en un byte.
- En la imagen ext2, registra inodos y bloques antes del lote, después del agotamiento, tras retirar un archivo y tras reponerlo.
- Explica por qué borrar un archivo vacío puede liberar un inodo sin reducir los bloques asignados al directorio raíz.
- Diseña un informe para un fallo ENOSPC que incluya operación, ruta, montaje, contadores, restricciones y verificación posterior.
- Explica por qué una suma du incompleta por permisos no demuestra que df esté equivocado.
- Calcula los bloques de datos del modelo para B=1024, longitud inicial 8192, offset 3071 y escritura de 1026 bytes.
En el tema 20 estudiaremos por qué los directorios también son archivos y cómo las operaciones sobre nombres modifican su contenido y los metadatos asociados.