Messages in this thread Patch in this message | | | Date | Wed, 11 Dec 2013 20:18:55 +0100 | From | Oleg Nesterov <> | Subject | PATCH? introduce get_compound_page (Was: process 'stuck' at exit) |
| |
On 12/11, Oleg Nesterov wrote: > > On 12/11, Thomas Gleixner wrote: > > > > On Wed, 11 Dec 2013, Oleg Nesterov wrote: > > > > > > I have to admit, I do not understand why we can't avoid this altogether. > > > > > > __get_page_tail() can find the stable ->first_page, why get_futex_key() > > > can't ? > > > > Because it can be split under us. > > I understand, but why we can't rely on compound_lock() like > __get_page_tail() does? > > OK, could you please explain why something like the pseudo-code > below can't work?
Seriously. Can the path below work?
With this change get_futex_key() can simply do
page_head = get_compound_head(page); if (page_head) put_page(page); else page_head = page;
instead of CONFIG_TRANSPARENT_HUGEPAGE/else code.
(and we can also remove "bool get_page_head" from __get_page_tail_foll).
I am sure I missed something. But I am curious and I'd like to understand what I have missed.
Thanks,
Oleg.
--- a/mm/swap.c +++ b/mm/swap.c @@ -210,7 +210,7 @@ EXPORT_SYMBOL(put_page); * This function is exported but must not be called by anything other * than get_page(). It implements the slow path of get_page(). */ -bool __get_page_tail(struct page *page) +static struct page *__get_compound_head(struct page *page, bool and_tail) { /* * This takes care of get_page() if run on a tail page @@ -234,8 +234,9 @@ bool __get_page_tail(struct page *page) * cannot race here. */ VM_BUG_ON(!PageHead(page_head)); - __get_page_tail_foll(page, false); - return true; + if (and_tail) + get_huge_page_tail(page); + return page_head; } else { /* * __split_huge_page_refcount run @@ -260,17 +261,34 @@ bool __get_page_tail(struct page *page) flags = compound_lock_irqsave(page_head); /* here __split_huge_page_refcount won't run anymore */ if (likely(PageTail(page))) { - __get_page_tail_foll(page, false); + if (and_tail) + get_huge_page_tail(page); got = true; } compound_unlock_irqrestore(page_head, flags); - if (unlikely(!got)) + + if (likely(got)) + return page_head; + else put_page(page_head); } - return got; + return NULL; +} + +bool __get_page_tail(struct page *page) +{ + return !!__get_compound_head(page, true); } EXPORT_SYMBOL(__get_page_tail); +struct page *get_compound_head(struct page *page) +{ + if (PageTail(page)) + return __get_compound_head(page, false); + else + return NULL; +} + /** * put_pages_list() - release a list of pages * @pages: list of pages threaded on page->lru
| |