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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to