Как ядро ​​монтирует корневой раздел?

29

Мой вопрос касается загрузки системы Linux из отдельного раздела / boot. Если большинство файлов конфигурации находятся в отдельном разделе /, как ядро ​​правильно монтирует его во время загрузки?

Любая проработка этого была бы великолепна. Я чувствую, что мне не хватает чего-то простого. В основном меня интересует процесс и порядок операций.

Благодарность!

РЕДАКТИРОВАТЬ: Я думаю, что мне нужно было спросить больше о файле dev, который используется в параметре корневого ядра. Например, скажем, я задаю свой корневой параметр как root = / dev / sda2. Как ядро ​​отображает файл / dev / sda2?

Мистер Шикаданс
источник
Хотя люди ниже описывают initrd, мало обсуждается, почему используется initrd. У меня сложилось такое впечатление, что дистрибутивы, подобные Debian, хотят использовать одно ядро ​​на множестве разных машин с одинаковой архитектурой, но, возможно, с совершенно разным оборудованием Это стало возможным благодаря модульной поддержке оборудования через модули ядра. Initrd не требует большой аппаратной поддержки для загрузки, и, как только он это делает, он загружает необходимые аппаратные модули для продолжения. Разработки / исправления к этому приветствуются.
Фахим Митха
Вы не можете смонтировать / boot без использования / mount, поскольку нет каталога / boot без /
psusi

Ответы:

20

Linux изначально загружается с RAM- initrdдиска (называемого , для "INITial RamDisk") как /. Этого диска достаточно, чтобы найти настоящий корневой раздел (включая любые необходимые драйверы и модули файловой системы). Он монтирует корневой раздел во временную точку монтирования на initrd, а затем вызывает, pivot_root(8)чтобы поменять местами корневую и временную точки монтирования, оставляя initrdположение для umountредактирования и фактическую корневую файловую систему включенной /.

geekosaur
источник
2
Что если у вас нет такого initrd, как LFS (linuxfromscratch.org)?
Мистер Шикаданс
@Мистер. Shickadance: Не глядя на то, как работает LFS, я бы предположил, что они удостоверяются, что в ядре есть все необходимые модули, скомпилированные в него (или загруженные через GRUB 2, причем такая возможность достаточно нова, что еще не многие дистрибутивы заметили это), поэтому может начаться с реального корневого раздела.
geekosaur
4
@Мистер. Shickadance. Это не просто LFS, у которого нет initrd. Любой, кто собирает свое собственное ядро, имеет возможность не использовать initrd, что я и делаю в Gentoo.
Jonescb
1
@Faheem: модули grub2 отличаются от модулей ядра. Я вижу некоторую возможность для grub2 загружать модули ядра, но я не знаю, сработает ли это для ядра Linux или только для * BSD (где загрузчик загружает модули ядра нормально). Я подозреваю, что ядру нужно научить, где искать карту адресов для загруженных модулей, и всем нужно перейти на grub2 (grub1 все еще стандартен в некоторых дистрибутивах).
geekosaur
1
Initrd был заменен на initramfs, так как pivot_root считался грязным хаком.
psusi
41

В древние времена ядро ​​было жестко запрограммировано, чтобы знать основной / младший номер устройства root fs, и монтировало это устройство после инициализации всех драйверов устройств, которые были встроены в ядро. rdevУтилита может быть использована для изменения количества корневого устройства в образе ядра без необходимости перекомпилировать его.

В конце концов появились загрузчики, которые могли передать командную строку ядру. Если root=аргумент был передан, это говорит ядру, где находится корень fs вместо встроенного значения. Драйверы, необходимые для доступа, должны быть встроены в ядро. Несмотря на то, что аргумент выглядит как обычный узел устройства в /devкаталоге, очевидно, что нет /devкаталога до монтирования корневого fs, поэтому ядро ​​не может искать там узел dev. Вместо этого некоторые хорошо известные имена устройств жестко запрограммированы в ядре, поэтому строку можно преобразовать в номер устройства. Из-за этого ядро ​​может распознавать такие вещи, как /dev/sda1, но не более экзотические вещи, такие /dev/mapper/vg0-rootкак UUID тома или тома.

Позже initrdпришло в картину. Наряду с ядром загрузчик будет загружать initrdобраз, представляющий собой сжатый образ файловой системы (образ gzipped ext2, образ gzipped romfs, в конечном итоге squashfs стал доминирующим). Ядро распаковывает этот образ в виртуальный диск и монтирует виртуальный диск как корень fs. Этот образ содержит некоторые дополнительные драйверы и загрузочные скрипты вместо реальных init. Эти загрузочные сценарии выполняли различные задачи для распознавания оборудования, активации таких вещей, как raid-массивы и LVM, обнаружение UUID и синтаксический анализ командной строки ядра, чтобы найти реальный корень, который теперь можно указывать с помощью UUID, метки тома и других сложных вещей. Затем он смонтировал настоящий root-файл /initrd, затем выполнил pivot_rootсистемный вызов для замены ядра /и/initrd, затем exec /sbin/initдля реального корня, который затем размонтирует /initrdи освободит виртуальный диск.

Наконец, сегодня у нас есть initramfs. Это похоже на initrd, но вместо сжатого образа файловой системы, загружаемого в виртуальный диск, это сжатый архив cpio. Tmpfs монтируется как корень, и архив там извлекается. Вместо использования pivot_root, которое считалось грязным хаком, initramfsзагрузочные скрипты монтируют настоящий корень /root, удаляют все файлы в корне tmpfs, затем chrootв /rootи исполняют /sbin/init.

