В списках рассылки freebsd-fs@ и freebsd-stable@ было несколько жалоб на то, что FreeBSD 8.2 и предыдущие сборки 8-STABLE не грузятся при использовании загрузочного кода zfsboot. Сам я никогда его не использовал, у меня везде "стандартная" схема - GPT + 3 раздела (freebsd-boot, freebsd-swap и freebsd-zfs). Решил я проверить эту проблему.
Почти два дня я провел, совмещая работу и эксперименты в virtualbox'е. И это я ещё не все возможные варианты попробовал. У меня была виртуальная машина с 8.1-STABLE, я обновил её и оставил /usr/obj для установки собранной системы на другие образы дисков.
Первым вариантом для тестирования я выбрал ZFS пул, создаваемый на целом диске без использования таблиц разделов. Выбор пал на такую конфигурацию благодаря одному моему коллеге, которого я уже упоминал как-то в своём блоге. Он написал статью, обобщив свой опыт по установке FreeBSD на ZFS. Он же периодически подкидывает мне ссылки на обсуждение своей статьи. Там-то как раз и обсуждался такой метод установки. Установку можно описать буквально несколькими командами (набираю по памяти, мог что-нибудь забыть):
Проблема подтвердилась сразу. Самое неприятное, что никакого удобного способа отладить загрузочный код я не видел. Единственное, что приходило на ум - читать код и вставлять printf'ы в определённые места, для того чтобы хоть как-то отслеживать процесс выполнения загрузочного кода.
Чтение исходников - это часто бывает полезным. Вот, например, объяснение последних двух команд - почему именно такие параметры? ;) Это можно понять из исходного кода.
Образ загрузочного кода zfsboot состоит из двух частей - zfsboot1 и zfsboot2. Первая часть предназначена для записи в первый сектор диска, куда BIOS обычно передаёт управление для загрузки системы. Грубо говоря, zfsboot1 - это образ MBR с небольшой частью загрузочного кода, который выполняет некоторые стандартные манипуляции для загрузчика, загружает zfsboot2, а так же предоставляет ему некоторые сервисные функции. Написан он на ассемблере. Вторая часть - zfsboot2, написана на Си. Она уже обладает значительно большим функционалом, и размер у неё, соответственно, побольше. В частности, она выполняет поиск ZFS пула и загружает из него zfsloader.
Так вот, первая команда dd выполняет запись zfsboot1 в первый сектор диска. Вторая команда выполняет запись zfsboot2 по смещению в 512 кбайт. Это место внутри ZFS во FreeBSD специально зарезервировано под загрузочный код:
Как видно из комментария, его размер может достигать трёх с половиной мегабайт. На данный момент в 9.0-CURRENT с ZFS v28 его размер чуть больше 32кбайт, но для "ровного" числа он создаётся размером 64 кбайт, в которых чуть меньше половины забито нулями, + 512 байт от zfsboot1.
Вернёмся к решению проблемы. Как мне стало известно из переписки с людьми, сообщившими о проблеме, не работает zfsboot в 9.0-CURRENT примерно с сентября 2010 года. А именно тогда туда были внесены крупные изменения. Методом printf'а я нашёл, что зависание происходит в функции drvread, которая вызывает код чтения секторов диска из zfsboot1. Сравнив содержимое этой функции с тем, что было до тех изменений было замечено всего одно маленькое отличие.
Я вернул убранную строчку и всё заработало. Попутно, была обнаружена ошибка в ассемблерном коде, появившаяся после внедрения ZFS v28. Сейчас я выполняю дополнительные тесты для проверки, не повлияет ли это изменение на другие варианты загрузки, о которых, возможно, напишу позднее. Для тех, кому нужен загрузочный код zfsboot сейчас, то пропатченную версию из 8.2-STABLE можно взять здесь.
Так же, тестируя уже рабочий код zfsboot'а в virtualbox'е обнаружилась другая проблема - если в системе присутствует несколько дисков, а диск с пулом не является первым в списке BIOS'а, то не удаётся загрузиться выбрав устройство загрузки из меню BIOS'а. Возможно это особенность BIOS'а virtualbox'а. Если кто-то может проверить на реальном железе, буду рад комментарию.
Почти два дня я провел, совмещая работу и эксперименты в virtualbox'е. И это я ещё не все возможные варианты попробовал. У меня была виртуальная машина с 8.1-STABLE, я обновил её и оставил /usr/obj для установки собранной системы на другие образы дисков.
Первым вариантом для тестирования я выбрал ZFS пул, создаваемый на целом диске без использования таблиц разделов. Выбор пал на такую конфигурацию благодаря одному моему коллеге, которого я уже упоминал как-то в своём блоге. Он написал статью, обобщив свой опыт по установке FreeBSD на ZFS. Он же периодически подкидывает мне ссылки на обсуждение своей статьи. Там-то как раз и обсуждался такой метод установки. Установку можно описать буквально несколькими командами (набираю по памяти, мог что-нибудь забыть):
# zpool create z ad6 # zfs create z/root # cd /usr/src # make DESTDIR=/z/root installworld distribution installkernel # zpool set bootfs=z/root z # zpool set cachefile=/z/root/boot/zfs/zpool.cache z # cat > /z/root/boot/loader.conf zfs_load="YES" vfs.root.mountfrom="zfs:z/root" ^D # echo 'zfs_enable="YES"' > /z/root/etc/rc.conf # touch /z/root/etc/fstab # zfs set mountpoint=none z # zpool export z # dd if=/boot/zfsboot of=/dev/ad6 count=1 # dd if=/boot/zfsboot of=/dev/ad6 skip=1 seek=1024
Проблема подтвердилась сразу. Самое неприятное, что никакого удобного способа отладить загрузочный код я не видел. Единственное, что приходило на ум - читать код и вставлять printf'ы в определённые места, для того чтобы хоть как-то отслеживать процесс выполнения загрузочного кода.
Чтение исходников - это часто бывает полезным. Вот, например, объяснение последних двух команд - почему именно такие параметры? ;) Это можно понять из исходного кода.
Образ загрузочного кода zfsboot состоит из двух частей - zfsboot1 и zfsboot2. Первая часть предназначена для записи в первый сектор диска, куда BIOS обычно передаёт управление для загрузки системы. Грубо говоря, zfsboot1 - это образ MBR с небольшой частью загрузочного кода, который выполняет некоторые стандартные манипуляции для загрузчика, загружает zfsboot2, а так же предоставляет ему некоторые сервисные функции. Написан он на ассемблере. Вторая часть - zfsboot2, написана на Си. Она уже обладает значительно большим функционалом, и размер у неё, соответственно, побольше. В частности, она выполняет поиск ZFS пула и загружает из него zfsloader.
Так вот, первая команда dd выполняет запись zfsboot1 в первый сектор диска. Вторая команда выполняет запись zfsboot2 по смещению в 512 кбайт. Это место внутри ZFS во FreeBSD специально зарезервировано под загрузочный код:
/* * Size and offset of embedded boot loader region on each label. * The total size of the first two labels plus the boot area is 4MB. */ #define VDEV_BOOT_OFFSET (2 * sizeof (vdev_label_t)) #define VDEV_BOOT_SIZE (7ULL << 19) /* 3.5M */
Как видно из комментария, его размер может достигать трёх с половиной мегабайт. На данный момент в 9.0-CURRENT с ZFS v28 его размер чуть больше 32кбайт, но для "ровного" числа он создаётся размером 64 кбайт, в которых чуть меньше половины забито нулями, + 512 байт от zfsboot1.
Вернёмся к решению проблемы. Как мне стало известно из переписки с людьми, сообщившими о проблеме, не работает zfsboot в 9.0-CURRENT примерно с сентября 2010 года. А именно тогда туда были внесены крупные изменения. Методом printf'а я нашёл, что зависание происходит в функции drvread, которая вызывает код чтения секторов диска из zfsboot1. Сравнив содержимое этой функции с тем, что было до тех изменений было замечено всего одно маленькое отличие.
Я вернул убранную строчку и всё заработало. Попутно, была обнаружена ошибка в ассемблерном коде, появившаяся после внедрения ZFS v28. Сейчас я выполняю дополнительные тесты для проверки, не повлияет ли это изменение на другие варианты загрузки, о которых, возможно, напишу позднее. Для тех, кому нужен загрузочный код zfsboot сейчас, то пропатченную версию из 8.2-STABLE можно взять здесь.
Так же, тестируя уже рабочий код zfsboot'а в virtualbox'е обнаружилась другая проблема - если в системе присутствует несколько дисков, а диск с пулом не является первым в списке BIOS'а, то не удаётся загрузиться выбрав устройство загрузки из меню BIOS'а. Возможно это особенность BIOS'а virtualbox'а. Если кто-то может проверить на реальном железе, буду рад комментарию.
Спасибо, весьма познавательно. Сегодня по тупости второй раз наступил на эти грабли (первый раз вылезло где-то в январе'11).
ОтветитьУдалитьПравда сегодня заливал zfsboot у себя на буке на живой системе, включив предварительно kern.geom.debugflags=16. После ребута - описанная вами ситуация. Попытка реанимировать с помощью пропатченного zfsboot по вашей ссылке окончилась неудачей - при загрузке zfsboot: No ZFS pools located, can't boot
Такая же ситуация
ОтветитьУдалитьпри загрузке версии 32 кб zfsboot: No ZFS pools located.
версия zfsboot от 2011-Apr-11 16:29:17 64 kb пишет Read error
Диск в системе один
Нужно больше информации. Какая версия системы, пула, zfs, обнаруживается ли пул при загрузке с livecd, разметка диска в точности такая как описано тут или есть отличия?
ОтветитьУдалитьFreebsd 9 current
ОтветитьУдалитьZFS filesystem version 5
ZFS pool version 28
Да пул при загрузке с mfsbsd импортируется.
zfs list
dboot2 291G 1,05T 256G none
dboot2/mysql 84,4M 1,05T 4,22M /var/db/mysql
dboot2/mysql/ibdata 68,0M 1,05T 58,3M /var/db/mysql/ibdata
dboot2/mysql/iblogs 12,1M 1,05T 10,0M /var/db/mysql/iblogs
dboot2/swap 4,13G 1,06T 1,23G -
dboot2/tmp 73K 1,05T 39K /tmp
dboot2/usr 24,5G 1,05T 14,7G /usr
dboot2/usr/home 314M 1,05T 313M /usr/home
dboot2/usr/ports 7,14G 1,05T 320M /usr/ports
dboot2/usr/ports/distfiles 6,48G 1,05T 6,48G /usr/ports/distfiles
dboot2/usr/ports/packages 3,49M 1,05T 3,49M /usr/ports/packages
dboot2/usr/src 369M 1,05T 345M /usr/src
dboot2/var 5,60G 1,05T 5,27G /var
dboot2/var/crash 50,5K 1,05T 31,5K /var/crash
dboot2/var/db 292M 1,05T 191M /var/db
dboot2/var/db/pkg 25,1M 1,05T 19,1M /var/db/pkg
dboot2/var/empty 22K 1,05T 22K /var/empty
dboot2/var/log 27,0M 1,05T 26,0M /var/log
dboot2/var/mail 51K 1,05T 32K /var/mail
dboot2/var/run 188K 1,05T 104K /var/run
dboot2/var/tmp 350K 1,05T 258K /var/tmp
Грузилось и с вашего загрузичка (который был 32 кб)пока не сделал zfs upgrade до 5 версии файловой системы.
Тот zfsboot, что был 32кб - он из 8.2-STBALE, а ZFS v28 туда ещё не смерджили. Файл, который выложен сейчас - он из CURRENT, и он работает у меня. Попробуйте перезаписать ещё раз с правильными смещениями.. Больше посоветовать нечего, несколько человек мне отписывались о том, что он работает.
ОтветитьУдалитьПроблема решилась банальным zpool import c live-cd.
ОтветитьУдалить> anon комментирует...
ОтветитьУдалить>
> Такая же ситуация
> при загрузке версии 32 кб zfsboot: No ZFS pools located.
>
> версия zfsboot от 2011-Apr-11 16:29:17 64 kb пишет Read error
> Диск в системе один
Та же самая ситуация приключилась на боевом сервере в датацентре, только загрузочный пул из двух дисков в зеркале. Перед этим дважды протестировал сценарий обновления в VirtualBox-е - все нормально...
Правильное смещение это
ОтветитьУдалитьdd if=/boot/zfsboot of=/dev/ad1 count=1
dd if=/boot/zfsboot of=/dev/ad1 skip=1 seek=1024
?
Поясняю ситуацию
Грузилось с Вашего загрузчика 32кб после zpool upgrade, после zfs upgrade перестало грузиться и со старого (32кб) и текущим.
Перешел на gpt.
Андрей, подскажите,а как сейчас обстоят дела с этой проблемой?
ОтветитьУдалитьВчера ради экспериментов обновил тестовую машину до текущего 8.2-STABLE и перевел пул на 28-ю версию + фс на 5-ю. После этого система перестала грузиться ни с одним из загрузчиков. Сейчас глянул - ваш патч в STABLE уже присутствует, однако при старте получается все тот же "Read error"
Сейчас в списке рассылки freebsd-stable@ John Baldwin пытается отладить и решить эту проблему, можете проследить или поучавствовать. Тема: ZFS boot inside on the second partition inside a slice
ОтветитьУдалитьУ меня после обновления прошивки на двух из четырёх дисков, на каждом из которых первый раздел отдан под ZFS mirror с системой, перестало загружаться с ошибкой "ZFS: i/o error -all block copies unavailable". 9.0-BETA2.
ОтветитьУдалитьХотелось бы спросить, а что если пользователь создал пул не на том месте, где следовало и решил его удалить! Принудительное удаление через #zpool destroy -f ему никакого результата не принесло и по команде #zpool import все равно показывается пул, который вроде как убил! Подобное возникло у меня: http://sysadmins.ru/topic334772.html . Возникло когда учился ставить FreeBSD на MBR+ZFS и сейчас весит "артефакт", который вроде как работе не мешает, но тем не менее хочется убрать с глаз долой )
ОтветитьУдалитьДумаю для этого нужно перезаписать zfs vdev labels. Их всего 4, две вначале диска, две в конце. Каждая метка занимает 256к. Включая загрузочный код, это 4М в начале и 512к в конце.
ОтветитьУдалитьPS. Я не проверял, просто предположение.
Спрашивал в IRC, но пусть и тут будет, может кто проходя подскажет :)
ОтветитьУдалитьИмеется FreeBSD-CURRENT, установленна на root ZFS с таким вот разбиением
> gpart show
=> 34 625142381 ada0 GPT (298G)
34 128 1 freebsd-boot (64k)
162 26621952 2 freebsd-ufs (12G)
26622114 8388608 3 freebsd-swap (4.0G)
35010722 590131693 4 freebsd-zfs (281G)
Всё в общем то работает, но хотелось бы ещё каким то шаманством запускать иногда систему с ada0p2, а новый загрузчик напрочь утратил функцию загрузки по F1, F2..., да и вообще похоже хочет только zfs :(
Вариант с GRUB конечно есть, но как то уж очень не хорошо.
Проблема в том, что загрузочный код сейчас может грузить либо с ZFS - gptzfsboot, либо с UFS - gptboot. Поэтому со штатным загрузчиком не выйдет. Для нескольких UFS в на GPT можно установить аттрибуты bootme/bootonce для выбора с какой ФС грузиться, это не совсем удобно (в сравнении с F1..F2), но хоть что-то.
УдалитьПри выполнении zpool upgrade появляется подсказка, что нужно выполнить
ОтветитьУдалитьgpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da0
что делать если использовал zfsboot ?
На сколько я помню, единственным 100% работающим вариантом тут я вляется загрузка с livefs и проделывание манипуляций с dd. У меня есть незаконченный код, который будет это делать через "zpool bootcode", но пока он незавершён и времени на него пока нет...
Удалить