Глава 18. Сложные темы

18.1. Как можно узнать больше о внутреннем устройстве FreeBSD?
18.2. Как можно оказать помощь проекту FreeBSD?
18.3. Что такое снапшоты и релизы?
18.4. Можно ли работать с -CURRENT при ограниченном доступе в Internet?
18.5. Я написал некоторое добавление к ядру, кому его послать?
18.6. Что делать при аварийном останове системы?
18.7. Перестала работать функция dlsym() для исполняемых файлов ELF!
18.8. Как я могу увеличить или уменьшить адресное пространство ядра в архитектуре i386?

18.1.

Как можно узнать больше о внутреннем устройстве FreeBSD?

Список относящихся к делу книг можно найти в разделе Руководства Библиография по внутреннему устройству операционной системы.

Кроме того, большинство общих знаний о UNIX(R) непосредственно применимо к FreeBSD.

18.2.

Как можно оказать помощь проекту FreeBSD?

Пожалуйста, обратитесь к соответствующей статье, в которой вы получите советы относительно того, как это сделать. Ваша помощь более чем приветствуется!

18.3.

Что такое снапшоты и релизы?

В Хранилище Subversion сейчас находятся 4 активно/полуактивно развивающихся ветки FreeBSD. (Более ранние ветки изменяются очень редко, именно поэтому в разработке только 4 активные ветки):

  • stable/8/, также известная как 8-STABLE

  • stable/9/, также известная как 9-STABLE

  • stable/10/, также известная как 10-STABLE

  • head/, также известная как -CURRENT и 11-CURRENT

HEAD - это не настоящий тэг ветки. Это символьная константа для обозначения текущего, не ветвящегося, находящегося в разработке дерева, то есть -CURRENT.

На данный момент -CURRENT является находящимся в разработке деревом 11.X; ветка 10-STABLE, stable/10/, отделилась от -CURRENT в январе 2014 года года, а ветка 9-STABLE, stable/9/, отделилась от -CURRENT в сентябре 2011 года.

18.4.

Можно ли работать с -CURRENT при ограниченном доступе в Internet?

Да, это можно делать без скачивания полного дерева исходных текстов с помощью системы CTM.

18.5.

Я написал некоторое добавление к ядру, кому его послать?

Обратитесь к статье о том, как помочь проекту FreeBSD, чтобы выяснить, как это сделать.

И спасибо Вам за Ваши усилия!

18.6.

Что делать при аварийном останове системы?

Вот типичная паника ядра:

Fatal trap 12: page fault while in kernel mode
fault virtual address   = 0x40
fault code              = supervisor read, page not present
instruction pointer     = 0x8:0xf014a7e5
stack pointer           = 0x10:0xf4ed6f24
frame pointer           = 0x10:0xf4ed6f28
code segment            = base 0x0, limit 0xfffff, type 0x1b
                        = DPL 0, pres 1, def32 1, gran 1
processor eflags        = interrupt enabled, resume, IOPL = 0
current process         = 80 (mount)
interrupt mask          =
trap number             = 12
panic: page fault

Этого сообщения не достаточно. Здесь важно значение указателя инструкций, но оно зависит от конфигурации, поскольку значение меняется для каждого конкретного файла ядра. Если это ядро GENERIC из одного из снэпшотов, то кто-то ещё может отследить функцию, вызвавшую ошибку, но в случае со специально сконфигурированным ядром только вы можете сказать нам, где случилась ошибка.

Чтобы продолжить:

  1. Запишите значение указателя инструкций. Заметьте, что часть 0x8: в этом случае не важна: нам нужна часть 0xf0xxxxxx.

  2. Когда система перезагрузится, сделайте следующее:

    % nm -n kernel.that.caused.the.panic | grep f0xxxxxx

    где f0xxxxxx - это значение указателя инструкций. Однако неприятность заключается в том, что вы не получите точного соответствия, так как в таблице имен ядра для точек входа в функции даны адреса на начало функций, а указатель инструкций будет указывать куда-то внутрь её тела. Если вы не получили точного соответствия, опустите последнюю цифру в значении указателя инструкций и попробуйте снова:

    % nm -n kernel.that.caused.the.panic | grep f0xxxxx

    Если и это не привело ни к каким результатам, отрежьте следующую цифру. Повторяйте, пока не получите хоть что-то. Результатом будет список функций, которые, возможно, привели к аварийному останову. Этот механизм обнаружения ошибочного места довольно неточен, но это всё же лучше, чем ничего.

Тем не менее, лучшим способом выяснить причину, вызвавшую аварийный останов, является получение аварийного дампа системы, а затем использование kgdb(1) для получения трассировки вызовов в этом дампе.

