Всё это хорошо, но что если все потоки pdflushзависнут в ожидании записи в одну и ту же перегруженную очередь? В этом случае производительность нескольких потоков pdflushне будет выше производительности одного потока, а количество занятой памяти станет значительно большим. Чтобы уменьшить такой эффект, для потоков pdflushреализован алгоритм предотвращения зависания (congestion avoidance). Потоки активно начинают обратную запись страниц для тех очередей, которые не перегружены. В результате потоки pdflushраспределяют свою работу по разным очередям и воздерживаются от записи в перегруженную очередь. Когда все потоки pdflushзаняты работой и запускается новый поток, то это означает, что они действительно заняты.
В связи с усовершенствованием алгоритмов обратной записи страниц, включая введение демона bdflush, ядро серии 2.6 позволяет поддерживать в загруженном состоянии значительно большее количество дисков, чем в более старых версиях ядер. При активной работе потоки pdflushмогут обеспечить большую пропускную способность сразу для большого количества дисковых устройств.
В этой главе был рассмотрен страничный кэш и обратная запись страниц. Было показано, как ядро выполняет все операции страничного ввода-вывода, как операции записи откладываются с помощью дискового кэша и как данные записываются на диск с помощью группы потоков пространства ядра pdflush.
На основании материала последних нескольких глав вы получили устойчивое представление о том, как выполняется управление памятью и файловыми системами. Теперь давайте перейдем к теме модулей и посмотрим, ядро Linux обеспечивает модульную и динамическую инфраструктуру для загрузки кода ядра во время работы системы.
Несмотря на то что ядро является монолитным, в том смысле что все ядро выполняется в общем защищенном адресном домене, ядро Linux также является модульным, что позволяет выполнять динамическую вставку и удаление кода ядра в процессе работы системы. Соответствующие подпрограммы, данные, а также точки входа и выхода группируются в общий бинарный образ, загружаемый объект ядра, который называется модулем. Поддержка модулей позволяет системам иметь минимальное базовое ядро с опциональными возможностями и драйверами, которые компилируются в качестве модулей. Модули также позволяют просто удалять и перегружать код ядра, что помогает при отладке, а также дает возможность загружать драйверы по необходимости в ответ на появление новых устройств с функциями горячего подключения.
В этой главе рассказывается о хитростях, которые стоят за поддержкой модулей в ядре, и о том, как написать свой собственный модуль.
В отличие от разработки основных подсистем ядра, большинство из которых были уже рассмотрено, разработка модулей подобна созданию новой прикладной программы, по крайней мере в том, что модули имеют точку входа, точку выхода и находятся каждый в своем бинарном файле.
Может показаться банальным, но иметь возможность написать программу, которая выводит сообщение "Hello World!", и не сделать этого- просто смешно. Итак, леди и джентльмены, модуль "Hello, World!".
/*
* hello.c - модуль ядра Hello, World!
*/
#include
#include
#include
/*
* hello_init - функция инициализации, вызывается при загрузке модуля,
* В случае успешной загрузки модуля возвращает значение нуль,
* и ненулевое значение в противном случае.
*/
static int hello_init(void) {
printk(KERN_ALERT "I bear a charmed life.\n");
return 0;
}
/*
* hello_exit - функция завершения, вызывается при выгрузке модуля.
*/
static void hello_exit(void) {
printk(KERN_ALERT "Out, out, brief candle!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE{"GPL");
MODULE_AUTHOR("Shakespeare");
Это самый простой модуль ядра, который только может быть. Функция hello_init()регистрируется с помощью макроса module_init()в качестве точки входа в модуль. Она вызывается ядром при загрузке модуля. Вызов module_init()— это не вызов функции, а макрос, который устанавливает значение своего параметра в качестве функции инициализации. Все функции инициализации должны соответствовать следующему прототипу.
int my_init(void);
Так как функция инициализации редко вызывается за пределами модуля, ее обычно не нужно экспортировать и можно объявить с ключевым словом static.
Читать дальше