среда, 27 июня 2012 г.

Тестирование патчей для загрузчика

Прошло уже почти три месяца со дня публикации сообщения о патчах к загрузочному коду. И вот, на прошлой неделе я решил заняться этим вплотную. В итоге, создал бранч в SVN, куда стал коммитить свои наработки. Теперь все жалющие принять участие в тестировании могут это сделать :)

Историю изменений можно посмотреть здесь: http://svn.freebsd.org/base/user/ae/bootcode/
Патч относительно 10-CURRENT тут: http://people.freebsd.org/~ae/boot.diff

Какие изменения были сделаны:
  1. На основе кода, используемого в GEOM_PART были написаны функции, предоставляющий интерфейс для поиска таблицы разделов на носителе и выдачи информации о разделах.
  2. Было удалено много старого, дублирующегося кода.
  3. Похожий по назнаению код в "драйверах" дисков  загрузчика был унифицирован и объединён в нескольких функциях, а так же переписан с использованием нового API работы с таблицами разделов.
  4. zfsloader был научен использовать информацию о таблицах разелов, что значительно ускорило его работу на системах, в которых установлено много жёстких дисков.
  5. loader теперь умеет полноценно работать с GPT, т.е. проверяеят контрольные суммы, в случае необходимости умеет находить резервную копию GPT.
  6. В код PMBR так же внесены изменения, которые научили его находить резервную копию GPT, только CRC он не проверяет из-за ограничений на объём кода.
  7. gptboot и PMBR при обнаружении повреждений в заголовке основной таблицы GPT ищут резервную копию в последнем секторе. Если же там её нет, но есть метаданные GEOM класса, то они смотрят в предыдущем секторе. Т.е. теперь, иметь GPT внутри GEOM_MIRROR стало ещё безопаснее, даже в случае поверждения основной таблицы, загрузочный код сможет найти резервную.
На 9-ку патчи пока не накладываются, возможно после выходных avg@ сделает MFC нескольких своих изменений в коде, обеспечивающем загрузку с ZFS, тогда будет возможность тестировать и на STABLE.

понедельник, 2 апреля 2012 г.

Проблемы в работе zfsloader во FreeBSD

Сначала небольшой оффтопик - поддержка LDM уже включена во FreeBSD 10-CURRENT и в ближайшие пару недель будет перенесена в STABLE. В отличие от первоначальных патчей, текущая реализация умеет работать с дисками, размеченными GPT. А в остальном всё осталось примерно так же.

Теперь о теме сообщения. Возможно некоторые из вас замечали, что при загрузке FreeBSD c ZFS в качестве корневой файловой системы, наблюдается некоторая задержка между идентификацией дисков и началом загрузки ядра. Эта задержка в ряде случаев (например, большое количество дисков; много разделов; система в гостевой виртуальной машине) может составлять довольно ощутимое время.

Потратив некоторое время на изучение кода в каталоге sys/boot, могу сделать вывод, что работа нашего загрузчика zfsloader далеко не оптимальна. И корни этой проблемы растут с давних времён.

Во-первых, на данный момент из-за "ограниченности vs. универсальности" интерфейса libstand(3) нет никакой возможности определить количество найденных дисков из кода инициализации ZFS. Поэтому ZFS просто последовательно пробует открыть каждый диск поддерживаемый загрузчиком, а это 32 штуки (от "disk0:" до "disk31:").

Во-вторых, опять же, нет никакой возможности из кода инициализации ZFS узнать тип таблицы разделов и количество разделов в ней, чтобы проверить наличие ZFS на этих разделах. Поэтому выполняется простой перебор всех возможных разделов из диапазона от 1 до 128, например, выполняется попытка откыть "disk0p1:", если не удалось, то делается попытка открыть "disk0s1:" и т.д. до 128.

В-третьих, из-за привязанности к интерфейсу libstand(3), код работы с дисковыми устройствами выполняет чтение таблицы разделов, её проверку и т.д. на каждый вызов open(2). Т.е. когда код инициализации ZFS открывает "disk0:", затем открывает каждый его раздел. Все эти действия приводят к повторному чтению таблицы разделов.

Это частично компенсируется наличием уровня блочного кэша (да, даже у загрузчика он есть). Но размер его всего 16 кБайт, поэтому промахи имеют место быть, особенно для случая с GPT, когда таблица разделов занимает от 34 секторов.

