FAQ FreeBSD - Дистрибутивы FreeBSD. Часть 3
ОГЛАВЛЕНИЕ
13.12. Альтернативный метод размещения каталогов
В ответ на вопрос о других методах размещения каталогов могу сказать, что
используемая в настоящее схема не претерпела изменений с 1983 года. Эти
соглашения были предназначены для оригинальной файловой системы FFS, я никогда
их не пересматривал. Эта схема прекрасно работает, позволяя избежать
переполнения групп дорожек. Как некоторые из вас замечали, она работает плохо
при поиске. Большинство файловых систем создаются из архивов, которые были
созданы с глубиной первого поиска (aka ftw). Это приводит к тому, что их
каталоги размещаются на нескольких группах дорожек, создавая наихудший случай
для последующего поиска глубиной один. Если бы было известно общее количество
каталогов, которые должны быть созданы, выходом было бы создание (общее
количество / количество групп дорожек) на дорожку группу перед переходом.
Обычно это число определяется чисто эвристически. Даже при использовании
маленького фиксированное числа, скажем 10, значительно улучшает ситуацию. Чтобы
различать операции восстановления от обычных операций (где текущий алгоритм
подходит), вы можете использовать объединение в кластеры объёмом до 10, если
они делаются в окне, равным 10 секундам. Во всяком случае, я думаю, что это
требует некоторых экспериментов.
Кирк МакКузик (Kirk McKusick), Сентябрь 1998
13.13. Что делать при аварийном остановах системы
[Этот раздел был вырезан из письма, написанного Bill Paul <Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.> в
список рассылки freebsd-current Dag-Erling C. SmЬrgrav <Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.>,
который исправил несколько опечаток и добавил комментарии в квадратных скобках]
From: Bill Paul <Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.>
Subject: Re: the fs fun never stops
To: Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.
Date: Sun, 20 Sep 1998 15:22:50 -0400 (EDT)
Cc: Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.
[<Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.> отправил письмо, содержащее следующее аварийное сообщение
системы]
> 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 одного из снэпшотов, то кто-то ещё может отследить функцию, вызвав
шую ошибку, но если вы работаете со специально отконфигурированным ядром, то
только вы можете сказать нам, где случилась ошибка.
Вот что вы должны сделать:
* Запишите значение указателя инструкций. Заметьте, что часть 0x8: в этом
случае не важна: нам нужна часть 0xf0xxxxxx.
* Когда система перезагрузится, сделайте следующее:
% nm -n /kernel.that.caused.the.panic | grep f0xxxxxx
где f0xxxxxx - это значение указателя инструкций. Однако неприятность
заключается в том, что вы не получите точного соответствия, так как в
таблице имен ядра для точек входа в функции даны адреса на начало функций,
а указатель инструкций будет указывать куда-то внутрь её тела. Если вы не
получили точного соответствия, опустите последнюю цифру в значении
указателя инструкций и попробуйте снова, то есть:
% nm -n /kernel.that.caused.the.panic | grep f0xxxxx
Если и это не привело ни к каким результатам, отрежьте следующую цифру. Пов
торяйте, пока не получите хоть что-то. Результатом будет список функций,
которые, возможно, привели к аварийному останову. Этот механизм обнаружения
ошибочного места довольно неточен, но это всё же лучше, чем ничего.
Зачастую люди приводят подобные аварийные сообщения, на редко кто утруждается
привести соответствие указателя инструкций с функцией в таблице символов ядра.
Лучшим способом выяснить причину, вызвавшую аварийный останов, является
создание аварийного дампа системы, а затем использование gdb(1) для трассировки
вызовов. Конечно, это зависит от корректности работы gdb(1) с -CURRENT, что я
гарантировать не могу (помнится, кто-то говорил, что новый ELF gdb(1)
некорректно работает с аварийными дампами ядра: необходимо проверить это до в
ыхода 3.0, иначе не избежать краски стыда на наших лицах после выпуска CD).
Во всяком случае, обычно я использую такой способ:
* Отредактируйте конфигурационный файл ядра, добавив строку options DDB, если
вам зачем-то понадобился встроенный отладчик. (Я использую его в основном
для указания точек останова, если подозреваю возникновение бесконечных
циклов.)
* Выполните config -g KERNELCONFIG для создания каталога построения ядра.
* cd /sys/compile/KERNELCONFIG; make
* Дождитесь окончания компиляции ядра.
* make install
* reboot
В процессе выполнения команды make(1) будут построены два ядра, kernel и
kernel.debug. kernel будет установлен как /kernel, тогда как kernel.debug может
быть использован в качестве источника отладочной информации для gdb(1).
Чтобы включить сброс аварийного дампа, вам нужно отредактировать файл /etc/
rc.conf так, чтобы устройство dumpdev указывало на раздел подкачки. В этом
случае скрипты rc(8) будут вызывать команду dumpon(8) для включения создания ав
арийных дампов. Вы можете запустить команду dumpon(8) вручную. После аварийной
остановки аварийный дамп может быть получен с помощью программы savecore(8);
если значение переменной dumpdev было установлено в /etc/rc.conf, скрипты rc(8)
запустят savecore(8) автоматически и поместят аварийный дамп в каталог /var/
crash.
Note: Аварийные дампы FreeBSD обычно имеют размер, равный физическому объё
му оперативной памяти вашей машины. Так что если у вас 64МБ ОЗУ, вы
получите дамп размером 64МБ. Поэтому вы должны удостовериться, что в
каталоге /var/crash достаточно места для хранения дампа. Либо вы можете в
ручную запустить savecore(8) и создать аварийный дамп в другом каталоге,
где достаточно места. Размер аварийного дампа можно уменьшить, указав в
конфигурации ядра options MAXMEM=(размер) подходящее значение для объёма
памяти, которое будет использоваться ядром. Например, если у вас 128 МБ
ОЗУ, вы можете ограничить использование памяти ядром 16 мегабайтами, так
что размер аварийного дампа будет равен 16МБ, а не 128.
Как только вы получили аварийный дамп, вы можете выполнить трассировку вызовов
с помощью gdb(1) таким образом:
% gdb -k /sys/compile/KERNELCONFIG/kernel.debug /var/crash/vmcore.0
(gdb) where
Заметьте, что при этом может быть выведено несколько экранов информации; в
идеале вы должны использовать script(1) для их перехвата. При использовании
необработанного образа ядра со всей отладочной информацией может быть найдена
конкретная строка исходного текста ядра, при достижении которой случилась ав
арийная остановка. Для выяснения последовательности событий, приведших к ав
арийному останову, обычно читается трассировка стека снизу вверх. Вы можете
также использовать gdb(1) для вывода значений различных переменных или
структур, чтобы выяснить состояние системы во время аварии.
Теперь, если вы в самом деле душевнобольной и у вас есть второй компьютер, то
можете настроить gdb(1) для удалённой отладки, так, что сможете использовать
gdb(1) на одном компьютере, чтобы отладить ядро на другом, включая использов
ание точек останова, пошагового прохода по коду ядра, всё как с обычной
прикладной программой. Я пока с этим не игрался, так как не часто имею в
озможность поставить две машины одну напротив другой для отладки.
[Билл (Bill) добавил: "Я забыл обратить ваше внимание на одну вещь: если у вас
включена поддержка DDB и ядро переходит в режим отладки, вы можете намеренно в
ызвать аварийный останов (и создание аварийного дампа), набрав 'panic' в
командной строке ddb. Этот процесс может снова вызвать отладчик. В этом случае
наберите 'continue' и процесс будет завершён созданием аварийного дампа." -ed]
13.14. Перестала работать функция dlsym() для ELF!
По умолчанию при работе с форматом ELF символы, определённые в выполнимом
файле, не доступны динамическому загрузчику. Поэтому при вызове функции dlsym
(), которая осуществляет поиск по дескриптору, полученному после вызова dlopen
(NULL, flags), желаемый результат достигнут не будет.
Если вы хотите осуществить поиск в выполнимом файле процесса с помощью функции
dlsym(), вам нужно компоновать выполнимый файл с опцией -export-dynamic компоно
вщика ELF.
13.15. Увеличение и уменьшение адресного пространства ядра
По умолчанию размер адресного пространства ядра равен 256 МБ во FreeBSD 3.x и 1
ГБ во FreeBSD 4.x. Если вы используете FreeBSD в качестве сервера с интенсивной
сетевой нагрузкой (скажем, большой FTP или HTTP сервер), вы можете обнаружить,
что 256 МБ недостаточно.
Каким же образом можно увеличить адресное пространство? Здесь есть два момента.
Во-первых, вам нужно указать ядру выделить большее количество адресного
пространства для самого ядра. Во-вторых, так как ядро загружается в верхнюю
часть адресного пространства, вам нужно уменьшить адрес загрузки так, чтобы он
не вышел за верхнюю границу.
Первая проблема решается увеличением значения константы NKPDE в файле src/sys/
i386/include/pmap.h. В случае 1 ГБ адресного пространства он должен выглядеть
примерно так:
#ifndef NKPDE
#ifdef SMP
#define NKPDE 254 /* addressable number of page tables/pde's */
#else
#define NKPDE 255 /* addressable number of page tables/pde's */
#endif /* SMP */
#endif
Для вычисления значения NKPDE разделите желаемый объём адресного пространства
(в мегабайтах) на четыре и вычтите из получившегося числа единичку в случае
однопроцессорной машины и двоечку в случае многопроцессорного ядра.
Для достижения второй цели вам нужно правильный адрес для загрузки ядра: просто
отнимите размер адресного пространства (в байтах) от 0x100100000; результат
будет равным 0xc0100000 для адресного пространства в 1 ГБ. Установите значение
константы LOAD_ADDRESS в файле src/sys/i386/conf/Makefile.i386 в это значение;
затем установите значение счётчика в начале списка секций в файле src/sys/i386/
conf/kernel.script в то же самое значение, как это сделано здесь:
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(btext)
SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/obj/elf/home/src/tmp/usr/i386-unknown-freebsdelf/lib);
SECTIONS
{
/* Read-only sections, merged into text segment: */
. = 0xc0100000 + SIZEOF_HEADERS;
.interp : { *(.interp) }
После этого переконфигурируйте и перестройте ядро. Вы можете столкнуться с
проблемами при работе утилит ps(1), top(1) и подобных им; решить их может make
world (или ручная перекомпиляция libkvm, ps и top после копирования исправ
ленного pmap.h в /usr/include/vm/).
ЗАМЕЧАНИЕ: Размер адресного пространства ядра должен быть кратен четырём
мегабайтам.
[David Greenman <Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.> добавил: Я думаю, что размер адресного
пространства ядра должен быть степенью двойки, но я в этом не уверен. Для
работы с верхними адресами памяти использовался код старого загрузчика, и я
ожидаю по крайней мере точность в 256 МБ.]
Jordan K. Hubbard <Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в вашем браузере должен быть включен Javascript.>