LINUX.ORG.RU

Чиним тормоза и зависоны GRUB

 ,


0

1

По результатам вчерашнего изучения ситуации с зависанием os-prober-а, о чем писал в теме Немейнстримные RPM-based дистрибутивы: зачем и почему (комментарий)

По итогу причиной оказалась запредельная крутизна O()-метрики алгоритма из-за некачественного кода.

Проблем оказалось две. Первая затрагивает логику работы утилиты grub-mount. А вторая общую логику работы файловой подсистемы GRUB. Вот они:

  1. https://github.com/wandrien/grub/issues/1

  2. https://github.com/wandrien/grub/issues/2

Вот ветка с фиксом для 1-й проблемы: https://github.com/wandrien/grub/commits/grub-mount-fixes

2-й еще не занимался.

Я пока не стал писать в апстрим. Загрузил код на гитхаб и там же разместил тексты багрепортов. Как сформирую цельный пачсет, тогда напишу в апстрим на Саванну.

Желающие помочь с кодом/пул-реквестами/тестированием/исправлением моего английского/умными идеями - are welcome.

Да, по второму багу. Знаете, что GRUB делает на каждом вызове функции grub_file_open()? Каждый раз заново детектирует файловую систему на разделе.

Я пока не знаю, разумного объяснения, почему так сделано. Ну то есть… если это сделано специально?

Пока что считаю, что это просто было сделано по принципу «работает и ладно», и поэтому исправить проблему труда не составит. Дальше посмотрим…

Ответ на: комментарий от chenbr0

Я затрудняюсь с пониманием вопроса. Данная проблема проявляется в нативном grub и в утилите grub-mount при чтении каталогов с большим количеством файлов. При чем тут freebsd.

wandrien ★★
() автор топика

Тоже помню какие-то тормоза в grub-е, но поскольку он нужен раз в месяц то даже не думал разбираться. Но твою инициативу одобряю, подобные гадости надо искоренять.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

По итогу причиной оказалась запредельная крутизна O()-метрики алгоритма из-за некачественного кода.

Из вашего описания видно, что «метрика вызовов функции» становится O(N*2), что упрощается до O(N), здесь нет O(N^2), более того, всё это кешируется ещё при первом обращении. Вероятно проблема в чём-то другом, например, логических или физических повреждениях диска.

raspopov
()
Ответ на: комментарий от raspopov

здесь нет O(N^2)

int i, j, size = 1000;
for (i = 0; i < size; i++)
{
  for (j = 0; j <= i; j++)
  {
     printf("%d, %d\n", i, j);
  }
}

Какова сложность алгоритма относительно size?

всё это кешируется ещё при первом обращении

Нет.

Вероятно проблема в чём-то другом, например, логических или физических повреждениях диска.

Нет.

wandrien ★★
() автор топика
Последнее исправление: wandrien (всего исправлений: 1)

Мне интересно. Почему GRUB до сих пор популярен на UEFI системах? Мне кажется, что лучше либо EFISTUB, если без дуалбутов. А если с дуалбутами, то rEFInd. Нет убогой генерации конфига, обнаруживает загрузчики прямо на месте. Нескучные обои тоже есть. Статические конфиги тоже поддерживаются. И зачем везде пихают grub?

Werenter ★★★
()
Последнее исправление: Werenter (всего исправлений: 1)
Ответ на: комментарий от wandrien

И то, не совсем. GRUB не может, будучи загруженным в EFI режиме, запускать ОС в режиме BIOS. А если нет полной переносимости, то мне кажется надо делать так: делать в зависимости от режима, в котором запустили установщик, выбор загрузчика. Если BIOS - то граб, и выбирать нечего. А если UEFI - то на выбор grub, rEFInd и EFISTUB. Естественно привести краткие описания каждого из вариантов. По умолчанию можно оставить таки граб.

Werenter ★★★
()
Ответ на: комментарий от raspopov

Тогда с примером реального кода, пожалуйста, а то я даже grub_file_open() не нашёл в исходниках grub.

Реальный код есть по ссылке. Я потратил вечер, чтобы локализовать проблему и разобраться в коде, и еще половину рабочего дня, чтобы работать с кодом. Потрудитесь и вы.

Вы grep по исходникам запустить не посчитали нужным, но выше уверенно заявляли «всё это кешируется ещё при первом обращении».

wandrien ★★
() автор топика
Ответ на: комментарий от Werenter

Всё не так

GRUB не может, будучи загруженным в EFI режиме, запускать ОС в режиме BIOS.

т.е. «прошивка» работает как и планировалось.

Или имеется ввиду нечто другое?

Для установленного линукса можно менять режим загрузки

  • установить требуемый загрузчик
  • переключить режим в Биос

Кстати… Ядро EFIstub в legacy же в принципе не умеет?

master_0K
()
Ответ на: комментарий от master_0K

