[make-initrd] [devel] syslinux
Alexey Gladkov
legion at altlinux.ru
Mon Apr 22 03:04:50 MSK 2019
On Sun, Apr 21, 2019 at 05:44:14PM +0200, Michael A. Kangin wrote:
> On 04/21/2019 03:43 PM, Alexey Gladkov wrote:
>
> >> А есть еще какой-то "payload" для тестирования сетевой загрузки?
> >
> > Не очень понял вопроса.
>
> Какая-нибудь фича, которая бы пользовалась сетью для обретения корневой
> FS. Ну, чтобы система полностью могла загрузиться.
>
> nfsroot не работает, CLB на новую версию не спортировано, netboot
> (который выкачивал tgz и распаковывал в tmpfs) тоже не спортирован.
> А больше мне ничего на ум не приходит.
Никакие другие мне тоже не известны. Но раз вы подняли эту проблему, то,
возможно, мы сейчас сделаем такую фичу и починим nfsroot.
> > Попробую сделать это в ближайшее время. Буду признателен, если
> > заинтересованные в таком варианте протестируют перед релизом.
>
> Разумеется.
> Думаю, было бы неплохо так же рассматривать NFS как транспорт для других
> фич, по давним замерам производительности смонтировать squashfs по NFS
Интересная мысль. Она хорошо согласуется с необходимостью монтирования
cd-диска, который тоже является промежуточной стадией. По сути нет разницы
между разными промежуточными стадиями. Правда пока этот механизм я не
придумал.
> может оказаться заметно быстрее, чем чистый корень:
>
> https://lists.altlinux.org/pipermail/ltsp-server/2012-August/002532.html
Интересно.
> >> Еще большой вопрос - как написать фичу? Есть какая-то образцовая
> >> работающая фича? Или документация, с бест-практиками, примерами...
> >
> > Каждая фича приносит какой-то новый функционал. У меня нет документации
> > для этого. Бест-практики появляются, когда достаточное количество людей
> > занимаются их написанием. В моём случае это не так.
>
> Боюсь, тут может быть некоторый замкнутый круг.
Конечно есть.
> Чтобы появилось хоть некоторое количество таких людей, у них должно быть
> понимание, как это делать. Или хотя бы с чего начать.
Дело в том, что для самого себя писать документацию сложно. А заставить
себя в такой ситуации ещё сложнее. Также вы же понимаете что когда один
разрабатываешь что-то, то многие вещи кажутся самоочевидными.
Я надеюсь, что благодаря вам и Леониду, вашим вопросам я смогу заполнить
пробелы.
> В старой версии M-I я попытался взять за основу упомянутый netboot и
> написать свою фичу по его мотивам. Результат, конечно, так себе, и далёк
> от любых бест-практик, но оно хотя бы заработало. И было некое
> понимание, что скрипт в post/udev/ выполнится после работы udev'а, и в
> рамках этого скрипта можно реализовать всю необходимую логику.
Сейчас добавление дополнительной функциональности стало ещё проще. Весь
рантайм выглядит как обычная система с сервисами. Встроиться можно куда
угодно.
> Сейчас, с новой версией M-I, нет ни понимания, ни документации, ни
> работающего референсного примера.
Для каждой фичи встраиваться нужно в разные места. Если вы хотите
обработать новый тип загрузки (тот же nfs), то нужно встраиваться нужно в
одно место. Если же вам нужно загрузить консольный шрифт и раскладку, то в
другое. Всё это сильно зависит.
> Я смутно догадываюсь, что сейчас фичу нужно оформлять какими-то
> udev-коллбеками, фильтрами и хуками, но абсолютно не представляю, с чего
> начать.
udev-коллбэки это лишь часть эвентов. Они позволяют реагировать на
загрузку модулей. Сейчас через тот же механизм можно реагировать на этапы
конфигурации сети.
> Поэтому буду рад любым советам и намёкам (варианты for dummies, in a
> nutshell вообще бесценны для снижения порога вхождения и сглаживания
> лёрнинг курвы :)
Ок )) Я постараюсь описать некоторые моменты.
> >> Я думал попробовать взять за основу nfsroot, но, похоже, он вообще не
> >> "запускается". По крайней мере ни одного упоминания в /var/log нет, в
> >> dmesg только о загруженном модуле nfs.
> >
> > Безотносительно работает nfsmount или нет эта фича хорошо показывает как
> > добавляются новые варианты загрузки.
>
> Меня только смущает, что эта фича даже не пробует начать работать в boot
> runtime, по крайней мере, я не никакого признака не заметил - в логах
> пусто, в /.initrd/ ничего не грепается и не ищется.
Ни md_run, ни nfsroot ничего не пишут в процессе работы. Это неприятно.
Поэтому я двигаюсь в сторону отказа от них.
> rules.mk, config.mk - тут в принципе понятно. Но я наткнулся на странный
> результат с модулем nfs. В первый раз, когда я делал образ initrd с этой
> фичей, в него попал модуль nfs, согласно
> NFS_PRELOAD = af_packet nfs
> ...
> MODULES_PRELOAD += $(NFS_PRELOAD)
>
> Однако, после нескольких попыток разобраться, почему она не работает, и
nfsroot работало. Возможно, какого-то модуля ядра не хватает.
> в частности после попытки применения рецепта с вики DISABLE_GUESS = root
> (https://www.altlinux.org/Make-initrd#nfsroot)
Просто для справки, я стараюсь вынести документацию с этой вики на github.
> этот модуль попадать в образ initrd перестал, даже с явным указанием
> MODULES_ADD += nfs в /etc/initrd.mk.
Пожалуйста сделайте пример конфига, где это можно воспроизвести. Это очень
странно.
> Получается, сборка образа initrd не совсем воспроизводима, и от раза к
> разу может давать разные результаты?
Сборка образа отталкивается от того как был сконфигурён корень. Тут всё
довольно просто.
> Может, есть где сказать нечто вроде "make clean"? Я впервые сталкиваюсь
> с таким поведением, и даже не знаю, куда посмотреть.
Одна попытка сборки с другой никак не связана и не пересекается.
> /etc/initrd/cmdline.d/nfsroot - тут, как я полагаю, нужно
> зарегистрировать все-все boot parameters, которыми фича собирается
> пользоваться.
Верно.
Выяснилось, что некоторые пользователи жалуются на ошибки, когда указывают
rootdelay=five.
Из этого вылилась система валидации параметров cmdline.
> Чем отличается register_parameter от register_array (и, судя по
> исходникам, есть еще register_alias), в каких случаях пользоваться той
> или иной функцией, какой синтаксис для _array - указывать несколько раз
> один и тот же параметр, или внутри одного параметра что-то перечислить
> через запятую? Разглядывание лаконичного кода этих функций в исходниках
> просветления, увы, не принесло...
Вот как это как раз пример того, что мне казалось очевидным, а
оказывается, что это не так.
Семантика у этих функций такая:
register_parameter <type> <varname> [<default>]
Функция регистрирует параметр <varname> и типом <type>. Также можно
указать значение по умолчанию.
register_array <type> <varname>
Позволяет создать "массив" с определённым типом. По правилам /proc/cmdline
параметр с тем же именем, находящийся правее переписывает предыдущие. В
некоторых случаях хочется иметь возможность получить их все как массив
значений. Пример такого параметра IP. Каждое последующее его указание не
отменяет предыдущий, а конфигурирует другой интерфейс.
register_alias <varname> <another-name> [<another-name> ...]
Эта функция создана для указания более одного имени для одно и того же
параметра. Это полезно если возникает необходимость переименовать
параметр или сделать слой совместимости, например, с dracut по некоторым
параметрам.
type может быть string, number, bool.
varname это не оригинальное имя, которое может быть указано в
/proc/cmdline, а имя после обработки. Дело в том, что в /proc/cmdline
параметры совсем не shell-like. Они могут содержать дефисы или точки.
Поэтому make-initrd приводит имена параметров к uppercase и заменяет
дефисы и точки на подчёркивания. В такой форме они и регистрируются.
> Как дальше пользоваться этими параметрами? делать в каждом скрипте
> инклюд . /.initrd/initenv, и ссылаться на переменную параметра, как уже
> существующую?
Сервис data/etc/rc.d/init.d/cmdline отвечает за разбор cmdline параметров.
Он же создаёт /.initrd/initenv. Это необходимо в том числе и из-за того,
что некоторые параметры используются более чем в одном месте и имеют
значения по умолчанию. Производить анализ cmdline каждый раз, где нужен
параметр очень неудобно по понятным причинам. Поэтому анализ производится
лишь один раз и результат записывается в /.initrd/initenv, который
импортируют все остальные скрипты.
> В cmdline писать параметр маленькими буковками, а
> переменную ожидать, что она существует с именем заглавными буквами?
Параметры вы можете писать какими угодно буквами. Вы можете использовать
дефис вместо подчёркивания, а в коде всегда работать с параметром
названный заглавными и с подчёркиванием.
> /etc/udev/rules.d/99-nfsroot.rules - так, тут какое-то правило udev.
> SUBSYSTEM=="net", ACTION=="online", RUN+="/lib/uevent/filters/nfsroot"
> т.е. когда сеть будет в онлайне, начнёт действовать фильтр событий
> /lib/uevent/filters/nfsroot, если я правильно трактую.
Да. Вы всё правильно поняли.
> Наверное, для всех сетевых фич это будет более-менее однотипно.
> "Пользовательским фичам" рекомендуется использовать номер 99-?
Пока полиси на эту тему у меня нет. У вас есть идеи ?
> /lib/uevent/filters/nfsroot - этот файл уже значительно менее понятен.
> [ -n "$NFSROOT" ] || [ "$ROOT" != '/dev/nfs' ] ||
> NFSROOT='auto'
>
> [ -n "$NFSROOT" ] ||
> exit 0
>
> exit 0 нужно использовать, когда мы недовольны качеством предоставленных
> параметров, еще чем-нибудь, и не хотим оказывать услугу?
Как вы уже правильно заметили этот скрипт выполняется udev'ом. Не нужно
завершаться с ненулевым кодом возврата, если не было ошибки. Если
написать:
[ -n "$NFSROOT" ] || exit
то exit без аргумента будет использовать код возврата от предыдущей
операции, а это 1 так как переменная NFSROOT пуста.
> event="$(make_event)"
> showenv -q > "$event"
> release_event nfsroot "$event"
>
> Эти заклинания использовать, как_есть?
Заклинания не нужно выполнять никогда. Лучше знать, что происходит. Я
попробую коротко рассказать что это и почему оно так.
udev не может выполнять долгие задания. В udev(1) для RUN написано:
This can only be used for very short-running foreground tasks. Running an
event process for a long period of time may block all further events for
this or a dependent device.
И так было с самого начала. Поэтому обработка событий разделена на две
части и скрипты (filters) из udev ничего сами не делают. Они лишь
подготавливают условия для реальных обработчиков (handlers). Фильтры
выполняются udev'ом параллельно и формируют очередь, которая разбирается
демоном ueventd (User EVENT Daemon). ueventd делает это последовательно
так как порядок выполнения handlers важен.
Теперь зная это возвращаемся к этим трём строчкам. Эти функции описаны в
data/bin/uevent-sh-functions.
Функция make_event создаёт временный файл для эвента и печатает его имя.
Далее showenv печатает в этот файл текущие переменные окружения. Это
делается из-за того, что udev передаёт параметры устройства через
окружение. Таким образом handler получит то же самое окружение, что и
filter. Ну и наконец сформированный эвент передаётся на обработку ueventd
функцией release_event.
> Я посмотрел доступные файлы в /lib/uevent/filters, но никакой системы
> использования понять не сумел, все они достаточно разношерстные.
Они подготавливают окружение для разных handler'ов, да, они все разные.
> /lib/uevent/handlers/040-nfsroot - это уже похоже на скрипт, в котором
> делается реальная работа.
Это handler.
> Всю логику необходимо помещать внутрь функции handler() как я понимаю.
Да. Но нужно помнить, что пока этот скрипт не завершит работу следующий не
будет запущен.
> for e in "$eventdir"/nfsroot.*; do
> [ -f "$e" ] || break
> ( . "$e"; handler; ) ||
> rc=1
> done_event "$e"
> done
> Эти заклинания будут неизменны?
Эти "заклинания" будут зависеть от логики обработчика.
> Во всех просмотренных хандлерах ссылка на эвенты выглядит как
> "$eventdir"/nfsroot.*, "$eventdir/network.$ev_type",
> "$eventdir"/mountdev.*, etc.
> Однако, внутри этой директории /.initrd/uevent-events находятся файлы вида:
> done.network.addr.update.29.84.XXXNRubtr
> done.network.addr.update.29.85.XXXHB5F1u
> done.network.config.update.13.56.XXXPsND17
> done.network.config.update.13.59.XXXJrrdH9
> done.network.hostname.update.29.84.XXXwup0dr
>
> т.е. они не подпадают под ожидаемые маски. Это нормально?
Это выполненные задания (см. uevent-sh-functions). Так как initrd
удаляется быстро, то нет смысла их удалять. Но для отладки они очень важны.
> В некоторых фичах оформляется еще служба init.d, однако, в nfsroot
> например такой службы нет. В каких случаях делать, в каких не надо?
Всё также как и в обычной системе. Если вам нужна отдельная служба, то
нужно делать сервис, если нет, то не нужно.
> Если есть init.d/service, как можно в рантайме сделать на него ссылки в
> rcN.d (есть ли местный аналог chkconfig)?
В initrd используется lsb заголовки для сервисов. Сервисы могут
предоставлять как реальное имя так и виртуальное имя. Это очень старый
механизм и о нём я много рассказывать не буду. Подробнее здесь [1][2].
Ссылки создаются в процессе создания обарза утилитой sort-lsb.
> Если в рантайме нужно делать какие-то мелкие действия, обязательно ли
> оформлять для этого init.d/сервис, или есть какой-то аналог rc.local?
Не понял вопроса.
> Работают ли еще старые механизмы pre/ post/ скриптов?
Нет. Раньше были стадии перед которыми можно было вклиниться, но с v2
функционально их не стало и даже для обратной совместимости неоткуда их
вызвать.
Я очень долго просил откликнуться тех у кого есть фичи, чтобы помочь в
адаптации. Всем кто откликнулся я помог.
> Замечания, появляющиеся в ходе тестирования сети, предпочтительней
> оформлять багами или для начала лучше писать сюда (для обсуждения и
> понимания, баг это или фича)?
На релиз в сизифе баги стоит вешать в багзиллу. До релиза пишите в личку
или на github.
[1] https://github.com/legionus/make-initrd/blob/master/docs/InitramfsServices.md
[2] https://github.com/legionus/make-initrd/blob/master/docs/BootRuntime.md
P.S. Уф. У вас длинное письмо. Я постарался ответить на всё. Извините,
если получилось слишком много.
P.P.S. Если вы найдёте время помочь мне с документацией того, что мы тут
обсуждаем, то вы мне очень поможете сделать всё понятнее.
--
Rgrds, legion
More information about the Make-initrd
mailing list