Skip to content

Commit

Permalink
radix-tree: clear all tags in radix_tree_node_rcu_free
Browse files Browse the repository at this point in the history
Commit f446daa ("mm: implement
writeback livelock avoidance using page tagging") introduced a new
radix tree tag, increasing the number of tags in each node from 2 to
3. It did not, however, fix up the code in
radix_tree_node_rcu_free() that cleans up after radix_tree_shrink()
and hence could leave stray tags set in the new tag array.

The result is that the livelock avoidance code added in the the
above commit would hit stale tags when doing tag based lookups,
resulting in livelocks when trying to traverse the tree.

Fix this problem in radix_tree_node_rcu_free() so it doesn't happen
again in the future by using a loop to walk all the tags up to
RADIX_TREE_MAX_TAGS to clear the stray tags radix_tree_shrink()
leaves behind.

Signed-off-by: Dave Chinner <[email protected]>
Acked-by: Nick Piggin <[email protected]>
Acked-by: Jan Kara <[email protected]>
  • Loading branch information
Dave Chinner authored and dchinner committed Aug 23, 2010
1 parent da5cabf commit b6dd086
Showing 1 changed file with 4 additions and 2 deletions.
6 changes: 4 additions & 2 deletions lib/radix-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,14 +174,16 @@ static void radix_tree_node_rcu_free(struct rcu_head *head)
{
struct radix_tree_node *node =
container_of(head, struct radix_tree_node, rcu_head);
int i;

/*
* must only free zeroed nodes into the slab. radix_tree_shrink
* can leave us with a non-NULL entry in the first slot, so clear
* that here to make sure.
*/
tag_clear(node, 0, 0);
tag_clear(node, 1, 0);
for (i = 0; i < RADIX_TREE_MAX_TAGS; i++)
tag_clear(node, i, 0);

node->slots[0] = NULL;
node->count = 0;

Expand Down

0 comments on commit b6dd086

Please sign in to comment.