Na mojej ext4
partycji systemu plików mogę uruchomić następujący kod:
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
co daje
Before:
0 sparse100M
2f282b84e7e608d5852449ed940bfc51 /dev/loop0
After:
0 sparse100M
Robi to samo na tmpfs jak w przypadku:
fs="/tmp"
daje
Before:
0 /tmp/sparse100M
2f282b84e7e608d5852449ed940bfc51 /dev/loop0
After:
102400 /tmp/sparse100M
co w zasadzie oznacza, że coś, co spodziewałem się po prostu odczytać dane, spowodowało, że rzadki plik „wysadził się w powietrze jak balon”?
Spodziewam się, że tmpfs
dzieje się tak z powodu mniej doskonałej obsługi rzadkich plików w systemie plików, a zwłaszcza z powodu braku ioctl FIEMAP, ale nie jestem pewien, co powoduje takie zachowanie? Czy możesz mi powiedzieć?
ext4
tmpfs
sparse-files
ludzkośćANDpeace
źródło
źródło
Odpowiedzi:
Po pierwsze , nie jesteś sam w zagadkach dotyczących tego rodzaju problemów.
Nie ogranicza się to tylko do
tmpfs
problemu, o którym wspominano w NFSv4 .Kiedy
md5sum
próbuje skanować plik, jawnie decyduje się to zrobić w kolejności sekwencyjnej , co ma sens w oparciu o to, co próbuje zrobić md5sum.Ponieważ w pliku znajdują się zasadniczo „dziury”, ten sekwencyjny odczyt spowoduje (w niektórych sytuacjach), że operacja kopiowania podczas zapisu spowoduje wypełnienie pliku. To powoduje głębszy problem związany z tym, czy
fallocate()
implementowane w systemie plików jest obsługiwaneFALLOC_FL_PUNCH_HOLE
.Na szczęście nie tylko to
tmpfs
obsługuje, ale istnieje mechanizm „wykopywania” dziur z powrotem.Za pomocą narzędzia CLI
fallocate
możemy z powodzeniem wykryć i ponownie wykopać te dziury.Zgodnie z
man 1 fallocate
:fallocate
działa jednak na poziomie plików, a kiedy pracujeszmd5sum
na urządzeniu blokowym (żądając sekwencyjnych odczytów), masz do czynienia z dokładną przerwą między tym, jakfallocate()
powinien działać syscall. Widzimy to w akcji:W działaniu na podstawie Twojego przykładu widzimy:
Teraz ... to odpowiada na twoje podstawowe pytanie. Moje ogólne motto brzmi: „stań się dziwny”, więc kopałem dalej ...
Widać, że tylko akt wykonywania
losetup
zmienia rozmiar pliku rozrzedzony. Staje się to więc interesującą kombinacjątmpfs
przecinania się mechanizmu HOLE_PUNCHfallocate
i urządzeń blokowych.źródło
tmpfs
obsługuje rzadkie pliki i dziurkacz. To sprawia, że jest to tak mylące -tmpfs
obsługuje to, więc po co iść i wypełniać rzadkie dziury podczas czytania przez urządzenie pętli?losetup
nie zmienia rozmiaru pliku, ale tworzy urządzenie blokowe, które w większości systemów jest następnie skanowane w poszukiwaniu treści takich jak: czy istnieje tablica partycji? czy istnieje system plików z UUID? powinienem wtedy utworzyć / dev / disk / by-uuid / symlink? A te odczyty już powodują przydzielenie części pliku rzadkiego, ponieważ z jakiegoś tajemniczego powodu tmpfs wypełnia dziury w (niektórych) odczytach.loop.c
) i zobaczyłem, że istnieją dwie odpowiednie funkcje :lo_read_simple
ilo_read_transfer
. Istnieją pewne niewielkie różnice w sposobie przydzielania pamięci niskiego poziomu ... wlo_read_transfer
rzeczywistości żąda nieblokowania io fromslab.h
(GFP_NOIO
) podczas wykonywaniaalloc_page()
połączenia.lo_read_simple()
z drugiej strony nie działaalloc_page()
.