]> git.baikalelectronics.ru Git - kernel.git/commit
idr: Fix idr_get_next race with idr_remove
authorMatthew Wilcox (Oracle) <willy@infradead.org>
Tue, 14 May 2019 20:05:45 +0000 (16:05 -0400)
committerMatthew Wilcox (Oracle) <willy@infradead.org>
Mon, 3 Jun 2019 03:00:24 +0000 (23:00 -0400)
commitc0c4e801731eb48129d25bb1b56fa75e05a9433f
tree896b8028b37e5fe8705f113a7a628c3e1da85de4
parent915ac5f42bcc024df307fd8d6b2909dab6a2ea21
idr: Fix idr_get_next race with idr_remove

If the entry is deleted from the IDR between the call to
radix_tree_iter_find() and rcu_dereference_raw(), idr_get_next()
will return NULL, which will end the iteration prematurely.  We should
instead continue to the next entry in the IDR.  This only happens if the
iteration is protected by the RCU lock.  Most IDR users use a spinlock
or semaphore to exclude simultaneous modifications.  It was noticed once
the PID allocator was converted to use the IDR, as it uses the RCU lock,
but there may be other users elsewhere in the kernel.

We can't use the normal pattern of calling radix_tree_deref_retry()
(which catches both a retry entry in a leaf node and a node entry in
the root) as the IDR supports storing entries which are unaligned,
which will trigger an infinite loop if they are encountered.  Instead,
we have to explicitly check whether the entry is a retry entry.

Fixes: 5e6bb5690b62 ("Reimplement IDR and IDA using the radix tree")
Reported-by: Brendan Gregg <bgregg@netflix.com>
Tested-by: Brendan Gregg <bgregg@netflix.com>
Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
lib/idr.c
tools/testing/radix-tree/idr-test.c