Linux Kernel Architecture

(Jacob Rumans) #1

Chapter 16: Page and Buffer Cache


linked list in which eachb_this_pageelement points to the next buffer. The only exception is the last
buffer, whereb_this_pageholds a null pointer:

fs/buffer.c
void create_empty_buffers(struct page *page,
unsigned long blocksize, unsigned long b_state)
{
struct buffer_head *bh, *head, *tail;

head = alloc_page_buffers(page, blocksize, 1);
...

The function then iterates over all buffer heads to set their state and generate a cyclic list:

fs/buffer.c
do {
bh->b_state |= b_state;
tail = bh;
bh = bh->b_this_page;
} while (bh);
tail->b_this_page = head;
...

The state of the buffers depends on the state of the data in the page in memory:

fs/buffer.c
if (PageUptodate(page) || PageDirty(page)) {
bh = head;
do {
if (PageDirty(page))
set_buffer_dirty(bh);
if (PageUptodate(page))
set_buffer_uptodate(bh);
bh = bh->b_this_page;
} while (bh != head);
}
attach_page_buffers(page, head);
}

set_buffer_dirtyandset_buffer_uptodateset the corresponding flagsBH_DirtyandBH_Uptodate,
respectively, in the buffer head.

The concluding invocation ofattach_page_buffersassociates the buffer with the page in two separate
steps:


  1. ThePG_privatebit is set in the page flags to inform the rest of the kernel code that the
    privateelement of thepageinstance is in use.

  2. Theprivateelement of the page is equipped with a pointer to the first buffer head in the
    cyclic list.


At first sight, setting thePG_Privateflag would not appear to be a far-reaching action. However, it
is important because it is the only way that the kernel is able to detect whether a page has attached
Free download pdf