diff options
Diffstat (limited to 'kernel/futex.c')
-rw-r--r-- | kernel/futex.c | 14 |
1 files changed, 11 insertions, 3 deletions
diff --git a/kernel/futex.c b/kernel/futex.c index ee25f5ba4aca..33664f70e2d2 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -469,7 +469,7 @@ 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; | 472 | struct page *page, *tail; |
473 | struct address_space *mapping; | 473 | struct address_space *mapping; |
474 | int err, ro = 0; | 474 | int err, ro = 0; |
475 | 475 | ||
@@ -530,7 +530,15 @@ again: | |||
530 | * considered here and page lock forces unnecessarily serialization | 530 | * considered here and page lock forces unnecessarily serialization |
531 | * From this point on, mapping will be re-verified if necessary and | 531 | * From this point on, mapping will be re-verified if necessary and |
532 | * page lock will be acquired only if it is unavoidable | 532 | * page lock will be acquired only if it is unavoidable |
533 | */ | 533 | * |
534 | * Mapping checks require the head page for any compound page so the | ||
535 | * head page and mapping is looked up now. For anonymous pages, it | ||
536 | * does not matter if the page splits in the future as the key is | ||
537 | * based on the address. For filesystem-backed pages, the tail is | ||
538 | * required as the index of the page determines the key. For | ||
539 | * base pages, there is no tail page and tail == page. | ||
540 | */ | ||
541 | tail = page; | ||
534 | page = compound_head(page); | 542 | page = compound_head(page); |
535 | mapping = READ_ONCE(page->mapping); | 543 | mapping = READ_ONCE(page->mapping); |
536 | 544 | ||
@@ -654,7 +662,7 @@ again: | |||
654 | 662 | ||
655 | key->both.offset |= FUT_OFF_INODE; /* inode-based key */ | 663 | key->both.offset |= FUT_OFF_INODE; /* inode-based key */ |
656 | key->shared.inode = inode; | 664 | key->shared.inode = inode; |
657 | key->shared.pgoff = basepage_index(page); | 665 | key->shared.pgoff = basepage_index(tail); |
658 | rcu_read_unlock(); | 666 | rcu_read_unlock(); |
659 | } | 667 | } |
660 | 668 | ||