Message ID | 151205770380.15209.10247550092954624820.stgit@localhost.localdomain |
---|---|
State | New |
Series | "tcache: Repeat invalidation in tcache_invalidate_node_pages()" |
Headers | show |
diff --git a/mm/tcache.c b/mm/tcache.c index d1a2c53e11a..cbc50d4b8bc 100644 --- a/mm/tcache.c +++ b/mm/tcache.c @@ -903,13 +903,15 @@ tcache_invalidate_node_pages(struct tcache_node *node) struct page *pages[TCACHE_PAGEVEC_SIZE]; pgoff_t index = 0; unsigned nr_pages; + bool repeat; int i; /* * First forbid new page insertions - see tcache_page_tree_replace. */ node->invalidated = true; - +again: + repeat = false; while ((nr_pages = tcache_lookup(pages, node, index, TCACHE_PAGEVEC_SIZE, indices))) { for (i = 0; i < nr_pages; i++) { @@ -925,13 +927,20 @@ tcache_invalidate_node_pages(struct tcache_node *node) tcache_lru_del(node->pool, page, false); local_irq_enable(); tcache_put_page(page); - } else + } else { local_irq_enable(); + repeat = true; + } } cond_resched(); index++; } + if (repeat) { + index = 0; + goto again; + } + WARN_ON(node->nr_pages != 0); }
tcache_shrink_scan() tcache_destroy_pool tcache_lru_isolate() tcache_grab_pool() ... page_cache_get_speculative() -->cnt == 2 ... tcache_put_pool() --> pool cnt zero ... wait_for_completion(&pool->completion); tcache_reclaim_pages tcache_invalidate_node_pages() __tcache_reclaim_page() tcache_lookup() page_cache_get_speculative --> cnt == 3 __tcache_page_tree_delete page_ref_freeze(2) -->fail page_ref_freeze(2) -->fail On 30.11.2017 19:02, Kirill Tkhai wrote: > When there are more than 2 users of a page, __tcache_page_tree_delete() > fails to freeze it. We skip it and never try to freeze the page again. > > In this case the page remains not invalidated, and tcache_node->nr_pages > never decremented. Later, we catch WARN_ON() reporting about this. > > The patch fixes the problem. In case of we failed to invalidate a page, > we remember that, and return to such pages after others are invalidated. > > https://jira.sw.ru/browse/PSBM-78354 > > Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com> > --- > mm/tcache.c | 13 +++++++++++-- > 1 file changed, 11 insertions(+), 2 deletions(-) > > diff --git a/mm/tcache.c b/mm/tcache.c > index d1a2c53e11a..cbc50d4b8bc 100644 > --- a/mm/tcache.c > +++ b/mm/tcache.c > @@ -903,13 +903,15 @@ tcache_invalidate_node_pages(struct tcache_node *node) > struct page *pages[TCACHE_PAGEVEC_SIZE]; > pgoff_t index = 0; > unsigned nr_pages; > + bool repeat; > int i; > > /* > * First forbid new page insertions - see tcache_page_tree_replace. > */ > node->invalidated = true; > - > +again: > + repeat = false; > while ((nr_pages = tcache_lookup(pages, node, index, > TCACHE_PAGEVEC_SIZE, indices))) { > for (i = 0; i < nr_pages; i++) { > @@ -925,13 +927,20 @@ tcache_invalidate_node_pages(struct tcache_node *node) > tcache_lru_del(node->pool, page, false); > local_irq_enable(); > tcache_put_page(page); > - } else > + } else { > local_irq_enable(); > + repeat = true; > + } > } > cond_resched(); > index++; > } > > + if (repeat) { > + index = 0; > + goto again; > + } > + > WARN_ON(node->nr_pages != 0); > } > >
When there are more than 2 users of a page, __tcache_page_tree_delete() fails to freeze it. We skip it and never try to freeze the page again. In this case the page remains not invalidated, and tcache_node->nr_pages never decremented. Later, we catch WARN_ON() reporting about this. The patch fixes the problem. In case of we failed to invalidate a page, we remember that, and return to such pages after others are invalidated. https://jira.sw.ru/browse/PSBM-78354 Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com> --- mm/tcache.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)