Prima di tutto, non sei il solo a preoccuparti di questo tipo di problemi.
Questo non è solo limitato a, tmpfs
ma è stato un problema citato con
NFSv4 .
Se un'applicazione legge "buchi" in un file sparse, il file system converte i blocchi vuoti in blocchi "reali" pieni di zeri e li restituisce all'applicazione.
Quando md5sum
tenta di scansionare un file, sceglie esplicitamente di farlo in
ordine sequenziale , il che ha molto senso in base a ciò che md5sum sta tentando di fare.
Poiché ci sono fondamentalmente "buchi" nel file, questa lettura sequenziale causerà (in alcune situazioni) una copia in scrittura come un'operazione per riempire il file. Questo quindi entra in un problema più profondo fallocate()
riguardo all'implementazione o meno del supporto del filesystem FALLOC_FL_PUNCH_HOLE
.
Fortunatamente, non solo tmpfs
supporta questo, ma esiste un meccanismo per "scavare" i fori.
Usando l'utilità CLI fallocate
possiamo rilevare e scavare nuovamente questi buchi con successo.
Secondo man 1 fallocate
:
-d, --dig-holes
Detect and dig holes. This makes the file sparse in-place, without
using extra disk space. The minimum size of the hole depends on
filesystem I/O block size (usually 4096 bytes). Also, when using
this option, --keep-size is implied. If no range is specified by
--offset and --length, then the entire file is analyzed for holes.
You can think of this option as doing a "cp --sparse" and then
renaming the destination file to the original, without the need for
extra disk space.
See --punch-hole for a list of supported filesystems.
fallocate
funziona a livello di file , tuttavia, e quando si esegue md5sum
su un dispositivo a blocchi (richiedendo letture sequenziali) si inciampa nello spazio esatto tra come fallocate()
dovrebbe funzionare la syscall. Possiamo vederlo in azione:
In azione, usando il tuo esempio vediamo quanto segue:
$ fs=$(mktemp -d)
$ echo ${fs}
/tmp/tmp.ONTGAS8L06
$ dd if=/dev/zero of=${fs}/sparse100M conv=sparse seek=$((100*2*1024-1)) count=1 2>/dev/null
$ echo "Before:" "$(ls ${fs}/sparse100M -s)"
Before: 0 /tmp/tmp.ONTGAS8L06/sparse100M
$ sudo losetup /dev/loop0 ${fs}/sparse100M
$ sudo md5sum /dev/loop0
2f282b84e7e608d5852449ed940bfc51 /dev/loop0
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 102400 /tmp/tmp.ONTGAS8L06/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 0 /tmp/tmp.ONTGAS8L06/sparse100M
Ora ... questo risponde alla tua domanda di base. Il mio motto generale è "diventare strano", quindi ho approfondito ...
$ fs=$(mktemp -d)
$ echo ${fs}
/tmp/tmp.ZcAxvW32GY
$ dd if=/dev/zero of=${fs}/sparse100M conv=sparse seek=$((100*2*1024-1)) count=1 2>/dev/null
$ echo "Before:" "$(ls ${fs}/sparse100M -s)"
Before: 0 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo losetup /dev/loop0 ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 1036 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51 /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 1036 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 520 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51 /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 520 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 516 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51 /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 512 /tmp/tmp.ZcAxvW32GY/sparse100M
$ fallocate -d ${fs}/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 0 /tmp/tmp.ZcAxvW32GY/sparse100M
$ sudo md5sum ${fs}/sparse100M
2f282b84e7e608d5852449ed940bfc51 /tmp/tmp.ZcAxvW32GY/sparse100M
$ echo "After:" "$(ls ${fs}/sparse100M -s)"
After: 0 /tmp/tmp.ZcAxvW32GY/sparse100M
Si vede che semplicemente l'atto di eseguire le losetup
modifiche modifica la dimensione del file sparse. Quindi questa diventa un'interessante combinazione di dove tmpfs
, il meccanismo HOLE_PUNCH fallocate
e i dispositivi di blocco si intersecano.