В-четвёртых, для случая с GPT не проверяется ни контрольная сумма, ни резервная таблица с заголовком. Т.е. возможен вариант, когда у второй ступени загрузочного кода gptzfsboot и zfsloader будут разные представления о таблицах разделов.

В итоге, я написал вот такой вот патч, который решает часть проблем, но всё же далеко не идеален. Хотя, судя по отзывам увеличивает скорость инициализации загрузчика на порядок.

В идеале же хочется выделить логику работы с таблицами разделов (а он встречается в sys/boot не один и не два раза) в отдельные файлы с необходимым интерфейсом, не зависящим от libstand(3). Но пока работа в этом направлении идёт неспешно.

понедельник, 12 марта 2012 г.

FreeBSD и динамические диски Windows

Некоторое время назад в IRC обсуждалась тема невозможности доступа из FreeBSD к динамическим томам Windows, которые так же известны как тома LDM (Logical Disk Manager). Задача показалась мне интересной и вполне решаемой. В итоге, после проведения "обзора технической литераторы" и известных реализаций, оказалось, что формат метаданных не такой уж и тривиальный. К тому же, нет ниодной официальной публикации этого формата. Единственной информацией, похожей на документацию были описания от уже умершего проекта linux-ntfs. Реализация с открытым кодом тоже была одна, от того же проекта. Эта же реализация сейчас находится и в ядре linux. Ещё нашлась утилита от Марка Руссиновича, выводящая информацию о LDM и пара его публикация на эту тему.

По своим возможностям LDM напоминает LVM в linux. В качестве таблицы разделов LDM может предоставить порядка 2000 томов (нигде не нашёл точной информации, поэтому оценка дана изходя из размеров). Кроме функции таблицы разделов LDM может реализовывать RAID0, RAID1, RAID5, объединения из нескольких дисков, а также различные комбинации из перечисленного. Microsoft лицензировала LDM у Veritas, но по возможностям продукт Veritas более функциональный и изначально был доступен для UNIX. Ходят слухи, что у Microsoft и Veritas были какие-то судебные разбирательства из-за LDM. Но суть не в этом...

Метаданные LDM обладают некоторой избыточностью для отказоустойчивости. Во-первых, внутри группы дисков LDM хранит свои метаданные на каждом диске. Во-вторых, внутри самих метаданных некоторые структуры дублируются, а так же имеется журнал транзакций изменений внутри базы LDM. Для пользователей FreeBSD диск с LDM обычно выглядит как диск с MBR на котором имеются разделы с типом "ms-ldm-data" или его цифровой эквивалент "!66". Но, LDM может работать и с дисками, размеченными GPT. На них кроме раздела "ms-ldm-data" присутствует ещё раздел с типом "ms-ldm-metadata". Метаданные занимают 1 Мегабайт в конце диска. Кроме того, у дисков с MBR имеется ещё дополнительный заголовок в 6-ом секторе, по этому заголовку можно найти расположение основных метаданных. Как показала практика, находиться они могут не в самом конце диска.

Углубляться в строение я не буду, если интересно - можно почитать по ссылкам выше. Хотя, практические эксперименты выявили несколько несоответствий описания с реальностью.

В итоге, теперь чтобы получить доступ к разделам на LDM из FreeBSD можно воспользоваться написанным мною модулем geom_part_ldm. Модуль умеет находить и парсить базу LDM, и на основе прочитанной информации создавать разделы. Поддерживаются только простые тома, а так же зеркальные тома при установке переменной kern.geom.part.ldm.show_mirrors=1. Для реализации span/stripe/raid5 желающие вполне могут воспользоваться услугами класса GEOM_RAID :)

Если у кого-то возникнут проблемы с этим модулем, пишите. Есть желание включить его в head/, если никто не будет против.

пятница, 3 февраля 2012 г.

Проблемы при обновлении с FreeBSD 7+ до 9.0

Почти месяц прошёл со дня выхода FreeBSD 9.0 и уже (только сейчас!) появляются первые жалобы о неудачных обновлениях. Я буду говорить в первую очередь о том, что "сломал" я - это добавление проверок корректности метаданных в GEOM класс PART.
Эти проверки были добавлены более полугода назад. Расскажу (оправдаюсь) для чего они нужны. Во-первых, конечно же, что бы уберечь пользователей от потери данных, разного рода паник ядра, которые могут возникнуть когда информация в метаданных таблиц разделов не соответствует действительности. Например, когда границы нескольких разделов пересекаются, т.е. один раздел содержит в себе другой раздел или его часть; когда раздел выходит за физические границы носителя или частично перекрывает служебные данные таблицы разделов.

