Opcja extents w systemach plików ext4

Spis treści

Dziś postanowiłem sprawdzić jak wygląda struktura plików mojego dysku. Chodzi oczywiście o ich fragmentację. Zgodnie z tym co pokazał mi fsck , pofragmentowanych plików jest 350. Po zapuszczeniu defragmentacji via e4defrag ilość tych plików spadła do nieco ponad 100 i jeśli by się przyjrzeć procesowi defragmentacji, to można było zauważyć linijki mające extents: 100 -> 10 . Wychodzi na to, że plik dalej jest w kawałkach i nie idzie go zdefragmentować. Jak rozumieć taki zapis?

Extents, czyli zakresy bloków

System plików ext4 ma opcję extents , która odpowiada za przydział pewnej ilości bloków w formie ciągłej. Chodzi o to, że domyślny blok danych na dysku ma 4 KiB i jeśli wgrywamy plik, który waży 1 GiB, to zostanie on podzielony na 262,144 jednostki. By odczytać później taki plik, trzeba będzie się tyle razy odwołać do dysku, a to spowalnia transfer danych, zwłaszcza w dyskach hdd. Poza tym, ilość metadanych opisująca ten plik jest przeogromna. W przypadku opcji extents , system plików jest w stanie oznaczyć zakres bloków do 128 MiB i jeśli w takim przypadku wgramy ten 1 GiB plik, to jego odczyt będzie można zrobić w 8 podejściach. Poprawia to wydajność, drastycznie zmniejsza ilość metadanych i redukuje fragmentację plików.

Cały ten mechanizm zakresów działa mniej więcej w poniższy sposób. Przy tworzeniu systemu plików są definiowane grupy bloków. Jako, że system plików ext4 ma domyślny rozmiar bloków 4 KiB oraz, że każdy i-węzeł ma 256 bajtów, daje nam to 16 i-węzłów na blok. Każda grupa bloków ma 8192 i-węzły, co przekłada się na 512 bloków, które są przeznaczone na same i-węzły (2 MiB danych). Grupa zaś składa się z 32768 bloków, czyli 128 MiB i to właśnie kryje się pod nazwą extents.

W każdym i-węźle zarezerwowanych jest 60 bajtów na zakresy bloków. Każdy z zakresów ma 12 bajtów, do tego dochodzi jeszcze 12 bajtowy nagłówek. Zatem każdy i-węzeł jest w stanie obsłużyć 4 zakresy. Taki zakres można porównać do klastra w systemach plików ntfs. Mamy tam określony początkowy adres bloku oraz liczbę kolejnych bloków składających się na ten zakres. Zatem jeśli plik by miał 512 MiB, to bez problemu taki i-węzeł jest go w stanie obsłużyć. Natomiast w przypadku większych plików, system plików ext4 buduje drzewo zakresowe (extent tree). System plików ext4 dba dość mocno o to by pliki były ciągłe ale zdarzają się takie, które mają więcej niż jeden zakres i to te pliki zwykliśmy nazywać pofragmentowanymi.

Fragmentacja plików

Każdy system plików posiada statystyki, a w nich znajdują się przeróżne informacje. Nas interesują głównie dane na temat pofragmentowanych plików, które możemy odczytać posługując się narzędziem fsck :

# fsck.ext4 -nfv /dev/mapper/kabi
...
      111 non-contiguous files (0.0%)
...

W tym przypadku jest to 111 pofragmentowanych plików, co oznacza, że pliki nie są ciągłe i mają kilka zakresów bloków. Z powyższego logu nie dowiemy się jednak ile kawałków mają te pliki. To zaś możemy ustalić posługując się narzędziem filefrag , przykładowo:

