Показаны сообщения с ярлыком GEOM. Показать все сообщения
Показаны сообщения с ярлыком GEOM. Показать все сообщения

вторник, 1 июля 2014 г.

Реализация disklabel64 для FreeBSD

В этом посте я хочу рассказать о не так давно добавленной поддержке disklabel64 в GEOM_PART. Эта "таблица разделов" используется в DragonFlyBSD. На сколько я могу судить по коду, используется она там по-умолчанию. Я не являюсь пользователем DragonFlyBSD, но не смотря на это, я подписан на их рассылку для разработчиков, в которую посылаются commit messages. Так как это всё же форк FreeBSD, то их кодовая база пока ещё довольно близка к FreeBSD и там бывают интересные коммиты.
disklabel64 является неким гибридом GPT и disklabel, используемой во всех BSD. Число 64 в названии намекает на то, что все смещения и размеры внутри метаданных являются 64-битными, в отличие от disklabel, где они были 32-битными. Ещё одно важное отличие - в 64-битной версии все смещения указаны в байтах, а не в секторах. Это, при соблюдении некоторых условий, должно позволить disklabel64 оставаться работоспособной при изменении размера сектора. Например, когда у вас есть диск, где размер сектора можно переключить перемычкой. Если создать disklabel64 на диске, у которого размер сектора 512 байт, а потом через некоторое время переключить его на 4096 байт, то для пользователя ничего не изменится. А в GPT такой трюк не получится. Полезность этого функционала конечно довольно сомнительна, но она заложена в дизайн.
По-умолчанию disklabel64 может иметь 16 разделов, но резервирует место для 32. Они так же как в disklabel именуются буквами латиницы. Но для совместимости со старым софтом, раздел 'с' недоступен для пользователя. Если кто-то не помнит, то раньше в disklabel этот раздел адресовал весь диск или раздел, на котором находится disklabel. В disklabel64 пользователь не может обратиться к области метаданных через разделы. Т.е. метаданные защищены от "самоуничтожения". В disklabel если вы специально не позаботились и не создали раздел 'a' со смещением относительно начала диска, то у вас имеется возможность уничтожить метаданные выполнив запись на раздел.
Сами разделы обзавелись UUID'ами. Каждый раздел имеет свой уникальный UUID. Тип раздела может быть указан двумя способами - так же как в disklabel при помощи 8-битного числа, либо как в GPT при помощи UUID. Сама disklabel64 тоже имеет UUID, а так же 64 байта для символьной метки. Т.е. при желании можно добавить соответствующую поддержку в geom_label и использовать эти UUID'ы как метки.
Место для загрузочного кода резервируется между метаданными и началом доступного пользователю места для создания разделов. По-умолчанию это 32 кбайта.
В метаданные заложена возможность наличия резервной копии, но пока что она нигде не реализована.

Если у вас установлена DragonFlyBSD, то теперь у вас есть возможность обратиться к её разделам. Если конечно вы используете UFS :)

понедельник, 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 хочу сообщить, что в текущей версии было исправлено несколько ошибок. Последнюю версию можно скачать тут.

среда, 27 июля 2011 г.

Доступ к образам дисков VirtualBox из host системы

В списке рассылки freebsd-emulation был задан вопрос "как получить доступ к содержимому образа диска от VirtualBox?". Задача показалась мне интересной.

Немного погуглив нашёл вот такое описание формата. Прочитав его, немного покопался в исходниках VirtualBox и вот, за пару вечеров написал GEOM модуль для доступа к этим образам.

Модуль простенький, рассчитан он на одну версию метаданных (хотя добавить старые версии не сложно, но лень и не на чем тестировать), предоставляет доступ только для чтения. Код можно посмотреть здесь. Пользоваться просто - загружаете модуль, подключаете образ диска через mdconfig и, теоретически, он должен обнаружиться и для него будет создан провайдер с суффиксом .vdi. Примерно вот так:

# make 
# make load
/sbin/kldload -v /usr/home/butcher/work/vbox/mod/geom_vdi.ko
Loaded /usr/home/butcher/work/vbox/mod/geom_vdi.ko, id=5
# sysctl debug.bootverbose=1
debug.bootverbose: 0 -> 1
# mdconfig -f 10G_GPT_UFS.vdi
md0
GEOM_VDI: valid signature detected.
GEOM_VDI: Provider md0.vdi created.
# gpart show md0.vdi
=>      34  20971453  md0.vdi  GPT  (10G)
        34       256        1  freebsd-boot  (128k)
       290   2097152        2  freebsd-swap  (1.0G)
   2097442   4194304        3  freebsd-ufs  (2.0G)
   6291746  14679741        4  freebsd-ufs  (7G)

# geom vdi list
Geom name: md0.vdi
dataoffset: 41472
blocksoffset: 512
blockscount: 10240
blocksize: 1048576
mediasize: 10737418240
Providers:
1. Name: md0.vdi
   Mediasize: 10737418240 (10G)
   Sectorsize: 512
   Mode: r0w0e0
Consumers:
1. Name: md0
   Mediasize: 468754944 (447M)
   Sectorsize: 512
   Mode: r0w0e0

четверг, 28 апреля 2011 г.

Метки разделов и выравнивание в gpart


На этой неделе я опубликовал два патча, в тестировании которых мне нужна помощь, возможно, среди читателей найдутся желающие :)

Первый патч предназначен для решения проблемы с метками разделов, которые, как известно, реализуются сейчас классом GEOM_LABEL. Основная проблема в том, что для приемлемой работы с метками GEOM_LABEL предъявляет некоторые требования к провайдерам. Например, обнаружение меток GEOM_LABEL выполняет только во время tasting. Изменение меток может быть обнаружено только при условии использования механизма spoiling с последующим retaste. Что при существующей реализации класса GEOM_PART не представляется возможным.
Класс GEOM_PART управляет таблицей разделов и метки этих разделов хранятся в таблице, а не на провайдере раздела. Поэтому, при изменении метки механизм spoiling'а не запускается для провайдера раздела.

