Linux Kernel Architecture

(Jacob Rumans) #1

Chapter 16: Page and Buffer Cache


As usual, it is first necessary to check that buffersare actually attached to the page — this cannot be taken
for granted. As when a page is read,page_has_buffersis invoked to check whether buffers are present.
If not, they are created usingcreate_empty_buffers.

The kernel then iterates a total of three times over the list of buffers, as shown in the code flow diagram:


  1. The purpose of the first iteration is to create a mapping between the buffer and the block
    device for all unmapped but dirty buffers. The function held in theget_blockfunction
    pointer is invoked to find the matching block of the block device for the buffer.

  2. In the second iteration, all dirty buffers are filtered out; this can be checked by
    test_clear_buffer_dirty— if the flag was set, it is deleted when the func-
    tion is invoked because the buffer contents are due to be written back immedi-
    ately.^13 mark_buffer_async_writesets theBH_Async_Writestate bit and assigns
    end_buffer_async_writeas the BIO completion handler tob_end_io.
    At the end of this iteration,set_page_writebacksets thePG_writebackflag for the full
    page.

  3. In the third and final iteration, all buffers marked withBH_Async_Writein the previous
    pass are forwarded to the block layer that performs the actual write operation by invoking
    submit_bh, which submits a corresponding request to the block layer (by means of BIOs; see
    Chapter 6).


When the write operation for a buffer terminates,end_buffer_async_writeis invoked automatically to
check whether this also applies for all other buffers of the page. If so, all processes that are sleeping on
the queue associated with the page and that are waiting for this event are woken.

16.5.4 Independent Buffers


Buffers are used not only in the context of pages. In earlier versions of the Linux kernel, all caching was
implemented with buffers without resorting to page caching. The value of this approach has diminished
in successive versions, and nearly all importance has been attached to full pages. However, there are still
situations in which access to block device data is performed on the block level and not on the page level
in the view of higher-level code. To help speed up such operations, the kernel provides yet another cache
known as anLRU buffer cachediscussed below.

This cache for independent buffers is not totally divorced from the page cache. Since RAM memory
is always managed in pages, buffered blocks must also be held in pages, with the result that there are
some points of contact with the page cache. These cannot and should not be ignored — after all, access
to individual blocks is still possible via the buffer cache without having to worry about the organization
of the blocks into pages.

Modeof Operation


Why LRU? As we know, this abbreviation stands forleast recently usedand refers to a general method
in which the elements of a set that are most frequently used can be managed efficiently. If an element is
frequently accessed, the likelihood is that it resides in RAM (and is therefore cached). Less frequently or
seldom used elements drop out of the cache automatically with time.

(^13) At this point, the kernel must also callbuffer_mappedto ensure that there is a mapping for the buffer. This is not the case if
there are holes in files, but then there is nothing to write back.

Free download pdf