Роберт Лав - Разработка ядра Linux
- Название:Разработка ядра Linux
- Автор:
- Жанр:
- Издательство:Издательский дом Вильямс
- Год:2006
- Город:Москва
- ISBN:5-8459-1085-4
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Роберт Лав - Разработка ядра Linux краткое содержание
В книге детально рассмотрены основные подсистемы и функции ядер Linux серии 2.6, включая особенности построения, реализации и соответствующие программны интерфейсы. Рассмотренные вопросы включают: планирование выполнения процессов, управление временем и таймеры ядра, интерфейс системных вызовов, особенности адресации и управления памятью, страничный кэш, подсистему VFS, механизмы синхронизации, проблемы переносимости и особенности отладки. Автор книги является разработчиком основных подсистем ядра Linux. Ядро рассматривается как с теоретической, так и с прикладной точек зрения, что может привлечь читателей различными интересами и потребностями.
Книга может быть рекомендована как начинающим, так и опытным разработчикам программного обеспечения, а также в качестве дополнительных учебных материалов.
Разработка ядра Linux - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Флаги, которые используются драйверами, могут быть определены на основании значения этого флага, что позволяет гарантированно избежать перекрытия с битами, которые официально используются уровнем блочного ввода-вывода.
Поле b_count
— это счетчик использования буфера. Значение этого поля увеличивается и уменьшается двумя функциями, которые определены в файле следующим образом.
static inline void get_bh(struct buffer_head *bh) {
atomic_inc{&bh->b_count);
}
static inline void put_bh(struct buffer_head *bh) {
atomic_dec(&bh->b_count);
}
Перед тем как манипулировать заголовком буфера, необходимо увеличить значение счетчика использования с помощью функции get_bh()
, что гарантирует, что во время работы буфер не будет освобожден. Когда работа с заголовком буфера закончена, необходимо уменьшить значение счетчика, ссылок с помощью функции put_bh()
.
Физический блок на жестком диске, которому соответствует буфер, — это блок с логическим номером b_blocknr
, который находится на блочном устройстве b_bdev
.
Физическая страница памяти, в которой хранятся данные буфера, соответствует значению поля b_page
. Поле b_data
— это указатель прямо на данные блока (которые хранятся где-то в странице памяти b_page
), размер блока хранится в поле b_size
. Следовательно, блок хранится в памяти, начиная с адреса b_data
и заканчивая адресом ( b_data + b_size
).
Назначение заголовка буфера — это описание отображения между блоком на диске и буфером в физической памяти (т.е. последовательностью байтов, которые хранятся в указанной странице памяти). Выполнение роли дескриптора отображения буфер-блок — единственное назначение этой структуры данных ядра.
В ядрах до серии 2.6 заголовок буфера был значительно более важной структурой данных. По существу, это была единица ввода-вывода данных в ядре. Он не только выполнял роль дескриптора для отображения буфер-блок-страница физической памяти, но и выступал контейнером для всех операций блочного ввода-вывода. Это приводило к двум проблемам. Первая проблема заключалась в том, что заголовок буфера был большой и громоздкой структурой данных (сегодня он несколько уменьшился в размерах), а кроме того, выполнение операций блочного ввода-вывода в терминах заголовков буферов было непростой и довольно непонятной задачей. Вместо этого, ядру лучше работать со страницами памяти, что одновременно и проще и позволяет получить большую производительность. Использовать большой заголовок буфера, описывающий отдельный буфер (который может быть размером со страницу памяти), — неэффективно. В связи с этим в ядрах серии 2.6 было сделано много работы, чтобы дать возможность ядру выполнять операции непосредственно со страницами памяти и пространствами адресов, вместо операций с буферами. Некоторые из этих операций обсуждаются в главе 15, "Страничный кэш и обратная запись страниц", где также рассматривается структура address_space
и демоны pdflush
.
Вторая проблема, связанная с заголовками буферов, — это то, что они описывают только один буфер. Когда заголовок буфера используется в качестве контейнера для операций ввода-вывода, то это требует, чтобы ядро разбивало потенциально большую операцию блочного ввода-вывода на множество мелких структур buffer_head
, что в свою очередь приводит к ненужным затратам памяти для храпения структур данных. В результате, основной целью при создании серии ядра 2.5 была разработка нового гибкого и быстрого контейнера для операций блочного ввода-вывода. В результат появилась структура bio
, которая будет рассмотрена в следующем разделе.
Структура bio
Основным контейнером для операций ввода-вывода в ядре является структура bio, которая определена в файле . Эта структура представляет активные операции блочного ввода-вывода в виде списка сегментов ( segment ). Сегмент — это участок буфера, который является непрерывным в физической памяти, т.е. отдельные буферы не обязательно должны быть непрерывными в физической памяти. Благодаря тому, что буфер может представляться в виде нескольких участков, структура bio
даст возможность выполнять операции блочного ввода-вывода, даже если данные одного буфера хранятся в разных местах памяти. Ниже показана структура bio
с комментариями, описывающими назначение каждого поля.
struct bio {
sector_t bi_sector; /* соответствующий сектор на диске */
struct bio *bi_next; /* список запросов */
struct block_device *bi_bdev; /* соответствующее блочное устройство */
unsigned long bi_flags; /* состояние и флаги команды */
unsigned long bi_rw; /* чтение или запись? */
unsigned short bi_vcnt; /* количество структур bio vec
в массиве bi_io_vec */
unsigned short bi_idx; /* текущий индекс в массиве bi_io_vec */
unsigned short bi_phys_segments; /* количество сегментов
после объединения */
unsigned short bi_hw_segments; /* количество сегментов после
перестройки отображения */
unsigned int bi_size; /* объем данных для ввода-вывода */
unsigned int bi_hw_front_size; /* размер первого
объединяемого сегмента */
unsigned int bi_hw_front_size; /* размер последнего объединяемого
сегмента */
unsigned int bi_max_vecs; /* максимально возможное количество
структур bio_vecs */
struct bio_vec *bi_io_vec; /* массив структур bio_vec */
bio_end_io_t *bi_end_io; /* метод завершения ввода-вывода */
atomic_t bi_cnb; /* счетчик использования */
void *bi_private; /* поле для информации создателя */
bio_destructor_t *bi_destructor; /* деструктор */
};
Главное назначение структуры bio
— это представление активной (выполняющейся) операции блочного ввода-вывода. В связи с этим большинство полей этой структуры являются служебными. Наиболее важные поля — это bi_io_vecs
, bi_vcnt
и bi_idx
.
Поле bi_io_vecs
указывает на начало массива структур bio_vec
. Эти структуры используются в качестве списка отдельных сегментов в соответствующей операции блочного ввода-вывода. Каждый экземпляр структуры bio_vec
представляет собой вектор следующего вида: <���страница памяти, смещение, размер>
, который описывает определенный сегмент, соответственно страницу памяти, где этот сегмент хранится, положение блока — смещение внутри страницы — и размер блока. Массив рассмотренных векторов описывает весь буфер полностью. Структура bio_vec
определена в файле следующим образом.
struct bio_vec {
/* указатель на страницу физической памяти, где находится этот буфер */
struct page *bv_page;
/* размер буфера в байтах */
unsigned int bv_len;
/* смещение в байтах внутри страницы памяти, где находится буфер */
Интервал:
Закладка: