Linux Kernel Architecture

(Jacob Rumans) #1

Chapter 16: Page and Buffer Cache


If a buffer head is found,__find_get_blockinvokes thebh_lru_installfunction to add it to the cache.
The kernel returns to__getblkaftertouch_bufferhas been invoked to mark the page associated with
the buffer usingmark_page_accessed(see Chapter 18).

The second code path implemented in__getblk_slowmust be entered if__find_get_blockreturns a
null pointer. This path guarantees that at least the space required for the buffer head and data element is
reserved. Its implementation is relatively short:

fs/buffer.c
static struct buffer_head *
__getblk_slow(struct block_device *bdev, sector_t block, int size)
{
...
for (;;) {
struct buffer_head * bh;
int ret;

bh = __find_get_block(bdev, block, size);
if (bh)
return bh;

ret = grow_buffers(bdev, block, size);
if (ret < 0)
return NULL;
if (ret == 0)
free_more_memory();
}
}

Surprisingly, the first thing__getblk_slowdoes is to invoke__find_get_block— the function that has
just failed. If a buffer head is found, it is returned by the function. Of course, the function only succeeds
if another CPU has installed the desired buffer and created the corresponding data structures in memory
in the meantime. Although this is admittedly not very likely, it still has to be checked.

This rather strange behavior becomes clear when we examine the exact course of the function. It is, in
fact, an endless loop that repeatedly tries to read the buffer using__find_get_block. Obviously, the
code doesn’t content itself with doing nothing if the function fails. The kernel usesgrow_buffersto try
to reserve memory for the buffer head and buffer dataand to add this space to the kernel data structures:


  1. If this is successful,__find_get_blockis invoked again, and this returns the desired
    buffer_head.

  2. If the call togrow_buffersreturns a negative result, this means that the block lies outside
    the possible maximum addressable page cache range, and the loop is aborted because the
    desired block does not physically exist.

  3. Ifgrow_buffersreturns 0, then not enough memory was available to grow the buffers, and
    the subsequent call tofree_more_memorytries to fix this condition by trying to release more
    RAM as described in Chapters 17 and 18.


This is why the functions are packed into an endless loop — the kernel tries again and again to create the
data structures in memory until it finally succeeds.
Free download pdf