Назад | Перейти на главную страницу

Определить точное местоположение GRUB / GRUB не работает после копирования образа диска

Я подготовил образ сервера Ubuntu с VirtualBox. Чтобы передать образ на SSD сервера, я сначала ddотредактировал MBR (512 байт), а затем раздел LVM (PV, содержащий корневой раздел, уменьшился до 3 ГБ). Серверу не удалось загрузиться из-за отсутствия некоторых частей GRUB. Появлялась подсказка о спасении grub.

Как я узнал из документации GRUB, это имеет смысл, потому что ее части (обычно) хранятся в дисковом пространстве между MBR и первым разделом.

Но как узнать где именно?

Я знаю, что могу просто скопировать все пространство перед первым разделом, но мне любопытно, есть ли какая-нибудь команда, которая показывает точное расположение различных частей GRUB.

Разъяснение: Отдельного загрузочного раздела нет. Есть только физический том LVM, содержащий только корневой раздел (с папкой / boot). Проблема с загрузкой также может быть решена с помощью chrootвставляя в скопированный образ и выполняя grub-install.

В MBR, созданной GRUB2, начиная со смещения 0x5c, существует 64-битное значение с прямым порядком байтов, указывающее номер следующего блока диска, который будет загружен. Часто это блок 0x00000000 00000001, то есть следующий блок после MBR.

(Согласно древнему соглашению DOS, первый раздел будет начинаться в начале цилиндра №1, поэтому обычно имеется ряд неиспользуемых блоков, доступных на цилиндре №0 после MBR. В современных системах первый раздел обычно выравнивается, начиная с блок # 2048, т.е. ровно 1 МБ от начала диска. Это дает еще больше свободных блоков перед началом первого раздела.)

Этот второй блок содержит еще немного кода ядра GRUB и список блоков, в котором указаны блоки для загрузки остальной части образа ядра GRUB. Черный список находится в самом конце этого блока. Каждая запись в черном списке имеет длину 12 байтов и имеет следующую структуру:

struct __attribute__ ((packed)) g2_blist_entry {
  uint64_t start_lba;  # the LBA block number of the first block covered by this entry
  uint16_t num_blocks; # number of blocks to read
  uint16_t startseg;   # segment address in memory to write them to
};

Обычно в черном списке есть только одна запись, охватывающая все остальные блоки для чтения, начиная с блока 0x00000000 00000002.

Длина основного образа GRUB зависит от версии GRUB и количества модулей, добавленных к ядру GRUB.

Например, в моей системе Debian 9, которая использует устаревшую загрузку MBR, GRUB включает в общей сложности 103 блока после MBR. На виртуальной машине RHEL 7.4 общая длина после MBR составляет 107 блоков.