Предлагаемый мной патч отключает реализацию меток gpt/gptid в GEOM_LABEL и добавляет новый класс PART::LABEL. Он тесно связан с классом PART и, кроме того, имеет несколько функциональных отличий от GEOM_LABEL. Во-первых, он не использует механизм tasting, объекты класса и его провайдеры создаются по инициативе класса PART. Во-вторых, он не использует механизм spoiling, поэтому его провайдеры существуют всё время, а не исчезают, когда какой либо связанный провайдер начинает использоваться. Благодаря этому устраняется проблема с изменением меток, которые становятся видны сразу после изменения. И, на мой взгляд, удобнее, когда метки в /dev существуют всегда. К тому же, кроме реализации gpt/gptid я добавил поддержку меток в схемы PC98 и APM.

Я планирую включить этот патч в head/ примерно через неделю. Второй патч не вносит изменений в ядро. Он добавляет к утилите gpart(8) новую опцию "-а alignment", при использовании которой gpart выполняет выравнивание создаваемых разделов на заданную величину. Например так:

# gpart create -s gpt md0
md0 created
# gpart show md0
=>    34  409533  md0  GPT  (200M)
      34  409533       - free -  (200M)

# gpart add -t freebsd-boot -s 128k -a 4k md0
md0p1 added
# gpart add -t freebsd-ufs -s 60m -a 4k md0
md0p2 added
# gpart add -t freebsd-ufs -a 4k md0
md0p3 added
# gpart show md0
=>    34  409533  md0  GPT  (200M)
      34       6       - free -  (3.0K)
      40     256    1  freebsd-boot  (128K)
     296  122880    2  freebsd-ufs  (60M)
  123176  286384    3  freebsd-ufs  (139M)
  409560       7       - free -  (3.5K)

понедельник, 20 декабря 2010 г.

GEOM: практические знания. Часть 2.

Продолжить начатую ранее тему устройства GEOM я хотел бы с таких понятий как tasting, orphanization и spoiling. Для пользователя системы наиболее интересным наверно покажется первый термин. Tasting - это процесс автоматической настройки geom объектов. Этот процесс инициируется подсистемой GEOM каждый раз, когда создаётся новый GEOM класс или провайдер. С точки зрения алгоритма работы эти два случая немного различаются, так tasting при создании нового провайдера выглядит примерно так:
  1. Ядро проходит в цикле по списку известных ему GEOM классов.
  2. Для каждого из них вызывается метод класса taste, который уже в зависимости от реализации класса может создать новый geom объект, либо посчитать этот новый провайдер неподходящим для использования классом.
В случае, когда создаётся новый класс, алгоритм такой:
  1. Ядро проходит в цикле по списку известных ему GEOM классов.
  2. Для каждого класса просматривается каждый существующий geom объект и все его провайдеры, которые передаются на проверку в метод taste для нового класса. А тот уже решает, подходит ему этот провайдер или нет.
Таким образом сделана возможность своего рода "plug-and-play". При загрузке модуля ядра, реализующего какой-то новый GEOM класс, у него имеется возможность автоматически найти нужный провайдер и начать выполнять свои действия.

Рассмотрим пример возможного сценария работы tasting при обнаружении жесткого диска:
  1. Драйвер жесткого диска создаёт geom объект ada0 класса DISK, тот в свою очередь создаёт провайдер ada0.
  2. Создание провайдера инициирует tasting. Последовательность может отличаться, но мы предположим такое развитие событий - вызывается метод taste класса DEV. Этот класс служит для создания файлов устройств в файловой системе devfs. Т.е. это его мы можем поблагодарить за создание /dev/ada0 (стоит заметить, что этот класс не создаёт своих провайдеров).
  3. На этом процесс tasting не заканчивается. Предположим, что в списке классов, которые знает ядро, следующим стоит класс PART. Ядро вызывает метод taste этого класса, он считывает секторы этого провайдера, в которых могут находиться таблицы разделов, и проверяет есть ли они там. Если есть, то создаются новые провайдеры, в соответствии с таблицей разделов. Это, в свою очередь, опять же инициирует tasting.
Многие GEOM классы (не все) хранят свои метаданные на диске, обычно для этого используется один последний сектор. Метод taste этих классов считывает нужный классу сектор провайдера и проверяет считанные данные, если он находит там метаданные класса, он предпринимает какие либо действия. Чтобы пользователь случайно не повредил метаданные, размер создаваемого классом провайдера обычно меньше на один сектор. Например, когда вы создаёте зеркало на основе класса MIRROR, то размер итогового mirror/gm0 будет на один сектор меньше, чем размер провайдеров, из которых он состоит. Повреждение, перезапись последнего сектора, изменение размера провайдера или размера сектора - всё это приводит к тому, что метод taste не обнаружит свои метаданные на провайдере, а значит и не будет создан geom объект этого класса. Поэтому, если вы задумали нечто такое - не удивляйтесь последствиям :)


Про tasting сказать вроде больше нечего, перейдём к orphanization. Это обратный tasting процесс, во время которого провайдеры уничтожаются. В переводе orphanization означает "осиротение" и это не просто так. Например, когда вы отключаете жесткий диск, драйвер диска посылает классу DISK команду на уничтожение. Тот, в свою очередь, инициирует процесс "осиротения" и все объекты geom, связанные с провайдером диска через консьюмеров "информируются" о том, что они стали "сиротами". Им передаётся код ошибки, который будет возвращён пользователю при любых попытка взаимодействия с осиротевшими провайдерами. Т.е. если вы попробуете записать данные на такой провайдер, то получите ошибку. Информирование выполняется через вызов базового для всех классов метода orphan, в реализации которого разработчик может предусмотреть действия, необходимые для завершения работы объекта. Ну и заканчивается этот процесс самоуничтожением всех осиротевших провайдеров и объектов. Если не углубляться в особенности реализации, то можно сказать, что "оно" всё делает "само". Само находит что ему нужно во время tasting, само уничтожается во время orphanization :)

Теперь рассмотрим spoiling. Этот механизм предназначен для защиты от устаревших метаданных. Стоит понимать, что защащются здесь не метаданные, а находящийся в памяти geom объект. Так как система оперирует с данными в памяти, важно чтобы они были синхронизированы с метаданными на диске.