В любом случае, метод таков:

  1. Убедитесь в том, что в файле конфигурации ядра имеется следующая строка:

    makeoptions     DEBUG=-g          # Build kernel with gdb(1) debug symbols
  2. Перейдите в каталог /usr/src:

    # cd /usr/src
  3. Скомпилируйте ядро:

    # make buildkernel KERNCONF=MYKERNEL
  4. Дождитесь завершения компиляции.

  5. # make installkernel KERNCONF=MYKERNEL
  6. Выполните перезагрузку.

Примечание:

Если не указать KERNCONF, то будет собрано и установлено ядро GENERIC.

В процессе выполнения команды make(1) будут построены два ядра, /usr/obj/usr/src/sys/MYKERNEL/kernel и /usr/obj/usr/src/sys/MYKERNEL/kernel.debug. kernel будет установлен как /boot/kernel/kernel, тогда как kernel.debug может быть использован в качестве источника отладочных символов для kgdb(1).

Чтобы получать аварийный дамп, отредактируйте файл /etc/rc.conf так, чтобы устройство dumpdev указывало на раздел подкачки или имело значение AUTO. В этом случае скрипты rc(8) будут вызывать команду dumpon(8) для создания аварийных дампов. Эту команду можно также запускать вручную. После аварийной остановки аварийный дамп может быть получен с помощью программы savecore(8) если значение переменной dumpdev было установлено в /etc/rc.conf, скрипты rc(8) запустят savecore(8) автоматически и поместят аварийный дамп в каталог /var/crash.

Примечание:

Аварийные дампы FreeBSD обычно имеют размер, равный объёму оперативной памяти. Поэтому убедитесь в наличии достаточного места для хранения дампа в каталоге /var/crash. Либо запустите вручную savecore(8), чтобы создать аварийный дамп в другом каталоге, где достаточно места. Размер аварийного дампа можно уменьшить, указав в конфигурации ядра options MAXMEM=N, где N - значение в Кбайт для объёма памяти, которое будет использоваться ядром. Например, для 1 Гбайт ОЗУ установите ограничение на использование памяти ядром в 128 Мбайт, так чтобы размер аварийного дампа был равен 128 Мбайт, а не 1 Гбайт.

Как только аварийный дамп получен, трассировку вызовов можно получить таким образом:

% kgdb /usr/obj/usr/src/sys/MYKERNEL/kernel.debug /var/crash/vmcore.0
(kgdb) backtrace

Заметьте, что это может дать несколько экранов полезной информации. Лучше всего использовать script(1) для перехвата всего вывода. При использовании необработанного файла ядра со всей отладочной информацией может быть найдена конкретная строка исходного текста ядра, при достижении которой случилась аварийная остановка. Для выяснения последовательности событий, приведших к аварийному останову, трассировка стека обычно читается снизу вверх. Также можно использовать kgdb(1) для вывода значений различных переменных или структур, чтобы выяснить состояние системы во время аварии.

Подсказка:

Если есть второй компьютер, то можно настроить kgdb(1) для удалённой отладки, включая точки останова и пошаговый проход по коду ядра.

Примечание:

Если включена поддержка DDB и ядро переходит в режим отладки, можно намеренно вызвать аварийный останов и создание аварийного дампа, набрав panic в приглашении командной строки ddb. Выполнение фазы аварийного останова может снова остановиться с вызовом отладчика. В этом случае наберите continue, и процесс будет завершён созданием аварийного дампа.

18.7.

Перестала работать функция dlsym() для исполняемых файлов ELF!

По умолчанию при работе с форматом ELF символы, определённые в исполняемом файле, не доступны динамическому загрузчику. Поэтому при вызове функции dlsym(), которая осуществляет поиск по дескриптору, полученному после вызова dlopen(NULL, flags), желаемый результат достигнут не будет.

Чтобы осуществить поиск символов в исполняемом файле процесса с помощью функции dlsym(), выполните компоновку исполняемого файла с параметром --export-dynamic компоновщика ELF (ld(1)).

18.8.

Как я могу увеличить или уменьшить адресное пространство ядра в архитектуре i386?

По умолчанию размер адресного пространства ядра для i386 равен 1 Гбайт (2 Гбайт для PAE). Для работы сервера с интенсивной сетевой нагрузкой или при использовании ZFS этого может быть недостаточно.

Чтобы увеличить доступное пространство, добавьте следующую строку в файл конфигурации ядра и пересоберите ядро:

options KVA_PAGES=N

Чтобы получить нужное значение для N, разделите желаемый размер адресного пространства (в мегабайтах) на четыре (для 2 Гбайт это будет 512).

Этот, и другие документы, могут быть скачаны с https://download.freebsd.org/ftp/doc/.

По вопросам, связанным с FreeBSD, прочитайте документацию прежде чем писать в <questions@FreeBSD.org>.

По вопросам, связанным с этой документацией, пишите в рассылку <doc@FreeBSD.org>.