On Mon 01-12-14 17:58:00, Johannes Weiner wrote:
> Tejun, while reviewing the code, spotted the following race condition
> between the dirtying and truncation of a page:
> 
> __set_page_dirty_nobuffers()       __delete_from_page_cache()
>   if (TestSetPageDirty(page))
>                                      page->mapping = NULL
>                                    if (PageDirty())
>                                      dec_zone_page_state(page, NR_FILE_DIRTY);
>                                      dec_bdi_stat(mapping->backing_dev_info, 
> BDI_RECLAIMABLE);
>     if (page->mapping)
>       account_page_dirtied(page)
>         __inc_zone_page_state(page, NR_FILE_DIRTY);
>       __inc_bdi_stat(mapping->backing_dev_info, BDI_RECLAIMABLE);
> 
> which results in an imbalance of NR_FILE_DIRTY and BDI_RECLAIMABLE.
> 
> Dirtiers usually lock out truncation, either by holding the page lock
> directly, or in case of zap_pte_range(), by pinning the mapcount with
> the page table lock held.  The notable exception to this rule, though,
> is do_wp_page(), for which this race exists.  However, do_wp_page()
> already waits for a locked page to unlock before setting the dirty
> bit, in order to prevent a race where clear_page_dirty() misses the
> page bit in the presence of dirty ptes.  Upgrade that wait to a fully
> locked set_page_dirty() to also cover the situation explained above.
> 
> Afterwards, the code in set_page_dirty() dealing with a truncation
> race is no longer needed.  Remove it.
> 
> Reported-by: Tejun Heo <t...@kernel.org>
> Signed-off-by: Johannes Weiner <han...@cmpxchg.org>
> Cc: <sta...@vger.kernel.org>
> ---
>  include/linux/writeback.h |  1 -
>  mm/memory.c               | 26 ++++++++++++++++----------
>  mm/page-writeback.c       | 43 ++++++++++++-------------------------------
>  3 files changed, 28 insertions(+), 42 deletions(-)
> 
> diff --git a/include/linux/writeback.h b/include/linux/writeback.h
> index a219be961c0a..00048339c23e 100644
> --- a/include/linux/writeback.h
> +++ b/include/linux/writeback.h
> @@ -177,7 +177,6 @@ int write_cache_pages(struct address_space *mapping,
>                     struct writeback_control *wbc, writepage_t writepage,
>                     void *data);
>  int do_writepages(struct address_space *mapping, struct writeback_control 
> *wbc);
> -void set_page_dirty_balance(struct page *page);
>  void writeback_set_ratelimit(void);
>  void tag_pages_for_writeback(struct address_space *mapping,
>                            pgoff_t start, pgoff_t end);
> diff --git a/mm/memory.c b/mm/memory.c
> index 3e503831e042..73220eb6e9e3 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -2150,17 +2150,23 @@ reuse:
>               if (!dirty_page)
>                       return ret;
>  
> -             /*
> -              * Yes, Virginia, this is actually required to prevent a race
> -              * with clear_page_dirty_for_io() from clearing the page dirty
> -              * bit after it clear all dirty ptes, but before a racing
> -              * do_wp_page installs a dirty pte.
> -              *
> -              * do_shared_fault is protected similarly.
> -              */
>               if (!page_mkwrite) {
> -                     wait_on_page_locked(dirty_page);
> -                     set_page_dirty_balance(dirty_page);
> +                     struct address_space *mapping;
> +                     int dirtied;
> +
> +                     lock_page(dirty_page);
> +                     dirtied = set_page_dirty(dirty_page);
> +                     mapping = dirty_page->mapping;
> +                     unlock_page(dirty_page);
> +
> +                     if (dirtied && mapping) {
> +                             /*
> +                              * Some device drivers do not set page.mapping
> +                              * but still dirty their pages
> +                              */
  The comment doesn't make sense to me here. Is it meant to explain why we
check 'mapping' in the above condition? I always thought truncate is the
main reason.

                                                                Honza

-- 
Jan Kara <j...@suse.cz>
SUSE Labs, CR
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to