linux-mm.kvack.org archive mirror
 help / color / mirror / Atom feed
* Buffer Head Doubts
@ 2002-09-03  9:11 Anil Kumar
  2002-09-03 18:17 ` Andrew Morton
  0 siblings, 1 reply; 2+ messages in thread
From: Anil Kumar @ 2002-09-03  9:11 UTC (permalink / raw)
  To: linux-mm

Hello All,

  I am going through the source code of linux kernel 2.5.32 and have some 
 simple doubts.
 
1:What is  the philosophy behind introducing Address Space concept 
  

struct address_space{

        struct inode            *host;          /* owner: inode,  
block_device */
        struct radix_tree_root  page_tree;      /* radix tree of all pages
*/   
        rwlock_t                page_lock;      /* and rwlock protecting
it */
        struct list_head        clean_pages;    /* list of clean pages */
        struct list_head        dirty_pages;    /* list of dirty pages */
        struct list_head        locked_pages;   /* list of locked pages */
        struct list_head        io_pages;       /* being prepared for I/O
*/
        unsigned long           nrpages;        /* number of total pages
*/
        struct address_space_operations *a_ops; /* methods */
        list_t                  i_mmap;         /* list of private
mappings */
        list_t                  i_mmap_shared;  /* list of private
mappings */
        spinlock_t              i_shared_lock;  /* and spinlock protecting
it */
        unsigned long           dirtied_when;   /* jiffies of first page
dirtying */
        int                     gfp_mask;       /* how to allocate the
pages */
        struct backing_dev_info *backing_dev_info; /* device readahead,
etc */
        spinlock_t               private_lock;   /* for use by the
address_space*/
        struct list_head        private_list;   /* ditto */
        struct address_space    *assoc_mapping; /* ditto */
};

   What is meaning of  field assoc_mapping,private_lock  ?
 
2: In buffer head structure

struct buffer_head {
        /* First cache line: */
        unsigned long b_state;          /* buffer state bitmap (see above)
*/
        atomic_t b_count;               /* users using this block */
        struct buffer_head *b_this_page;/* circular list of page's buffers
*/
        struct page *b_page;            /* the page this bh is mapped to
*/

        sector_t b_blocknr;             /* block number */
        u32 b_size;                     /* block size */
        char *b_data;                   /* pointer to data block */

        struct block_device *b_bdev;
        bh_end_io_t *b_end_io;          /* I/O completion */
        void *b_private;                /* reserved for b_end_io */
        struct list_head b_assoc_buffers; /* associated with another
mapping */
};

  What is this b_assoc_buffers and where used ?

3: In file buffer.c  before function definition  buffer_busy
comment is given about  try_to_free_buffers

/*
 * try_to_free_buffers() checks if all the buffers on this particular page
 * are unused, and releases them if so.
 *
 * Exclusion against try_to_free_buffers may be obtained by either
 * locking the page or by holding its mapping's private_lock.
 *
 * If the page is dirty but all the buffers are clean then we need to
 * be sure to mark the page clean as well.  This is because the page
 * may be against a block device, and a later reattachment of buffers
 * to a dirty page will set *all* buffers dirty.  Which would corrupt
 * filesystem data on the same device.
 *
 * The same applies to regular filesystem pages: if all the buffers are
 * clean then we set the page clean and proceed.  To do that, we require
 * total exclusion from __set_page_dirty_buffers().  That is obtained with
 * private_lock.
 *
 * try_to_free_buffers() is non-blocking.
 */

 I can not understand what exactly this comment  means ?

and also why  code segment (between Line  /*--------*/ is there)
in following code.

int try_to_free_buffers(struct page *page)
{
        struct address_space * const mapping = page->mapping;
        struct buffer_head *buffers_to_free = NULL;
        int ret = 0;

        BUG_ON(!PageLocked(page));
        if (PageWriteback(page))
                return 0;
/*----------------------------------------------------------------------*/
        if (mapping == NULL) {          /* swapped-in anon page */
                ret = drop_buffers(page, &buffers_to_free);
                goto out;
        }
/*------------------------------------------------------------------------*/

        spin_lock(&mapping->private_lock);
        ret = drop_buffers(page, &buffers_to_free);
        if (ret && !PageSwapCache(page)) {

...


  If mapping is NULL then why we need to drop_buffers in that case.How can
buffer head be associated with an anonymous page ?

Regards,
Anil


--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Buffer Head Doubts
  2002-09-03  9:11 Buffer Head Doubts Anil Kumar
@ 2002-09-03 18:17 ` Andrew Morton
  0 siblings, 0 replies; 2+ messages in thread
From: Andrew Morton @ 2002-09-03 18:17 UTC (permalink / raw)
  To: Anil Kumar; +Cc: linux-mm

Anil Kumar wrote:
> 
> Hello All,
> 
>   I am going through the source code of linux kernel 2.5.32 and have some
>  simple doubts.
> 
> 1:What is  the philosophy behind introducing Address Space concept

