a look at btrfs

March 3, 2011

Решил сегодня посмотреть на btrfs от компании Oracle. В статье описано много плюшек, но я ее начал читать только сейчас, когда начал писать пост :].

Первое, что меня привлекло в ней - это высокая скорость доступа к данным и относительная простота внтурненнего устройства.

Я только потом узнал, что btrfs очень эффективно хранит маленькие файлы и старается сжимать данные с помощью zlib и lzo.

Решил я ее испробовать, когда наткнулся на описание исправленного бага в недавно вышедшем ядре 2.6.38.

Времена немного изменились. Теперь я держу не только системный каталог ебилдов, но и еще cvs дерево portage (так называемый gentoo-x86 tree), чтобы вносить в него изменения.

Обновление gentoo-x86 (cvs update) у меня занимало 40 минут, причем бОльшую часть времени занимает чтение огромного числа файлов: в каждом каталоге находится подкаталог CVS, а в нем 3 файла:

Каталогов в gentoo-x86 (не включая подкаталоги CVS):

$ find -type d | grep -v CVS | wc -l
21594

Итого при cvs update нужно прочитать минимум ~60000 файлов с диска.

Самое интересное, что эти 3 файла одинаковы во всех каталогах CVS. Если бы файловая система поддерживала дедупликацию, то эти 3 файла прочитались бы с диска 1 раз! (поддержка дедупликации планируется в btrfs).

btrfs поддерживает копирование-при-записи (COW), так что я мог бы вручную заменить все копии этих файлов на один удалением файла CVS/Root и копированием файла с этого же раздела btrfs из другого места (для этого нужна утилита cp из coreutils-8.10 или выше). Это еще предстоит попробовать.

Эксперимент я начал с малого: создал блочное устройство на 2GB и записал туда gentoo-x86:

$ dd if=/dev/zero of=btrfs.image bs=$((1024 * 1024)) count=2048
$ losetup /dev/loop0 btrfs.image
$ mkfs.btrfs -LBTRFS_TESTIE /dev/loop0
$ mount /dev/loop0 ut/
$ cp -r .../gentoo-x86 ut/

Это заняло больше 30 минут. Думаю, что бОльшаю часть времени тратилась на чтение файлов со страшно фрагментированной ext4. Пока это дело копировалось я изучал команды утилиты btrfs. У нее apt (или git)-подобный интерфейс:

$ btrfs
Usage:
    btrfs filesystem show [<uuid>|<label>]
        Show the info of a btrfs filesystem. If no <uuid> or <label>
        is passed, info of all the btrfs filesystem are shown.
    btrfs filesystem df <path>
        Show space usage information for a mount point
# много-много еще всего

Я попробовал такие штуки:

$ btrfs filesystem defrag ut/
$ btrfs filesystem balance ut/

Как оказалось, defrag дефрагментирует один файл (или метаданные каталога), так что придется запускать defrag на все файлы раздела, если нужна полная дефрагментация.

Кстати, их домашняя страница содержит много полезной информации.

Дождавшись копирования я решил сменить владельца ut/gentoo-x86 на себя:

$ chown -R slyfox:users ut/
Segmentation Fault

Нехорошо. В dmesg светился OOps ядра. Я заселился на IRC канал #btrfs на freenode. Там Carey Underwood сказал мне, что это неизвестные баг ядра и я его зарепортил.

Carey также рассказал, что это отсутствие обработки нехватки места на диске в ядре. Интересно, что gentoo-x86 весит примерно 170MB “чистого веса” (без учета внутренней фрагментации) и 848MB на ext4 (с учетом фрагментации) (на самом деле чуть больше, так как не учитывется место в таблице инодов - это порядка 170000 * 256 = ~44MB). То есть в btrfs куда-то девался еще 1 GB.

Carey пояснил, что в btrfs блоки под данные и метаданные выделяются очень большие (порядка 1 GB), и скорее всего у меня один из этих типов блоков, а новый выделиться не смог. Это не чувствуется на файловых системах размером больше 10GB, но на моей игрушке еще как. btrfs имеет режим, когда метаданные и данные используют одни и те же блоки: так называемый —-mixed.

Он предложил мне попробовать патч в btrfs-progs, который позволяет создавать mixed файлухи. Заодно я решил попробовать lzo компрессию, а не zlib (умолчальную).

$ mkfs.btrfs -LBTRFS_TESTIE --mixed /dev/loop0
$ mount -o compress=lzo image.btrfs ut/

После этого я без проблем залил туда:

Это чуть-чуть больше 2GB. df и btrfs fi df ut/ говорили, что свободно еще 300MB.

После этого я успешно сменил владельца. Обновление gentoo-x86 с cvs заняло 16 минут. Раза в три быстрее, чем на фрагментированной ext4.

Сконвертировал свой 4GB раздел с 300000 файлов на винчестере чтобы попробовать btrfs на реальном железе:

$ df -h
Файловая система      Разм  Исп  Дост  Исп% смонтирована на
/dev/sda10            4,5G  752M  3,7G  17% /mnt/portage # уже btrfs
/dev/loop1            4,2G  2,1G  1,9G  52% /mnt/ut      # образ ext4 (создан dd if=/dev/sda10 of=...)

Раздел btrfs больше на 300MB за счет того, что btrfs не создает таблицы инодов, а хранит иноды как и данные в выделяемых блоках. При создании ext4 я зарезервировал таблицу на 1.1 млн инодов. Каждый элемент “весит” 256 байт. Это и есть наши 300MB (gentoo-x86 меньше на btrfs).

Очень рекомендую почитать их wiki. там есть такие штуки, как создание именованных слепков файловой системы. Их можно очень прикольно использовать как бэкапы или как отдельные файловые системы.