• Andrew Morton's avatar
    [PATCH] writeback from address spaces · 090da372
    Andrew Morton authored
    [ I reversed the order in which writeback walks the superblock's
      dirty inodes.  It sped up dbench's unlink phase greatly.  I'm
      such a sleaze ]
    
    The core writeback patch.  Switches file writeback from the dirty
    buffer LRU over to address_space.dirty_pages.
    
    - The buffer LRU is removed
    
    - The buffer hash is removed (uses blockdev pagecache lookups)
    
    - The bdflush and kupdate functions are implemented against
      address_spaces, via pdflush.
    
    - The relationship between pages and buffers is changed.
    
      - If a page has dirty buffers, it is marked dirty
      - If a page is marked dirty, it *may* have dirty buffers.
      - A dirty page may be "partially dirty".  block_write_full_page
        discovers this.
    
    - A bunch of consistency checks of the form
    
    	if (!something_which_should_be_true())
    		buffer_error();
    
      have been introduced.  These fog the code up but are important for
      ensuring that the new buffer/page code is working correctly.
    
    - New locking (inode.i_bufferlist_lock) is introduced for exclusion
      from try_to_free_buffers().  This is needed because set_page_dirty
      is called under spinlock, so it cannot lock the page.  But it
      needs access to page->buffers to set them all dirty.
    
      i_bufferlist_lock is also used to protect inode.i_dirty_buffers.
    
    - fs/inode.c has been split: all the code related to file data writeback
      has been moved into fs/fs-writeback.c
    
    - Code related to file data writeback at the address_space level is in
      the new mm/page-writeback.c
    
    - try_to_free_buffers() is now non-blocking
    
    - Switches vmscan.c over to understand that all pages with dirty data
      are now marked dirty.
    
    - Introduces a new a_op for VM writeback:
    
    	->vm_writeback(struct page *page, int *nr_to_write)
    
      this is a bit half-baked at present.  The intent is that the address_space
      is given the opportunity to perform clustered writeback.  To allow it to
      opportunistically write out disk-contiguous dirty data which may be in other zones.
      To allow delayed-allocate filesystems to get good disk layout.
    
    - Added address_space.io_pages.  Pages which are being prepared for
      writeback.  This is here for two reasons:
    
      1: It will be needed later, when BIOs are assembled direct
         against pagecache, bypassing the buffer layer.  It avoids a
         deadlock which would occur if someone moved the page back onto the
         dirty_pages list after it was added to the BIO, but before it was
         submitted.  (hmm.  This may not be a problem with PG_writeback logic).
    
      2: Avoids a livelock which would occur if some other thread is continually
         redirtying pages.
    
    - There are two known performance problems in this code:
    
      1: Pages which are locked for writeback cause undesirable
         blocking when they are being overwritten.  A patch which leaves
         pages unlocked during writeback comes later in the series.
    
      2: While inodes are under writeback, they are locked.  This
         causes namespace lookups against the file to get unnecessarily
         blocked in wait_on_inode().  This is a fairly minor problem.
    
         I don't have a fix for this at present - I'll fix this when I
         attach dirty address_spaces direct to super_blocks.
    
    - The patch vastly increases the amount of dirty data which the
      kernel permits highmem machines to maintain.  This is because the
      balancing decisions are made against the amount of memory in the
      machine, not against the amount of buffercache-allocatable memory.
    
      This may be very wrong, although it works fine for me (2.5 gigs).
    
      We can trivially go back to the old-style throttling with
      s/nr_free_pagecache_pages/nr_free_buffer_pages/ in
      balance_dirty_pages().  But better would be to allow blockdev
      mappings to use highmem (I'm thinking about this one, slowly).  And
      to move writer-throttling and writeback decisions into the VM (modulo
      the file-overwriting problem).
    
    - Drops 24 bytes from struct buffer_head.  More to come.
    
    - There's some gunk like super_block.flags:MS_FLUSHING which needs to
      be killed.  Need a better way of providing collision avoidance
      between pdflush threads, to prevent more than one pdflush thread
      working a disk at the same time.
    
      The correct way to do that is to put a flag in the request queue to
      say "there's a pdlfush thread working this disk".  This is easy to
      do: just generalise the "ra_pages" pointer to point at a struct which
      includes ra_pages and the new collision-avoidance flag.
    090da372
buffer.c 58.3 KB