The
Buffer Cache
Figure 9.7: The Buffer Cache
As
the mounted file systems are used they generate a lot of requests to the block
devices to read and write data blocks. All block data read and write requests
are given to the device drivers in the form of buffer_head data structures via standard
kernel routine calls. These give all of the information that the block device
drivers need; the device identifier uniquely identifies the device and the
block number tells the driver which block to read. All block devices are viewed
as linear collections of blocks of the same size. To speed up access to the
physical block devices, Linux maintains a cache of block buffers. All of the
block buffers in the system are kept somewhere in this buffer cache, even the
new, unused buffers. This cache is shared between all of the physical block
devices; at any one time there are many block buffers in the cache, belonging
to any one of the system's block devices and often in many different states. If
valid data is available from the buffer cache this saves the system an access
to a physical device. Any block buffer that has been used to read data from a
block device or to write data to it goes into the buffer cache. Over time it
may be removed from the cache to make way for a more deserving buffer or it may
remain in the cache as it is frequently accessed.
Block buffers within the cache
are uniquely identfied by the owning device identifier and the block number of
the buffer. The buffer cache is composed of two functional parts. The first
part is the lists of free block buffers. There is one list per supported buffer
size and the system's free block buffers are queued onto these lists when they
are first created or when they have been discarded. The currently supported
buffer sizes are 512, 1024, 2048, 4096 and 8192 bytes. The second functional
part is the cache itself. This is a hash table which is a vector of pointers to
chains of buffers that have the same hash index. The hash index is generated
from the owning device identifier and the block number of the data block.
Figure 9.7 shows the hash table together with a few
entries. Block buffers are either in one of the free lists or they are in the
buffer cache. When they are in the buffer cache they are also queued onto Least
Recently Used (LRU) lists. There is an LRU list for each buffer type and these
are used by the system to perform work on buffers of a type, for example,
writing buffers with new data in them out to disk. The buffer's type reflects
its state and Linux currently supports the following types:
clean
Unused,
new buffers,
locked
Buffers
that are locked, waiting to be written,
dirty
Dirty
buffers. These contain new, valid data, and will be written but so far have not
been scheduled to write,
shared
Shared
buffers,
unshared
Buffers
that were once shared but which are now not shared,
Whenever a file system needs to
read a buffer from its underlying physical device, it trys to get a block from
the buffer cache. If it cannot get a buffer from the buffer cache, then it will
get a clean one from the appropriate sized free list and this new buffer will
go into the buffer cache. If the buffer that it needed is in the buffer cache,
then it may or may not be up to date. If it is not up to date or if it is a new
block buffer, the file system must request that the device driver read the
appropriate block of data from the disk.
Like all caches, the buffer cache
must be maintained so that it runs efficiently and fairly allocates cache
entries between the block devices using the buffer cache. Linux uses the bdflush
kernel daemon to perform a lot of
housekeeping duties on the cache but some happen automatically as a result of
the cache being used.
No comments:
Post a Comment