На первый взгляд, это просто dd
:
dd if=sparsefile of=sparsefile conv=notrunc bs=1M
Это читает весь файл и записывает все содержимое обратно в него.
Для того, чтобы написать только само отверстие, сначала нужно определить, где находятся эти отверстия. Вы можете сделать это с помощью либо filefrag
или hdparm
:
filefrag:
# filefrag -e sparsefile
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 1048575: 187357696.. 188406271: 1048576:
1: 1572864.. 2621439: 200704128.. 201752703: 1048576: 188406272: last,eof
sparsefile: 2 extents found
HDPARM:
# hdparm --fibmap sparsefile
sparsefile:
filesystem blocksize 4096, begins at LBA 0; assuming 512 byte sectors.
byte_offset begin_LBA end_LBA sectors
0 1498861568 1507250175 8388608
6442450944 1605633024 1614021631 8388608
Этот файл примера, как вы говорите, имеет 10G
размер с 2G
отверстием. Он имеет два экстента, первое покрытие 0-1048575
, второе 1572864-2621439
, что означает, что отверстие 1048576-1572864
(в блоках размером 4k, как показано filefrag
). Информация, отображаемая hdparm
как та же самая, просто отображается по-разному (первый экстент охватывает 8388608
512-байтовые сектора, начиная с 0, поэтому это 0-4294967295
байты, поэтому дыра 4294967296-6442450944
в байтах.
Обратите внимание, что вам может быть показано значительно больше экстентов в случае фрагментации. К сожалению, ни одна из команд не показывает дыры напрямую, и я не знаю ни одной, которая делает это, поэтому вы должны вывести ее из показанных логических смещений.
Теперь, заполнив это 1048576-1572864
отверстие, dd
как показано выше, можно сделать, добавив соответствующие (идентичные) seek
/ skip
значения и count
. Обратите внимание, что он bs=
был адаптирован для использования 4k
секторов, как filefrag
указано выше. (Для bs=1M
этого вам придется адаптировать значения поиска / пропуска / подсчета, чтобы отразить 1M
размерные блоки).
dd if=sparsefile of=sparsefile conv=notrunc \
bs=4k seek=1048576 skip=1048576 count=$((-1048576+1572864))
Хотя вы можете заполнить дыры /dev/zero
вместо того, чтобы читать дыру в самом файле (что также приведет к нулю), безопаснее читать изsparsefile
любом случае, так что вы не повредите свои данные в случае неправильного смещения.
В более новых версиях GNU dd
вы можете придерживаться большего размера блока и указывать все значения в байтах:
dd if=sparsefile of=sparsefile conv=notrunc bs=1M \
iflag=skip_bytes,count_bytes oflag=seek_bytes \
seek=4294967296 skip=4294967296 count=$((-4294967296+6442450944))
filefrag
после запуска этого:
# sync
# filefrag -e sparsefile
Filesystem type is: 58465342
File size of sparsefile is 10737418240 (2621440 blocks of 4096 bytes)
ext: logical_offset: physical_offset: length: expected: flags:
0: 0.. 1572863: 187357696.. 188930559: 1572864:
1: 1572864.. 2621439: 200704128.. 201752703: 1048576: 188930560: last,eof
sparsefile: 2 extents found
Из-за фрагментации это все еще две степени. Однако логические смещения показывают, что на этот раз дыр нет, поэтому файл больше не является разреженным.
Естественно, это dd
решение - очень ручной подход к вещам. Если вам это нужно на регулярной основе, было бы легко написать небольшую программу, которая заполняет такие пробелы. Если он уже существует в качестве стандартного инструмента, я еще не слышал об этом.
В конце концов, есть инструмент, который, fallocate
кажется, работает после моды:
fallocate -l $(stat --format="%s" sparsefile) sparsefile
Однако, наконец, в случае XFS, хотя он выделяет физическую область для этого файла, он фактически не обнуляет его. filefrag
показывает такие экстенты как выделенные, но неписанные.
2: 3.. 15: 7628851.. 7628863: 13: 7629020: unwritten
Это недостаточно для того, чтобы иметь возможность считывать правильные данные непосредственно с блочного устройства. Он только резервирует место для хранения, необходимое для будущих записей.
cat sparsefile 1<> sparsefile
. Вы можете использоватьfallocate
Linux, чтобы избежать необходимости записывать эти байты NUL, если все, что вам нужно, это место, которое будет выделено.fallocate
. Это имеет,--dig-holes
но нет--fill-holes
. Тем не менее, кажется, что он работает достаточно хорошо, когда вы указываете размер. Я отредактирую свой ответ.fallocate
есть ,-z
которые могут быть использованы в Linux 3.14 и выше на ext4 и XFS (вы должны запустить его с-o
и-l
для всех разреженных участков я полагаю).-z
не сохранит ваши данные, если вам случится ошибочное смещение, поэтому я буду придерживатьсяdd
этого ...