Si miro el contenido de sleepimage o swapfile en /var/vm
, me parece que es sólo 1,07G de bytes nulos. Yo esperaría que contengan datos reales, o si no se están utilizando que sean un archivo 0B. He comprobado unas cuantas versiones de SO diferentes y he verificado que esto es así desde la 10.9 hasta la 11.6, así que dudo que sea algo particular de una configuración o sistema de archivos determinado.
Respuesta
¿Demasiados anuncios?Decidí indagar un poco en el código fuente del kernel y tengo una respuesta aproximada, pero aún no está 100% claro. Si echas un vistazo a IOHibernateIO.cpp
dentro del IOHibernateSystemPostWake
se ve la siguiente llamada (nota: ligeramente diferente para 10.11+, pero se acaba llamando a la misma función)
if (kFSOpened == gFSState)
{
// invalidate & close the image file
gIOHibernateCurrentHeader->signature = kIOHibernateHeaderInvalidSignature;
if ((fileRef = gIOHibernateFileRef))
{
gIOHibernateFileRef = 0;
IOSleep(TRIM_DELAY);
kern_close_file_for_direct_io(fileRef,
#if DISABLE_TRIM
0, 0, 0, 0, 0);
#else
0, (caddr_t) gIOHibernateCurrentHeader,
sizeof(IOHibernateImageHeader),
0,
gIOHibernateCurrentHeader->imageSize);
#endif
}
gFSState = kFSIdle;
}
return (kIOReturnSuccess);
Es importante, DISABLE_TRIM
se define como 0, por lo que acabamos llamando a kern_close_file_for_direct_io
cuya firma es la siguiente:
void
kern_close_file_for_direct_io(struct kern_direct_file_io_ref_t * ref,
off_t write_offset, caddr_t addr, vm_size_t write_length,
off_t discard_offset, off_t discard_end)
y cuya aplicación parece emitir primero un DKIOCUNMAP
ioctl para los extensiones que pertenecen al archivo de hibernación, luego copia write_length
bytes de la dirección de memoria addr
en el archivo. Si miramos un poco hacia atrás, gIOHibernateCurrentHeader
se pone a cero en la memoria después de escribir la imagen de hibernación durante IOHibernateSystemSleep
.
Esto nos lleva a unas cuantas conclusiones, así como a unas cuantas preguntas persistentes:
-
Efectivamente, este parece ser el comportamiento previsto, y puedo ver un
DKIOCUNMAP
que se emite dentro devm_compressor_backing_file.c
por lo que asumo que algo similar ocurre con los archivos de intercambio también. -
Sin embargo, no sé qué significa esto para el espacio ocupado físicamente en el disco. En el caso de APFS esto es trivial ya que soporta archivos dispersos (por lo que incluso si el archivo es realmente 1,7G de bytes nulos no importará), pero ¿qué pasa con HFS+? Tengo entendido que el
DKIOCUNMAP
ioctl se traduce efectivamente en el comando TRIM de las SSD para limpiar los bloques usados:
El método doUnmap fue introducido como reemplazo del método doDiscard. Realiza una función similar, que es liberar los bloques de disco que no son utilizados por el sistema de archivos. A diferencia del método doDiscard, que es capaz de liberar sólo una serie de bloques de disco físicamente contiguos, el método doUnmap recibe un array que contiene uno o más rangos de bloques de disco que ya no están en uso. Un proceso del espacio de usuario puede realizar esta acción enviando el ioctl DKIOCUNMAP.
lo que parece implicar que, a pesar de que el nivel del sistema de archivos piensa que el tamaño del archivo es de 1,7G, ninguno de esos extents apunta realmente a bloques válidos en el disco, y por lo tanto el tamaño físico del archivo es mucho menor. Esto también explicaría por qué son 1,7G de ceros, ya que asumo que el controlador del SSD al recibir el comando de recorte podría implementar RZAT (devolver ceros después del recorte). Esta hipótesis se podría comprobar probando esto en un disco giratorio y viendo si se devuelven datos.