ZFS и FreeBSD
Содержание
ZFS и FreeBSD
После ряда успешных экспериментов по использованию ZFS во FreeBSD я решил создать эту страничку. Думаю, найдутся те, кому покажется это интересным.
Опишу процесс установки, которым я уже неоднократно пользовался для установки FreeBSD 8.0-CURRENT, используя в качестве корневой файловой системы (да и вообще, всех файловых систем) ZFS.
Установочный Flash диск
Первой системой, куда я устанавливал FreeBSD подобным образом был мой EeePC. И установка происходила с USB Flash, так как USB CD у меня нет... Процесс подготовки флэшки имеет некоторые особенности, возможно я опишу их позже. Пока только замечу, что она представляет собой установленную систему в корень которой скопирован каталог с дистрибутивом из установочного ISO образа FreeBSD. Если взглянуть на содержимое корневой файловой системы этой флэшки, то можно увидеть вот что:
%ls -l / total 55 -rw-r--r-- 2 root wheel 784 20 июл 16:17 .cshrc -rw-r--r-- 2 root wheel 251 20 июл 16:17 .profile drwxrwxr-x 2 root operator 512 25 май 12:22 .snap drwxr-xr-x 14 root wheel 512 15 июл 21:58 8.0-BETA2-amd64 dr-xr-xr-x 13 root wheel 512 25 май 12:42 8.0-CURRENT-200905 -r--r--r-- 1 root wheel 6191 20 июл 16:17 COPYRIGHT drwxr-xr-x 2 root wheel 1024 20 июл 14:40 bin drwxr-xr-x 7 root wheel 512 20 июл 16:17 boot dr-xr-xr-x 6 root wheel 512 29 июл 11:57 dev -rw------- 1 root wheel 4096 28 июл 20:42 entropy drwxr-xr-x 20 root wheel 2048 29 июл 12:11 etc lrwxr-xr-x 1 root wheel 8 29 июл 12:11 home -> usr/home drwxr-xr-x 3 root wheel 1536 20 июл 14:48 lib drwxr-xr-x 2 root wheel 512 20 июл 14:39 libexec drwxr-xr-x 2 root wheel 512 4 май 19:39 media drwxr-xr-x 2 root wheel 512 4 май 19:39 mnt dr-xr-xr-x 2 root wheel 512 4 май 19:39 proc drwxr-xr-x 2 root wheel 2560 20 июл 14:47 rescue drwxr-xr-x 2 root wheel 512 28 июл 20:39 root drwxr-xr-x 2 root wheel 2560 20 июл 16:21 sbin lrwxr-xr-x 1 root wheel 11 20 июл 16:16 sys -> usr/src/sys drwxrwxrwt 7 root wheel 512 29 июл 11:59 tmp drwxr-xr-x 13 root wheel 512 28 июл 20:30 usr drwxr-xr-x 23 root wheel 512 29 июл 11:59 var
Здесь 8.0-BETA2-amd64 и 8.0-CURRENT-200905 - каталоги, скопированные с ISO образов.
%ls -l /8.0-BETA2-amd64/ total 26 drwxr-xr-x 2 root wheel 1024 15 июл 21:51 base drwxr-xr-x 2 root wheel 512 15 июл 21:51 catpages drwxr-xr-x 2 root wheel 512 15 июл 21:51 dict drwxr-xr-x 2 root wheel 512 15 июл 21:51 doc drwxr-xr-x 2 root wheel 512 15 июл 21:51 games drwxr-xr-x 2 root wheel 512 15 июл 21:51 info drwxr-xr-x 2 root wheel 1536 15 июл 21:54 kernels drwxr-xr-x 2 root wheel 512 15 июл 21:51 lib32 drwxr-xr-x 2 root wheel 512 15 июл 21:51 manpages drwxr-xr-x 2 root wheel 512 15 июл 21:55 ports drwxr-xr-x 2 root wheel 512 15 июл 21:51 proflibs drwxr-xr-x 2 root wheel 2560 15 июл 21:57 src
Процесс установки
Разметка диска
Итак. Устанавливаю я на обычный офисный компьютер, до этого на нём был FreeDOS. В качестве таблицы разделов я буду использовать GPT, поэтому предварительно нужно удалить текущую таблицу разделов.
# gpart show ad4 => 63 312581745 ad4 MBR (149G) 63 11293632 1 !12 [active] (5.4G) 11293695 301288113 - free - (144G)
Удаляю все (в данном случае единственный) разделы:
# gpart delete -i 1 ad4 ad4s1 deleted
Уничтожаю таблицу разделов:
# gpart destroy ad4 ad4 destroyed
Теперь создаю таблицу GPT и 3 раздела - 1-ый для установки на него загрузчика, 2-ой для раздела подкачки (swap), 3-ий для ZFS пула, куда будет устанавливаться система.
# gpart create -s GPT ad4 ad4 created # gpart show ad4 => 34 312581741 ad4 GPT (149G) 34 312581741 - free - (149G)
Создаваемый раздел характеризуется тремя параметрами: смещение начального блока LBA, размер и тип. Доступный для использования блок LBA можно определить по выводу команды gpart show ad4
. В первом столбце строки с записью "- free -" выводится номер блока, с которого начинается неиспользуемое пространство.
Загрузочный раздел начинается по смещению 34 блока от начала диска - сразу после таблицы GPT. Его размер я задаю в 256 блоков, это составляет 128кБайт. В принципе для моих целей достаточно и 32кБайт, но я сделал с запасом. Тип раздела "freebsd-boot" означает, что этот раздел выделен специально под загрузчик FreeBSD:
# gpart add -b 34 -s 256 -t freebsd-boot -l boot0 ad4 ad4p1 added # gpart show ad4 => 34 312581741 ad4 GPT (149G) 34 256 1 freebsd-boot (128K) 290 312581485 - free - (149G)
Параметр -b указывает смещение начального блока создаваемого раздела, а -s - его размер. Уже начиная с версии 8.0-BETA1 в параметрах утилиты gpart можно опускать эти параметры, а так же использовать суффиксы для указания размера создаваемого раздела. По-умолчанию, смещение начального блока берётся минимальным возможным. А размер, если не указан - всё оставшееся свободное пространство. Например, та же команда для создания загрузочного раздела выглядела бы вот так:
# gpart add -s 128k -t freebsd-boot -l boot0 ad4
Теперь создаю раздел для свопа. Цель создания отдельного раздела для свопа в том, чтобы была возможность записи в него дампа ядра при паниках. А подобная возможность для свопа, который находится на ZFS, вроде бы, ещё не реализована. Размер раздела будет 2ГБайта, в блоках это = 1024*1024*2*2 (в 1кБайте два блока). Тип раздела "freebsd-swap":
# gpart add -b 290 -s 4194304 -t freebsd-swap -l swap0 ad4 ad4p2 added # gpart show ad4 => 34 312581741 ad4 GPT (149G) 34 256 1 freebsd-boot (128K) 290 4194304 2 freebsd-swap (2.0G) 4194594 308387181 - free - (147G)
Теперь создаю раздел для ZFS пула, отведу под него 60ГБайт. Тип раздела "freebsd-zfs":
# gpart add -b 4194594 -s 125829120 -t freebsd-zfs -l disk0 ad4 ad4p3 added # gpart show ad4 => 34 312581741 ad4 GPT (149G) 34 256 1 freebsd-boot (128K) 290 4194304 2 freebsd-swap (2.0G) 4194594 125829120 3 freebsd-zfs (60G) 130023714 182558061 - free - (87G)
Создание файловой системы
Разделы созданы, можно создавать файловые системы. Для этого нужно загрузить модуль ядра zfs.ko и создать пул на 3-ем разделе ad4p3, но здесь можно применить небольшую стратегическую уловку. При создании разделов добавляли к каждому метку, соответвенно теперь можно использовать именно метку раздела. При добавлении второго и последующего дисков, а также при разбитии их на разделы, не будет проблем с загрузкой и монтированием пула:
# kldload zfs # ls -l /dev/ad4* crw-r----- 1 root operator 0, 63 29 июл 11:57 /dev/ad4 crw-r----- 1 root operator 0, 79 29 июл 12:42 /dev/ad4p1 crw-r----- 1 root operator 0, 86 29 июл 13:00 /dev/ad4p2 crw-r----- 1 root operator 0, 88 29 июл 13:03 /dev/ad4p3 # zpool create -m /mnt amd64 /dev/gpt/disk0 # zpool set bootfs=amd64 amd64
После создания пула его корень будет смонтирован в /mnt
и определён как загрузочный раздел (через свойство bootfs).
Теперь можно создать дополнительные разделы. Предварительно я устанавливаю свойство atime=off
для корневой системы, чтобы оно унаследовалось всеми вновь создаваемыми файловыми системами:
# zfs set atime=off amd64 # zfs create amd64/var # zfs create amd64/usr # zfs create amd64/tmp # zfs create amd64/var/tmp # zfs create -o compression=gzip amd64/var/crash # zfs create -o compression=gzip -o mountpoint=/mnt/usr/src amd64/src # zfs create -o compression=gzip -o mountpoint=/mnt/usr/ports amd64/ports # zfs create -o mountpoint=/mnt/usr/ports/distfiles amd64/distfiles # zfs create -o mountpoint=/mnt/usr/home amd64/home # zfs create -o mountpoint=/mnt/usr/local amd64/local # zfs create -o mountpoint=/mnt/usr/obj amd64/obj # zfs create amd64/var/db # chmod 1777 /mnt/tmp /mnt/var/tmp # zfs list NAME USED AVAIL REFER MOUNTPOINT amd64 342K 58,6G 22K /mnt amd64/tmp 18K 58,6G 18K /mnt/tmp amd64/usr 95K 58,6G 22K /mnt/usr amd64/home 18K 58,6G 18K /mnt/usr/home amd64/local 18K 58,6G 18K /mnt/usr/local amd64/obj 18K 58,6G 18K /mnt/usr/obj amd64/ports 37K 58,6G 19K /mnt/usr/ports amd64/distfiles 18K 58,6G 18K /mnt/usr/ports/distfiles amd64/src 18K 58,6G 18K /mnt/usr/src amd64/var 76K 58,6G 22K /mnt/var amd64/var/crash 18K 58,6G 18K /mnt/var/crash amd64/var/db 18K 58,6G 18K /mnt/var/db amd64/var/tmp 18K 58,6G 18K /mnt/var/tmp
Поясню для чего создавать столько отдельных файловых систем:
- различные свойства для файловых систем, например, компрессия для /usr/src, /usr/ports и /var/crash;
- большая гибкость при планировании бэкапов, например, для /var/db, /usr/home и /usr/local можно создавать снэпшоты по отдельному расписанию;
- у меня иногда возникает необходимость смонтировать /usr/obj в другое место (например, в chroot другой системы).
Установка системы
Устанавливать систему я буду традиционным способом - чере sysinstall. Для этого нужно его просто запустить :) Далее, я выбираю пункт "Custom installation" и в подпунтке "Options" я изменяю следующие настройки:
- Release Name = 8.0-BETA2-amd64
Это имя должно совпадать с именем каталога, в котором находятся файлы скопированные с ISO образа.
- Install Root = /mnt
Это путь, куда смонтирован корень файловой системы ZFS.
- Media Type = File System
После выбора File System оставляю поле ввода пустым.
После выхода из окна настройки "Options", я выбираю необходимые для установки компоненты "Distributions". Помимо всего прочего, обязательно нужно установить исходные тексты системы. В принципе, это всё. Жмём "Commit" и ждём пока всё скопируется.
Первоначальные настройки и загрузчик
После установки системы переношу ядро с модулями в каталог /mnt/boot/kernel:
# cd /mnt/boot/ # rm -r kernel # mv GENERIC kernel
Создаю /mnt/etc/fstab и добавляю туда swap раздел, только для именования я буду использовать GPT идентификатор:
# glabel list ad4p2 Geom name: ad4p2 Providers: 1. Name: gptid/bb1e61bd-7c3f-11de-8123-00215a749ae8 Mediasize: 2147483648 (2.0G) Sectorsize: 512 Mode: r0w0e0 secoffset: 0 offset: 0 seclength: 4194304 length: 2147483648 index: 0 Consumers: 1. Name: ad4p2 Mediasize: 2147483648 (2.0G) Sectorsize: 512 Mode: r0w0e0 # glabel list ad4p2 | grep gptid >> /mnt/etc/fstab # vi /mnt/etc/fstab # cat /mnt/etc/fstab #Device Mountpoint FStype Options Dump Pass# /dev/gptid/bb1e61bd-7c3f-11de-8123-00215a749ae8 none swap sw 0 0
Использование идентификатора GPT позволит в дальнейшем забыть про редактирование fstab при изменении именования диска, например, после включения диска в другой SATA порт или использовании эксперементального ahci(4) драйвера.
Ну или использовать схему с метками:
# cat /mnt/etc/fstab #Device Mountpoint FStype Options Dump Pass# /dev/gpt/swap0 none swap sw 0 0
Теперь добавлю загрузку модуля zfs в loader.conf и rc.conf:
# echo 'zfs_enable="YES"' >> /mnt/etc/rc.conf # echo 'zfs_load="YES"' >> /mnt/boot/loader.conf # echo 'vfs.root.mountfrom="zfs:amd64"' >> /mnt/boot/loader.conf
В опции загрузчика vfs.root.mountfrom указываю тип файловой системы zfs и имя пула amd64. Теперь нужно скомпилировать новый загрузчик. Нужен он для загрузки системы с ZFS, к сожалению, по умолчанию поддержка ZFS в загрузчике отключена. Для этого я и установливал исходники системы. Поддержка ZFS включается опцией LOADER_ZFS_SUPPORT, её я добавлю в /mnt/etc/src.conf для того, чтобы при дальнейших обновлениях системы случайно не забыть её.
# echo 'LOADER_ZFS_SUPPORT=YES' >> /mnt/etc/src.conf
На флэшке у меня установлена FreeBSD для i386, а сейчас я устанавливаю версию для amd64. Чтобы не "насиловать" флэшку, я создам символическую ссылку /usr/obj на /mnt/usr/obj.
# ln -s /mnt/usr/obj /usr/obj # ls -l /usr/obj lrwxr-xr-x 1 root wheel 12 30 июл 06:16 /usr/obj -> /mnt/usr/obj
Вообще, если бы я устанавливал не amd64 версию системы, то я бы смонтировал devfs в /mnt/dev, затем сделал chroot /mnt
, собрал там загрузчик и установил его, но в данном случае это проблематично. Поэтому в /etc/src.conf моей флэшки тоже содержится нужная опция:
# cat /etc/src.conf LOADER_ZFS_SUPPORT=YES
И так, скомпилирую и установлю новый загрузчик:
# cd /mnt/usr/src/sys/boot/ # make DESTDIR=/mnt TARGET=amd64 TARGET_ARCH=amd64 obj depend all # cd i386/loader/ # make DESTDIR=/mnt TARGET=amd64 TARGET_ARCH=amd64 install
Для make важным параметром здесь является DESTDIR=/mnt. Благодаря ему loader будет установлен в /mnt/boot/.
Финальные шаги
В завершение осталось сделать несколько действий:
- Записать защитный MBR перед таблицей GPT опцией -b. Он служит для защиты GPT таблицы от операционок и программ, которые ничего не знают о GPT.
- Записать загрузочный код в созданный ранее раздел с типом "freebsd-boot" опцией -p. Этот код содержится в файле /mnt/boot/gptzfsboot.
# gpart bootcode -b /mnt/boot/pmbr -p /mnt/boot/gptzfsboot -i 1 ad4 ad4 has bootcode
- Скопировать zpool.cache, в котором содержится информация о созданном пуле ZFS. Он нужен для того, чтобы свежеустановленная система сразу нашла ZFS пул без предварительного его импорта командой
zpool import
.
# zpool export amd64 && zpool import amd64 # cp /boot/zfs/zpool.cache /mnt/boot/zfs/
- Изменить точки монтирования для файловых систем.
# zfs set mountpoint=legacy amd64 # zfs set mountpoint=/usr amd64/usr # zfs set mountpoint=/usr/local amd64/local # zfs set mountpoint=/usr/src amd64/src # zfs set mountpoint=/usr/ports amd64/ports # zfs set mountpoint=/usr/ports/distfiles amd64/distfiles # zfs set mountpoint=/usr/obj amd64/obj # zfs set mountpoint=/var amd64/var # zfs set mountpoint=/tmp amd64/tmp
Для корневой файловой системы точка монтирования установлена в legacy. Т.е. ZFS не будет монтировать корневую файловую систему автоматически. Она будет смонтирована после того как ядро инициирует монтирование корневой файловой системы.
Вот и всё, перезагружаемся и работаем.