Всё это хорошо, но что если все потоки 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
.
Читать дальше