На моем ext4
разделе файловой системы я могу запустить следующий код:
fs="/mnt/ext4"
#create sparse 100M file on ${fs}
dd if=/dev/zero \
of=${fs}/sparse100M conv=sparse seek=$((100*2*1024-1)) count=1 2> /dev/null
#show its actual used size before
echo "Before:"
ls ${fs}/sparse100M -s
#setting the sparse file up as loopback and run md5sum on loopback
losetup /dev/loop0 ${fs}/sparse100M
md5sum /dev/loop0
#show its actual used size afterwards
echo "After:"
ls ${fs}/sparse100M -s
#release loopback and remove file
losetup -d /dev/loop0
rm ${fs}/sparse100M
который дает
Before:
0 sparse100M
2f282b84e7e608d5852449ed940bfc51 /dev/loop0
After:
0 sparse100M
Делаем то же самое с tmpfs, как с:
fs="/tmp"
доходность
Before:
0 /tmp/sparse100M
2f282b84e7e608d5852449ed940bfc51 /dev/loop0
After:
102400 /tmp/sparse100M
что в основном означает, что то, что я ожидал, просто прочитав данные, заставило разреженный файл «взорваться, как воздушный шар»?
Я ожидаю, что это из-за менее совершенной поддержки разреженных файлов в tmpfs
файловой системе, и в частности из-за отсутствия ioctl FIEMAP, но я не уверен, что вызывает такое поведение? Можешь мне сказать?
ext4
tmpfs
sparse-files
humanityANDpeace
источник
источник
Ответы:
Во-первых, вы не одиноки, ломая голову над такими проблемами.
Это не только ограничено,
tmpfs
но было проблемой, процитированной с NFSv4 .Когда
md5sum
пытается сканировать файл, он явно решает сделать это в последовательном порядке , что имеет большой смысл в зависимости от того, что пытается сделать md5sum.Так как в файле есть «дыры», это последовательное чтение (в некоторых ситуациях) приведет к операции копирования при записи, чтобы заполнить файл. Затем возникает более глубокий вопрос о том,
fallocate()
поддерживает ли реализованная в файловой системе системаFALLOC_FL_PUNCH_HOLE
.К счастью, это не только
tmpfs
поддерживает, но и есть механизм, чтобы «выкопать» отверстия обратно.Используя утилиту CLI,
fallocate
мы можем успешно обнаружить и заново выкопать эти дыры.Согласно
man 1 fallocate
:fallocate
работает на уровне файлов, и когда вы работаетеmd5sum
с блочным устройством (запрашивая последовательное чтение), выfallocate()
попадаете в точный промежуток между тем, как должен работать системный вызов. Мы можем увидеть это в действии:В действии, используя ваш пример, мы видим следующее:
Теперь ... это отвечает на ваш основной вопрос. Мой общий девиз - "Странно", поэтому я продолжил ...
Вы видите , что только акт выполнения
losetup
изменяет размер разреженного файла. Таким образом, это становится интересной комбинацией того, гдеtmpfs
пересекаются механизм HOLE_PUNCHfallocate
и блочные устройства.источник
tmpfs
поддерживает разреженные файлы и punch_hole. Вот что делает его таким запутанным -tmpfs
поддерживает это, так зачем идти и заполнять разреженные отверстия при чтении через петлевое устройство?losetup
не изменяет размер файла, но создает блочное устройство, которое в большинстве систем затем сканируется на предмет содержимого: есть ли таблица разделов? Есть ли файловая система с UUID? тогда я должен создать / dev / disk / by-uuid / symlink? И эти чтения уже приводят к тому, что части разреженного файла выделяются, потому что по какой-то таинственной причине tmpfs заполняет дыры в (некоторых) чтениях.loop.c
) и увидел, что есть две соответствующие функции :lo_read_simple
&lo_read_transfer
. Есть некоторые незначительные различия в том, как они выполняют низкоуровневое выделение памяти ...lo_read_transfer
фактически запрашивает неблокирующую функцию io изslab.h
(GFP_NOIO
) во время выполненияalloc_page()
вызова.lo_read_simple()
с другой стороны, не выполняетalloc_page()
.