Рассмотрим эту структуру с комментариями, которые описывают назначение каждого поля.
struct buffer_head {
unsigned long b_state; /* флаги состояния буфера */
atomic_t b_count; /* счетчик использования буфера */
struct buffer_head *b_this_page; /* список буферов в текущей
странице памяти */
struct page *b_page; /* соответствующая страница памяти */
sector_t b_blocknr; /* логический номер блока */
u32 b_size; /* размер блока (в байтах) */
char *b_data; /* указатель на буфер в странице памяти */
struct block_device *b_bdev; /* соответствующее блочное устройство */
bh_end_io_t *b_end_io; /* метод завершения ввода-вывода */
void *b_private; /* данные метода завершения */
struct list_head b_assoc_buffers; /* список связанных отображений */
};
Поле b_ state
содержит состояние определенного буфера. Это значение может содержать один или несколько флагов, которые перечислены в табл. 13.1. Возможные значения флагов описаны в виде перечисления bh_state_bits
, которое описано в файле .
Таблица 13.1. Значения флагов поля bh_state
Флаг состояния |
Назначение |
BH_Uptodate |
Буфер содержит действительные данные |
BH_Dirty |
Буфер изменен (содержимое буфера новее соответствующих данных на диске, и поэтому буфер должен быть записан на диск) |
BH_Lock |
Для буфера выполняется операция чтения-записи дисковых данных, и буфер заблокирован, чтобы предотвратить конкурентный доступ |
BH_Req |
Буфер включен в запрос |
BH_Mapped |
Буфер является действительным и отображается на дисковый блок |
BH_New |
Буфер только что выделен и к нему еще не было доступа |
BH_Async_Read |
Для буфера выполняется асинхронная операция чтения |
BH_Async_Write |
Для буфера выполняется асинхронная операция записи |
BH_Delay |
С буфером еще не связан дисковый блок |
BH_Boundary |
Буфер является последним в последовательности смежных блоков — следующий за ним блок не является смежным с этой серией |
Перечисление bh_state_bits
также содержит в качестве последнего элемента флаг BH_PrivateStart
. Этот флаг не является разрешенным значением флага, а соответствует первому биту, который можно использовать по усмотрению разработчиков кода. Все биты, номер которых больше или равен значению BH_PrivateStart
, не используются подсистемой блочного ввода-вывода и безопасно могут использоваться драйверами, которым необходимо хранить информацию в поле b_state
.
Флаги, которые используются драйверами, могут быть определены на основании значения этого флага, что позволяет гарантированно избежать перекрытия с битами, которые официально используются уровнем блочного ввода-вывода.
Поле 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
.
Читать дальше