Речь шла о том, чтобы загрузчик не переустанавливать, а делать так: имеем загрузчик, запускаемый в UEFI режиме, но умеющий и BIOS загрузку(читать загрузочный сектор). Это было бы полезно на некоторых говноноутах, где нет legacy режима, но хочется использовать например Windows XP. То есть имеем UEFI загрузчик, в котором реализована BIOS загрузка, прямо в загрузчике.

Werenter ★★★
()
Ответ на: комментарий от wandrien

Вы grep по исходникам запустить не посчитали нужным

GitHub не переиндексировал исходники на момент моей первой проверки репы (я даже не знал что так бывает, если честно), а вот сейчас уже вижу результаты поиска…

raspopov
()
Ответ на: комментарий от Werenter

Так оно не работает. Состояние компьютера при загрузке в legacy и в UEFI сильно разное.

У винды это жестко задано (режим загрузки и т.п.). Хочешь менять: переустанавливай. В линукс всё иначе: нужно установить и сконфигурировать загрузчик. И этого обычно хватает.

Это было бы полезно на некоторых говноноутах, где нет legacy режима, но хочется использовать например Windows XP

«Натягиваешь» ВМ, которая имитирует «старый-добрый биос» и в ней сразу запускаешь «динозавра» вроде Windows XP

master_0K
()
27 апреля 2024 г.
Ответ на: комментарий от Werenter

Один хрен некропостинг пошёл…

А если с дуалбутами, то rEFInd.

Сравни список поддерживаемых фс у обоих для начала. А ещё я слышал умную фразу, что «рефинд - это менеджер(boot manager), а граб - загрузчик(bootloader)». Правда я не знаю, что это значит :)

Нет убогой генерации конфига, обнаруживает загрузчики прямо на месте.

Граб тоже так умеет

set timeout=3

insmod regexp

load_env

if [ -n "$last_selected" ] ; then
        set default="$last_selected"
fi


set kernelCmdLine="root=PARTUUID=a97cbeae-e056-4e68-8ab0-2d53fd5e37ca rootfstype=xfs ro"
search --fs-uuid c3c15b5b-79d8-410a-8dbd-59d467d0225c --set root

#https://lists.gnu.org/archive/html/grub-devel/2010-08/msg00060.html

for linuxKernel in /vmlinuz-* ; do
        menuentry "$linuxKernel" {

                if [ "$last_selected" != "$chosen" ] ; then
                        echo "[GRUB] Updating env"
                        set last_selected="$chosen"
                        save_env last_selected
                fi

                echo "[GRUB] Loading $chosen"
                linux $1 $kernelCmdLine
                echo ""
        }
done


menuentry 'Memtest86+'{
        search --fs-uuid 43ac4df5-bcd0-4984-bf63-b1fb9e1ebcc3 --set root
        linux16 /boot/memtest86plus/memtest.bin
}

menuentry 'Halt'{halt}
menuentry 'Reboot'{reboot}

Этот конфиг, который я однажды написал под свои нужды, избавляет от необходимости каждый раз обновлении ядра генерировать конфиг заново. Он делает ровно то, что ты описал выше как преимущество рефинда - автоматически обнаруживает все ядра, которые начинаются с «vmlinuz-» и выводит их в меню для выбора.

Нескучные обои тоже есть.

Как и в грабе.

И зачем везде пихают grub?

Затем, что он просто работает?

u5er
()
Ответ на: комментарий от u5er

Сравни список поддерживаемых фс у обоих для начала

Вот список драйверов фс поддерживаемых рефиндом, какую фс поддерживает груб а рефинд нет? ;)

