tcache_attach_page() written with the assumption that the slot in the page_tree may be already occupied by other page, so it replaces such page. However, such situations should never be possible at all. Before putting any page to the tcache we supposed to either get this page from tcache or invalidate it. So when we put the page, slot in tcache page_tree should be already empty.
Just in case add WARN_ON(err == -EXISTS) to catch such not supposed to happen situations. https://jira.sw.ru/browse/PSBM-64727 Signed-off-by: Andrey Ryabinin <aryabi...@virtuozzo.com> --- mm/tcache.c | 44 +++++++++++++------------------------------- 1 file changed, 13 insertions(+), 31 deletions(-) diff --git a/mm/tcache.c b/mm/tcache.c index 94f03832804..3778523bbce 100644 --- a/mm/tcache.c +++ b/mm/tcache.c @@ -716,14 +716,11 @@ static inline void tcache_put_page(struct page *page) } } -static int tcache_page_tree_replace(struct tcache_node *node, pgoff_t index, - struct page *page, struct page **old_page) +static int tcache_page_tree_insert(struct tcache_node *node, pgoff_t index, + struct page *page) { - void **pslot; int err = 0; - *old_page = NULL; - /* * If the node was invalidated after we looked it up, abort in order to * avoid clashes with tcache_invalidate_node_pages. @@ -733,22 +730,13 @@ static int tcache_page_tree_replace(struct tcache_node *node, pgoff_t index, goto out; } - pslot = radix_tree_lookup_slot(&node->page_tree, index); - if (pslot) { - *old_page = radix_tree_deref_slot_protected(pslot, - &node->tree_lock); - radix_tree_replace_slot(pslot, page); - __dec_zone_page_state(*old_page, NR_FILE_PAGES); + err = radix_tree_insert(&node->page_tree, index, page); + WARN_ON(err == -EEXIST); + if (!err) { + if (!node->nr_pages++) + tcache_hold_node(node); + __this_cpu_inc(nr_tcache_pages); __inc_zone_page_state(page, NR_FILE_PAGES); - } else { - err = radix_tree_insert(&node->page_tree, index, page); - BUG_ON(err == -EEXIST); - if (!err) { - if (!node->nr_pages++) - tcache_hold_node(node); - __this_cpu_inc(nr_tcache_pages); - __inc_zone_page_state(page, NR_FILE_PAGES); - } } out: return err; @@ -784,24 +772,18 @@ static struct page *tcache_page_tree_delete(struct tcache_node *node, static noinline_for_stack int tcache_attach_page(struct tcache_node *node, pgoff_t index, struct page *page) { - struct page *old_page; unsigned long flags; int err = 0; tcache_init_page(page, node, index); spin_lock_irqsave(&node->tree_lock, flags); - err = tcache_page_tree_replace(node, index, page, &old_page); - if (err) - goto out; - - if (old_page) { - tcache_lru_del(node->pool, old_page, false); - tcache_put_page(old_page); + err = tcache_page_tree_insert(node, index, page); + if (!err) { + tcache_hold_page(page); + tcache_lru_add(node->pool, page); } - tcache_hold_page(page); - tcache_lru_add(node->pool, page); -out: + spin_unlock_irqrestore(&node->tree_lock, flags); return err; } -- 2.13.0 _______________________________________________ Devel mailing list Devel@openvz.org https://lists.openvz.org/mailman/listinfo/devel