That's a bit before my time, but...  I view the separation of the address_space
out of struct inode as providing a few things:

- A separation between the "control plane" and the "data plane", to use a
  networking analogy.  The address_space contains stuff to do with the data
  in the file, and the inode contains the control/metadata/security/other random
  stuff.  (Arguably, things like i_size, i_blkbits, i_blocks should be in the
  address_space, not the inode).

- Some filesystems (Coda) want to back their inodes by files on other filesystems.
  For example, a Code inode's i_mapping will point at an ext2 file's i_data.

- A filesystem may wish to manage additional metadata via the rich address_space
  functions in the core kernel.  For example, ext2 indirect blocks could be a
  filesystem-private address_space.  A file's indirects don't need all the other
  inode stuff - just the data plane operations.

> ...
>    What is meaning of  field assoc_mapping,private_lock  ?

For a successful fsync(), ext2 needs to write out and wait upon its
indirect blocks as well as the file data.  Those indirects are represented
by buffer_heads (a buffer_head is the kernel's abstraction for a disk block.
It doesn't "buffer" anything any more).

So each file maintains a list of buffer_heads at mapping.private_list.  These
are the buffers which need to be written for fsync.  mapping.private_list
is the base of a list of buffers, attached via buffer_head.b_assoc_buffers.

The locking for this list used to be a single kernel-wide lock.  In 2.5 that
got changed - the lock is the mapping.private_lock of the address_space which
contains the data for those buffers.  This is usually the i_mapping of the
blockdev which backs the filesystem.

mapping.assoc_mapping is the "associated mapping".  In practice it points
at the address_space which backs the buffers which are attached to private_list.
assoc_mapping is really only there so we can find the lock for the private_list.

These things have the anonymous "private_list/private_lock" identifiers
to indicate that these are private utility objects whose application
is defined by the address space's address_space_operations.  In practice
however, they can only contain buffer_heads, because a few parts of the core
kernel still assume that (destroy_inode, generic_osync_inode).

> 2: In buffer head structure
> 
> ...
>   What is this b_assoc_buffers and where used ?

See above - blockdev buffers attached to an S_ISREG file's private_list,
protected by the blockdev's i_mapping->private_lock.
 
> 3: In file buffer.c  before function definition  buffer_busy
> comment is given about  try_to_free_buffers
> 
> /*
>  * try_to_free_buffers() checks if all the buffers on this particular page
>  * are unused, and releases them if so.
>  *
>  * Exclusion against try_to_free_buffers may be obtained by either
>  * locking the page or by holding its mapping's private_lock.
>  *
>  * If the page is dirty but all the buffers are clean then we need to
>  * be sure to mark the page clean as well.  This is because the page
>  * may be against a block device, and a later reattachment of buffers
>  * to a dirty page will set *all* buffers dirty.  Which would corrupt
>  * filesystem data on the same device.
>  *
>  * The same applies to regular filesystem pages: if all the buffers are
>  * clean then we set the page clean and proceed.  To do that, we require
>  * total exclusion from __set_page_dirty_buffers().  That is obtained with
>  * private_lock.
>  *
>  * try_to_free_buffers() is non-blocking.
>  */
> 
>  I can not understand what exactly this comment  means ?

I do ;)  Have you any specific questions?
 
> and also why  code segment (between Line  /*--------*/ is there)
> in following code.
> 
> int try_to_free_buffers(struct page *page)
> {
>         struct address_space * const mapping = page->mapping;
>         struct buffer_head *buffers_to_free = NULL;
>         int ret = 0;
> 
>         BUG_ON(!PageLocked(page));
>         if (PageWriteback(page))
>                 return 0;
> /*----------------------------------------------------------------------*/
>         if (mapping == NULL) {          /* swapped-in anon page */
>                 ret = drop_buffers(page, &buffers_to_free);
>                 goto out;
>         }
> /*------------------------------------------------------------------------*/
> 
>         spin_lock(&mapping->private_lock);
>         ret = drop_buffers(page, &buffers_to_free);
>         if (ret && !PageSwapCache(page)) {
> 
> ...
> 
>   If mapping is NULL then why we need to drop_buffers in that case.How can
> buffer head be associated with an anonymous page ?

Um.  The comment is old.  It dates from the time when buffer_heads
were used as the IO container for swapdev I/O.

We don't do that any more - swap IO pages are encapsulated directly into
BIOs.

However this code path is still needed because we can very occasionally
see pages with a NULL ->mapping and attached buffers.  They occur when
truncate_complete_page() encounters a page with busy buffers (typically
the buffer is busy because it is attached to an in-progress ext3 transaction).
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2002-09-03 18:17 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-09-03  9:11 Buffer Head Doubts Anil Kumar
2002-09-03 18:17 ` Andrew Morton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox