Chapter 14. Disk Caches

This chapter deals with disk caches. It shows how Linux uses sophisticated techniques to improve system performances by reducing disk accesses as much as possible.

As mentioned in Section 12.1.1, a disk cache is a software mechanism that allows the system to keep in RAM some data that is normally stored on a disk, so that further accesses to that data can be satisfied quickly without accessing the disk.

Besides the dentry cache, which is used by the VFS to speed up the translation of a file pathname to the corresponding inode, two main disk caches—the buffer cache and the page cache—are used by Linux.

As suggested by its name, the buffer cache is a disk cache consisting of buffers; as we know from Section 13.4.3, each buffer stores a single disk block. The block I/O operations (described in Section 13.4.8.1 in the same chapter) rely on the buffer cache to reduce the number of disk accesses.

Conversely, the page cache is a disk cache consisting of pages; each page in the cache corresponds to several blocks of a regular file or a block device file. Of course, the exact number of blocks contained in a page depends on the size of the block. All such blocks are logically contiguous — that is, they represent an integral portion of a regular file or of a block device file. To reduce the number of disk accesses, before activating a page I/O operation (described in Section 13.4.8.2), the kernel should check whether the wanted data is already stored in the page cache.

Table 14-1 shows how some widely used I/O operations use the buffer and page caches. Some of the examples given refer to the Ext2 filesystem, but they can apply to almost all disk-based filesystems.

Table 14-1. Use of the buffer cache and page cache

Kernel function

System call

Cache

I/O operation

bread( )

None

Buffer

Read an Ext2 superblock

bread( )

None

Buffer

Read an Ext2 inode

generic_file_read( )

getdents( )

Page

Read an Ext2 directory

generic_file_read( )

read( )

Page

Read an Ext2 regular file

generic_file_write( )

write( )

Page

Write an Ext2 regular file

generic_file_read( )

read( )

Page

Read a block device file

generic_file_write( )

write( )

Page

Write a block device file

filemap_nopage( )

None

Page

Access a memory-mapped file

brw_page( )

None

Page

Access to swapped-out page

Each operation in this table appears in subsequent chapters:

Read an Ext2 superblock

See Section 13.4.8.1. See also Chapter 17.

Read an Ext2 inode

See Section 15.1.3. See also Chapter 17 for the Ext2 filesystem.

Read an Ext2 directory

See Section 15.1.1. See also Chapter 17 for the Ext2 filesystem.

Read an Ext2 regular file

See Section 15.1.1.

Write an Ext2 regular file

See Section 15.1.3. See also Chapter 17 for the Ext2 filesystem.

Read a block device file

See Section 15.1.1.

Write a block device file

See Section 15.1.3.

Access a memory-mapped file

See Section 15.2.

Access to swapped-out page

See Section 13.4.8.2. See also Chapter 16.

For each type of I/O activity, the table also shows the system call required to start it (if any) and the main corresponding kernel function that handles it.

The table shows that accesses to memory-mapped files and swapped-out pages do not require system calls; they are transparent to the programmer. Once a file memory mapping is set up and swapping is activated, the application program can access the mapped file or the swapped-out page as if it were present in memory. It is the kernel's responsibility to delay the process until the required page is located on disk and brought into RAM.

You'll also notice that the same kernel function, namely generic_file_read( ), is used to read from block device files and from regular files. Similarly, generic_file_write( ) is used to write both into block device files and into regular files. We describe these functions in Chapter 15.