3

I was diving into the kernel source code and I noticed this function set_bh_page(). However, I could not understand clearly what it does.

I could only find this comment in the fs/buffer.c file:

/* Link the buffer to its page */

set_bh_page(bh, page, offset);

But it is still not clear to me what it does.

So, to make it clear, I want to understand what is the relationship of this function call to the buffer and physical page, as well as if it has anything to do with the page cache itself.

UPDATE 1:

The function alloc_page_buffers() calls this set_bh_page(), and there is some comment about that, as follows:

Create the appropriate buffers when a given a page for data area and the size of each buffer.. User the bh->b_this_page linked list to follow the buffers created. Return NULL if unable to create more buffers.

And I checked who calls the alloc_page_buffers(), which one of them is the read_page(), that has this description:

Read a page from a file.

We both read the page, and attach buffers to the page to record the address of each block (using bmap). These addresses will be used to write the block later, completely bypassing the filesystem. This usage is similar to how swap files are handled, and allows us to write to a file with no concerns of memory allocation failing.

So, by looking through the source code of read_page(), my understanding is that the buffer_head allocated must be associated to its physical page address, like a direct mapping.

Is that correct?

Hadi Brais
  • 22,259
  • 3
  • 54
  • 95
campescassiano
  • 809
  • 5
  • 18

1 Answers1

1

When the kernel needs to access a block from a block device and it discovers that there is no page in the page cache that contains the block, it allocates a page, called a block device buffer page or simply a buffer page, and then writes to it the requested block(s). The process starts with the grow_buffers function, which calls alloc_page_buffers, which is declared as follows:

struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, bool retry);

page points to the descriptor of the buffer page that is going to hold the block. size represents the size of a block in bytes, where all blocks of the buffer page are of the same size. Note that a block is a memory region of the block device, while a buffer is a memory region of main memory. A buffer holds data of a single block and it is of the same size. So a buffer page looks like this:

       .
       .
       .
|-------------|
|    buffer   |
|-------------|
|    buffer   |
|-------------|
|    buffer   |
|-------------|
       .
       .
       .

The block contained in each buffer is identified by a buffer head. You can find the struct declaration of buffer_head here. The b_bdev and b_blocknr fields together identify a block on a block device. Note that each buffer head has a pointer to the next buffer head within the same buffer page. The alloc_page_buffers function allocates and initializes the buffer heads of all the buffers of the specified buffer page. alloc_page_buffers calls the set_bh_page function to initialize two particular fields of the buffer head, b_page and b_data, which are described by the comments in the code:

struct page *b_page;    /* the page this bh is mapped to */
char        *b_data;    /* pointer to data within the page */

As you can see, it "links the buffer to its page".

Hadi Brais
  • 22,259
  • 3
  • 54
  • 95