В общем, это те ситуации когда ядро не может решить что делать. Проверки эти были добавлены в базовый модуль и не зависят от типа таблиц (схем), поэтому касаются всех поддерживаемых таблиц разделов.

В версии FreeBSD 9+ система по-умолчанию отказывается работать с таблицей разделов, в которой будут обнаружены подобные несоответствия. Узнать об этом можно увидев при загрузке сообщение:
 GEOM_PART: integrity check failed (имя_провайдера, имя_схемы)
Если вам интересно, что же там не так, то можно включить режим verbose boot и тогда ядро напишет о всех несоответствиях, найденных в метаданных. Если этот диск не загрузочный, то режим можно включить через sysctl и выполнить retaste для диска, чтобы увидеть в консоли и в логах все сообщения:
# sysctl debug.bootverbose=1
# true > /dev/ada1
Что же делать, если вам непосчастливилось и у вас обнаружилась такая таблица разделов? В качестве временного решения можно отключить эти проверки через sysctl или loader.conf:

# sysctl kern.geom.part.check_integrity=0
Тогда система будет себя вести почти как раньше. Т.е. вы сможете получить доступ к данным, которые у вас были до этого на диске. Но вы не сможете делать изменения в таблице разделов, так как она будет отмечена как повреждённая. Это значит, что, исправить повреждения не удастся без полного уничтожения таблицы разделов. Кстати, запись загрузочного кода то же считается попыткой изменить таблицу разделов.

Теперь о жалобах после обновления. Возникают они обычно от тех пользователей, которые используют gmirror, созданный по методу: на готовой системе захотелось зеркало. Т.е. была система, добавили ещё один диск, переписали последний сектор и сделали зеркало.

А получилось, что раздел, размер которого был во весь диск, фактически уменьшился на 1 сектор, при этом, информация в таблице разделов осталась прежней. Если же в конце диска у вас было свободное пространство, то, скорее всего, никаких проблем при обновлении не будет.

Чтобы исправить эту проблему нужно пересоздать таблицу разделов на зеркале. Сделать это можно следующим образом:
  • удалить один компонент из зеркала и уничтожить таблицу разделов на нём;
  • создать новое зеркало на этом диске и уже на нём создать таблицу разделов;
  • создать разделы и файловые системы, записать загрузочный код, выполнить dump+restore данных со старого зеркала на новое;
  • выполнить необходимые правки в /etc/fstab и /boot/loader.conf (если необходимо);
  • перезагрузиться с нового зеркала, после этого уничтожить старое зеркало, таблицу разделов на нём и подключить диск в новое зеркало.
Пример последовательности команд описан в этом письме. Многие советуют мигрировать с конфигурации, в котрой используется зеркало из целых дисков, на GPT + несколько gmiror для разлных разделов, но мне кажется, что такая схема будет проигрывать по производительности, хотя для некоторых случаев может оказаться приемлимой.

Хочу сразу предупредить, что проверки целостности метаданных уже перенесены в ветку 8-STABLE, и в грядущем 8.3-RELEASE они уже будут присутствовать (который уже не за горами).  По-умолчанию проверки будут отключены, поэтому при обновлении разделы не будут неожиданно теряться. Но чтобы избежать этого в дальнейшем, рекомендую не забывать о правильной последовательности создания зеркала в новых установках системы.

Пользователям netmond хочу сообщить, что в текущей версии было исправлено несколько ошибок. Последнюю версию можно скачать тут.

воскресенье, 20 ноября 2011 г.

FreeBSD mini-summit в Москве

В субботу 19-го ноября в Москве, в офисе компании Рамблер прошёл "русскоязычный FreeBSD mini-summit". Организация этого мероприятия произошла довольно спонтанно, буквально три недели назад во внутренней рассылке Глеб Смирнов предложил провести встречу, подобную той, что была летом в Киеве, и вот - собралось почти 30 человек. Кроме коммитеров FreeBSD на саммите были гости из NetBSD, а так же интересующиеся ребята из Яндекса, Рамблера и Вадим Гончаров :).
 Планировалось, что каждый участник расскажет о том, чем занимается в данное время и, возможно, будет подготовлено несколько докладов. Так же, в планах было провести некоторое время за "хаканьем" кода, но, к сожалению, я уже не успел на этом поприсутствовать.
