• Matthew Wilcox (Oracle)'s avatar
    xarray: Fix early termination of xas_for_each_marked · 7e934cf5
    Matthew Wilcox (Oracle) authored
    xas_for_each_marked() is using entry == NULL as a termination condition
    of the iteration. When xas_for_each_marked() is used protected only by
    RCU, this can however race with xas_store(xas, NULL) in the following
    way:
    
    TASK1                                   TASK2
    page_cache_delete()         	        find_get_pages_range_tag()
                                              xas_for_each_marked()
                                                xas_find_marked()
                                                  off = xas_find_chunk()
    
      xas_store(&xas, NULL)
        xas_init_marks(&xas);
        ...
        rcu_assign_pointer(*slot, NULL);
                                                  entry = xa_entry(off);
    
    And thus xas_for_each_marked() terminates prematurely possibly leading
    to missed entries in the iteration (translating to missing writeback of
    some pages or a similar problem).
    
    If we find a NULL entry that has been marked, skip it (unless we're trying
    to allocate an entry).
    Reported-by: default avatarJan Kara <jack@suse.cz>
    CC: stable@vger.kernel.org
    Fixes: ef8e5717 ("page cache: Convert delete_batch to XArray")
    Signed-off-by: default avatarMatthew Wilcox (Oracle) <willy@infradead.org>
    7e934cf5
xarray.c 53.3 KB