ZFS и FreeBSD

Материал из OpenWiki
Перейти к: навигация, поиск

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 не будет монтировать корневую файловую систему автоматически. Она будет смонтирована после того как ядро инициирует монтирование корневой файловой системы.

Вот и всё, перезагружаемся и работаем.

Дополнительная информация