linux/fs/fscache
Jan Kara 5e4c0d9741 lib/radix-tree.c: make radix_tree_node_alloc() work correctly within interrupt
With users of radix_tree_preload() run from interrupt (block/blk-ioc.c is
one such possible user), the following race can happen:

radix_tree_preload()
...
radix_tree_insert()
  radix_tree_node_alloc()
    if (rtp->nr) {
      ret = rtp->nodes[rtp->nr - 1];
<interrupt>
...
radix_tree_preload()
...
radix_tree_insert()
  radix_tree_node_alloc()
    if (rtp->nr) {
      ret = rtp->nodes[rtp->nr - 1];

And we give out one radix tree node twice.  That clearly results in radix
tree corruption with different results (usually OOPS) depending on which
two users of radix tree race.

We fix the problem by making radix_tree_node_alloc() always allocate fresh
radix tree nodes when in interrupt.  Using preloading when in interrupt
doesn't make sense since all the allocations have to be atomic anyway and
we cannot steal nodes from process-context users because some users rely
on radix_tree_insert() succeeding after radix_tree_preload().
in_interrupt() check is somewhat ugly but we cannot simply key off passed
gfp_mask as that is acquired from root_gfp_mask() and thus the same for
all preload users.

Another part of the fix is to avoid node preallocation in
radix_tree_preload() when passed gfp_mask doesn't allow waiting.  Again,
preallocation in such case doesn't make sense and when preallocation would
happen in interrupt we could possibly leak some allocated nodes.  However,
some users of radix_tree_preload() require following radix_tree_insert()
to succeed.  To avoid unexpected effects for these users,
radix_tree_preload() only warns if passed gfp mask doesn't allow waiting
and we provide a new function radix_tree_maybe_preload() for those users
which get different gfp mask from different call sites and which are
prepared to handle radix_tree_insert() failure.

Signed-off-by: Jan Kara <jack@suse.cz>
Cc: Jens Axboe <jaxboe@fusionio.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2013-09-11 15:59:36 -07:00
..
cache.c FS-Cache: Fix object state machine to have separate work and wait states 2013-06-19 14:16:47 +01:00
cookie.c FS-Cache: Add interface to check consistency of a cached object 2013-09-06 09:17:30 +01:00
fsdef.c FS-Cache: Simplify cookie retention for fscache_objects, fixing oops 2013-06-19 14:16:47 +01:00
histogram.c FS-Cache: Add use of /proc and presentation of statistics 2009-04-03 16:42:37 +01:00
internal.h FS-Cache: Add interface to check consistency of a cached object 2013-09-06 09:17:30 +01:00
Kconfig fscache: drop references to slow-work 2010-07-22 22:58:58 +02:00
main.c FS-Cache: Simplify cookie retention for fscache_objects, fixing oops 2013-06-19 14:16:47 +01:00
Makefile FS-Cache: Allow the current state of all objects to be dumped 2009-11-19 18:11:04 +00:00
netfs.c FS-Cache: Simplify cookie retention for fscache_objects, fixing oops 2013-06-19 14:16:47 +01:00
object-list.c FS-Cache: Simplify cookie retention for fscache_objects, fixing oops 2013-06-19 14:16:47 +01:00
object.c FS-Cache: Simplify cookie retention for fscache_objects, fixing oops 2013-06-19 14:16:47 +01:00
operation.c FS-Cache: Don't use spin_is_locked() in assertions 2013-06-19 14:16:47 +01:00
page.c lib/radix-tree.c: make radix_tree_node_alloc() work correctly within interrupt 2013-09-11 15:59:36 -07:00
proc.c FS-Cache: Allow the current state of all objects to be dumped 2009-11-19 18:11:04 +00:00
stats.c fs/fscache/stats.c: fix memory leak 2013-04-29 15:54:27 -07:00