Ранее я рассказывал о счётчиках доступа, которые по-совместительству служат для ограничения доступа. Этими же счётчиками подсистема GEOM пользуется для активации механизма spoiling. Когда кто-либо обращается к провайдеру, он явно или неявно вызывает функцию g_access, в которой указывается желаемый режим доступа. Например, вы записываете что-то на диск, для этого вам нужно получить "разрешение" на запись, при этом счётчик w увеличивается. Как только вы прекращаете запись - счётчик уменьшается. Переход состояния счётчика w из нуля в значение большее нуля вызывает механизм spoiling. При этом все консьюмеры этого провайдера предупреждаются о том, что кто-то открыл провайдера для записи. Никто не знает, что вы туда будете записывать, но если geom объекту это важно (там могут быть его метаданные), то он примет информацию к сведению. Обычно "принять к сведению" означает, что geom объект самоуничтожится (так же, как он это делает во время orphanization). Но стоит вам завершить запись, чтобы значение счётчика w перешло в ноль, будет иницирован процесс re-tasting по алгоритму, используемому при создании нового провайдера.

Таким образом срабатывает защита от устаревших метаданных. Если вы измените метаданные, или же просто произведёте запись не связанную с ними, то GEOM класс, использующий провайдера, заново обнаружит свои метаданные на нём и автоматически сконфигурируется. Если же вы удалите или повредите метаданные, то spoiling уничтожит geom объект, использующий провайдер. Жизненный пример на эту тему - gpart vs. bsdlabel:

# gpart show md0 md0s1
=>     9  204786  md0  MBR  (100M)
       9  204786    1  freebsd  (100M)

=>     0  204786  md0s1  BSD  (100M)
       0   51200      1  freebsd-ufs  (25M)
   51200   51200      2  freebsd-ufs  (25M)
  102400   51200      4  freebsd-ufs  (25M)
  153600   51186         - free -  (25M)

# bsdlabel -w md0s1
# gpart show md0 md0s1
=>     9  204786  md0  MBR  (100M)
       9  204786    1  freebsd  (100M)

=>     0  204786  md0s1  BSD  (100M)
       0      16         - free -  (8.0K)
      16  204770      1  !0  (100M)

В первом выводе gpart show есть два geom объекта класса PART. md0 - представляет таблицу разделов MBR, а md0s1 - является партицией MBR, провайдером объекта md0, и, в то же время, содержит разметку BSD. Выполнив bsdlabel -w мы выполнили запись на раздел md0s1, изменив метаданные объекта md0s1. При этом, в момент вызова команды bsdlabel она открыла провайдера md0s1 для записи, что инициировало spoiling - самоуничтожение объекта md0s1 и всех его партиций. После завершения записи на провайдере md0s1 снова были найдены метаданные разметки BSD, но на этот раз там один раздел.

Ещё один пример, эксплуатирующий эти особенности GEOM - это запуск механизма re-tasting в ручную. Хотя, честно говоря, мне он ниразу не понадобился, но в списках рассылки вчтречаются люди, которым это нужно. Делается это просто, нужно всего лишь "открыть" провайдер для записи и "закрыть" его, например так:

# true > /dev/ada2 

Это инициирует re-tasting и GEOM классы заново "обследуют" этот провайдер.