# filefrag -v /media/morfik/sdb7-usb-WDC_WD15_EARS-00/1024
Filesystem type is: ef53
File size of /media/morfik/sdb7-usb-WDC_WD15_EARS-00/1024 is 1073741824 (262144 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..   32767:      34816..     67583:  32768:
   1:    32768..   63487:      67584..     98303:  30720:
   2:    63488..   96255:     100352..    133119:  32768:      98304:
   3:    96256..  126975:     133120..    163839:  30720:
   4:   126976..  159743:     165888..    198655:  32768:     163840:
   5:   159744..  190463:     198656..    229375:  30720:
   6:   190464..  223231:     231424..    264191:  32768:     229376:
   7:   223232..  253951:     264192..    294911:  30720:
   8:   253952..  262143:     296960..    305151:   8192:     294912: last,eof
/media/morfik/sdb7-usb-WDC_WD15_EARS-00/1024: 5 extents found

Powyżej mamy plik 1024MiB, który zdaje się mieć 9 zakresów ale na samym dole w logu widzimy, że jest ich tylko 5. Tego typu informację należy traktować w taki sposób, że plik ma 9 zakresów bloków ale tylko 5 fragmentów, tj. zakresów które nie występują jeden po drugim, w efekcie czego jest jakaś przerwa między nimi i to jest faktyczna fragmentacja w systemie plików ext4.

Połowa z tych zakresów ma 128MiB (32768 bloków), czyli maksimum dla systemu plików ext4, natomiast pozostałe mają nieco mniej, co oznacza, że istnieje możliwość uzyskania mniejszej fragmentacji. Poza tym w kolumnie expected mamy 4 oczekiwane offsety bloków i jest to physical_offset + length poprzedniego zakresu. Idealna sytuacja to ta, w której mamy ciąg zakresów jeden za drugim. Możemy spróbować zdefragmentować ten plik kilka razy przy pomocy e4defrag . Choć jeśli posiadamy dużą ilości danych na dysku, cały proces może nic nam nie dać. Mi jednak się udało nieco zoptymalizować ten plik:

# filefrag -v /media/morfik/sdb7-usb-WDC_WD15_EARS-00/1024
Filesystem type is: ef53
File size of /media/morfik/sdb7-usb-WDC_WD15_EARS-00/1024 is 1073741824 (262144 blocks of 4096 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0..   32767:    1161216..   1193983:  32768:
   1:    32768..   65535:    1193984..   1226751:  32768:
   2:    65536..   98303:    1226752..   1259519:  32768:
   3:    98304..  131071:    1259520..   1292287:  32768:
   4:   131072..  163839:    1292288..   1325055:  32768:
   5:   163840..  196607:    1325056..   1357823:  32768:
   6:   196608..  229375:    1357824..   1390591:  32768:
   7:   229376..  262143:    1390592..   1423359:  32768:             last,eof
/media/morfik/sdb7-usb-WDC_WD15_EARS-00/1024: 1 extent found

Jest to ten sam plik zdefragmentowany kilka razy. Jak widzimy nie ma już pozycji w kolumnie expected , zaś length wszędzie wskazuje na 32768 , czyli 128MiB zakres. Mimo, że ten plik ma 8 zakresów, to nie jest traktowany przez system jako pofragmentowany.

Ten powyższy plik został wgrany na partycję, która praktycznie była pusta i miała około 458 GiB. Dlatego zakresy są 128 MiB. Jeśli jednak weźmiemy sobie bardziej zapchany system plików, to jego wolna przestrzeń może się prezentować np. w poniższy sposób:

# e2freefrag /dev/mapper/kabi
...
HISTOGRAM OF FREE EXTENT SIZES:
Extent Size Range :  Free extents   Free Blocks  Percent
    4K...    8K-  :          3955          3955    0.06%
    8K...   16K-  :          3495          8194    0.13%
   16K...   32K-  :          2601         13165    0.20%
   32K...   64K-  :          2622         28991    0.45%
   64K...  128K-  :          2565         58267    0.90%
  128K...  256K-  :          1576         71371    1.11%
  256K...  512K-  :          1331        118346    1.83%
  512K... 1024K-  :          1058        190532    2.95%
    1M...    2M-  :          1202        444210    6.89%
    2M...    4M-  :          1211        884489   13.71%
    4M...    8M-  :          1249       1803998   27.97%
    8M...   16M-  :           622       1643226   25.48%
   16M...   32M-  :           198       1024999   15.89%
   32M...   64M-  :            16        163082    2.53%

Na tej partycji jest wolnych jeszcze 25 GiB ale jak widzimy wyżej, w obrębie tego systemu plików nie mamy wolnej przestrzeni, która by miała więcej niż 32-64 MiB. Zatem jeśli byśmy wgrali plik 1GiB, to zostanie on podzielony na dość sporą ilość zakresów. Dlatego też warto pamiętać, by nie tworzyć małych partycji i nie zapychać ich w dość znacznym stopniu, bo to powoduje drastyczną fragmentację wolnej przestrzeni i pliki zamiast być alokowane w kilku zakresach obok siebie, zaczynają być oznaczane przez dziesiątki, setki czy nawet tysiące z nich i do tego porozrzucane w obrębie całej partycji, co znacznie spowalnia operacje na plikach.

Mikhail Morfikov avatar
Mikhail Morfikov
Po ponad 10 latach spędzonych z różnej maści linux'ami (Debian/Ubuntu, OpenWRT, Android) mogę śmiało powiedzieć, że nie ma rzeczy niemożliwych i problemów, których nie da się rozwiązać. Jedną umiejętność, którą ludzki umysł musi posiąść, by wybrnąć nawet z tej najbardziej nieprzyjemniej sytuacji, to zdolność logicznego rozumowania.