psusi
источник
1
После chroot tmpfs автоматически отключается? Это просто исчезает?
jiggunjer
@jiggunjer, нет, он все еще там, он просто пустой (кроме каталога / root) и больше не используется.
Псуси
Я узнал что-то новое о каждой итерации root fs, которую вы упомянули. Отличный ответ!
jpaugh
3

Похоже, вы спрашиваете, как ядро ​​«знает», какой раздел является корневым разделом, без доступа к файлам конфигурации в / etc.

Ядро может принимать аргументы командной строки, как и любая другая программа. GRUB или большинство других загрузчиков могут принимать аргументы командной строки в качестве пользовательского ввода или сохранять их и делать различные комбинации аргументов командной строки доступными через меню. Загрузчик передает аргументы командной строки ядру при его загрузке (я не знаю названия или механизма этого соглашения, но, вероятно, это похоже на то, как приложение получает аргументы командной строки от вызывающего процесса в работающем ядре).

Один из этих вариантов командной строки root, где вы можете указать корневую файловую систему, то есть root=/dev/sda1.

Если ядро ​​использует initrd, загрузчик отвечает за то, чтобы сообщить ядру, где оно находится, или помещает initrd в стандартную область памяти (я думаю) - по крайней мере, так работает на моем Guruplug.

Вполне возможно не указывать его, а затем сразу начать паниковать с ядром, жалуясь на то, что он не может найти корневую файловую систему.

Могут быть и другие способы передачи этой опции ядру.

LawrenceC
источник
3
Это правильное объяснение, когда нет initrd / initramfs, но в нем не хватает части головоломки. Обычно ядро ​​идентифицирует устройство, например, /dev/sda1потому что это запись в файловой системе. Вы могли бы сделать cp -p /dev/sda1 /tmp/fooи /tmp/fooпредставляете одно и то же устройство. В командной строке ядра ядро ​​использует встроенный синтаксический анализатор, который следует обычному соглашению об именах устройств: sda1означает первый раздел первого SCSI-подобного диска.
Жиль "ТАК - перестань быть злым"
@ Жиль, так что современные ядра до сих пор не справляются с монтированием тома на основе UUID? без initrdили initramfsя имею в виду. Это должен быть «простой» раздел в /dev/sdxформе?
Jiggunjer
1
@jiggunjer Современные ядра поддерживают поиск тома по UUID. См init/do_mounts.c.
Жиль "ТАК - прекрати быть злым"
1

Grub монтирует /bootраздел и затем запускает ядро. В конфигурации Grub он сообщает ядру, что использовать в качестве корневого устройства.

Например, в Grub's menu.lst:

kernel /boot/linux root=/dev/sda2
jonescb
источник
1

Да ладно, GRUB не «монтирует» / boot, он просто читает «menu.lst» и некоторые модули, он также не является частью ядра LINUX. Когда вы вызываете ядро, вы передаете «корневой» аргумент с корневым разделом. В худшем случае ядро ​​знает, что just / boot был смонтирован (LOL).

Далее: geekosaur прав, Linux использует исходный псевдодиск в формате сжатого изображения, а затем монтирует реальную корневую файловую систему с помощью вызова pivot_root. Таким образом, Linux начинает работать с образа, а затем с вашего локального диска.

D4RIO
источник
1
У Grub определенно есть возможность «монтировать» файловую систему, особенно в Grub2. Конечно, все, на что он способен / делает / с этим, это ищет загрузочные ядра той или иной полосы, но это все еще монтируется. Кроме того, Linux не требует initrd, если ваше ядро ​​не скомпилировало драйверы, необходимые для вашего жесткого диска в качестве модулей.
Шадур
5
ibm.com/developerworks/linux/library/l-linuxboot Это довольно краткое описание того, что ядро ​​Linux делает при загрузке.
Jsbillings
2
@Shadur, из man- страницы по монтированию : Все файлы, доступные в системе Unix, расположены в одном большом дереве, иерархии файлов, с корнем в /. Эти файлы могут быть распределены по нескольким устройствам. Команда mount служит для присоединения файловой системы, найденной на каком-либо устройстве, к большому файловому дереву. - Поскольку файловые системы, используемые GRUB, не привязаны к файловой иерархии, она НЕ монтируется .
D4RIO
1
@Shadur, BTW: Очевидно, что initrd не нужен, поскольку это просто другая корневая файловая система, но обычно он используется как небольшой корневой каталог при загрузке, поскольку ядро ​​загружает необходимое для загрузки, затем загружается и, наконец, загружает все остальное.
D4RIO
1
@ d4rio Они монтируются GRUB, а не linux - это легче понять, когда вы рассматриваете grub как отдельную ОС для микроядра, а не просто как загрузчик.
Шадур
1

Загрузчик, будь то grub или lilo или что-то еще, сообщает ядру, где искать с root=флагом, и дополнительно загружает начальный виртуальный диск в память через initrdперед загрузкой ядра.

Затем ядро ​​загружает, тестирует свое оборудование и драйверы устройств и просматривает систему на предмет того, что оно может видеть (вы можете просмотреть эту диагностическую информацию, набрав dmesg; в настоящее время оно, вероятно, прокручивается слишком быстро, чтобы видеть), а затем пытается смонтировать раздел, упомянутый в root=параметр.

Если присутствует initrd, он монтируется первым, и все модули / драйверы на нем загружаются и проверяются перед монтированием корневой файловой системы. Таким образом, вы можете скомпилировать драйверы для ваших жестких дисков в виде модулей и при этом иметь возможность загружаться.

Shadur
источник