PATCH? introduce get_compound_page (Was: process 'stuck' at exit)

From: Oleg Nesterov
Date: Wed Dec 11 2013 - 14:18:39 EST


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

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/