Итак, немного о темах докладов и обсуждений.
Глеб Смирнов (glebius@) рассказал о новой реализации CARP, почему ему не нравилась старая, что уже сделано и что ещё предстоит сделать. Во время обсуждения прозвучало несколько интересных вопросов и предложений, которые, как мне показалось, Глеб взял на заметку. 
Лев Серебряков (lev@) рассказал о своих проектах по переработке кода модуля geom_raid5 и системе оповещения о событиях в geom.
Александр Черников (melifaro@) рассказал для чего нужен MPLS, об уже проделанной работе по реализации поддержки MPLS во FreeBSD и bird, о текущих проблемах в интерфейсах ядра, тормозящих разработку.
Андрей Пантюхин (sat@) рассказал о проблемах в нашей систем управления rc.d и пытался выяснить какими решениями пользуются присутствующие для обхода этих проблем.
Сергей Скворцов (skv@) выступил с докладом о некритичных, но усложняющих жизнь проблемах в системе портов и предложил варианты по их решению.
Игорь Сысоев (автор nginx) рассказал о проблемах во FreeBSD, мешающих ему, как разработчику высокопроизводительного сервера, а так же поделился мыслями о том, какие API  ему хотелось бы видеть во FreeBSD.
Руслан Ермилов (ru@) задал вопрос присутствующим - нужен ли нам проект по переводу man-страниц? Сошлись на том, что проект нужен, но для продолжения этой работы необходимы свежие силы. Причём как среди переводящих, так и среди редакторов, и рецензентов.
В целом, мероприятие прошло успешно, но, половины дня для такого количества человек всё же было маловато.

вторник, 8 ноября 2011 г.

Ликбез по UEFI

Многие пользователи ПК имеют представление о том, что такое BIOS, для чего и как он работает. Но в последнее время появилась альтернатива, стремительно вытесняющая BIOS с наших ПК, а на серверном оборудовании уже прочно обосновавшаяся - это EFI и его более современный родственник UEFI.

Extensible Firmware Interface (EFI) впервые был предложен компанией Intel в качестве замены BIOS для своей новой 64-битной платформы IA64 (Itanium). Позднее Intel выпустила обновлённую спецификацию EFI 1.10, которая уже не привязывалась к платформе Itanium и могла использоваться для x86.

Чтобы труды Intel не пропали зря и народ обратил внимание на EFI был организован Unified EFI Forum, куда вошло несколько крупных компаний и который занялся дальнейшим развитием спецификации EFI. Чем он уже десять лет успешно занимается и на данный момент актуальной версией спецификации является UEFI 2.3.1.

Что же описывает эта спецификация? Честно говоря - МНОГО всего. Более 2000 страниц, и это только один из нескольких документов. UEFI firmware уже можно сравнивать с операционными системами. Для UEFI есть свои драйверы, свои сервисы и приложения. Даже есть свой шелл, который описан в отдельном документе UEFI Shell Specification. А вообще, конечно, идея правильная. Хорошо, когда всё стандартизовано и есть конкуренция, чего нельзя было сказать о BIOS.

Кстати, таблица GPT тоже описана в спецификации UEFI.

Итак, как же всё это работает? Разработчик аппаратной платформы пишет firmware, которая соответствует спецификациям UEFI и выполняет действия по описанным протоколам. Существует несколько инструментариев для разработчика связанных с UEFI компонентов. Некоторые из них - закрытые и коммерческие, некоторые - с открытым исходным кодом и свободно распространяемые. Разрабатывать firmware на ассемблере теперь нет нужды, хотя это тоже возможно. К интрументариям разработчика прилагаются все необходимые библиотеки и заголовочные файлы для разработки на языке Си. То же относится и к драйверам, и к EFI приложениям.

Так вот, эта firmware подобно BIOS помещается во flash память и в общем-то, цель у неё такая же - инициализировать оборудование для работы и передать управление операционной системе. Архитектурно она организована модульно и состоит из нескольких уровней, выполняющихся на различных этапах загрузки с момента включения питания. Подробную схему того, какие модули выполняются в какой момент времени, можно посмотреть в UEFI Platform Initialization Specification. Если в кратце, то это: предварительная инициализация памяти, процессоров, устройств и подготовка окружения для запуска следующих уровней firmware; загрузка драйверов устройств и запуск менеджера загрузки, который выполняет выбор устройства и запуск загрузчика операционной системы.

