• Andrew Morton's avatar
    [PATCH] __set_page_dirty_nobuffers race fix · d61ae266
    Andrew Morton authored
    Running __mark_inode_dirty() against a swapcache page is illegal and will
    oops.
    
    I see a race in set_page_dirty() wherein it can be called with a PageSwapCache
    page, but if the page is removed from swapcache after
    __set_page_dirty_nobuffers() drops tree_lock(), we have the situation where
    PageSwapCache() is false, but local variable `mapping' points at swapcache.
    
    Handle that by checking for non-null mapping->host.  We don't care about the
    page state at this point - we're only interested in the inode.
    
    
    
    There is a converse case: what if a page is added to swapcache as we are
    running set_page_dirty() against it?
    
    In this case the page gets its PG_dirty flag set but it is not tagged as dirty
    in the swapper_space radix tree.  The swap writeout code will handle this OK
    and test_clear_page_dirty()'s call to
    radix_tree_tag_clear(PAGECACHE_TAG_DIRTY) will silently have no effect.  The
    only downside is that future radix-tree-based writearound won't notice that
    such pages are dirty and swap IO scheduling will be a teensy bit worse.
    
    
    The patch also fixes the (silly) testing of local variable `mapping' to see if
    the page was truncated.  We should test page_mapping() for that.
    d61ae266
page-writeback.c 21.7 KB