diff options
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 63 |
1 files changed, 14 insertions, 49 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index 8a310e240cda..eed92a8a4c49 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -469,7 +469,8 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) | |||
469 | { | 469 | { |
470 | unsigned long address = (unsigned long)uaddr; | 470 | unsigned long address = (unsigned long)uaddr; |
471 | struct mm_struct *mm = current->mm; | 471 | struct mm_struct *mm = current->mm; |
472 | struct page *page, *page_head; | 472 | struct page *page; |
473 | struct address_space *mapping; | ||
473 | int err, ro = 0; | 474 | int err, ro = 0; |
474 | 475 | ||
475 | /* | 476 | /* |
@@ -519,46 +520,9 @@ again: | |||
519 | else | 520 | else |
520 | err = 0; | 521 | err = 0; |
521 | 522 | ||
522 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | 523 | lock_page(page); |
523 | page_head = page; | ||
524 | if (unlikely(PageTail(page))) { | ||
525 | put_page(page); | ||
526 | /* serialize against __split_huge_page_splitting() */ | ||
527 | local_irq_disable(); | ||
528 | if (likely(__get_user_pages_fast(address, 1, !ro, &page) == 1)) { | ||
529 | page_head = compound_head(page); | ||
530 | /* | ||
531 | * page_head is valid pointer but we must pin | ||
532 | * it before taking the PG_lock and/or | ||
533 | * PG_compound_lock. The moment we re-enable | ||
534 | * irqs __split_huge_page_splitting() can | ||
535 | * return and the head page can be freed from | ||
536 | * under us. We can't take the PG_lock and/or | ||
537 | * PG_compound_lock on a page that could be | ||
538 | * freed from under us. | ||
539 | */ | ||
540 | if (page != page_head) { | ||
541 | get_page(page_head); | ||
542 | put_page(page); | ||
543 | } | ||
544 | local_irq_enable(); | ||
545 | } else { | ||
546 | local_irq_enable(); | ||
547 | goto again; | ||
548 | } | ||
549 | } | ||
550 | #else | ||
551 | page_head = compound_head(page); | ||
552 | if (page != page_head) { | ||
553 | get_page(page_head); | ||
554 | put_page(page); | ||
555 | } | ||
556 | #endif | ||
557 | |||
558 | lock_page(page_head); | ||
559 | |||
560 | /* | 524 | /* |
561 | * If page_head->mapping is NULL, then it cannot be a PageAnon | 525 | * If page->mapping is NULL, then it cannot be a PageAnon |
562 | * page; but it might be the ZERO_PAGE or in the gate area or | 526 | * page; but it might be the ZERO_PAGE or in the gate area or |
563 | * in a special mapping (all cases which we are happy to fail); | 527 | * in a special mapping (all cases which we are happy to fail); |
564 | * or it may have been a good file page when get_user_pages_fast | 528 | * or it may have been a good file page when get_user_pages_fast |
@@ -570,12 +534,13 @@ again: | |||
570 | * | 534 | * |
571 | * The case we do have to guard against is when memory pressure made | 535 | * The case we do have to guard against is when memory pressure made |
572 | * shmem_writepage move it from filecache to swapcache beneath us: | 536 | * shmem_writepage move it from filecache to swapcache beneath us: |
573 | * an unlikely race, but we do need to retry for page_head->mapping. | 537 | * an unlikely race, but we do need to retry for page->mapping. |
574 | */ | 538 | */ |
575 | if (!page_head->mapping) { | 539 | mapping = compound_head(page)->mapping; |
576 | int shmem_swizzled = PageSwapCache(page_head); | 540 | if (!mapping) { |
577 | unlock_page(page_head); | 541 | int shmem_swizzled = PageSwapCache(page); |
578 | put_page(page_head); | 542 | unlock_page(page); |
543 | put_page(page); | ||
579 | if (shmem_swizzled) | 544 | if (shmem_swizzled) |
580 | goto again; | 545 | goto again; |
581 | return -EFAULT; | 546 | return -EFAULT; |
@@ -588,7 +553,7 @@ again: | |||
588 | * it's a read-only handle, it's expected that futexes attach to | 553 | * it's a read-only handle, it's expected that futexes attach to |
589 | * the object not the particular process. | 554 | * the object not the particular process. |
590 | */ | 555 | */ |
591 | if (PageAnon(page_head)) { | 556 | if (PageAnon(page)) { |
592 | /* | 557 | /* |
593 | * A RO anonymous page will never change and thus doesn't make | 558 | * A RO anonymous page will never change and thus doesn't make |
594 | * sense for futex operations. | 559 | * sense for futex operations. |
@@ -603,15 +568,15 @@ again: | |||
603 | key->private.address = address; | 568 | key->private.address = address; |
604 | } else { | 569 | } else { |
605 | key->both.offset |= FUT_OFF_INODE; /* inode-based key */ | 570 | key->both.offset |= FUT_OFF_INODE; /* inode-based key */ |
606 | key->shared.inode = page_head->mapping->host; | 571 | key->shared.inode = mapping->host; |
607 | key->shared.pgoff = basepage_index(page); | 572 | key->shared.pgoff = basepage_index(page); |
608 | } | 573 | } |
609 | 574 | ||
610 | get_futex_key_refs(key); /* implies MB (B) */ | 575 | get_futex_key_refs(key); /* implies MB (B) */ |
611 | 576 | ||
612 | out: | 577 | out: |
613 | unlock_page(page_head); | 578 | unlock_page(page); |
614 | put_page(page_head); | 579 | put_page(page); |
615 | return err; | 580 | return err; |
616 | } | 581 | } |
617 | 582 | ||