Для чего нужны драйверы? Драйверы должны поставляться производителями периферийных устройств. Они используются firmware для организации взаимодействия между устройством и UEFI приложением. С их помощью firmware может организовывать так называемые Runtime и Boot Services. Эти сервисы, в свою очередь, предоставляют набор функций, которые могут использовать UEFI приложения, сами драйверы, а так же загрузчик операционной системы.

Например, на сервере есть какой-то RAID контроллер с UEFI драйвером. Этот драйвер предоставляет базовые возможности доступа к содержимому своих RAID-массивов на блочном уровне через Boot Services. Т.е. например, загрузчик или какое-то другое UEFI приложение, используя определённые в спецификации API и протоколы, может прочитать информацию с тома RAID контроллера и, к примеру, выполнить загрузку ядра операционной системы. После загрузки ядро должно завершить работу с Boot Services и использовать свой полнофункциональный драйвер.

Другой пример - драйвер для сетевого адаптера может предоставить доступ к сети для загрузки операционной системы, либо для какого-то UEFI приложения, работающего с сетью. Эти драйверы могут предоставлять доступ к адаптеру не только в качестве Boot Services, но и как Runtime Services. Т.е. если у операционной системы нет драйвера для такого адаптера, то она может использовать стандартный API и продолжать работу с адаптером (на практике о таком использовании сетевых UEFI драйверов никто не слышал ;).

Вернёмся от драйверов к менеджеру загрузки. В его задачи входит выбор устройства загрузки и UEFI приложения в соответствии с настроенным порядком загрузки. Порядок определяется глобальными переменными из NVRAM, т.е. грубо говоря, настройками "BIOS". Например, если после инициализации UEFI firmware на сервере выбрать запуск меню настроек, то там отобразится список, порядок пунктов в котором будет выбран на основании этих самых глобальных переменных из NVRAM. В этом же списке могут оказаться дополнительные драйверы, загрузчики операционных систем, дополнительные UEFI приложения, найденные на EFI разделах дисков.

В спецификации UEFI в главе о таблице разделов GPT определены только два зарезервированных уникальных идентификатора GUID для типов разделов. Один из них используется для EFI System Partition. Этот раздел в таблице GPT используется для хранения дополнительных UEFI приложений, драйверов и загрузчиков операционных систем. Внутри этого раздела находится файловая система FAT с некоторыми дополнительными возможностями и требованиями. Сами же приложения представляют собой бинарники в формате PE/COFF (Microsoft Portable Executable and Common Object File Format).
Т.е. при желании можно смонтировать этот раздел и посмотреть, что там находится. Как, впрочем, и разместить там дополнительные приложения. Только необходимо поддерживать требуемую иерархию и именование файлов в файловой системе.

Дополнительные приложения могут выполнять самые разные функции. Например, это могут быть программы для диагностики оборудования, сетевые приложения, утилиты для работы с дисками и разделами, наконец - командный интерпретатор UEFI Shell.

суббота, 29 октября 2011 г.

Отчёт: Август - Октябрь

Последнее время на блог всё не находилось времени. Завал на работе, командировки, проверки, комиссии, отмена перехода на зимнее время... В общем, хочу рассказать обо всём понемногу.

Во-первых, хочу ещё раз поздравить Александра Черникова с награждением коммит битом за его настойчивость в продвижении своих патчей :).

По причине отсутствия времени и заморозки кода коммитил мало. Глядя на архив почты можно отметить:
  • добавление в man gpart секции BOOTSTRAPPING, посвящённой образам загрузочного кода, которые используется во FreeBSD с различными таблицами разделов;
  • исправления в gpart(8), fdisk(8), boot0cfg(8);
  • ликвидирована возможная в некоторых случаях паника в geom_part.
Что касается netmond, то всё что было "указано" в ТЗ - решено, заказчик доволен. Окончательную версию можно брать здесь.

Сейчас взялся за решение нескольких PR касающихся bsnmpd, в частности решил переделать реализацию доступа к информации о дисках и разделах в модуле hostres.

В geom_part_gpt была добавлена поддержка Boot Camp. Конфигурироваться из FreeBSD оно не может, но система может обнаруживать наличие Boot Camp и стараться не сломать его, если будут производиться какие-либо изменения в таблице GPT.

И ещё, после командировки заезжал в Москву, посетил офис Яндекса:



По внутреннему обустройству видно, что ребята живут на работе и им это нравится :)