На этом пока всё. На счёт продолжения не уверен, но, возможно, будет ещё одна заметка.

    пятница, 10 декабря 2010 г.

    GEOM: практические знания. Часть 1.

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

    Начнём с определений. Что такое GEOM класс? Классом он называется в связи с похожестью на классы в Си++. Т.е. это некоторая структура, содержащая в себе методы-функции которые реализуют возможности этого класса. Набор методов стандартный для всех классов. Грубо говоря, разработка какого-то нового класса - это новая реализация этих методов.

    GEOM класс может иметь объекты (а может и не иметь). Если проводить аналогии с классами Си++, то это переменные этого класса. Например, есть GEOM класс MIRROR, он предоставляет возможность создавать зеркала. Когда вы загружаете модуль ядра, либо он у вас вкомпилирован туда, то ядро "знает" о существовании такого класса. Но когда вы создаёте зеркало, вы создаёте объект этого класса.

    Каждый объект geom может иметь "провайдера" (provider), даже несколько. Провайдер, это в общем-то то, ради чего GEOM и придуман. Они предоставляют пользователю услугу реализуемую GEOM классом. Тот же GEOM класс MIRROR предоставляет нам провайдера, например mirror/gm0, работая с которым мы получаем "услугу", реализующую программное зеркало.

    Другим важным понятием является консьюмер (consumer). Консьюмер - это то, через что geom объект получает доступ к провайдерам других объектов geom. Пример: у вас есть два жестких диска. Кстати говоря, драйверы дисков создают geom объекты класса DISK. Вы можете выполнить команду "geom DISK list", чтобы просмотреть информацию об объектах класса DISK:

     > geom DISK list
    Geom name: ada0
    Providers:
    1. Name: ada0
       Mediasize: 41110142976 (38G)
       Sectorsize: 512
       Mode: r0w0e0
       fwsectors: 63
       fwheads: 16
    
    Geom name: ada1
    Providers:
    1. Name: ada1
       Mediasize: 163928604672 (153G)
       Sectorsize: 512
       Mode: r2w2e5
       fwsectors: 63
       fwheads: 16
    
    Как видно, у меня тут два диска ada0 и ada1. Они у меня разные да и заняты данными, так что портить для демонстрации я их не буду. Создам два идентичных объекта класса MD:

    # mdconfig -s 100m
    md0
    # mdconfig -s 100m
    md1
    # geom MD list
    Geom name: md0
    Providers:
    1. Name: md0
       Mediasize: 104857600 (100M)
       Sectorsize: 512
       Mode: r0w0e0
       type: swap
       length: 104857600
       fwsectors: 0
       fwheads: 0
       unit: 0
    
    Geom name: md1
    Providers:
    1. Name: md1
       Mediasize: 104857600 (100M)
       Sectorsize: 512
       Mode: r0w0e0
       type: swap
       length: 104857600
       fwsectors: 0
       fwheads: 0
       unit: 1
    Как видно из вывода команд, у нас есть два объекта md0 и md1, у каждого из них по одному провайдеру, соответственно md0 и md1. Теперь, при создании geom объекта класса MIRROR его консьюмеры подключатся к провайдерам объектов md0 и md1, и будет создан провайдер mirror/gm0:

    # gmirror label gm0 md0 md1
    # geom MIRROR list
    Geom name: gm0
    State: COMPLETE
    Components: 2
    Balance: load
    Slice: 4096
    Flags: NONE
    GenID: 0
    SyncID: 1
    ID: 7231867
    Providers:
    1. Name: mirror/gm0
       Mediasize: 104857088 (100M)
       Sectorsize: 512
       Mode: r0w0e0
    Consumers:
    1. Name: md0   Mediasize: 104857600 (100M)
       Sectorsize: 512
       Mode: r1w1e1
       State: ACTIVE
       Priority: 0
       Flags: NONE
       GenID: 0
       SyncID: 1
       ID: 2647920667
    2. Name: md1
       Mediasize: 104857600 (100M)
       Sectorsize: 512
       Mode: r1w1e1
       State: ACTIVE
       Priority: 1
       Flags: NONE
       GenID: 0
       SyncID: 1
       ID: 4248479672
    
    Думаю этого должно быть достаточно для понимания, если недостаточно, попробуйте прочитать ещё раз :)

    Глядя на вывод команды geom <КЛАСС> list можно увидеть много полезной информации, для каждого класса "полезность" определил разработчик, поэтому у каких-то классов больше, у других - меньше, у третьих вообще ничего нет...

    Я бы хотел обратить внимание на строку содержащую слово "Mode:" и набор букв с цифрами. Она есть у всех провайдеров и консьюмеров и показывает режим доступа, который осуществляется по отношению к ним на данный момент. В первом выводе "geom MD list" режим доступа к провайдерам отображается как "r0w0e0". Это означает, что никто не пытается с них читать (r = 0), никто не пытается на них записывать (w = 0) и никто не пытается получить эксклюзивный доступ к ним (e = 0).

    Эти счётчики служат не только для отображения информации о текущем состоянии провайдеров и консьюмеров. Они так же являются ограничителями доступа. Например, если кто-то уже получил эксклюзивный доступ к провайдеру, то любой другой желающий получить доступ к нему будет "обрадован" сообщением об ошибке EPERM - "Operation not permitted". Наверное, многие из вас сталкивались с этим сообщением при попытке записать загрузочный код на провайдер, который содержит смонтированные разделы. Именно эта "защита от прострела ноги" отключается переменной "kern.geom.debugflags=16".

    Если выполнить команду "geom MD list" сейчас, после создания зеркала на них, то мы увидим, что у провайдеров изменился режим:

    # geom MD list
    Geom name: md0
    Providers:
    1. Name: md0
       Mediasize: 104857600 (100M)
       Sectorsize: 512
       Mode: r1w1e1
       type: swap
       length: 104857600
       fwsectors: 0
       fwheads: 0
       unit: 0
    
    Geom name: md1
    Providers:
    1. Name: md1
       Mediasize: 104857600 (100M)
       Sectorsize: 512
       Mode: r1w1e1
       type: swap
       length: 104857600
       fwsectors: 0
       fwheads: 0
       unit: 1
    
    Это постарались консьюмеры объекта mirror/gm0. Т.е. теперь, эти провайдеры защищены от случайной записи с вашей стороны, а значит и объект mirror/gm0 не будет неприятно удивлён испорченными данными. Поэтому использование "kern.geom.debugflags=16" является плохой практикой.

    ... Продолжение следует ...

    четверг, 29 апреля 2010 г.

    sade - редактор диска, часть 5.

    Немного новостей о ходе работы. Марсель закоммитил два исправления, о которых я упоминал ранее. Теперь, вроде бы нет препятствующих разработке багов.

    Я же выделил код и объявления структур и функций для работы с устройствами, партициями и файловыми системами в отдельную группу файлов. Позже оформлю их в виде библиотеки. Написал код для получения информации о файловых системах и сохранения его в список, которой используется внутри редактора файловых систем. Сделал базовую реализацию редактора, пока что он отображает список партиций имеющих тип freebsd-swap и freebsd-ufs:
    На список команд не обращайте внимание, это copy-paste из редактора партиций. В принципе, кроме того что видно в списке сейчас, информационная структура хранит ещё данные о том смонтирована ли файловая система и опции монтирования из /etc/fstab.
    Сделал так же проверку на наличие меток glabel, под которыми данное устройство может быть смонтировано или записано в fstab. Правда пока эта проверка достаточно формальная, потому как перебрать все возможные метки какие могут быть - достаточно нетривиальная задача.

    Дальше буду думать, какие команды добавить в этот редактор и потихоньку их реализовывать.
    Ещё надо что-то придумать с механизмом commit/undo для этого редактора. Небольшой набросок механизма ведения истории действий с возможностью отката и сохранения я сделал, но ясной картины как я буду его использовать пока нет.

    пятница, 23 апреля 2010 г.

    gpart resize - лёд тронулся.

    Ну вот, переодическое "капанье на мозг" :-) дало первые результаты. Marcel закоммитил мой патч, добавляющий поддержку изменения размера провайдеров внутри схемы. Константин Белоусов (kib@) посоветовал не забыть через некоторое время напомнить ему сделать MFC. Думаю недельки через 3-4 можно будет начинать "напоминать" :-)

    А пока, отправил ему письмо с благодарностью и ссылками на следующие два патча :-)

    gpart recover - восстановление таблицы GPT

    Когда я писал патч для изменения размеров партиций, я пытался решить свою задачу, что, в принципе, мне удалось. Тут в списке рассылки freebsd-geom@ появился человек, заинтересованный в изменении размера носителя, на котором находится схема GPT. У него используется RAID контроллер, который позволяет наращивать дисковое пространство, что-то вроде `zpool attach`. Вставил ещё диск, подключил его к рейду и вот - у тебя уже больше свободного места. Проблема только в том, что GPT хранит две копии метаданных - в начале диска и в конце.
    Соответственно, после увеличения размера носителя, вторая копия будет находится уже не в конце и система при подключении этой GPT схемы выдаст в лог такие строчки:
    GEOM: md0: the secondary GPT table is corrupt or invalid.
    GEOM: md0: using the primary only -- recovery suggested.
    Но, на данный момент, штатной возможности восстановить метаданные нет. Она есть в планах на wiki.freebsd.org. И я уже спрашивал Марселя о том, что он думает на этот счёт, но ответа не получил. Поэтому немного почитав код реализации схемы GPT, сделал набросок патча, который помимо восстановления метаданных позволяет выполнять такую "махинацию" с изменением размера носителя. Патч и пример использования можно посмотреть тут.

    четверг, 22 апреля 2010 г.

    sade - редактор диска, часть 4

    После небольшого перерыва решил продолжить эпопею с sade.

    От marcel@ по прежнему тишина, поэтому думаю придётся отказаться от использования geom_part.so в пользу libgeom. В связи с этим предстоит частичное дублирование кода из geom_part.so у себя. В основном это будет код записи загрузочного кода и автоподбора параметров. Но зато стандартно и без лишних костылей...

    После непродолжительных обсуждений в IRC и некоторого обдумывания придумал, как примерно будет выглядеть интерфейс для работы с ZFS и создания файловых систем. К тому же решил, что будет полезной возможность создания RAID при помощи GEOM классов. Поэтому добавил главное меню, в котором пока 3 пункта:
    [Image]
    Пока что работает только второй, но дело сдвинулось с мёртвой точки.

    По моей логике работа с sade будет выглядеть примерно так:
    1. Сначала пользователь может зайти в раздел RAID (если ему нужно это) и там выбрать устройства, которые он планирует объединить в RAID. Причём кроме обычных gmirror и gstripe думаю туда же добавить и возможность создания ZFS пула из нескольких устройств (т.е. mirror, raidz, raidz2). Возможно стоит туда же втиснуть возможность конфигурирования gjournal, geli,... Но про последние пока не думал, да и не использовал я их по сути.
    2. После создания конфигурации для RAID, либо сразу, если она не нужна, пользователь заходит во второй пункт. Тут уже открывается список устройств, из которых можно выбрать только одно (единовременно) и дальше типовой функционал gpart. Создание схемы, добавление партиций на неё и запись загрузочного кода. Сюда же входит создание разметки BSD. Для ZFS будет отдельный редактор, больше похожий на редактор файловых систем. Он будет открываться при выборе ZFS пула из списка устройств. Или когда пользователь выберет в списке возможных схем "создание ZFS пула".

      Вообще, работу с ZFS думаю реализовать по аналогии с партициями. Создание пула соответствует созданию схемы, а создание датасетов - созданию партиций. Т.е. например, когда в редакторе партиций нажать Enter на партиции с типом freebsd-zfs, то будет предложено создать пул на ней (если конечно там его ещё нет), после чего откроется редактор ZFS, в котором можно создавать датасеты.
    3. После создания партиций пользователь должен будет выйти в главное меню и выбрать третий пункт. Это будет тоже отдельный редактор, над созданием которого сейчас я начинаю работать. Это будет список, пока я планирую выводить 4 столбика:
      имя_провайдера<--->тип_ФС<--->Размер<--->Точка монтирования

      В список поддерживаемых ФС пока планирую включить: ufs, zfs, swap. Ещё там может отображаться "empty" и "unknown". "empty" для свежесозданных партиций, а "unknown" для случая когда нет прав для того чтобы определить тип ФС или ещё чего-то непредвиденного.
    Вот как-то так..

    воскресенье, 11 апреля 2010 г.

    sade - редактор диска, часть 3

    По совету Константина (kib@) опубликовал RFC в списках рассылки freebsd-current@ и freebsd-geom@ на тему переписывания sade(8). Как оказалось я не единственный, кто этим занимается, но другим, пока что, показать совсем нечего. Поэтому решил продолжать сам.

    Закончил все функции редактора и нашёл ещё один "полубаг" в реализации схемы APM. Класс не находит метаданные схемы APM, если после её создания не было создано ниодной партиции. Но в общем-то это не так страшно.

    Из плюсов этого RFC было то, что ответил Marcel. Написал что он очень занят, но патчи нужно всётаки коммитить, попросил переслать всё, что я ему посылал до этого. Переслал. Опять тишина...

    Исправил баг в схеме MBR, который вызывал панику при отмене удаления схемы. Модифицировал подобным же образом все схемы, которые могут зависеть от геометрии провайдера. Ответа пока тоже нет...

    Выложил всё, что накодил для sade вместе со скриншотами. Если кто желает, можете потестить, только осторожно, механизмы вызова паники я вроде бы описывал ранее.

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

    По загрузочному коду довольно много неясности вносит наличие множества различных вариантов и отсутсвие опыта использования большинства из них :)
    Для разных схем есть различные реализации загрузочного кода, из которых сам я пробовал только mbr и boot0 для MBR схемы, и gptzfsboot с pmbr для схемы GPT. А ведь есть ещё и другие схемы, которые используются на аппартных архитектурах, которые я вообще не видел, таких как PC98 и APM. Наверное, сделаю только то, что сам пробовал, а дальше уж видно будет.

    По файловым системам тоже пока вопросов больше чем ответов. По сути, FreeBSD работает только с двумя файловыми системами - UFS и ZFS. С ZFS отдельная история, так как она не обычная файловая система, а ещё и в некоторой степени LVM. Поэтому, думаю что стоит начать с реализации только UFS. Дальше опять вопросы - где должен быть реализован функционал создания файловых систем? Внутри редактора партиций или же в отдельном редакторе? С точки зрения моей логики, вроде бы удобнее создать файловую систему сразу после создания партиции. Но опять же, куда в редакторе размещать все элементы интерфейса? Где отображать точку монтирования, опции для newfs и т.п.?

    Короче, работы ещё полно...

    среда, 7 апреля 2010 г.

    sade - редактор диска, часть 2

    Фреймворк для создания "нестандартных" диалогов практически готов, по крайней мере он почти обеспечивает мои текущие нужды. Называется он "customdlg". Появилось пара мыслей по его улучшению, но это пока можно отложить на будущее. Как говорится - нет предела совершенству :).

    После фреймворка я продолжил реализацию оставшихся функций редактора партиций. На данный момент уже работают:
    • Create Slice - создание партиций;
    • Delete Slice - удаление партиций; когда все партиции удалены эта же команда предлагает уничтожить текущую схему (gpart destroy);
    • Undo All Changes - отмена несохранённых изменений (gpart undo);
    • Write Changs - сохранение изменений на провайдер (gpart commit);
    • Set Active - установка аттрибута активной партиции для схем MBR и PC98 (gpart set -a active);
    • Inspect Slices - откытие субредактора партиций для схемы BSD, т.е. если имеется партиция с типом "freebsd" то нажав на ней Enter открывается тот же редактор партиций (если необходимо, с предложением создать схему BSD на провайдере) но слегка ограниченный.
    В принципе, нереализованными остались только команды "Change Type" и "Set Label", которые я решил объединить в один диалог. Но это дело получаса работы. И тогда можно будет анонсировать куда-нибудь в freebsd-hackers@ или freebsd-geom@, посмотреть что люди думают, может какие-то предложения будут дельные.

    Да, ещё.  В процессе реализации функционала и тестирования было обнаружено два бага в реализации класса PART. Первый заключается в том, что созданную схему "BSD" и "VTOC8" нельзя отменить при помощи команды "gpart undo". Эту проблему я решил, осталось дождаться, что ответит мэйнтейнер gpart. Ну и второй - он уже более неприятен. После создания схемы MBR без разделов, попытке удалить её и отменить удаление, в модуле geom_part_mbr происходит деление на ноль и паника. Покопавшись немного простого решения не нашёл, пока открыл PR. Если Marcel до завтра не ответит, буду пытаться решать сам.

    четверг, 1 апреля 2010 г.

    sade - редактор диска

    После изучения GEOM класса PART и беглого просмотра кода редактирования слайсов в sysinstall и "отпочковавшегося"  от него sade, захотелось научить их делать это "правильно" :)

    Но чем дальше я читал код sade и думал как бы его лучше изменить, тем всё грустнее мне казалась эта перспектива. Поэтому я начал с малого, набросал код функций для типовых операций, проводимых с диском. Сначала это были функции получения списка устройств, пригодных для разметки, и получения таблицы партиций на устройстве. Эти действия легко реализуются при помощи libgeom. Попутно изучал более подробно код sade и пробовал различные примеры по использованию libdialog и ncurses.

    Когда встала задача написания функций редактирования таблиц партиций, то мне показалось целесообразным использовать уже написанный код библиотеки geom_part, которая используется утилитой gpart(8). Всё бы ничего, но как оказалось, библиотека не предназначена для этого. Т.е. в рамках приложения gpart(8) она это вполне успешно делает, но вот из своего приложения её использовать нельзя, так как библиотека обрабатывает ошибки при помощи вызовов err(3) и abort(3). Пришлось отучить её от этого, после чего получилось использовать её код.

    В своих же функциях мне просто осталось правильно сформировать запрос, заполнив нужные параметры, и вызвать функцию из библиотеки geom_part.

    Очень полезной оказалась и встроенная поддержка отложенных операций в классе PART, т.е. из своего приложения можно выполнять различные действия с таблицей партиций, а при необходимости можно сделать откат, либо сохранить все изменения на диск.

    Далее я принялся за интерфейс пользователя. По-началу дело шло неплохо. Вот так к примеру выглядит окно выбора устройств:
    Приятным бонусом от использования libgeom стало появление в списке устройств различных GEOM провайдеров. Вообще, полный список поддерживаемых устройств выглядит так:
            {"DISK",        "disk device"},
            {"MD",          "memory backed virtual disk"},
            {"ZFS::ZVOL",   "ZFS volume"},
            {"MIRROR",      "GEOM based mirror (RAID1)"},
            {"STRIPE",      "GEOM based stripe (RAID0)"},
            {"RAID3",       "GEOM based RAID3 array"},
            {"CONCAT",      "GEOM based concatenated disk"},
            {"ELI",         "GEOM based encrypted disk"},
            {"JOURNAL",     "GEOM based journalled disk"},
            {"MULTIPATH",   "GEOM based disk with multiple path"},
    
    Список редактируется легко, так что добавить новое, либо что-то убрать из него не составить труда.
    После выбора устройства по логике должен открываться редактор партиций, за основу я взял существующий в sysinstall и sade, но слегка изменил и улучшил его. Вот так он выглядит:
    Пока что он ничего полезного не делает, кроме отображения списка партиций и навигации по нему. В дополнение к этому я сделал ещё один диалог, который открывается при выборе устройства, на котором ещё нет таблиц партиций:
    После выбора типа таблицы она создаётся на носителе и открывается редактор партиций.

    Вот. Это пока то, что удалось реализовать без особых сложностей. Теперь встала задача добавления новых диалогов. Как оказалось библиотека libdialog предоставляет довольно скудные возможности для создания диалогов, отличающихся от стандартных. А те что предоставляет, выглядят как-то "топорно". Поэтому... Пишу вот сейчас некий "фреймворк" для создания нестандартных диалогов. Вот таким, к примеру, планируется диалог добавления нового слайса:
    БОльшая часть "фреймворка" уже написана. Осталось немного и можно будет продолжить реализовывать функции редактора партиций. Ну и ещё остались пока нерешённые вопросы:
    1. Что делать с ZFS?
    2. Как создавать файловые системы, надо ли их монтировать, надо ли их в fstab прописывать и т.п.

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

    gpart: изменение размера раздела

    Доделал поддержку изменения размера разделов для GEOM класса PART. На данный момент идеи "что бы туда ещё добавить" закончились, поэтому решил выложить патчи.

    Немного о цели патчей. Были у меня несколько машин, на которые я уже давно для тестов ставил FreeBSD с ZFS. Они полностью установлены на ZFS, но было оставлено свободное пространство "на всякий случай". Там используется GPT "схема" со "стандартной" разбивкой на три партиции: freebsd-boot, freebsd-swap и freebsd-zfs. Свободное место было оставлено в конце диска. И вот, в один прекрасный момент захотелось использовать свободное место. Но создавать отдельную партицию не хотелось после успешных экспериментов по расширению пула ZFS.

    После постановки задачи "как это сделать" очевидных решений найдено не было. Первое, что пришло на ум - поправить в таблице GPT размер партиции. Решил попробовать, подампил таблицу в файлы, поизучал формат... Решил посмотреть, что там в коде реализации. Оказалось, что "заготовка" базового метода resize уже имелась в коде класса. Только она ничего не делала, а возвращала ошибку ENOSYS.

    Я связался с автором класса PART - Marcel Moolenaar. Обсудил с ним что и как лучше реализовать. После чего взялся за эксперименты. Что в итоге получилось, можно увидеть здесь. Ход работы можно проследить в perforce.

    Если в кратце, то в начале пришлось заново вспомнить изучить для чего в дереве кода ядра используются файлы с расширением "*.m". Они применяются для создания подобия ООП в коде ядра. Как я уже упоминал ранее, структура класса PART интересна своей модульностью. Сам класс имеет базовые методы работы с партициями, а все детали реализации описываются в отдельных модулях схем. Так вот, в .m файлах описан программный "интерфейс" подобных модулей. Эти файлы обрабатываются awk скриптом во время компиляции ядра и генерируются файлы .c и .h.

    Грубо говоря, благодаря им и создаётся иллюзия ООП. Хотя на мой взгляд всё довольно условно :) Итак, реализовав базовый алгоритм изменения размера в ядре и добавив новую команду в утилиту управления gpart, я добавил поддержку в GPT схему. Потестировал на md(4) дисках - вроде работает и даже не паникует :)
    Решил попробовать на рабочей системе, попробовал - размер изменился, перезагрузился - пул "подхватил" свободное пространство и я счастлив :)

    После этого добавил поддержку в оставшиеся схемы, немного потестировал на том же md(4) и вроде всё. Да, только в EBR не стал добавлять, там как-то не всё гладко в реализации.

    Пример использования:
    # gpart show md0
    =>    34  409533  md0  GPT  (200M)
          34  204800    1  freebsd-zfs  (100M)
      204834  204733       - free -  (100M)
    
    # gpart resize -s 150m -i 1 md0
    md0p1 resized
    # gpart show md0
    =>    34  409533  md0  GPT  (200M)
          34  307200    1  freebsd-zfs  (150M)
      307234  102333       - free -  (50M)
    
    # gpart resize -i 1 md0
    md0p1 resized
    # gpart show md0
    =>    34  409533  md0  GPT  (200M)
          34  409533    1  freebsd-zfs  (200M)
    
    
    У команды resize есть два параметра "-i index" и "-s size". Указание индекса обязательно, а вот размер может быть вычислен автоматически. Изменяться может только смещение конца партиции, смещение начала всегда остаётся неизменным.

    И ещё важное замечание - изменяются только метаданные таблицы разделов, изменение размеров файловой системы нужно производить сторонними методами, например growfs для UFS. ZFS сама видит увеличение. Уменьшение разделов не запрещено и работает, но что на это скажет файловая система раздела - мне, честно говоря, не очень хочется узнавать :)

    четверг, 18 марта 2010 г.

    Использование gpart

    Утилита gpart служит для управления GEOM классом PART. На самом деле это хардлинк на утилиту geom(8), которая является универсальной утилитой управления для многих GEOM классов.

    Как я уже упоминал в предыдущей заметке, класс PART служит для работы с таблицами партиций и предоставляет доступ к провайдерам этих партиций. С появлением этой утилиты можно уже забыть такие утилиты как fdisk и bsdlabel, они морально устарели. Большинство их действий можно выполнять при помощи утилиты gpart. Нужно только понять и запомнить основные понятия - схема и партиция. Прежде чем создавать партиции, необходимо выбрать тип таблицы - схему. Например, для привычной разметки с использованием MBR необходимо выполнить команду 'gpart create' с указанием имени схемы в опции "-s mbr":
    # gpart create -f x -s mbr md0
    md0 created
    # gpart show md0
    =>     17  1023978  md0  MBR  (500M)
           17  1023978       - free -  (500M)
    
    # gpart commit md0
    
    Опция "-f x" указывает классу не вносить изменения на провайдер носителя сразу. Т.е. если вы не уверены в своих действиях, вы можете с каждой командой указывать эту опцию и после того как будете уверены, выполнить команду `gpart commit`, либо отменить изменения командой `gpart undo`. Не имеет значения, какой флаг вы укажете после опции "-f", т. к. класс отслеживает только наличие опции и её отличие от значения, принятого по-умолчанию. Если не указывать опцию "-f", то её значение по-умолчанию будет установлено в "-f C", что приведёт к автоматическому выполнению команды `gpart commit`.

    Таблица MBR может содержать максимум 4 записи, т.е. не более 4 партиций. После того как схема создана можно создавать партиции при помощи команды `gpart add`. Каждая партиция обладает несколькими обязательными свойствами - смещение начала, смещение конца, индекс в таблице и тип партиции. А так же одно дополнительное свойство, которым обладают партиции некоторых схем - символьная метка.  Все эти параметры видны пользователю, за исключением смещения конца. Смещение заменяется на вычисляемый из него размер.
    К тому же, для создания партиции при помощи утилиты gpart нужен только один обязательный параметр - это тип партиции, остальные параметры могут быть вычеслены автоматически.

    Тип партиции может быть задан символьным именем либо специальным номером, в зависимости от используемой схемы. Поддерживаемые символьные имена можно увидеть в мануале gpart(8). При необходимости задать какой-то специфический для схемы тип партиции, он указывается после знака восклицания. Например, для схемы MBR тип партиции FreeBSD представлен номером 165, который можно указать как "-t !165" (не забываем экранировать знак восклицания, если выполняем команду из shell - "\!165"), либо символьным именем "-t freebsd".

    Размер и смещение начала партиции по-умолчанию задаются в блоках, размер которых обычно соответствует размеру физического сектора, т.е. 512 байт. Для того чтобы не вычислять количество блоков, эти параметры можно указывать с суффиксом размера: b, k, m, g, t, p, e - т.е. от байт до экзабайт. Но есть одна особенность реализации - парсер при разборе этих параметров ещё не знает какой размер сектора имеет носитель, поэтому если он отличается от 512 байт, то лучше указывать размер в секторах, иначе размер будет вычислен неправильно.  Размер партиции указывается после опции "-s", а смещение начала - после "-b". При опускании любого из этих параметров они выбираются автоматически: смещение начала - на первый доступный блок, размер - на максимально возможный из доступного свободного пространства.

    Вычисление индекса партиции обычно можно оставить утилите gpart. Только если вам не нужна какая-нибудь особенная конфигурация, например, чтобы система устанавливалась на ad0s3 нужно указать параметр "-i 3".

    Итак, схема создана, создадим партицию:
    # gpart add -s 400m -t freebsd md0
    md0s1 added
    # gpart show md0
    =>     17  1023978  md0  MBR  (500M)
           17   819196    1  freebsd  (400M)
       819213   204782       - free -  (100M)
    
    
    Как видно, партиция была создана с типом "freebsd" и размером в 400 Мбайт, индекс и смещение начала были выбраны автоматически.

    Теперь на созданной партиции можно сделать дополнительную разметку для BSD схемы:
    # gpart create -s bsd md0s1
    md0s1 created
    # gpart show md0
    =>     17  1023978  md0  MBR  (500M)
           17   819196    1  freebsd  (400M)
       819213   204782       - free -  (100M)
    
    # gpart show md0s1
    =>     0  819196  md0s1  BSD  (400M)
           0  819196         - free -  (400M)
    
    
    Теперь добавим партиции, только вместо bsdlabel используем тот же gpart:
    # gpart add -s 100m -t freebsd-ufs md0s1
    md0s1a added
    # gpart add -s 100m -t freebsd-swap md0s1
    md0s1b added
    # gpart add -t freebsd-ufs md0s1
    md0s1d added
    # gpart show md0s1
    =>     0  819196  md0s1  BSD  (400M)
           0  204800      1  freebsd-ufs  (100M)
      204800  204800      2  freebsd-swap  (100M)
      409600  409596      4  freebsd-ufs  (200M)
    
    
    Всё достаточно легко и просто. Для записи загрузочного кода можно использовать всю ту же утилиту. Для этого предназначена команда `gpart bootcode`. Например, аналогом команды `bsdlabel -B` будет:
    # gpart bootcode -b /boot/boot md0s1
    md0s1 has bootcode
    
    Аналогично можно записать загрузочный код для схемы MBR:
    # gpart bootcode -b /boot/mbr md0
    md0 has bootcode
    
    Если же необходимо установить менеджер загрузки, то нужно всего лишь выбрать другой образ загрузочного кода - /boot/boot0. Так же, не стоит забывать, что у схемы MBR есть аттрибут активного раздела, чтобы его установить нужно использовать команду `gpart set`:
    # gpart set -a active -i 1 md0
    md0s1 has active set
    # gpart show md0
    =>     17  1023978  md0  MBR  (500M)
           17   819196    1  freebsd  [active]  (400M)
       819213   204782       - free -  (100M)
    
    
    В принципе, этого набора команд достаточно для работы. Если иметь понятие, что и для чего нужно сделать - то сложностей в использовании вообще не вижу. Даже если такая необходимость возникает нечасто, все команды утилиты gpart имеют описание:
    # gpart 
    usage: gpart add [-b start] [-s size] -t type [-i index] [-l label] [-f flags] geom
           gpart bootcode [-b bootcode] [-p partcode] [-i index] [-f flags] geom
           gpart commit geom
           gpart create -s scheme [-n entries] [-f flags] provider
           gpart delete -i index [-f flags] geom
           gpart destroy [-f flags] geom
           gpart modify -i index [-l label] [-t type] [-f flags] geom
           gpart set -a attrib -i index [-f flags] geom
           gpart show [-lr] [geom ...]
           gpart undo geom
           gpart unset -a attrib -i index [-f flags] geom
           gpart help
           gpart list [name ...]
           gpart status [-s] [name ...]
           gpart load [-v]
           gpart unload [-v]
    

    среда, 10 марта 2010 г.

    Немного о GEOM классе PART

    В 7-ую версию FreeBSD был добавлен GEOM класс PART, который заменил собой несколько классов, реализующих поддержку таблиц партиций, таких как BSD, MBR, PC98.

    Не слишком углубляясь в технические подробности реализации назначение класса PART можно представить в виде некоторого модульного механизма ядра для управления различными таблицами партиций.

    Каждый пользователь FreeBSD в той или иной мере знаком как минимум с двумя типами таблиц партиций - это MBR и BSD, а в последнее время, стал пользоваться популярностью ещё один тип - GPT. В терминологии класса PART эти типы таблиц представлены "схемами". А модульность реализации позволяет включать поддержку различных схем в виде отдельных модулей ядра. Для этого реализация класса включает в себя инфраструктуру с базовыми действиями схожими для различных типов таблиц партиций. А реализация особенностей каждой из "схем" содержится в отдельных модулях, которые благодаря интерфейсу kobj(9) подключаются в базовую инфраструктуру класса.

    Когда подсистема GEOM инициализирует класс PART, базовая инфраструктура класса выполняет "пробу" для каждой зарегистрированной схемы. Т.е. класс выполняет поиск метаданных схемы на носителях. Так, например, схема MBR реализует поддержку таблицы основных разделов, содержащейся в главной загрузочной записи MBR. Если "схема" обнаружит свои метаданные на носителе, она создаёт "провайдеры", через которые осуществляется доступ к партициям. Для пользователя партиции этой схемы выглядят как <имя_провайдера>s%d, где %d - номер индекса партиции в таблице. Т.е. привычные всем имена типа ad0s1 можно разделить на имя провайдера носителя ad0 и имя партиции s1, где 1 - это номер партиции в таблице.

    Схема BSD реализует поддержку bsd-разделов. Это те, которые раньше создавались утилитой bsdlabel (или ещё раньше disklabel). Имена партиций этой схемы именуются латинскими буквами, например, ad0s1a. Здесь ad0 - имя провайдера носителя, s1 - имя провайдера схемы MBR, т.е. на диске ad0 была создана схема MBR и уже на первой партиции этой схемы была создана схема BSD c партицией, определяемой именем "a".

    Схема GPT реализует поддержку GUID таблицы разделов. Имена партиций при использовании этой схемы формируются в зависимости от типа. Тип задаётся при создании партиции, о нём я расскажу чуть позже. Но в общем, имя может быть либо "p%d" либо "s%d", где %d - номер индекса в таблице. Обычно это "p", имя "s" используется только для типа партиции "freebsd", обозначающего, что на данной партиции будет использоваться BSD схема.

    Ещё одна знакомая схема - EBR. Она используется для разметки партиций внутри расширенных разделов. И осталось ещё три неупомянутых схемы, поддержка которых реализована на сегодняшний день в классе PART: APM используемая в Apple Mac, PC98 используемая в NEC PC-9801, и VTOC8 используемая  на Sun'овских UltraSPARC.

    Это краткое описание я решил написать после нескольких часов, проведённых за изучением исходного кода этого класса. И в целом, его реализация мне понравилась. Можно сказать, что она довольно красива и в духе всей подсистемы GEOM.