]> git.baikalelectronics.ru Git - kernel.git/commit
xarray: Fix early termination of xas_for_each_marked
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Thu, 12 Mar 2020 21:29:11 +0000 (17:29 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 17 Apr 2020 08:50:18 +0000 (10:50 +0200)
commitf842ea88a984faa9bd807e8921bac36ecf9152fc
tree7edc69d8842380e2c6dc883bac5a5349934f7d61
parent4d0de09f17bcea260512791f3e464d3ab50f5b2a
xarray: Fix early termination of xas_for_each_marked

commit 43faee4a12fbfaf50dd43b849d38eae17b39bed3 upstream.

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: Jan Kara <jack@suse.cz>
CC: stable@vger.kernel.org
Fixes: f0c6bd3c48d9 ("page cache: Convert delete_batch to XArray")
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/linux/xarray.h
lib/xarray.c
tools/testing/radix-tree/Makefile
tools/testing/radix-tree/iteration_check_2.c [new file with mode: 0644]
tools/testing/radix-tree/main.c
tools/testing/radix-tree/test.h