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

вторник, 24 декабря 2013 г.

Что делать, если у вас маленький /, а обновить Федору очень хочется

В общем-то, не обязательно /, в общем случае это точка монтирования файловой системы, в которой находятся директории /var/lib/ и /var/tmp/. На моем рабочем компьютере эти директории находятся в корневой файловой системе, размер которой составляет всего 20 Гб. Это приводит к проблемам при штатном обновлении ядра через yum, что уж тогда говорить об обновлении всей системы.

Итак, обновляться я решил вчера, 23 декабря 2013 года, с Fedora 19 до Fedora 20, то есть уже после официального выхода Fedora 20. Инструмент для обновления - fedup-0.8.0-3, совсем недавно заменивший версию 0.7. Он запускается из командной строки и в процессе загрузки пакетов использует директории /var/lib/system-upgrade/ и /var/tmp/system-upgrade/. Опций для настройки других директорий нет (хотя в файле TODO.asciidoc, входящем в состав пакета fedup, такая возможность анонсируется в будущем). То есть, если запускать fedup без всяких предварительных настроек следующим образом:
fedup --network 20 --nogpgcheck
, то мой корневой раздел будет заполнен до отказа еще до начала реального обновления системы. Кстати, обратите внимание на опцию --nogpgcheck. Как я понял, она появилась в версии fedup 0.8, и без нее мой fedup не захотел работать.

Итак, что же делать? Самое очевидное решение - снести директории /var/lib/system-upgrade/ и /var/tmp/system-upgrade/ вместе с их содержимым, найти диск, на котором достаточно места для пары-тройки гигабайт обновлений, и создать символические ссылки на эти директории из /var/lib/system-upgrade и /var/tmp/system-upgrade. У меня нашлось достаточно места на диске, который монтируется в корневую файловую систему как /home. Поэтому, от имени суперпользователя я создал на нем две директории /home/fedup/cache/ и /home/fedup/packages/, а затем и упомянутые символические ссылки:
ln -s ../../home/fedup/cache /var/tmp/system-upgrade
ln -s ../../home/fedup/packages /var/lib/system-upgrade
Обратите внимание на то, что ссылки задаются не через абсолютные пути, а через относительные, это очень важно! Дело в том, что после перезагрузки системы для ее обновления все файловые системы, в том числе /home, будут смонтированы в /sysroot, а не в /, и загрузчик просто не сможет найти пакеты для обновления (см. об этом здесь).

В общем-то, на этом историю про обновление Fedora с небольшим дисковым пространством можно было бы и закончить. Но не тут-то было! Обновление Федоры - это почти всегда приключение, сопряженное с риском и опасностью, в которых не место домохозяйкам! После перезагрузки системы для дальнейшего обновления и загрузки нескольких сервисов systemd, запустился релэйблинг SELinux, как я понял на загруженные новые пакеты (хотя SELinux в системе у меня отключен). Помурыжив минут 15, компьютер перезагрузился, оставив опцию с апгрейдом системы в верхней строке загрузчика GRUB2. Я попробовал загрузить апгрейд снова: в итоге обычная загрузка GDM как ни в чем не бывало. То есть система не обновилась! Я перезагрузился в старое ядро от Fedora 19, снес Upgrade опцию из загрузчика:
fedup --resetbootloader
и запустил fedup--network 20 --nogpgcheck сначала. После серии таких попыток обновления я понял, что проблема не в новых пакетах, установленных неожиданным для fedup образом, а в чем-то другом. На правильный путь меня натолкнуло описание этого бага. В одном из комментариев было сказано про аргумент ядра systemd.unit=system-upgrade.target, который устанавливал старый fedup 0.7 для старта процесса обновления после перезагрузки системы. Я открыл /boot/grub2/grub.cfg, нашел секцию, соответствующую апгрейду системы, и вставил туда этот параметр, на авось, поскольку так и не понял, нужен ли он новому fedup 0.8 и установочному образу ядра. Кроме того, добавил туда же опцию selinux=0, чтобы не ждать релэйблинга новых пакетов (или чего-то там еще, не суть важно). Более того, новый fedup был так добр, что не установил в аргументы загрузки ядра опцию plymouth.splash=fedup: это в дальнейшем позволило наблюдать за реальным процессом установки пакетов в консоли, а не бестолковый графический прогрессбар. Если вы тоже захотите удалить эту опцию, то не пугайтесь, когда в процессе установки консоль заснет и дисплей погаснет: просто нажмите на клавиатуре Shift - это разбудит консоль.