usr/lib/efifs-aa64/affs_aa64.efi
usr/lib/efifs-aa64/bfs_aa64.efi
usr/lib/efifs-aa64/btrfs_aa64.efi
usr/lib/efifs-aa64/exfat_aa64.efi
usr/lib/efifs-aa64/ext2_aa64.efi
usr/lib/efifs-aa64/f2fs_aa64.efi
usr/lib/efifs-aa64/hfs_aa64.efi
usr/lib/efifs-aa64/hfsplus_aa64.efi
usr/lib/efifs-aa64/iso9660_aa64.efi
usr/lib/efifs-aa64/jfs_aa64.efi
usr/lib/efifs-aa64/nilfs2_aa64.efi
usr/lib/efifs-aa64/ntfs_aa64.efi
usr/lib/efifs-aa64/reiserfs_aa64.efi
usr/lib/efifs-aa64/sfs_aa64.efi
usr/lib/efifs-aa64/udf_aa64.efi
usr/lib/efifs-aa64/ufs2_aa64.efi
usr/lib/efifs-aa64/xfs_aa64.efi
usr/lib/efifs-aa64/zfs_aa64.efi
usr/lib/efifs-arm/
usr/lib/efifs-arm/affs_arm.efi
usr/lib/efifs-arm/bfs_arm.efi
usr/lib/efifs-arm/btrfs_arm.efi
usr/lib/efifs-arm/exfat_arm.efi
usr/lib/efifs-arm/ext2_arm.efi
usr/lib/efifs-arm/f2fs_arm.efi
usr/lib/efifs-arm/hfs_arm.efi
usr/lib/efifs-arm/hfsplus_arm.efi
usr/lib/efifs-arm/iso9660_arm.efi
usr/lib/efifs-arm/jfs_arm.efi
usr/lib/efifs-arm/nilfs2_arm.efi
usr/lib/efifs-arm/ntfs_arm.efi
usr/lib/efifs-arm/reiserfs_arm.efi
usr/lib/efifs-arm/sfs_arm.efi
usr/lib/efifs-arm/udf_arm.efi
usr/lib/efifs-arm/ufs2_arm.efi
usr/lib/efifs-arm/xfs_arm.efi
usr/lib/efifs-arm/zfs_arm.efi
usr/lib/efifs-ia32/
usr/lib/efifs-ia32/affs_ia32.efi
usr/lib/efifs-ia32/bfs_ia32.efi
usr/lib/efifs-ia32/btrfs_ia32.efi
usr/lib/efifs-ia32/exfat_ia32.efi
usr/lib/efifs-ia32/ext2_ia32.efi
usr/lib/efifs-ia32/f2fs_ia32.efi
usr/lib/efifs-ia32/hfs_ia32.efi
usr/lib/efifs-ia32/hfsplus_ia32.efi
usr/lib/efifs-ia32/iso9660_ia32.efi
usr/lib/efifs-ia32/jfs_ia32.efi
usr/lib/efifs-ia32/nilfs2_ia32.efi
usr/lib/efifs-ia32/ntfs_ia32.efi
usr/lib/efifs-ia32/reiserfs_ia32.efi
usr/lib/efifs-ia32/sfs_ia32.efi
usr/lib/efifs-ia32/udf_ia32.efi
usr/lib/efifs-ia32/ufs2_ia32.efi
usr/lib/efifs-ia32/xfs_ia32.efi
usr/lib/efifs-ia32/zfs_ia32.efi
usr/lib/efifs-riscv64/
usr/lib/efifs-riscv64/affs_riscv64.efi
usr/lib/efifs-riscv64/bfs_riscv64.efi
usr/lib/efifs-riscv64/btrfs_riscv64.efi
usr/lib/efifs-riscv64/exfat_riscv64.efi
usr/lib/efifs-riscv64/ext2_riscv64.efi
usr/lib/efifs-riscv64/f2fs_riscv64.efi
usr/lib/efifs-riscv64/hfs_riscv64.efi
usr/lib/efifs-riscv64/hfsplus_riscv64.efi
usr/lib/efifs-riscv64/iso9660_riscv64.efi
usr/lib/efifs-riscv64/jfs_riscv64.efi
usr/lib/efifs-riscv64/nilfs2_riscv64.efi
usr/lib/efifs-riscv64/ntfs_riscv64.efi
usr/lib/efifs-riscv64/reiserfs_riscv64.efi
usr/lib/efifs-riscv64/sfs_riscv64.efi
usr/lib/efifs-riscv64/udf_riscv64.efi
usr/lib/efifs-riscv64/ufs2_riscv64.efi
usr/lib/efifs-riscv64/xfs_riscv64.efi
usr/lib/efifs-riscv64/zfs_riscv64.efi
usr/lib/efifs-x64/
usr/lib/efifs-x64/affs_x64.efi
usr/lib/efifs-x64/bfs_x64.efi
usr/lib/efifs-x64/btrfs_x64.efi
usr/lib/efifs-x64/exfat_x64.efi
usr/lib/efifs-x64/ext2_x64.efi
usr/lib/efifs-x64/f2fs_x64.efi
usr/lib/efifs-x64/hfs_x64.efi
usr/lib/efifs-x64/hfsplus_x64.efi
usr/lib/efifs-x64/iso9660_x64.efi
usr/lib/efifs-x64/jfs_x64.efi
usr/lib/efifs-x64/nilfs2_x64.efi
usr/lib/efifs-x64/ntfs_x64.efi
usr/lib/efifs-x64/reiserfs_x64.efi
usr/lib/efifs-x64/sfs_x64.efi
usr/lib/efifs-x64/udf_x64.efi
usr/lib/efifs-x64/ufs2_x64.efi
usr/lib/efifs-x64/xfs_x64.efi
usr/lib/efifs-x64/zfs_x64.efi
anonymous
()
Ответ на: комментарий от u5er

А ещё я слышал умную фразу, что «рефинд - это менеджер(boot manager), а граб - загрузчик(bootloader)».

Слышал звон да не знаю где он

Рефинд это и менеджер загрузчиков и загрузчик который непосредственно грузит ядро или приложение, такую функциональность с натяжкой и ограниченно груб предоставляет только с OS_prober подключенным

anonymous
()