Usrmerge: различия между версиями

Материал из ALT Linux Wiki
 
(не показано 35 промежуточных версий 4 участников)
Строка 2: Строка 2:


= Usrmerge =
= Usrmerge =
'''''Точный план действий сейчас вырабатывается, и его подробности могут измениться.'''''
Начиная с 23 апреля 2024 реализовано в Sisyphus. Текущие проблемы с обновлением описаны [[Branches/Sisyphus#Ошибки_обновления | тут]] и [[Usrmerge#User-visible_impact | тут]]
 
== Глоссарий ==
'''{{term|merged-usr}}'''-иерархией называется такая FHS-подобная иерархия каталогов, в которой все неизменяемые при работе файлы из операционной системы (т. е. из состава пакетов в репозитории ОС) помещаются либо внутри префикса ({{path|/usr}}), либо их местоположение является ссылкой внутрь префикса. В такой иерархии {{path|/bin}}, {{path|/lib}} и т. д. будут симлинками на {{path|/usr/bin}}, {{path|/usr/lib}} и т. д. Иерархия, не отвечающая этому правилу (например, та, которую создавал инсталлятор до p11), называется '''{{term|unmerged-usr}}'''.
 
'''{{term|split-usr}}'''-конфигурация подразумевает, что исполнимый файл в процессе pid 1 из корневой файловой системы стартует до монтирования {{path|/usr}}, расположенного на отдельном разделе. {{term|split-usr}} не следует путать с {{term|unmerged-usr}}, хоть системы со свойством {{term|split-usr}} и являются подмножеством систем {{term|unmerged-usr}}.


== Введение ==
== Введение ==
Исторически<ref>[http://lists.busybox.net/pipermail/busybox/2010-December/074114.html]</ref> в UNIX System V, а позже и в мейнстримных линукс-дистрибутивах разделяли каталоги {{path|/bin}} и {{path|/usr/bin}}, {{path|/lib$suff}} и {{path|/usr/lib$suff}}, и т. п., давая возможность разместить {{path|/usr}} на отдельной файловой системе от {{path|/}}, содержащего все эти подкаталоги.
Исторически<ref>[http://lists.busybox.net/pipermail/busybox/2010-December/074114.html]</ref> в UNIX System V, а позже и в мейнстримных линукс-дистрибутивах разделяли каталоги {{path|/bin}} и {{path|/usr/bin}}, {{path|/lib$suff}} и {{path|/usr/lib$suff}}, и т. п., давая возможность разместить {{path|/usr}} на отдельной файловой системе от {{path|/}}, содержащего все эти подкаталоги.


Позже, с увеличением средних размеров устройств хранения в машинах, сторонники разделения придумали другие обоснования (например, возможность из окружения в {{path|/{bin,sbin,libX,...}/}} починить немонтирующуюся {{path|/usr}}, но на сегодняшний день непонятно, какой набор утилит и нужных им so/иных файлов стоит признать частью "системы спасения", которая должна быть доступна без {{path|/usr}}, а какой — нет, ибо сами утилиты приобретают универсальный вид и широкие границы применимости. С развитием механизмов initramfs и живых загрузочных/установочных носителей, а также практикой "раздела восстановления" на локальном хранилище машины среди настольных дистрибутивов этот аргумент теряет всякий смысл.
Позже, с увеличением средних размеров устройств хранения в машинах, сторонники разделения придумали другие обоснования (например, возможность из окружения в {{path|/{bin,sbin,libX,...}/}} починить немонтирующуюся {{path|/usr}}). Но на сегодняшний день непонятно, какой набор утилит и нужных им so/иных файлов стоит признать частью "системы спасения", которая должна быть доступна без {{path|/usr}}, а какой — нет, ибо сами утилиты приобретают универсальный вид и широкие границы применимости. С развитием механизмов initramfs и живых загрузочных/установочных носителей, а также практикой "раздела восстановления" на локальном хранилище машины среди настольных дистрибутивов этот аргумент теряет всякий смысл.


Чем сохранять бесцельно дублирующие друг друга два класса мест для одних и тех же файлов, лучше оставить один из них, а другой устранить:
Чем сохранять бесцельно дублирующие друг друга два класса мест для одних и тех же файлов, лучше оставить один из них, а другой устранить:
Строка 13: Строка 18:
* либо поместить аналоги этих каталогов из {{path|/}} в {{path|/usr}}.
* либо поместить аналоги этих каталогов из {{path|/}} в {{path|/usr}}.


Из двух вариантов, входящих в рамки FHS<ref>[https://refspecs.linuxfoundation.org/FHS_3.0/fhs-3.0.pdf]</ref>, второй лучше хотя бы тем, что уменьшает к-во top-level каталогов, куда упаковывается постоянное содержимое пакетов, до одного. Сейчас среди FHS-совместимых дистрибутивов это типичный подход.
Из двух вариантов, входящих в рамки FHS<ref>[https://refspecs.linuxfoundation.org/FHS_3.0/fhs-3.0.pdf]</ref>, второй лучше хотя бы тем, что уменьшает количество top-level каталогов, куда упаковывается постоянное содержимое пакетов, до одного. Сейчас среди FHS-совместимых дистрибутивов это типичный подход, на который в том числе потихоньку начинают полагаться апстримы прикладных пакетов.


== Rationale ==
== Rationale ==
* Один каталог (пусть с не очень удачным именем {{path|/usr}}) как объект манипуляции и как общий носитель фиксированного содержимого пакетов удобнее россыпи каталогов, полный список которых даже невозможно построить. Появляется даже смысл рассматривать его в виде отдельной точки монтирования, которую можно держать общей на многих машинах под общим управлением.
* Один каталог (пусть с не очень удачным именем {{path|/usr}}) как объект манипуляции и как общий носитель фиксированного содержимого пакетов удобнее россыпи каталогов, полный список которых даже невозможно построить. Появляется даже смысл рассматривать его в виде отдельной точки монтирования, которую можно держать общей на многих машинах под общим управлением.
** Один каталог легче снапшотить, по нему легче гонять {{cmd|find}}, ...
** Один каталог легче снапшотить, по нему легче гонять {{cmd|find}}, ...
* Упаковка всего пакетного содержимого в {{path|/usr}} открывает дорогу к техническому {{path|/}}, который не находится на устройстве хранения и содержит только пустые каталоги-точки-монтирования.
* Упаковка всего пакетного содержимого в {{path|/usr}} открывает дорогу к виртуальному {{path|/}}, который не находится на устройстве хранения и содержит только пустые каталоги-точки-монтирования.
* Возникает осмысленное разделение между {{path|/usr}}, {{path|/var}} и {{path|/etc}}: первый каталог несёт в себе постоянное содержимое пакетов, не предназначенное к ручной модификации (не через пакетную систему или доставку образа), а другие два уже исторически применяются для переменного хранимого состояния и общесистемных конфигов.
* Возникает осмысленное разделение между {{path|/usr}}, {{path|/var}} и {{path|/etc}}: первый каталог несёт в себе постоянное содержимое пакетов, не предназначенное к ручной модификации (не через пакетную систему или доставку образа), а другие два уже исторически применяются для переменного хранимого состояния и общесистемных конфигов.
* Сборочным скриптам и прочим интеграционным программным компонентам не нужно будет перебирать каталоги, в которых находится программа.
* Сборочным скриптам и прочим интеграционным программным компонентам не нужно будет перебирать каталоги, в которых находится искомая программа.<ref>Вообще-то для этого нужно ещё провести слияние sbin и bin, но оно не несёт срочности и не рассматривается на этой странице.</ref>
* Начиная с версии 255, планируемой к выпуску в течение 2023, {{pkg|systemd}} [https://lists.freedesktop.org/archives/systemd-devel/2022-April/047673.html прекратит] поддержку split-usr и unmerged-usr.
* Начиная с версии 255, выпущенной в декабре 2023, {{pkg|systemd}} [https://lists.freedesktop.org/archives/systemd-devel/2022-April/047673.html прекратит] поддержку split-usr и unmerged-usr; вот [https://github.com/systemd/systemd/pull/27999/commits/cedcd0bc61913db1e37e19f00d3f97fc72436728 коммит].
** Из кода проекта {{pkg|systemd}}, помимо прочего, исчезнут все упоминания старых каталогов; например, директива <tt>ProtectKernelModules=</tt> больше не будет монтировать заглушку поверх <tt>/lib/modules</tt>, и т. п.


== Proposed changes ==
== Proposed changes ==
Необходимые действия можно разбить на две стадии.
Необходимые действия можно разбить на три стадии.


=== Стадия 1 ===
=== Стадия 1 ===
* Научить rpm автогенерировать симлинки на файлы {{path|/{bin,lib,...}/x}} => {{path|/usr/{bin,lib,...}/x}}, если в пакете указано <tt>Provides: /bin/x</tt> и упакован файл /usr/bin/x, и т. д.
1) Определить, что слиянию с аналогами внутри /usr подлежат следующие каталоги:
* Переназначить макросы: <tt>%_bindir</tt>, <tt>%_libdir</tt> и другие.
<pre>
* На стадии brp завершаться с ошибкой, если обнаружены разные файлы в {{path|/bin/x}} и {{path|/usr/bin/x}}, ...
  /bin
  /lib
  /lib32
  /lib64
  /libx32
  /sbin
</pre>
На каждой машине есть некоторые каталоги из этого списка; они и будут перенесены.
 
2) Ввести brp-модуль {{term|brp-dupe-bin}}, который на стадии brp завершается с ошибкой, если обнаружены разные файлы в {{path|/bin/x}} и {{path|/usr/bin/x}}, а если один из них есть ссылка на другой, устанавливает две копии такого файла по обоим путям с совпадающими атрибутами и контентом.
Это нужно, чтобы приблизительно 22 пакета могли устанавливаться на все варианты иерархий: и на unmerged-usr, и на merged-usr. Создавать жёсткую ссылку нежелательно: если {{path|/bin/x}} и {{path|/usr/bin/x}} лежат на разных файловых системах, такой пакет туда не установится: RPM не рассечёт жёсткую ссылку на два одинаковых файла.
Большинство пакетов, требующих исправления, достаточно будет просто пересобрать со специальным brp-модулем.
 
Некоторые пакеты, например, {{pkg|vim-common}}, упаковывают разные
файловые объекты в {{path|/bin}} и {{path|/usr/bin}}; другие пакеты ставят файлы прямо
в {{path|%buildroot/bin}}. Их потребуется исправить руками (готово: [[altbug:49541]]). (Справедливости ради,
многие из них и так понадобится обновить)
 
Полный список таких будущих конфликтов на 2024-03-16:
<pre>
[('bin/bsh', {'ash', 'bsh'}),
('bin/ksh', {'ksh', 'pdksh'}),
('bin/mail', {'mailutils', 'mailx'}),
('bin/ex', {'vi-traditional', 'vim-common', 'vim-minimal'}),
('bin/rview', {'vim-common', 'vim-minimal'}),
('bin/vi', {'vi-traditional', 'vim-minimal'}),
('sbin/halt', {'shepherd', 'systemd-sysvinit', 'sysvinit'}),
('sbin/reboot', {'shepherd', 'systemd-sysvinit', 'sysvinit'}),
('sbin/shutdown', {'shepherd', 'systemd-sysvinit', 'sysvinit'})]
</pre>
Из перечисленных множеств пересекающихся в будущем пакетов многие уже явно конфликтуют друг с другом.
 
3) Подготовить пакет {{pkg|filesystem}} версии 3: поместить в нём скрипт, срабатывающий в <tt>%pretrans</tt> и переносящий содержимое каталогов из списка 1 внутрь {{path|/usr}} (т. е. под префикс).
Сценарий файлтриггера должен будет давать предельно ясную информацию и диагностические сообщения на стандартные потоки.
Нужно будет либо положиться на static coreutils, либо очень осторожно обращаться с обычными и dynamic linker.
 
4) [[Usrmerge/UpgradePlan|Подготовить p10]] к плавному обновлению на p11 и предшествующие ему срезы сизифа.


=== Стадия 2 ===
=== Стадия 2 ===
Каждая инсталляция перейдёт к ней независимо, как только все пакеты в этой инсталляции будут содержать свои файлы под {{path|/usr}}.
Этот пункт вступает в действие на каждой машине индивидуально при
* В пакет <tt>filesystem</tt> добавить filetrigger, который заменяет {{path|/bin}} с симлинками на симлинк {{path|/bin}} -> {{path|/usr/bin}}.
обновлении её пакетов.
Перед транзакцией, в которой ставят новый пакет {{pkg|filesystem}}, скрипт из пункта 2 вводит симлинки, завершая процесс usrmerge на данной системе.
 
Каждая инсталляция перейдёт к ней независимо, по мере обновления пакетов.
 
=== Стадия 3 ===
[[Team|Мейнтейнеры]] пакетов перейдут к ней после выпуска [[Одиннадцатая платформа|p11]].
 
Заменить макросы, использующие старые каталоги (<tt>%_udevrulesdir</tt>,
<tt>%_tmpfilesdir</tt> и другие), и <span id="MigrateDirMacros">пересобрать с ними пакеты, что-либо
помещающие в эти каталоги</span>.
Приближённое число затрагиваемых бинарных пакетов:
<pre>
% grep -E '^/(bin|lib[^/]*|sbin)/[a-zA-Z0-9_-]+' contents-index \
  | grep -vE '^/lib/(systemd|udev|sysusers.d|modules[^/]*|modprobe.d|security|tmpfiles.d)'
  \ # exclude known places
  | cut -f2 -d$'\t' | grep -v '^/' # exclude path provides
  | sort -u | wc -l
524
</pre>
Это оценка по x86_64 + noarch. Исходных, конечно, будет меньше (333).
 
При обновлении на эти пакеты будет действовать правило 2, поэтому их
содержимое будет доступно.


== Incompatibilities ==
== Incompatibilities ==
Если корневая файловая система — каскадная композиция на базе, например, overlayfs, и каталоги {{path|/bin}} и подобные находятся ''не в верхнем'' слое стека — автоматически обновить такую корневую файловую систему на {{pkg|filesystem > 3}} '''не выйдет'''. Придётся либо не обновляться, либо пересобрать контейнер/систему на обновлённой пакетной базе.


== FAQ ==
== FAQ ==


Здесь будет секция ЧаВО, как только эти вопросы начнут часто задавать. :)
Рекомендуем прочитать другие материалы о преимуществах новой иерархии<ref>[https://www.freedesktop.org/wiki/Software/systemd/TheCaseForTheUsrMerge/ TheCaseForTheUsrMerge]</ref><ref>[https://www.freedesktop.org/wiki/Software/systemd/separate-usr-is-broken/ separate-usr-is-broken], примеры, где в ранней системе полагаются на наличие {{path|/usr}}}</ref>.
Пока что рекомендуем прочитать другие материалы с описанием преимуществ решения<ref>[https://www.freedesktop.org/wiki/Software/systemd/TheCaseForTheUsrMerge/]</ref>


'''Q: А что, если {{path|/usr}} на отдельном разделе по каким-то причинам не примонтируется?'''
'''Q: А что, если {{path|/usr}} на отдельном разделе по каким-то причинам не примонтируется?'''
Строка 52: Строка 118:
* Во-первых, для этого нужно, чтобы {{path|/}} '''смог''' смонтироваться, а {{path|/usr}} '''не смог'''.
* Во-первых, для этого нужно, чтобы {{path|/}} '''смог''' смонтироваться, а {{path|/usr}} '''не смог'''.
* Во-вторых, всё ещё нет критерия, по которому ту или иную программу и её зависимости можно либо отнести к "системе спасения", либо исключить из неё и сослать в {{path|/usr}}.
* Во-вторых, всё ещё нет критерия, по которому ту или иную программу и её зависимости можно либо отнести к "системе спасения", либо исключить из неё и сослать в {{path|/usr}}.
* В-третьих, нет ни одного задокументированного случая, где таким образом спасли какую-либо типичную GNU/Linux-систему, включая Альт, есть только [https://www.ecb.torontomu.ca/~elf/hack/recovery.html предание] из 1986 года, касавшееся non-Linux тех времён на компьютере тех времён. Рецептов такого восстановления в практически важных случаях, отчуждаемых от компетенций разработчиков ALT и умелых сисадминов, нет тем более. Следовательно, можно заключить, что цитируемая возможность восстановить {{path|/usr}} из {{path|/}} в общем случае является призрачной, и её стоит причислить к религиозным верованиям.
* В-третьих, нет ни одного задокументированного случая, где таким образом спасли какую-либо типичную GNU/Linux-систему, включая Альт, есть только [https://www.ecb.torontomu.ca/~elf/hack/recovery.html предание] из 1986 года, касавшееся non-Linux тех времён на компьютере тех времён. Рецептов такого восстановления, отчуждаемых от компетенций разработчиков ALT и умелых сисадминов, нет тем более. Следовательно, можно заключить, что в общем случае цитируемая возможность восстановить {{path|/usr}} из {{path|/}} — призрачна.
* Несмотря на всё это, нет ничего плохого в том, чтобы рецепт такого спасения (при помощи операционной избыточности инсталляции альта) администратору ''предложить'', но это должен быть явный механизм с минимумом издержек для остальной структуры системы. Есть множество вариантов это реализовать с разными преимуществами и минусами в разных установках; все они out of scope for this document.
 
'''Q: Зачем вам отдельная программа-конвертер? Есть же пакетный менеджер.'''
 
A: {{pkg|rpm}} не умеет заменять каталог (например, {{path|/x}}) на символическую ссылку. Ему надо помочь:
* скопировать всё из каталога {{path|/x}} под префикс (под {{path|/usr}}) в новый каталог,
* скопировать туда же содержимое аналогичного каталога {{path|/usr/x}} под префиксом,
* атомически поменять местами новый каталог и {{path|/usr/x}},
* атомически поменять местами {{path|/x}} и ссылку на новый,
* проследить, что в процессе ничего не потерялось, и удалить лишнее.
Проще всего это сделать на стадии <tt>%pretrans</tt> (дословно: ''перед транзакцией'', перед манипуляцией пакетов), чтобы к началу установки пакетов всё уже было готово и процесс не зависел от порядка, в котором {{prg|rpm}} ставит пакеты.
 
'''Q: Почему перед обновлением нужно явно устанавливать пакет {{pkg|usrmerge-hier-convert}}?'''
 
A: Его не так-то легко вытянуть по зависимостям. Совершая обновление системы, {{prg|apt}} формирует ''транзакцию'' для {{prg|rpm}} — своего рода техническое задание: «установи пакеты X, удали пакеты Y, обнови пакеты Z». Если в эту транзакцию попадает новый пакет {{pkg|filesystem}}, то {{pkg|usrmerge-hier-convert}} должен уже быть в системе на этапе <tt>%pretrans</tt>; его нельзя установить в той же транзакции.
 
'''Q: Зачем вы лезете в каталоги на стадии <tt>%pretrans</tt>? Почему бы не научить RPM автоматом класть compat-симлинки в {{path|/bin}}, если это самостоятельный каталог, а оригиналы в {{path|/usr/bin}}, и т. п.? А замену {{path|/bin}} на симлинк упаковать в файлтриггер и проводить тогда, когда там не осталось оригиналов.'''
 
A: Да, можно было бы написать файлтриггер, который проверяет, не состоят ли каталоги из списка 1 целиком из
симлинков внутрь {{path|/usr}}, и, если да, превращает такой каталог с симлинками в симлинк на каталог.
Правда, не вполне ясно, что он должен делать с {{path|/lib}}, внутри которого произвольная структура.
Главная же сложность здесь в том, что не так-то просто пропатчить {{prg|rpm}} соответствующим способом, особенно в условиях нехватки времени (core team минимум с 2017 года накладывали veto, пока не стало невмоготу). А ещё нужно было бы держать в репозитории два варианта пакета {{pkg|filesystem}}.


== User-visible impact ==
== User-visible impact ==
Меньше каталогов верхнего уровня в корне, кроме симлинков.
Меньше каталогов верхнего уровня в корне, кроме симлинков.
{{pkg|kernel-modules-nvidia}} для совместимости потребовалось переупаковать.
Для ядер, собранных в Sisyphus до момента переупаковки, эти модули обновить невозможно; соответственно, не получится на них откатиться, даже если они установлены в системе и известны загрузчику.
Чтобы обновить Sisyphus с unmerged-usr на merged-usr, недостаточно просто запустить обновление; нужно выполнить следующие действия:
# apt-get install usrmerge-hier-convert
Иными словами, программа {{prg|usrmerge-hier-convert}} должна уже быть в системе перед обновлением.
Перед установкой {{pkg|usrmerge-hier-convert}} проверяет, возможно ли преобразование файловой системы. Некоторые пакеты (их исчезающе мало) могут быть несовместимы с usrmerge, их придётся обновить или удалить заранее. Самый известный — {{pkg|vim}} (см. {{altbug|49541}}), который нужно обновить:
# apt-get install vim-console
После обновления и/или удаления таких пакетов надо снова попытаться установить {{pkg|usrmerge-hier-convert}}. Если проверка прошла успешно, можно обновляться.
# apt-get dist-upgrade
После обновления на новый {{pkg|filesystem}} пакет {{pkg|usrmerge-hier-convert}} ни для чего не нужен, и его можно смело удалить.
Это не коснётся обновления с p10; всё необходимое будет установлено в качестве обновлений в бранче p10.


== Appendix ==
== Appendix ==

Текущая версия от 03:14, 25 мая 2024


Usrmerge

Начиная с 23 апреля 2024 реализовано в Sisyphus. Текущие проблемы с обновлением описаны тут и тут

Глоссарий

merged-usr-иерархией называется такая FHS-подобная иерархия каталогов, в которой все неизменяемые при работе файлы из операционной системы (т. е. из состава пакетов в репозитории ОС) помещаются либо внутри префикса (/usr), либо их местоположение является ссылкой внутрь префикса. В такой иерархии /bin, /lib и т. д. будут симлинками на /usr/bin, /usr/lib и т. д. Иерархия, не отвечающая этому правилу (например, та, которую создавал инсталлятор до p11), называется unmerged-usr.

split-usr-конфигурация подразумевает, что исполнимый файл в процессе pid 1 из корневой файловой системы стартует до монтирования /usr, расположенного на отдельном разделе. split-usr не следует путать с unmerged-usr, хоть системы со свойством split-usr и являются подмножеством систем unmerged-usr.

Введение

Исторически[1] в UNIX System V, а позже и в мейнстримных линукс-дистрибутивах разделяли каталоги /bin и /usr/bin, /lib$suff и /usr/lib$suff, и т. п., давая возможность разместить /usr на отдельной файловой системе от /, содержащего все эти подкаталоги.

Позже, с увеличением средних размеров устройств хранения в машинах, сторонники разделения придумали другие обоснования (например, возможность из окружения в /{bin,sbin,libX,...}/ починить немонтирующуюся /usr). Но на сегодняшний день непонятно, какой набор утилит и нужных им so/иных файлов стоит признать частью "системы спасения", которая должна быть доступна без /usr, а какой — нет, ибо сами утилиты приобретают универсальный вид и широкие границы применимости. С развитием механизмов initramfs и живых загрузочных/установочных носителей, а также практикой "раздела восстановления" на локальном хранилище машины среди настольных дистрибутивов этот аргумент теряет всякий смысл.

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

  • либо переложить /usr/{bin,sbin,lib,libx32,lib64,libexec,local,share,src,...} в корень,
  • либо поместить аналоги этих каталогов из / в /usr.

Из двух вариантов, входящих в рамки FHS[2], второй лучше хотя бы тем, что уменьшает количество top-level каталогов, куда упаковывается постоянное содержимое пакетов, до одного. Сейчас среди FHS-совместимых дистрибутивов это типичный подход, на который в том числе потихоньку начинают полагаться апстримы прикладных пакетов.

Rationale

  • Один каталог (пусть с не очень удачным именем /usr) как объект манипуляции и как общий носитель фиксированного содержимого пакетов удобнее россыпи каталогов, полный список которых даже невозможно построить. Появляется даже смысл рассматривать его в виде отдельной точки монтирования, которую можно держать общей на многих машинах под общим управлением.
    • Один каталог легче снапшотить, по нему легче гонять find, ...
  • Упаковка всего пакетного содержимого в /usr открывает дорогу к виртуальному /, который не находится на устройстве хранения и содержит только пустые каталоги-точки-монтирования.
  • Возникает осмысленное разделение между /usr, /var и /etc: первый каталог несёт в себе постоянное содержимое пакетов, не предназначенное к ручной модификации (не через пакетную систему или доставку образа), а другие два уже исторически применяются для переменного хранимого состояния и общесистемных конфигов.
  • Сборочным скриптам и прочим интеграционным программным компонентам не нужно будет перебирать каталоги, в которых находится искомая программа.[3]
  • Начиная с версии 255, выпущенной в декабре 2023, systemd прекратит поддержку split-usr и unmerged-usr; вот коммит.
    • Из кода проекта systemd, помимо прочего, исчезнут все упоминания старых каталогов; например, директива ProtectKernelModules= больше не будет монтировать заглушку поверх /lib/modules, и т. п.

Proposed changes

Необходимые действия можно разбить на три стадии.

Стадия 1

1) Определить, что слиянию с аналогами внутри /usr подлежат следующие каталоги:

  /bin
  /lib
  /lib32
  /lib64
  /libx32
  /sbin

На каждой машине есть некоторые каталоги из этого списка; они и будут перенесены.

2) Ввести brp-модуль brp-dupe-bin, который на стадии brp завершается с ошибкой, если обнаружены разные файлы в /bin/x и /usr/bin/x, а если один из них есть ссылка на другой, устанавливает две копии такого файла по обоим путям с совпадающими атрибутами и контентом. Это нужно, чтобы приблизительно 22 пакета могли устанавливаться на все варианты иерархий: и на unmerged-usr, и на merged-usr. Создавать жёсткую ссылку нежелательно: если /bin/x и /usr/bin/x лежат на разных файловых системах, такой пакет туда не установится: RPM не рассечёт жёсткую ссылку на два одинаковых файла. Большинство пакетов, требующих исправления, достаточно будет просто пересобрать со специальным brp-модулем.

Некоторые пакеты, например, vim-common, упаковывают разные файловые объекты в /bin и /usr/bin; другие пакеты ставят файлы прямо в %buildroot/bin. Их потребуется исправить руками (готово: altbug:49541). (Справедливости ради, многие из них и так понадобится обновить)

Полный список таких будущих конфликтов на 2024-03-16:

[('bin/bsh', {'ash', 'bsh'}),
 ('bin/ksh', {'ksh', 'pdksh'}),
 ('bin/mail', {'mailutils', 'mailx'}),
 ('bin/ex', {'vi-traditional', 'vim-common', 'vim-minimal'}),
 ('bin/rview', {'vim-common', 'vim-minimal'}),
 ('bin/vi', {'vi-traditional', 'vim-minimal'}),
 ('sbin/halt', {'shepherd', 'systemd-sysvinit', 'sysvinit'}),
 ('sbin/reboot', {'shepherd', 'systemd-sysvinit', 'sysvinit'}),
 ('sbin/shutdown', {'shepherd', 'systemd-sysvinit', 'sysvinit'})]

Из перечисленных множеств пересекающихся в будущем пакетов многие уже явно конфликтуют друг с другом.

3) Подготовить пакет filesystem версии 3: поместить в нём скрипт, срабатывающий в %pretrans и переносящий содержимое каталогов из списка 1 внутрь /usr (т. е. под префикс). Сценарий файлтриггера должен будет давать предельно ясную информацию и диагностические сообщения на стандартные потоки. Нужно будет либо положиться на static coreutils, либо очень осторожно обращаться с обычными и dynamic linker.

4) Подготовить p10 к плавному обновлению на p11 и предшествующие ему срезы сизифа.

Стадия 2

Этот пункт вступает в действие на каждой машине индивидуально при обновлении её пакетов. Перед транзакцией, в которой ставят новый пакет filesystem, скрипт из пункта 2 вводит симлинки, завершая процесс usrmerge на данной системе.

Каждая инсталляция перейдёт к ней независимо, по мере обновления пакетов.

Стадия 3

Мейнтейнеры пакетов перейдут к ней после выпуска p11.

Заменить макросы, использующие старые каталоги (%_udevrulesdir, %_tmpfilesdir и другие), и пересобрать с ними пакеты, что-либо помещающие в эти каталоги. Приближённое число затрагиваемых бинарных пакетов:

% grep -E '^/(bin|lib[^/]*|sbin)/[a-zA-Z0-9_-]+' contents-index \
  | grep -vE '^/lib/(systemd|udev|sysusers.d|modules[^/]*|modprobe.d|security|tmpfiles.d)'
  \ # exclude known places
  | cut -f2 -d$'\t' | grep -v '^/' # exclude path provides
  | sort -u | wc -l
524

Это оценка по x86_64 + noarch. Исходных, конечно, будет меньше (333).

При обновлении на эти пакеты будет действовать правило 2, поэтому их содержимое будет доступно.

Incompatibilities

Если корневая файловая система — каскадная композиция на базе, например, overlayfs, и каталоги /bin и подобные находятся не в верхнем слое стека — автоматически обновить такую корневую файловую систему на filesystem > 3 не выйдет. Придётся либо не обновляться, либо пересобрать контейнер/систему на обновлённой пакетной базе.

FAQ

Рекомендуем прочитать другие материалы о преимуществах новой иерархии[4][5].

Q: А что, если /usr на отдельном разделе по каким-то причинам не примонтируется?

A: Тогда система не сможет загрузиться, как и в случае, если / по каким-то причинам не примонтируется.

Q: А раньше можно было, пользуясь программами в /, починить /usr

A: Несколько тезисов:

  • В-нулевых, для того, чтобы возникла такая ситуация, систему должны были установить так, чтобы /usr был отдельным от /, т. е. такая разметка преследовала какую-либо цель.
  • Во-первых, для этого нужно, чтобы / смог смонтироваться, а /usr не смог.
  • Во-вторых, всё ещё нет критерия, по которому ту или иную программу и её зависимости можно либо отнести к "системе спасения", либо исключить из неё и сослать в /usr.
  • В-третьих, нет ни одного задокументированного случая, где таким образом спасли какую-либо типичную GNU/Linux-систему, включая Альт, есть только предание из 1986 года, касавшееся non-Linux тех времён на компьютере тех времён. Рецептов такого восстановления, отчуждаемых от компетенций разработчиков ALT и умелых сисадминов, нет тем более. Следовательно, можно заключить, что в общем случае цитируемая возможность восстановить /usr из / — призрачна.
  • Несмотря на всё это, нет ничего плохого в том, чтобы рецепт такого спасения (при помощи операционной избыточности инсталляции альта) администратору предложить, но это должен быть явный механизм с минимумом издержек для остальной структуры системы. Есть множество вариантов это реализовать с разными преимуществами и минусами в разных установках; все они out of scope for this document.

Q: Зачем вам отдельная программа-конвертер? Есть же пакетный менеджер.

A: rpm не умеет заменять каталог (например, /x) на символическую ссылку. Ему надо помочь:

  • скопировать всё из каталога /x под префикс (под /usr) в новый каталог,
  • скопировать туда же содержимое аналогичного каталога /usr/x под префиксом,
  • атомически поменять местами новый каталог и /usr/x,
  • атомически поменять местами /x и ссылку на новый,
  • проследить, что в процессе ничего не потерялось, и удалить лишнее.

Проще всего это сделать на стадии %pretrans (дословно: перед транзакцией, перед манипуляцией пакетов), чтобы к началу установки пакетов всё уже было готово и процесс не зависел от порядка, в котором rpm ставит пакеты.

Q: Почему перед обновлением нужно явно устанавливать пакет usrmerge-hier-convert?

A: Его не так-то легко вытянуть по зависимостям. Совершая обновление системы, apt формирует транзакцию для rpm — своего рода техническое задание: «установи пакеты X, удали пакеты Y, обнови пакеты Z». Если в эту транзакцию попадает новый пакет filesystem, то usrmerge-hier-convert должен уже быть в системе на этапе %pretrans; его нельзя установить в той же транзакции.

Q: Зачем вы лезете в каталоги на стадии %pretrans? Почему бы не научить RPM автоматом класть compat-симлинки в /bin, если это самостоятельный каталог, а оригиналы в /usr/bin, и т. п.? А замену /bin на симлинк упаковать в файлтриггер и проводить тогда, когда там не осталось оригиналов.

A: Да, можно было бы написать файлтриггер, который проверяет, не состоят ли каталоги из списка 1 целиком из симлинков внутрь /usr, и, если да, превращает такой каталог с симлинками в симлинк на каталог. Правда, не вполне ясно, что он должен делать с /lib, внутри которого произвольная структура. Главная же сложность здесь в том, что не так-то просто пропатчить rpm соответствующим способом, особенно в условиях нехватки времени (core team минимум с 2017 года накладывали veto, пока не стало невмоготу). А ещё нужно было бы держать в репозитории два варианта пакета filesystem.

User-visible impact

Меньше каталогов верхнего уровня в корне, кроме симлинков.

kernel-modules-nvidia для совместимости потребовалось переупаковать. Для ядер, собранных в Sisyphus до момента переупаковки, эти модули обновить невозможно; соответственно, не получится на них откатиться, даже если они установлены в системе и известны загрузчику.

Чтобы обновить Sisyphus с unmerged-usr на merged-usr, недостаточно просто запустить обновление; нужно выполнить следующие действия:

# apt-get install usrmerge-hier-convert

Иными словами, программа usrmerge-hier-convert должна уже быть в системе перед обновлением.

Перед установкой usrmerge-hier-convert проверяет, возможно ли преобразование файловой системы. Некоторые пакеты (их исчезающе мало) могут быть несовместимы с usrmerge, их придётся обновить или удалить заранее. Самый известный — vim (см. altbug #49541), который нужно обновить:

# apt-get install vim-console

После обновления и/или удаления таких пакетов надо снова попытаться установить usrmerge-hier-convert. Если проверка прошла успешно, можно обновляться.

# apt-get dist-upgrade

После обновления на новый filesystem пакет usrmerge-hier-convert ни для чего не нужен, и его можно смело удалить.

Это не коснётся обновления с p10; всё необходимое будет установлено в качестве обновлений в бранче p10.

Appendix

  1. [1]
  2. [2]
  3. Вообще-то для этого нужно ещё провести слияние sbin и bin, но оно не несёт срочности и не рассматривается на этой странице.
  4. TheCaseForTheUsrMerge
  5. separate-usr-is-broken, примеры, где в ранней системе полагаются на наличие /usr}