Итак, как вы уже поняли, после добавления в аргументы загрузки ядра опции с systemd.unit, процесс пошел. Система обновилась, и после перезагрузки опция с апгрейдом системы ушла из меню GRUB2, что и должно было произойти. Однако, в момент загрузки новой Fedora 20 вернулась проблема с SELinux, с одной стороны неудивительно - я ведь устанавливал ее только для ядра, загружаемого для обновления системы. С другой стороны непонятно, почему fedup не вычистил эти пакеты сразу после обновления. После загрузки Fedora 20 и запуска fedup --clean все стало понятно: fedup сообщил, что он не в состоянии выполнить rmtree на символических ссылках. Пришлось вручную удалять все содержимое из директорий /home/fedup/cache/ и /home/fedup/packages/.

Осталось сказать, что проблему с нехваткой дискового пространства при обновлении ядра через yum решить просто - намного проще, чем с fedup. Создаем директорию /home/yum/cache/, открываем файл /etc/yum.conf и заменяем строку
cachedir=/var/cache/yum/$basearch/$releasever
на
cachedir=/home/yum/cache/$basearch/$releasever

четверг, 29 ноября 2012 г.

Закрашивание полей в linux консоли - баг или фича?

Пока разбирался с Powerline в linux консоли, обнаружил весьма интересный и поучительный баг. Поучительный - потому что пришлось просмотреть исходный код сразу четырех компонентов - плагина Powerline, vim, эмулятора видеотерминала и framebuffer драйвера в ядре linux. Баг проявляется при переключении между виртуальными консолями (в т.ч. графической) и заключается в закрашивании одного из полей монитора каким-либо цветом. На этой картинке цветная полоса находится внизу. Как это воспроизвести: запустите vim в консоли, но таким образом, чтобы сразу появлялась цветная статусная строка, для этого в $HOME/.vimrc должна присутствовать строка
set laststatus=2
Затем сразу же переключитесь в другую консоль и обратно - вы получите полосу, закрашенную цветом статусной строки в одном из полей консоли. Если теперь вы закроете vim и снова переключитесь в другую консоль и обратно, то цветная полоса уйдет.

Сначала я подумал, что во всем виноваты Powerline или vim, но потом до меня дошло, что user space программа не может быть виновна в закрашивании области, которая ей даже не доступна! Значит проблема в ядре, в частности в эмуляторе видеотерминала или драйвере фреймбуфера. В подтверждение этому - следующий эксперимент.

Запустите в консоли любую псевдографическую программу, например в своей системе я нашел программу system-config-firewall-tui. Программа переведет консоль в псевдографический режим с синим полем и тремя кнопками (одна из них - Отмена, так что ничего страшного после ее запуска не не произойдет). Внимательно посмотрите на края монитора. Теперь переключитесь в другую консоль и обратно. Количество синего увеличилось, не так ли? Закройте программу и нажмите несколько раз Enter чтобы добавить черного цвета снизу. Видите точно такую же полосу, как в vim, только синего цвета? Еще одно переключение туда-обратно сотрет ее.

Изучение кода ядра вскрыло проблему. Оказывается, при переключении консоли в функции fbcon_switch() (см. drivers/video/console/fbcon.c) вызывается функция fbcon_clear_margins(), которая вызывает метод ops->clear_margins(), который, в свою очередь, закрашивает поля (margins, но как правило, это одно поле) цветом vc->vc_video_erase_char (см. функцию ud_clear_margins() в drivers/video/console/fbcon_ud.c и подобные им в других подобных файлах, которые в свою очередь вызывают функцию attr_col_ec() из drivers/video/console/fbcon.h). Проблема в том, что цвет  vc->vc_video_erase_char в псевдографике может зависеть от погоды и расположения звезд.

Зачем это сделано? Как я понял, некоторые режимы фреймбуфера могут использовать поля монитора, и при переключении в другую консоль эти поля нужно очищать, чтобы не наблюдать все время, например, кусок застывшего видео сбоку или снизу. Как очищать, каким цветом? В интернете я нашел патч, написанный еще в 2003 году, в котором предлагалось закрашивать поля черным цветом (см. здесь и здесь), однако, как я понял из дискуссии, использовать черный цвет не всегда правильно, поскольку графические дисплеи могут быть разные. Таким образом, закрашивание цветом erase char - это меньшее из зол.