.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Fast Userspace Mutexes (which I call "Futexes!"). |
---|
3 | 4 | * (C) Rusty Russell, IBM 2002 |
---|
.. | .. |
---|
29 | 30 | * |
---|
30 | 31 | * "The futexes are also cursed." |
---|
31 | 32 | * "But they come in a choice of three flavours!" |
---|
32 | | - * |
---|
33 | | - * This program is free software; you can redistribute it and/or modify |
---|
34 | | - * it under the terms of the GNU General Public License as published by |
---|
35 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
36 | | - * (at your option) any later version. |
---|
37 | | - * |
---|
38 | | - * This program is distributed in the hope that it will be useful, |
---|
39 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
40 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
41 | | - * GNU General Public License for more details. |
---|
42 | | - * |
---|
43 | | - * You should have received a copy of the GNU General Public License |
---|
44 | | - * along with this program; if not, write to the Free Software |
---|
45 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
46 | 33 | */ |
---|
47 | 34 | #include <linux/compat.h> |
---|
48 | | -#include <linux/slab.h> |
---|
49 | | -#include <linux/poll.h> |
---|
50 | | -#include <linux/fs.h> |
---|
51 | | -#include <linux/file.h> |
---|
52 | 35 | #include <linux/jhash.h> |
---|
53 | | -#include <linux/init.h> |
---|
54 | | -#include <linux/futex.h> |
---|
55 | | -#include <linux/mount.h> |
---|
56 | 36 | #include <linux/pagemap.h> |
---|
57 | 37 | #include <linux/syscalls.h> |
---|
58 | | -#include <linux/signal.h> |
---|
59 | | -#include <linux/export.h> |
---|
60 | | -#include <linux/magic.h> |
---|
61 | | -#include <linux/pid.h> |
---|
62 | | -#include <linux/nsproxy.h> |
---|
63 | | -#include <linux/ptrace.h> |
---|
64 | | -#include <linux/sched/rt.h> |
---|
65 | | -#include <linux/sched/wake_q.h> |
---|
66 | | -#include <linux/sched/mm.h> |
---|
67 | | -#include <linux/hugetlb.h> |
---|
68 | 38 | #include <linux/freezer.h> |
---|
69 | | -#include <linux/bootmem.h> |
---|
| 39 | +#include <linux/memblock.h> |
---|
70 | 40 | #include <linux/fault-inject.h> |
---|
| 41 | +#include <linux/time_namespace.h> |
---|
71 | 42 | |
---|
72 | 43 | #include <asm/futex.h> |
---|
73 | 44 | |
---|
74 | 45 | #include "locking/rtmutex_common.h" |
---|
| 46 | +#include <trace/hooks/futex.h> |
---|
75 | 47 | |
---|
76 | 48 | /* |
---|
77 | 49 | * READ this before attempting to hack on futexes! |
---|
.. | .. |
---|
147 | 119 | * |
---|
148 | 120 | * Where (A) orders the waiters increment and the futex value read through |
---|
149 | 121 | * atomic operations (see hb_waiters_inc) and where (B) orders the write |
---|
150 | | - * to futex and the waiters read -- this is done by the barriers for both |
---|
151 | | - * shared and private futexes in get_futex_key_refs(). |
---|
| 122 | + * to futex and the waiters read (see hb_waiters_pending()). |
---|
152 | 123 | * |
---|
153 | 124 | * This yields the following case (where X:=waiters, Y:=futex): |
---|
154 | 125 | * |
---|
.. | .. |
---|
212 | 183 | struct rt_mutex pi_mutex; |
---|
213 | 184 | |
---|
214 | 185 | struct task_struct *owner; |
---|
215 | | - atomic_t refcount; |
---|
| 186 | + refcount_t refcount; |
---|
216 | 187 | |
---|
217 | 188 | union futex_key key; |
---|
218 | 189 | } __randomize_layout; |
---|
.. | .. |
---|
321 | 292 | if (IS_ERR(dir)) |
---|
322 | 293 | return PTR_ERR(dir); |
---|
323 | 294 | |
---|
324 | | - if (!debugfs_create_bool("ignore-private", mode, dir, |
---|
325 | | - &fail_futex.ignore_private)) { |
---|
326 | | - debugfs_remove_recursive(dir); |
---|
327 | | - return -ENOMEM; |
---|
328 | | - } |
---|
329 | | - |
---|
| 295 | + debugfs_create_bool("ignore-private", mode, dir, |
---|
| 296 | + &fail_futex.ignore_private); |
---|
330 | 297 | return 0; |
---|
331 | 298 | } |
---|
332 | 299 | |
---|
.. | .. |
---|
346 | 313 | #else |
---|
347 | 314 | static inline void compat_exit_robust_list(struct task_struct *curr) { } |
---|
348 | 315 | #endif |
---|
349 | | - |
---|
350 | | -static inline void futex_get_mm(union futex_key *key) |
---|
351 | | -{ |
---|
352 | | - mmgrab(key->private.mm); |
---|
353 | | - /* |
---|
354 | | - * Ensure futex_get_mm() implies a full barrier such that |
---|
355 | | - * get_futex_key() implies a full barrier. This is relied upon |
---|
356 | | - * as smp_mb(); (B), see the ordering comment above. |
---|
357 | | - */ |
---|
358 | | - smp_mb__after_atomic(); |
---|
359 | | -} |
---|
360 | 316 | |
---|
361 | 317 | /* |
---|
362 | 318 | * Reflects a new waiter being added to the waitqueue. |
---|
.. | .. |
---|
386 | 342 | static inline int hb_waiters_pending(struct futex_hash_bucket *hb) |
---|
387 | 343 | { |
---|
388 | 344 | #ifdef CONFIG_SMP |
---|
| 345 | + /* |
---|
| 346 | + * Full barrier (B), see the ordering comment above. |
---|
| 347 | + */ |
---|
| 348 | + smp_mb(); |
---|
389 | 349 | return atomic_read(&hb->waiters); |
---|
390 | 350 | #else |
---|
391 | 351 | return 1; |
---|
.. | .. |
---|
423 | 383 | && key1->both.offset == key2->both.offset); |
---|
424 | 384 | } |
---|
425 | 385 | |
---|
426 | | -/* |
---|
427 | | - * Take a reference to the resource addressed by a key. |
---|
428 | | - * Can be called while holding spinlocks. |
---|
| 386 | +enum futex_access { |
---|
| 387 | + FUTEX_READ, |
---|
| 388 | + FUTEX_WRITE |
---|
| 389 | +}; |
---|
| 390 | + |
---|
| 391 | +/** |
---|
| 392 | + * futex_setup_timer - set up the sleeping hrtimer. |
---|
| 393 | + * @time: ptr to the given timeout value |
---|
| 394 | + * @timeout: the hrtimer_sleeper structure to be set up |
---|
| 395 | + * @flags: futex flags |
---|
| 396 | + * @range_ns: optional range in ns |
---|
429 | 397 | * |
---|
| 398 | + * Return: Initialized hrtimer_sleeper structure or NULL if no timeout |
---|
| 399 | + * value given |
---|
430 | 400 | */ |
---|
431 | | -static void get_futex_key_refs(union futex_key *key) |
---|
| 401 | +static inline struct hrtimer_sleeper * |
---|
| 402 | +futex_setup_timer(ktime_t *time, struct hrtimer_sleeper *timeout, |
---|
| 403 | + int flags, u64 range_ns) |
---|
432 | 404 | { |
---|
433 | | - if (!key->both.ptr) |
---|
434 | | - return; |
---|
| 405 | + if (!time) |
---|
| 406 | + return NULL; |
---|
435 | 407 | |
---|
| 408 | + hrtimer_init_sleeper_on_stack(timeout, (flags & FLAGS_CLOCKRT) ? |
---|
| 409 | + CLOCK_REALTIME : CLOCK_MONOTONIC, |
---|
| 410 | + HRTIMER_MODE_ABS); |
---|
436 | 411 | /* |
---|
437 | | - * On MMU less systems futexes are always "private" as there is no per |
---|
438 | | - * process address space. We need the smp wmb nevertheless - yes, |
---|
439 | | - * arch/blackfin has MMU less SMP ... |
---|
| 412 | + * If range_ns is 0, calling hrtimer_set_expires_range_ns() is |
---|
| 413 | + * effectively the same as calling hrtimer_set_expires(). |
---|
440 | 414 | */ |
---|
441 | | - if (!IS_ENABLED(CONFIG_MMU)) { |
---|
442 | | - smp_mb(); /* explicit smp_mb(); (B) */ |
---|
443 | | - return; |
---|
444 | | - } |
---|
| 415 | + hrtimer_set_expires_range_ns(&timeout->timer, *time, range_ns); |
---|
445 | 416 | |
---|
446 | | - switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) { |
---|
447 | | - case FUT_OFF_INODE: |
---|
448 | | - smp_mb(); /* explicit smp_mb(); (B) */ |
---|
449 | | - break; |
---|
450 | | - case FUT_OFF_MMSHARED: |
---|
451 | | - futex_get_mm(key); /* implies smp_mb(); (B) */ |
---|
452 | | - break; |
---|
453 | | - default: |
---|
454 | | - /* |
---|
455 | | - * Private futexes do not hold reference on an inode or |
---|
456 | | - * mm, therefore the only purpose of calling get_futex_key_refs |
---|
457 | | - * is because we need the barrier for the lockless waiter check. |
---|
458 | | - */ |
---|
459 | | - smp_mb(); /* explicit smp_mb(); (B) */ |
---|
460 | | - } |
---|
461 | | -} |
---|
462 | | - |
---|
463 | | -/* |
---|
464 | | - * Drop a reference to the resource addressed by a key. |
---|
465 | | - * The hash bucket spinlock must not be held. This is |
---|
466 | | - * a no-op for private futexes, see comment in the get |
---|
467 | | - * counterpart. |
---|
468 | | - */ |
---|
469 | | -static void drop_futex_key_refs(union futex_key *key) |
---|
470 | | -{ |
---|
471 | | - if (!key->both.ptr) { |
---|
472 | | - /* If we're here then we tried to put a key we failed to get */ |
---|
473 | | - WARN_ON_ONCE(1); |
---|
474 | | - return; |
---|
475 | | - } |
---|
476 | | - |
---|
477 | | - if (!IS_ENABLED(CONFIG_MMU)) |
---|
478 | | - return; |
---|
479 | | - |
---|
480 | | - switch (key->both.offset & (FUT_OFF_INODE|FUT_OFF_MMSHARED)) { |
---|
481 | | - case FUT_OFF_INODE: |
---|
482 | | - break; |
---|
483 | | - case FUT_OFF_MMSHARED: |
---|
484 | | - mmdrop(key->private.mm); |
---|
485 | | - break; |
---|
486 | | - } |
---|
| 417 | + return timeout; |
---|
487 | 418 | } |
---|
488 | 419 | |
---|
489 | 420 | /* |
---|
.. | .. |
---|
529 | 460 | /** |
---|
530 | 461 | * get_futex_key() - Get parameters which are the keys for a futex |
---|
531 | 462 | * @uaddr: virtual address of the futex |
---|
532 | | - * @fshared: 0 for a PROCESS_PRIVATE futex, 1 for PROCESS_SHARED |
---|
| 463 | + * @fshared: false for a PROCESS_PRIVATE futex, true for PROCESS_SHARED |
---|
533 | 464 | * @key: address where result is stored. |
---|
534 | | - * @rw: mapping needs to be read/write (values: VERIFY_READ, |
---|
535 | | - * VERIFY_WRITE) |
---|
| 465 | + * @rw: mapping needs to be read/write (values: FUTEX_READ, |
---|
| 466 | + * FUTEX_WRITE) |
---|
536 | 467 | * |
---|
537 | 468 | * Return: a negative error code or 0 |
---|
538 | 469 | * |
---|
539 | 470 | * The key words are stored in @key on success. |
---|
540 | 471 | * |
---|
541 | 472 | * For shared mappings (when @fshared), the key is: |
---|
| 473 | + * |
---|
542 | 474 | * ( inode->i_sequence, page->index, offset_within_page ) |
---|
| 475 | + * |
---|
543 | 476 | * [ also see get_inode_sequence_number() ] |
---|
544 | 477 | * |
---|
545 | 478 | * For private mappings (or when !@fshared), the key is: |
---|
| 479 | + * |
---|
546 | 480 | * ( current->mm, address, 0 ) |
---|
547 | 481 | * |
---|
548 | 482 | * This allows (cross process, where applicable) identification of the futex |
---|
.. | .. |
---|
550 | 484 | * |
---|
551 | 485 | * lock_page() might sleep, the caller should not hold a spinlock. |
---|
552 | 486 | */ |
---|
553 | | -static int |
---|
554 | | -get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) |
---|
| 487 | +static int get_futex_key(u32 __user *uaddr, bool fshared, union futex_key *key, |
---|
| 488 | + enum futex_access rw) |
---|
555 | 489 | { |
---|
556 | 490 | unsigned long address = (unsigned long)uaddr; |
---|
557 | 491 | struct mm_struct *mm = current->mm; |
---|
.. | .. |
---|
567 | 501 | return -EINVAL; |
---|
568 | 502 | address -= key->both.offset; |
---|
569 | 503 | |
---|
570 | | - if (unlikely(!access_ok(rw, uaddr, sizeof(u32)))) |
---|
| 504 | + if (unlikely(!access_ok(uaddr, sizeof(u32)))) |
---|
571 | 505 | return -EFAULT; |
---|
572 | 506 | |
---|
573 | 507 | if (unlikely(should_fail_futex(fshared))) |
---|
.. | .. |
---|
583 | 517 | if (!fshared) { |
---|
584 | 518 | key->private.mm = mm; |
---|
585 | 519 | key->private.address = address; |
---|
586 | | - get_futex_key_refs(key); /* implies smp_mb(); (B) */ |
---|
587 | 520 | return 0; |
---|
588 | 521 | } |
---|
589 | 522 | |
---|
590 | 523 | again: |
---|
591 | 524 | /* Ignore any VERIFY_READ mapping (futex common case) */ |
---|
592 | | - if (unlikely(should_fail_futex(fshared))) |
---|
| 525 | + if (unlikely(should_fail_futex(true))) |
---|
593 | 526 | return -EFAULT; |
---|
594 | 527 | |
---|
595 | | - err = get_user_pages_fast(address, 1, 1, &page); |
---|
| 528 | + err = get_user_pages_fast(address, 1, FOLL_WRITE, &page); |
---|
596 | 529 | /* |
---|
597 | 530 | * If write access is not required (eg. FUTEX_WAIT), try |
---|
598 | 531 | * and get read-only access. |
---|
599 | 532 | */ |
---|
600 | | - if (err == -EFAULT && rw == VERIFY_READ) { |
---|
| 533 | + if (err == -EFAULT && rw == FUTEX_READ) { |
---|
601 | 534 | err = get_user_pages_fast(address, 1, 0, &page); |
---|
602 | 535 | ro = 1; |
---|
603 | 536 | } |
---|
.. | .. |
---|
654 | 587 | lock_page(page); |
---|
655 | 588 | shmem_swizzled = PageSwapCache(page) || page->mapping; |
---|
656 | 589 | unlock_page(page); |
---|
657 | | - put_page(page); |
---|
| 590 | + put_user_page(page); |
---|
658 | 591 | |
---|
659 | 592 | if (shmem_swizzled) |
---|
660 | 593 | goto again; |
---|
.. | .. |
---|
677 | 610 | * A RO anonymous page will never change and thus doesn't make |
---|
678 | 611 | * sense for futex operations. |
---|
679 | 612 | */ |
---|
680 | | - if (unlikely(should_fail_futex(fshared)) || ro) { |
---|
| 613 | + if (unlikely(should_fail_futex(true)) || ro) { |
---|
681 | 614 | err = -EFAULT; |
---|
682 | 615 | goto out; |
---|
683 | 616 | } |
---|
.. | .. |
---|
704 | 637 | |
---|
705 | 638 | if (READ_ONCE(page->mapping) != mapping) { |
---|
706 | 639 | rcu_read_unlock(); |
---|
707 | | - put_page(page); |
---|
| 640 | + put_user_page(page); |
---|
708 | 641 | |
---|
709 | 642 | goto again; |
---|
710 | 643 | } |
---|
.. | .. |
---|
712 | 645 | inode = READ_ONCE(mapping->host); |
---|
713 | 646 | if (!inode) { |
---|
714 | 647 | rcu_read_unlock(); |
---|
715 | | - put_page(page); |
---|
| 648 | + put_user_page(page); |
---|
716 | 649 | |
---|
717 | 650 | goto again; |
---|
718 | 651 | } |
---|
.. | .. |
---|
723 | 656 | rcu_read_unlock(); |
---|
724 | 657 | } |
---|
725 | 658 | |
---|
726 | | - get_futex_key_refs(key); /* implies smp_mb(); (B) */ |
---|
727 | | - |
---|
728 | 659 | out: |
---|
729 | | - put_page(page); |
---|
| 660 | + put_user_page(page); |
---|
730 | 661 | return err; |
---|
731 | | -} |
---|
732 | | - |
---|
733 | | -static inline void put_futex_key(union futex_key *key) |
---|
734 | | -{ |
---|
735 | | - drop_futex_key_refs(key); |
---|
736 | 662 | } |
---|
737 | 663 | |
---|
738 | 664 | /** |
---|
.. | .. |
---|
752 | 678 | struct mm_struct *mm = current->mm; |
---|
753 | 679 | int ret; |
---|
754 | 680 | |
---|
755 | | - down_read(&mm->mmap_sem); |
---|
756 | | - ret = fixup_user_fault(current, mm, (unsigned long)uaddr, |
---|
| 681 | + mmap_read_lock(mm); |
---|
| 682 | + ret = fixup_user_fault(mm, (unsigned long)uaddr, |
---|
757 | 683 | FAULT_FLAG_WRITE, NULL); |
---|
758 | | - up_read(&mm->mmap_sem); |
---|
| 684 | + mmap_read_unlock(mm); |
---|
759 | 685 | |
---|
760 | 686 | return ret < 0 ? ret : 0; |
---|
761 | 687 | } |
---|
.. | .. |
---|
821 | 747 | INIT_LIST_HEAD(&pi_state->list); |
---|
822 | 748 | /* pi_mutex gets initialized later */ |
---|
823 | 749 | pi_state->owner = NULL; |
---|
824 | | - atomic_set(&pi_state->refcount, 1); |
---|
| 750 | + refcount_set(&pi_state->refcount, 1); |
---|
825 | 751 | pi_state->key = FUTEX_KEY_INIT; |
---|
826 | 752 | |
---|
827 | 753 | current->pi_state_cache = pi_state; |
---|
.. | .. |
---|
864 | 790 | |
---|
865 | 791 | static void get_pi_state(struct futex_pi_state *pi_state) |
---|
866 | 792 | { |
---|
867 | | - WARN_ON_ONCE(!atomic_inc_not_zero(&pi_state->refcount)); |
---|
| 793 | + WARN_ON_ONCE(!refcount_inc_not_zero(&pi_state->refcount)); |
---|
868 | 794 | } |
---|
869 | 795 | |
---|
870 | 796 | /* |
---|
.. | .. |
---|
876 | 802 | if (!pi_state) |
---|
877 | 803 | return; |
---|
878 | 804 | |
---|
879 | | - if (!atomic_dec_and_test(&pi_state->refcount)) |
---|
| 805 | + if (!refcount_dec_and_test(&pi_state->refcount)) |
---|
880 | 806 | return; |
---|
881 | 807 | |
---|
882 | 808 | /* |
---|
.. | .. |
---|
901 | 827 | * refcount is at 0 - put it back to 1. |
---|
902 | 828 | */ |
---|
903 | 829 | pi_state->owner = NULL; |
---|
904 | | - atomic_set(&pi_state->refcount, 1); |
---|
| 830 | + refcount_set(&pi_state->refcount, 1); |
---|
905 | 831 | current->pi_state_cache = pi_state; |
---|
906 | 832 | } |
---|
907 | 833 | } |
---|
.. | .. |
---|
944 | 870 | * In that case; drop the locks to let put_pi_state() make |
---|
945 | 871 | * progress and retry the loop. |
---|
946 | 872 | */ |
---|
947 | | - if (!atomic_inc_not_zero(&pi_state->refcount)) { |
---|
| 873 | + if (!refcount_inc_not_zero(&pi_state->refcount)) { |
---|
948 | 874 | raw_spin_unlock_irq(&curr->pi_lock); |
---|
949 | 875 | cpu_relax(); |
---|
950 | 876 | raw_spin_lock_irq(&curr->pi_lock); |
---|
.. | .. |
---|
962 | 888 | if (head->next != next) { |
---|
963 | 889 | /* retain curr->pi_lock for the loop invariant */ |
---|
964 | 890 | raw_spin_unlock(&pi_state->pi_mutex.wait_lock); |
---|
965 | | - raw_spin_unlock_irq(&curr->pi_lock); |
---|
966 | 891 | spin_unlock(&hb->lock); |
---|
967 | | - raw_spin_lock_irq(&curr->pi_lock); |
---|
968 | 892 | put_pi_state(pi_state); |
---|
969 | 893 | continue; |
---|
970 | 894 | } |
---|
.. | .. |
---|
1011 | 935 | * [10] Found | Found | task | !=taskTID | 0/1 | Invalid |
---|
1012 | 936 | * |
---|
1013 | 937 | * [1] Indicates that the kernel can acquire the futex atomically. We |
---|
1014 | | - * came came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit. |
---|
| 938 | + * came here due to a stale FUTEX_WAITERS/FUTEX_OWNER_DIED bit. |
---|
1015 | 939 | * |
---|
1016 | 940 | * [2] Valid, if TID does not belong to a kernel thread. If no matching |
---|
1017 | 941 | * thread is found then it indicates that the owner TID has died. |
---|
.. | .. |
---|
1104 | 1028 | * and futex_wait_requeue_pi() as it cannot go to 0 and consequently |
---|
1105 | 1029 | * free pi_state before we can take a reference ourselves. |
---|
1106 | 1030 | */ |
---|
1107 | | - WARN_ON(!atomic_read(&pi_state->refcount)); |
---|
| 1031 | + WARN_ON(!refcount_read(&pi_state->refcount)); |
---|
1108 | 1032 | |
---|
1109 | 1033 | /* |
---|
1110 | 1034 | * Now that we have a pi_state, we can acquire wait_lock |
---|
.. | .. |
---|
1198 | 1122 | |
---|
1199 | 1123 | /** |
---|
1200 | 1124 | * wait_for_owner_exiting - Block until the owner has exited |
---|
| 1125 | + * @ret: owner's current futex lock status |
---|
1201 | 1126 | * @exiting: Pointer to the exiting task |
---|
1202 | 1127 | * |
---|
1203 | 1128 | * Caller must hold a refcount on @exiting. |
---|
.. | .. |
---|
1400 | 1325 | static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval) |
---|
1401 | 1326 | { |
---|
1402 | 1327 | int err; |
---|
1403 | | - u32 uninitialized_var(curval); |
---|
| 1328 | + u32 curval; |
---|
1404 | 1329 | |
---|
1405 | 1330 | if (unlikely(should_fail_futex(true))) |
---|
1406 | 1331 | return -EFAULT; |
---|
.. | .. |
---|
1525 | 1450 | { |
---|
1526 | 1451 | struct futex_hash_bucket *hb; |
---|
1527 | 1452 | |
---|
1528 | | - if (WARN_ON_SMP(!q->lock_ptr || !spin_is_locked(q->lock_ptr)) |
---|
1529 | | - || WARN_ON(plist_node_empty(&q->list))) |
---|
| 1453 | + if (WARN_ON_SMP(!q->lock_ptr) || WARN_ON(plist_node_empty(&q->list))) |
---|
1530 | 1454 | return; |
---|
| 1455 | + lockdep_assert_held(q->lock_ptr); |
---|
1531 | 1456 | |
---|
1532 | 1457 | hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock); |
---|
1533 | 1458 | plist_del(&q->list, &hb->chain); |
---|
.. | .. |
---|
1560 | 1485 | |
---|
1561 | 1486 | /* |
---|
1562 | 1487 | * Queue the task for later wakeup for after we've released |
---|
1563 | | - * the hb->lock. wake_q_add() grabs reference to p. |
---|
| 1488 | + * the hb->lock. |
---|
1564 | 1489 | */ |
---|
1565 | | - wake_q_add(wake_q, p); |
---|
1566 | | - put_task_struct(p); |
---|
| 1490 | + wake_q_add_safe(wake_q, p); |
---|
1567 | 1491 | } |
---|
1568 | 1492 | |
---|
1569 | 1493 | /* |
---|
.. | .. |
---|
1571 | 1495 | */ |
---|
1572 | 1496 | static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_pi_state *pi_state) |
---|
1573 | 1497 | { |
---|
1574 | | - u32 uninitialized_var(curval), newval; |
---|
| 1498 | + u32 curval, newval; |
---|
1575 | 1499 | struct task_struct *new_owner; |
---|
1576 | 1500 | bool postunlock = false; |
---|
1577 | 1501 | DEFINE_WAKE_Q(wake_q); |
---|
.. | .. |
---|
1672 | 1596 | struct futex_q *this, *next; |
---|
1673 | 1597 | union futex_key key = FUTEX_KEY_INIT; |
---|
1674 | 1598 | int ret; |
---|
| 1599 | + int target_nr; |
---|
1675 | 1600 | DEFINE_WAKE_Q(wake_q); |
---|
1676 | 1601 | |
---|
1677 | 1602 | if (!bitset) |
---|
1678 | 1603 | return -EINVAL; |
---|
1679 | 1604 | |
---|
1680 | | - ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_READ); |
---|
| 1605 | + ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, FUTEX_READ); |
---|
1681 | 1606 | if (unlikely(ret != 0)) |
---|
1682 | | - goto out; |
---|
| 1607 | + return ret; |
---|
1683 | 1608 | |
---|
1684 | 1609 | hb = hash_futex(&key); |
---|
1685 | 1610 | |
---|
1686 | 1611 | /* Make sure we really have tasks to wakeup */ |
---|
1687 | 1612 | if (!hb_waiters_pending(hb)) |
---|
1688 | | - goto out_put_key; |
---|
| 1613 | + return ret; |
---|
1689 | 1614 | |
---|
1690 | 1615 | spin_lock(&hb->lock); |
---|
1691 | 1616 | |
---|
| 1617 | + trace_android_vh_futex_wake_traverse_plist(&hb->chain, &target_nr, key, bitset); |
---|
1692 | 1618 | plist_for_each_entry_safe(this, next, &hb->chain, list) { |
---|
1693 | 1619 | if (match_futex (&this->key, &key)) { |
---|
1694 | 1620 | if (this->pi_state || this->rt_waiter) { |
---|
.. | .. |
---|
1700 | 1626 | if (!(this->bitset & bitset)) |
---|
1701 | 1627 | continue; |
---|
1702 | 1628 | |
---|
| 1629 | + trace_android_vh_futex_wake_this(ret, nr_wake, target_nr, this->task); |
---|
1703 | 1630 | mark_wake_futex(&wake_q, this); |
---|
1704 | 1631 | if (++ret >= nr_wake) |
---|
1705 | 1632 | break; |
---|
.. | .. |
---|
1708 | 1635 | |
---|
1709 | 1636 | spin_unlock(&hb->lock); |
---|
1710 | 1637 | wake_up_q(&wake_q); |
---|
1711 | | -out_put_key: |
---|
1712 | | - put_futex_key(&key); |
---|
1713 | | -out: |
---|
| 1638 | + trace_android_vh_futex_wake_up_q_finish(nr_wake, target_nr); |
---|
1714 | 1639 | return ret; |
---|
1715 | 1640 | } |
---|
1716 | 1641 | |
---|
.. | .. |
---|
1736 | 1661 | oparg = 1 << oparg; |
---|
1737 | 1662 | } |
---|
1738 | 1663 | |
---|
1739 | | - if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32))) |
---|
1740 | | - return -EFAULT; |
---|
1741 | | - |
---|
| 1664 | + pagefault_disable(); |
---|
1742 | 1665 | ret = arch_futex_atomic_op_inuser(op, oparg, &oldval, uaddr); |
---|
| 1666 | + pagefault_enable(); |
---|
1743 | 1667 | if (ret) |
---|
1744 | 1668 | return ret; |
---|
1745 | 1669 | |
---|
.. | .. |
---|
1776 | 1700 | DEFINE_WAKE_Q(wake_q); |
---|
1777 | 1701 | |
---|
1778 | 1702 | retry: |
---|
1779 | | - ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); |
---|
| 1703 | + ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ); |
---|
1780 | 1704 | if (unlikely(ret != 0)) |
---|
1781 | | - goto out; |
---|
1782 | | - ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE); |
---|
| 1705 | + return ret; |
---|
| 1706 | + ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, FUTEX_WRITE); |
---|
1783 | 1707 | if (unlikely(ret != 0)) |
---|
1784 | | - goto out_put_key1; |
---|
| 1708 | + return ret; |
---|
1785 | 1709 | |
---|
1786 | 1710 | hb1 = hash_futex(&key1); |
---|
1787 | 1711 | hb2 = hash_futex(&key2); |
---|
.. | .. |
---|
1799 | 1723 | * an MMU, but we might get them from range checking |
---|
1800 | 1724 | */ |
---|
1801 | 1725 | ret = op_ret; |
---|
1802 | | - goto out_put_keys; |
---|
| 1726 | + return ret; |
---|
1803 | 1727 | } |
---|
1804 | 1728 | |
---|
1805 | 1729 | if (op_ret == -EFAULT) { |
---|
1806 | 1730 | ret = fault_in_user_writeable(uaddr2); |
---|
1807 | 1731 | if (ret) |
---|
1808 | | - goto out_put_keys; |
---|
| 1732 | + return ret; |
---|
1809 | 1733 | } |
---|
1810 | 1734 | |
---|
1811 | 1735 | if (!(flags & FLAGS_SHARED)) { |
---|
.. | .. |
---|
1813 | 1737 | goto retry_private; |
---|
1814 | 1738 | } |
---|
1815 | 1739 | |
---|
1816 | | - put_futex_key(&key2); |
---|
1817 | | - put_futex_key(&key1); |
---|
1818 | 1740 | cond_resched(); |
---|
1819 | 1741 | goto retry; |
---|
1820 | 1742 | } |
---|
.. | .. |
---|
1850 | 1772 | out_unlock: |
---|
1851 | 1773 | double_unlock_hb(hb1, hb2); |
---|
1852 | 1774 | wake_up_q(&wake_q); |
---|
1853 | | -out_put_keys: |
---|
1854 | | - put_futex_key(&key2); |
---|
1855 | | -out_put_key1: |
---|
1856 | | - put_futex_key(&key1); |
---|
1857 | | -out: |
---|
1858 | 1775 | return ret; |
---|
1859 | 1776 | } |
---|
1860 | 1777 | |
---|
.. | .. |
---|
1881 | 1798 | plist_add(&q->list, &hb2->chain); |
---|
1882 | 1799 | q->lock_ptr = &hb2->lock; |
---|
1883 | 1800 | } |
---|
1884 | | - get_futex_key_refs(key2); |
---|
1885 | 1801 | q->key = *key2; |
---|
1886 | 1802 | } |
---|
1887 | 1803 | |
---|
.. | .. |
---|
1903 | 1819 | void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key, |
---|
1904 | 1820 | struct futex_hash_bucket *hb) |
---|
1905 | 1821 | { |
---|
1906 | | - get_futex_key_refs(key); |
---|
1907 | 1822 | q->key = *key; |
---|
1908 | 1823 | |
---|
1909 | 1824 | __unqueue_futex(q); |
---|
.. | .. |
---|
2014 | 1929 | u32 *cmpval, int requeue_pi) |
---|
2015 | 1930 | { |
---|
2016 | 1931 | union futex_key key1 = FUTEX_KEY_INIT, key2 = FUTEX_KEY_INIT; |
---|
2017 | | - int drop_count = 0, task_count = 0, ret; |
---|
| 1932 | + int task_count = 0, ret; |
---|
2018 | 1933 | struct futex_pi_state *pi_state = NULL; |
---|
2019 | 1934 | struct futex_hash_bucket *hb1, *hb2; |
---|
2020 | 1935 | struct futex_q *this, *next; |
---|
.. | .. |
---|
2061 | 1976 | } |
---|
2062 | 1977 | |
---|
2063 | 1978 | retry: |
---|
2064 | | - ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, VERIFY_READ); |
---|
| 1979 | + ret = get_futex_key(uaddr1, flags & FLAGS_SHARED, &key1, FUTEX_READ); |
---|
2065 | 1980 | if (unlikely(ret != 0)) |
---|
2066 | | - goto out; |
---|
| 1981 | + return ret; |
---|
2067 | 1982 | ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, |
---|
2068 | | - requeue_pi ? VERIFY_WRITE : VERIFY_READ); |
---|
| 1983 | + requeue_pi ? FUTEX_WRITE : FUTEX_READ); |
---|
2069 | 1984 | if (unlikely(ret != 0)) |
---|
2070 | | - goto out_put_key1; |
---|
| 1985 | + return ret; |
---|
2071 | 1986 | |
---|
2072 | 1987 | /* |
---|
2073 | 1988 | * The check above which compares uaddrs is not sufficient for |
---|
2074 | 1989 | * shared futexes. We need to compare the keys: |
---|
2075 | 1990 | */ |
---|
2076 | | - if (requeue_pi && match_futex(&key1, &key2)) { |
---|
2077 | | - ret = -EINVAL; |
---|
2078 | | - goto out_put_keys; |
---|
2079 | | - } |
---|
| 1991 | + if (requeue_pi && match_futex(&key1, &key2)) |
---|
| 1992 | + return -EINVAL; |
---|
2080 | 1993 | |
---|
2081 | 1994 | hb1 = hash_futex(&key1); |
---|
2082 | 1995 | hb2 = hash_futex(&key2); |
---|
.. | .. |
---|
2096 | 2009 | |
---|
2097 | 2010 | ret = get_user(curval, uaddr1); |
---|
2098 | 2011 | if (ret) |
---|
2099 | | - goto out_put_keys; |
---|
| 2012 | + return ret; |
---|
2100 | 2013 | |
---|
2101 | 2014 | if (!(flags & FLAGS_SHARED)) |
---|
2102 | 2015 | goto retry_private; |
---|
2103 | 2016 | |
---|
2104 | | - put_futex_key(&key2); |
---|
2105 | | - put_futex_key(&key1); |
---|
2106 | 2017 | goto retry; |
---|
2107 | 2018 | } |
---|
2108 | 2019 | if (curval != *cmpval) { |
---|
.. | .. |
---|
2135 | 2046 | */ |
---|
2136 | 2047 | if (ret > 0) { |
---|
2137 | 2048 | WARN_ON(pi_state); |
---|
2138 | | - drop_count++; |
---|
2139 | 2049 | task_count++; |
---|
2140 | 2050 | /* |
---|
2141 | 2051 | * If we acquired the lock, then the user space value |
---|
.. | .. |
---|
2162 | 2072 | case -EFAULT: |
---|
2163 | 2073 | double_unlock_hb(hb1, hb2); |
---|
2164 | 2074 | hb_waiters_dec(hb2); |
---|
2165 | | - put_futex_key(&key2); |
---|
2166 | | - put_futex_key(&key1); |
---|
2167 | 2075 | ret = fault_in_user_writeable(uaddr2); |
---|
2168 | 2076 | if (!ret) |
---|
2169 | 2077 | goto retry; |
---|
2170 | | - goto out; |
---|
| 2078 | + return ret; |
---|
2171 | 2079 | case -EBUSY: |
---|
2172 | 2080 | case -EAGAIN: |
---|
2173 | 2081 | /* |
---|
.. | .. |
---|
2178 | 2086 | */ |
---|
2179 | 2087 | double_unlock_hb(hb1, hb2); |
---|
2180 | 2088 | hb_waiters_dec(hb2); |
---|
2181 | | - put_futex_key(&key2); |
---|
2182 | | - put_futex_key(&key1); |
---|
2183 | 2089 | /* |
---|
2184 | 2090 | * Handle the case where the owner is in the middle of |
---|
2185 | 2091 | * exiting. Wait for the exit to complete otherwise |
---|
.. | .. |
---|
2255 | 2161 | * doing so. |
---|
2256 | 2162 | */ |
---|
2257 | 2163 | requeue_pi_wake_futex(this, &key2, hb2); |
---|
2258 | | - drop_count++; |
---|
2259 | | - continue; |
---|
2260 | | - } else if (ret == -EAGAIN) { |
---|
2261 | | - /* |
---|
2262 | | - * Waiter was woken by timeout or |
---|
2263 | | - * signal and has set pi_blocked_on to |
---|
2264 | | - * PI_WAKEUP_INPROGRESS before we |
---|
2265 | | - * tried to enqueue it on the rtmutex. |
---|
2266 | | - */ |
---|
2267 | | - this->pi_state = NULL; |
---|
2268 | | - put_pi_state(pi_state); |
---|
2269 | 2164 | continue; |
---|
2270 | 2165 | } else if (ret) { |
---|
2271 | 2166 | /* |
---|
.. | .. |
---|
2286 | 2181 | } |
---|
2287 | 2182 | } |
---|
2288 | 2183 | requeue_futex(this, hb1, hb2, &key2); |
---|
2289 | | - drop_count++; |
---|
2290 | 2184 | } |
---|
2291 | 2185 | |
---|
2292 | 2186 | /* |
---|
.. | .. |
---|
2300 | 2194 | double_unlock_hb(hb1, hb2); |
---|
2301 | 2195 | wake_up_q(&wake_q); |
---|
2302 | 2196 | hb_waiters_dec(hb2); |
---|
2303 | | - |
---|
2304 | | - /* |
---|
2305 | | - * drop_futex_key_refs() must be called outside the spinlocks. During |
---|
2306 | | - * the requeue we moved futex_q's from the hash bucket at key1 to the |
---|
2307 | | - * one at key2 and updated their key pointer. We no longer need to |
---|
2308 | | - * hold the references to key1. |
---|
2309 | | - */ |
---|
2310 | | - while (--drop_count >= 0) |
---|
2311 | | - drop_futex_key_refs(&key1); |
---|
2312 | | - |
---|
2313 | | -out_put_keys: |
---|
2314 | | - put_futex_key(&key2); |
---|
2315 | | -out_put_key1: |
---|
2316 | | - put_futex_key(&key1); |
---|
2317 | | -out: |
---|
2318 | 2197 | return ret ? ret : task_count; |
---|
2319 | 2198 | } |
---|
2320 | 2199 | |
---|
.. | .. |
---|
2334 | 2213 | * decrement the counter at queue_unlock() when some error has |
---|
2335 | 2214 | * occurred and we don't end up adding the task to the list. |
---|
2336 | 2215 | */ |
---|
2337 | | - hb_waiters_inc(hb); |
---|
| 2216 | + hb_waiters_inc(hb); /* implies smp_mb(); (A) */ |
---|
2338 | 2217 | |
---|
2339 | 2218 | q->lock_ptr = &hb->lock; |
---|
2340 | 2219 | |
---|
2341 | | - spin_lock(&hb->lock); /* implies smp_mb(); (A) */ |
---|
| 2220 | + spin_lock(&hb->lock); |
---|
2342 | 2221 | return hb; |
---|
2343 | 2222 | } |
---|
2344 | 2223 | |
---|
.. | .. |
---|
2353 | 2232 | static inline void __queue_me(struct futex_q *q, struct futex_hash_bucket *hb) |
---|
2354 | 2233 | { |
---|
2355 | 2234 | int prio; |
---|
| 2235 | + bool already_on_hb = false; |
---|
2356 | 2236 | |
---|
2357 | 2237 | /* |
---|
2358 | 2238 | * The priority used to register this element is |
---|
.. | .. |
---|
2365 | 2245 | prio = min(current->normal_prio, MAX_RT_PRIO); |
---|
2366 | 2246 | |
---|
2367 | 2247 | plist_node_init(&q->list, prio); |
---|
2368 | | - plist_add(&q->list, &hb->chain); |
---|
| 2248 | + trace_android_vh_alter_futex_plist_add(&q->list, &hb->chain, &already_on_hb); |
---|
| 2249 | + if (!already_on_hb) |
---|
| 2250 | + plist_add(&q->list, &hb->chain); |
---|
2369 | 2251 | q->task = current; |
---|
2370 | 2252 | } |
---|
2371 | 2253 | |
---|
.. | .. |
---|
2439 | 2321 | ret = 1; |
---|
2440 | 2322 | } |
---|
2441 | 2323 | |
---|
2442 | | - drop_futex_key_refs(&q->key); |
---|
2443 | 2324 | return ret; |
---|
2444 | 2325 | } |
---|
2445 | 2326 | |
---|
.. | .. |
---|
2463 | 2344 | static int __fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q, |
---|
2464 | 2345 | struct task_struct *argowner) |
---|
2465 | 2346 | { |
---|
2466 | | - u32 uval, uninitialized_var(curval), newval, newtid; |
---|
2467 | 2347 | struct futex_pi_state *pi_state = q->pi_state; |
---|
2468 | 2348 | struct task_struct *oldowner, *newowner; |
---|
| 2349 | + u32 uval, curval, newval, newtid; |
---|
2469 | 2350 | int err = 0; |
---|
2470 | 2351 | |
---|
2471 | 2352 | oldowner = pi_state->owner; |
---|
.. | .. |
---|
2720 | 2601 | |
---|
2721 | 2602 | /* Arm the timer */ |
---|
2722 | 2603 | if (timeout) |
---|
2723 | | - hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS); |
---|
| 2604 | + hrtimer_sleeper_start_expires(timeout, HRTIMER_MODE_ABS); |
---|
2724 | 2605 | |
---|
2725 | 2606 | /* |
---|
2726 | 2607 | * If we have been removed from the hash list, then another task |
---|
.. | .. |
---|
2732 | 2613 | * flagged for rescheduling. Only call schedule if there |
---|
2733 | 2614 | * is no timeout, or if it has yet to expire. |
---|
2734 | 2615 | */ |
---|
2735 | | - if (!timeout || timeout->task) |
---|
| 2616 | + if (!timeout || timeout->task) { |
---|
| 2617 | + trace_android_vh_futex_sleep_start(current); |
---|
2736 | 2618 | freezable_schedule(); |
---|
| 2619 | + } |
---|
2737 | 2620 | } |
---|
2738 | 2621 | __set_current_state(TASK_RUNNING); |
---|
2739 | 2622 | } |
---|
.. | .. |
---|
2780 | 2663 | * while the syscall executes. |
---|
2781 | 2664 | */ |
---|
2782 | 2665 | retry: |
---|
2783 | | - ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, VERIFY_READ); |
---|
| 2666 | + ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, FUTEX_READ); |
---|
2784 | 2667 | if (unlikely(ret != 0)) |
---|
2785 | 2668 | return ret; |
---|
2786 | 2669 | |
---|
.. | .. |
---|
2794 | 2677 | |
---|
2795 | 2678 | ret = get_user(uval, uaddr); |
---|
2796 | 2679 | if (ret) |
---|
2797 | | - goto out; |
---|
| 2680 | + return ret; |
---|
2798 | 2681 | |
---|
2799 | 2682 | if (!(flags & FLAGS_SHARED)) |
---|
2800 | 2683 | goto retry_private; |
---|
2801 | 2684 | |
---|
2802 | | - put_futex_key(&q->key); |
---|
2803 | 2685 | goto retry; |
---|
2804 | 2686 | } |
---|
2805 | 2687 | |
---|
.. | .. |
---|
2808 | 2690 | ret = -EWOULDBLOCK; |
---|
2809 | 2691 | } |
---|
2810 | 2692 | |
---|
2811 | | -out: |
---|
2812 | | - if (ret) |
---|
2813 | | - put_futex_key(&q->key); |
---|
2814 | 2693 | return ret; |
---|
2815 | 2694 | } |
---|
2816 | 2695 | |
---|
2817 | 2696 | static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val, |
---|
2818 | 2697 | ktime_t *abs_time, u32 bitset) |
---|
2819 | 2698 | { |
---|
2820 | | - struct hrtimer_sleeper timeout, *to = NULL; |
---|
| 2699 | + struct hrtimer_sleeper timeout, *to; |
---|
2821 | 2700 | struct restart_block *restart; |
---|
2822 | 2701 | struct futex_hash_bucket *hb; |
---|
2823 | 2702 | struct futex_q q = futex_q_init; |
---|
.. | .. |
---|
2826 | 2705 | if (!bitset) |
---|
2827 | 2706 | return -EINVAL; |
---|
2828 | 2707 | q.bitset = bitset; |
---|
| 2708 | + trace_android_vh_futex_wait_start(flags, bitset); |
---|
2829 | 2709 | |
---|
2830 | | - if (abs_time) { |
---|
2831 | | - to = &timeout; |
---|
2832 | | - |
---|
2833 | | - hrtimer_init_sleeper_on_stack(to, (flags & FLAGS_CLOCKRT) ? |
---|
2834 | | - CLOCK_REALTIME : CLOCK_MONOTONIC, |
---|
2835 | | - HRTIMER_MODE_ABS, current); |
---|
2836 | | - hrtimer_set_expires_range_ns(&to->timer, *abs_time, |
---|
2837 | | - current->timer_slack_ns); |
---|
2838 | | - } |
---|
2839 | | - |
---|
| 2710 | + to = futex_setup_timer(abs_time, &timeout, flags, |
---|
| 2711 | + current->timer_slack_ns); |
---|
2840 | 2712 | retry: |
---|
2841 | 2713 | /* |
---|
2842 | 2714 | * Prepare to wait on uaddr. On success, holds hb lock and increments |
---|
.. | .. |
---|
2883 | 2755 | hrtimer_cancel(&to->timer); |
---|
2884 | 2756 | destroy_hrtimer_on_stack(&to->timer); |
---|
2885 | 2757 | } |
---|
| 2758 | + trace_android_vh_futex_wait_end(flags, bitset); |
---|
2886 | 2759 | return ret; |
---|
2887 | 2760 | } |
---|
2888 | 2761 | |
---|
.. | .. |
---|
2915 | 2788 | static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, |
---|
2916 | 2789 | ktime_t *time, int trylock) |
---|
2917 | 2790 | { |
---|
2918 | | - struct hrtimer_sleeper timeout, *to = NULL; |
---|
| 2791 | + struct hrtimer_sleeper timeout, *to; |
---|
2919 | 2792 | struct task_struct *exiting = NULL; |
---|
2920 | 2793 | struct rt_mutex_waiter rt_waiter; |
---|
2921 | 2794 | struct futex_hash_bucket *hb; |
---|
.. | .. |
---|
2928 | 2801 | if (refill_pi_state_cache()) |
---|
2929 | 2802 | return -ENOMEM; |
---|
2930 | 2803 | |
---|
2931 | | - if (time) { |
---|
2932 | | - to = &timeout; |
---|
2933 | | - hrtimer_init_sleeper_on_stack(to, CLOCK_REALTIME, |
---|
2934 | | - HRTIMER_MODE_ABS, current); |
---|
2935 | | - hrtimer_set_expires(&to->timer, *time); |
---|
2936 | | - } |
---|
| 2804 | + to = futex_setup_timer(time, &timeout, FLAGS_CLOCKRT, 0); |
---|
2937 | 2805 | |
---|
2938 | 2806 | retry: |
---|
2939 | | - ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, VERIFY_WRITE); |
---|
| 2807 | + ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q.key, FUTEX_WRITE); |
---|
2940 | 2808 | if (unlikely(ret != 0)) |
---|
2941 | 2809 | goto out; |
---|
2942 | 2810 | |
---|
.. | .. |
---|
2966 | 2834 | * - EAGAIN: The user space value changed. |
---|
2967 | 2835 | */ |
---|
2968 | 2836 | queue_unlock(hb); |
---|
2969 | | - put_futex_key(&q.key); |
---|
2970 | 2837 | /* |
---|
2971 | 2838 | * Handle the case where the owner is in the middle of |
---|
2972 | 2839 | * exiting. Wait for the exit to complete otherwise |
---|
.. | .. |
---|
3010 | 2877 | * before __rt_mutex_start_proxy_lock() is done. |
---|
3011 | 2878 | */ |
---|
3012 | 2879 | raw_spin_lock_irq(&q.pi_state->pi_mutex.wait_lock); |
---|
3013 | | - /* |
---|
3014 | | - * the migrate_disable() here disables migration in the in_atomic() fast |
---|
3015 | | - * path which is enabled again in the following spin_unlock(). We have |
---|
3016 | | - * one migrate_disable() pending in the slow-path which is reversed |
---|
3017 | | - * after the raw_spin_unlock_irq() where we leave the atomic context. |
---|
3018 | | - */ |
---|
3019 | | - migrate_disable(); |
---|
3020 | | - |
---|
3021 | 2880 | spin_unlock(q.lock_ptr); |
---|
3022 | 2881 | /* |
---|
3023 | 2882 | * __rt_mutex_start_proxy_lock() unconditionally enqueues the @rt_waiter |
---|
.. | .. |
---|
3026 | 2885 | */ |
---|
3027 | 2886 | ret = __rt_mutex_start_proxy_lock(&q.pi_state->pi_mutex, &rt_waiter, current); |
---|
3028 | 2887 | raw_spin_unlock_irq(&q.pi_state->pi_mutex.wait_lock); |
---|
3029 | | - migrate_enable(); |
---|
3030 | 2888 | |
---|
3031 | 2889 | if (ret) { |
---|
3032 | 2890 | if (ret == 1) |
---|
.. | .. |
---|
3035 | 2893 | } |
---|
3036 | 2894 | |
---|
3037 | 2895 | if (unlikely(to)) |
---|
3038 | | - hrtimer_start_expires(&to->timer, HRTIMER_MODE_ABS); |
---|
| 2896 | + hrtimer_sleeper_start_expires(to, HRTIMER_MODE_ABS); |
---|
3039 | 2897 | |
---|
3040 | 2898 | ret = rt_mutex_wait_proxy_lock(&q.pi_state->pi_mutex, to, &rt_waiter); |
---|
3041 | 2899 | |
---|
.. | .. |
---|
3068 | 2926 | |
---|
3069 | 2927 | /* Unqueue and drop the lock */ |
---|
3070 | 2928 | unqueue_me_pi(&q); |
---|
3071 | | - |
---|
3072 | | - goto out_put_key; |
---|
| 2929 | + goto out; |
---|
3073 | 2930 | |
---|
3074 | 2931 | out_unlock_put_key: |
---|
3075 | 2932 | queue_unlock(hb); |
---|
3076 | 2933 | |
---|
3077 | | -out_put_key: |
---|
3078 | | - put_futex_key(&q.key); |
---|
3079 | 2934 | out: |
---|
3080 | 2935 | if (to) { |
---|
3081 | 2936 | hrtimer_cancel(&to->timer); |
---|
.. | .. |
---|
3088 | 2943 | |
---|
3089 | 2944 | ret = fault_in_user_writeable(uaddr); |
---|
3090 | 2945 | if (ret) |
---|
3091 | | - goto out_put_key; |
---|
| 2946 | + goto out; |
---|
3092 | 2947 | |
---|
3093 | 2948 | if (!(flags & FLAGS_SHARED)) |
---|
3094 | 2949 | goto retry_private; |
---|
3095 | 2950 | |
---|
3096 | | - put_futex_key(&q.key); |
---|
3097 | 2951 | goto retry; |
---|
3098 | 2952 | } |
---|
3099 | 2953 | |
---|
.. | .. |
---|
3104 | 2958 | */ |
---|
3105 | 2959 | static int futex_unlock_pi(u32 __user *uaddr, unsigned int flags) |
---|
3106 | 2960 | { |
---|
3107 | | - u32 uninitialized_var(curval), uval, vpid = task_pid_vnr(current); |
---|
| 2961 | + u32 curval, uval, vpid = task_pid_vnr(current); |
---|
3108 | 2962 | union futex_key key = FUTEX_KEY_INIT; |
---|
3109 | 2963 | struct futex_hash_bucket *hb; |
---|
3110 | 2964 | struct futex_q *top_waiter; |
---|
.. | .. |
---|
3122 | 2976 | if ((uval & FUTEX_TID_MASK) != vpid) |
---|
3123 | 2977 | return -EPERM; |
---|
3124 | 2978 | |
---|
3125 | | - ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_WRITE); |
---|
| 2979 | + ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, FUTEX_WRITE); |
---|
3126 | 2980 | if (ret) |
---|
3127 | 2981 | return ret; |
---|
3128 | 2982 | |
---|
.. | .. |
---|
3161 | 3015 | * rt_waiter. Also see the WARN in wake_futex_pi(). |
---|
3162 | 3016 | */ |
---|
3163 | 3017 | raw_spin_lock_irq(&pi_state->pi_mutex.wait_lock); |
---|
3164 | | - /* |
---|
3165 | | - * Magic trickery for now to make the RT migrate disable |
---|
3166 | | - * logic happy. The following spin_unlock() happens with |
---|
3167 | | - * interrupts disabled so the internal migrate_enable() |
---|
3168 | | - * won't undo the migrate_disable() which was issued when |
---|
3169 | | - * locking hb->lock. |
---|
3170 | | - */ |
---|
3171 | | - migrate_disable(); |
---|
3172 | 3018 | spin_unlock(&hb->lock); |
---|
3173 | 3019 | |
---|
3174 | 3020 | /* drops pi_state->pi_mutex.wait_lock */ |
---|
3175 | 3021 | ret = wake_futex_pi(uaddr, uval, pi_state); |
---|
3176 | | - migrate_enable(); |
---|
3177 | 3022 | |
---|
3178 | 3023 | put_pi_state(pi_state); |
---|
3179 | 3024 | |
---|
.. | .. |
---|
3231 | 3076 | out_unlock: |
---|
3232 | 3077 | spin_unlock(&hb->lock); |
---|
3233 | 3078 | out_putkey: |
---|
3234 | | - put_futex_key(&key); |
---|
3235 | 3079 | return ret; |
---|
3236 | 3080 | |
---|
3237 | 3081 | pi_retry: |
---|
3238 | | - put_futex_key(&key); |
---|
3239 | 3082 | cond_resched(); |
---|
3240 | 3083 | goto retry; |
---|
3241 | 3084 | |
---|
3242 | 3085 | pi_faulted: |
---|
3243 | | - put_futex_key(&key); |
---|
3244 | 3086 | |
---|
3245 | 3087 | ret = fault_in_user_writeable(uaddr); |
---|
3246 | 3088 | if (!ret) |
---|
.. | .. |
---|
3342 | 3184 | u32 val, ktime_t *abs_time, u32 bitset, |
---|
3343 | 3185 | u32 __user *uaddr2) |
---|
3344 | 3186 | { |
---|
3345 | | - struct hrtimer_sleeper timeout, *to = NULL; |
---|
| 3187 | + struct hrtimer_sleeper timeout, *to; |
---|
3346 | 3188 | struct rt_mutex_waiter rt_waiter; |
---|
3347 | | - struct futex_hash_bucket *hb, *hb2; |
---|
| 3189 | + struct futex_hash_bucket *hb; |
---|
3348 | 3190 | union futex_key key2 = FUTEX_KEY_INIT; |
---|
3349 | 3191 | struct futex_q q = futex_q_init; |
---|
3350 | 3192 | int res, ret; |
---|
.. | .. |
---|
3358 | 3200 | if (!bitset) |
---|
3359 | 3201 | return -EINVAL; |
---|
3360 | 3202 | |
---|
3361 | | - if (abs_time) { |
---|
3362 | | - to = &timeout; |
---|
3363 | | - hrtimer_init_sleeper_on_stack(to, (flags & FLAGS_CLOCKRT) ? |
---|
3364 | | - CLOCK_REALTIME : CLOCK_MONOTONIC, |
---|
3365 | | - HRTIMER_MODE_ABS, current); |
---|
3366 | | - hrtimer_set_expires_range_ns(&to->timer, *abs_time, |
---|
3367 | | - current->timer_slack_ns); |
---|
3368 | | - } |
---|
| 3203 | + to = futex_setup_timer(abs_time, &timeout, flags, |
---|
| 3204 | + current->timer_slack_ns); |
---|
3369 | 3205 | |
---|
3370 | 3206 | /* |
---|
3371 | 3207 | * The waiter is allocated on our stack, manipulated by the requeue |
---|
.. | .. |
---|
3373 | 3209 | */ |
---|
3374 | 3210 | rt_mutex_init_waiter(&rt_waiter, false); |
---|
3375 | 3211 | |
---|
3376 | | - ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, VERIFY_WRITE); |
---|
| 3212 | + ret = get_futex_key(uaddr2, flags & FLAGS_SHARED, &key2, FUTEX_WRITE); |
---|
3377 | 3213 | if (unlikely(ret != 0)) |
---|
3378 | 3214 | goto out; |
---|
3379 | 3215 | |
---|
.. | .. |
---|
3387 | 3223 | */ |
---|
3388 | 3224 | ret = futex_wait_setup(uaddr, val, flags, &q, &hb); |
---|
3389 | 3225 | if (ret) |
---|
3390 | | - goto out_key2; |
---|
| 3226 | + goto out; |
---|
3391 | 3227 | |
---|
3392 | 3228 | /* |
---|
3393 | 3229 | * The check above which compares uaddrs is not sufficient for |
---|
.. | .. |
---|
3396 | 3232 | if (match_futex(&q.key, &key2)) { |
---|
3397 | 3233 | queue_unlock(hb); |
---|
3398 | 3234 | ret = -EINVAL; |
---|
3399 | | - goto out_put_keys; |
---|
| 3235 | + goto out; |
---|
3400 | 3236 | } |
---|
3401 | 3237 | |
---|
3402 | 3238 | /* Queue the futex_q, drop the hb lock, wait for wakeup. */ |
---|
3403 | 3239 | futex_wait_queue_me(hb, &q, to); |
---|
3404 | 3240 | |
---|
3405 | | - /* |
---|
3406 | | - * On RT we must avoid races with requeue and trying to block |
---|
3407 | | - * on two mutexes (hb->lock and uaddr2's rtmutex) by |
---|
3408 | | - * serializing access to pi_blocked_on with pi_lock. |
---|
3409 | | - */ |
---|
3410 | | - raw_spin_lock_irq(¤t->pi_lock); |
---|
3411 | | - if (current->pi_blocked_on) { |
---|
3412 | | - /* |
---|
3413 | | - * We have been requeued or are in the process of |
---|
3414 | | - * being requeued. |
---|
3415 | | - */ |
---|
3416 | | - raw_spin_unlock_irq(¤t->pi_lock); |
---|
3417 | | - } else { |
---|
3418 | | - /* |
---|
3419 | | - * Setting pi_blocked_on to PI_WAKEUP_INPROGRESS |
---|
3420 | | - * prevents a concurrent requeue from moving us to the |
---|
3421 | | - * uaddr2 rtmutex. After that we can safely acquire |
---|
3422 | | - * (and possibly block on) hb->lock. |
---|
3423 | | - */ |
---|
3424 | | - current->pi_blocked_on = PI_WAKEUP_INPROGRESS; |
---|
3425 | | - raw_spin_unlock_irq(¤t->pi_lock); |
---|
3426 | | - |
---|
3427 | | - spin_lock(&hb->lock); |
---|
3428 | | - |
---|
3429 | | - /* |
---|
3430 | | - * Clean up pi_blocked_on. We might leak it otherwise |
---|
3431 | | - * when we succeeded with the hb->lock in the fast |
---|
3432 | | - * path. |
---|
3433 | | - */ |
---|
3434 | | - raw_spin_lock_irq(¤t->pi_lock); |
---|
3435 | | - current->pi_blocked_on = NULL; |
---|
3436 | | - raw_spin_unlock_irq(¤t->pi_lock); |
---|
3437 | | - |
---|
3438 | | - ret = handle_early_requeue_pi_wakeup(hb, &q, &key2, to); |
---|
3439 | | - spin_unlock(&hb->lock); |
---|
3440 | | - if (ret) |
---|
3441 | | - goto out_put_keys; |
---|
3442 | | - } |
---|
| 3241 | + spin_lock(&hb->lock); |
---|
| 3242 | + ret = handle_early_requeue_pi_wakeup(hb, &q, &key2, to); |
---|
| 3243 | + spin_unlock(&hb->lock); |
---|
| 3244 | + if (ret) |
---|
| 3245 | + goto out; |
---|
3443 | 3246 | |
---|
3444 | 3247 | /* |
---|
3445 | | - * In order to be here, we have either been requeued, are in |
---|
3446 | | - * the process of being requeued, or requeue successfully |
---|
3447 | | - * acquired uaddr2 on our behalf. If pi_blocked_on was |
---|
3448 | | - * non-null above, we may be racing with a requeue. Do not |
---|
3449 | | - * rely on q->lock_ptr to be hb2->lock until after blocking on |
---|
3450 | | - * hb->lock or hb2->lock. The futex_requeue dropped our key1 |
---|
3451 | | - * reference and incremented our key2 reference count. |
---|
| 3248 | + * In order for us to be here, we know our q.key == key2, and since |
---|
| 3249 | + * we took the hb->lock above, we also know that futex_requeue() has |
---|
| 3250 | + * completed and we no longer have to concern ourselves with a wakeup |
---|
| 3251 | + * race with the atomic proxy lock acquisition by the requeue code. The |
---|
| 3252 | + * futex_requeue dropped our key1 reference and incremented our key2 |
---|
| 3253 | + * reference count. |
---|
3452 | 3254 | */ |
---|
3453 | | - hb2 = hash_futex(&key2); |
---|
3454 | 3255 | |
---|
3455 | 3256 | /* Check if the requeue code acquired the second futex for us. */ |
---|
3456 | 3257 | if (!q.rt_waiter) { |
---|
.. | .. |
---|
3459 | 3260 | * did a lock-steal - fix up the PI-state in that case. |
---|
3460 | 3261 | */ |
---|
3461 | 3262 | if (q.pi_state && (q.pi_state->owner != current)) { |
---|
3462 | | - spin_lock(&hb2->lock); |
---|
3463 | | - BUG_ON(&hb2->lock != q.lock_ptr); |
---|
| 3263 | + spin_lock(q.lock_ptr); |
---|
3464 | 3264 | ret = fixup_pi_state_owner(uaddr2, &q, current); |
---|
3465 | 3265 | /* |
---|
3466 | 3266 | * Drop the reference to the pi state which |
---|
3467 | 3267 | * the requeue_pi() code acquired for us. |
---|
3468 | 3268 | */ |
---|
3469 | 3269 | put_pi_state(q.pi_state); |
---|
3470 | | - spin_unlock(&hb2->lock); |
---|
| 3270 | + spin_unlock(q.lock_ptr); |
---|
3471 | 3271 | /* |
---|
3472 | 3272 | * Adjust the return value. It's either -EFAULT or |
---|
3473 | 3273 | * success (1) but the caller expects 0 for success. |
---|
.. | .. |
---|
3486 | 3286 | pi_mutex = &q.pi_state->pi_mutex; |
---|
3487 | 3287 | ret = rt_mutex_wait_proxy_lock(pi_mutex, to, &rt_waiter); |
---|
3488 | 3288 | |
---|
3489 | | - spin_lock(&hb2->lock); |
---|
3490 | | - BUG_ON(&hb2->lock != q.lock_ptr); |
---|
| 3289 | + spin_lock(q.lock_ptr); |
---|
3491 | 3290 | if (ret && !rt_mutex_cleanup_proxy_lock(pi_mutex, &rt_waiter)) |
---|
3492 | 3291 | ret = 0; |
---|
3493 | 3292 | |
---|
.. | .. |
---|
3518 | 3317 | */ |
---|
3519 | 3318 | ret = -EWOULDBLOCK; |
---|
3520 | 3319 | } |
---|
3521 | | - |
---|
3522 | | -out_put_keys: |
---|
3523 | | - put_futex_key(&q.key); |
---|
3524 | | -out_key2: |
---|
3525 | | - put_futex_key(&key2); |
---|
3526 | 3320 | |
---|
3527 | 3321 | out: |
---|
3528 | 3322 | if (to) { |
---|
.. | .. |
---|
3624 | 3418 | static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, |
---|
3625 | 3419 | bool pi, bool pending_op) |
---|
3626 | 3420 | { |
---|
3627 | | - u32 uval, uninitialized_var(nval), mval; |
---|
| 3421 | + u32 uval, nval, mval; |
---|
3628 | 3422 | int err; |
---|
3629 | 3423 | |
---|
3630 | 3424 | /* Futex address must be 32bit aligned */ |
---|
.. | .. |
---|
3754 | 3548 | struct robust_list_head __user *head = curr->robust_list; |
---|
3755 | 3549 | struct robust_list __user *entry, *next_entry, *pending; |
---|
3756 | 3550 | unsigned int limit = ROBUST_LIST_LIMIT, pi, pip; |
---|
3757 | | - unsigned int uninitialized_var(next_pi); |
---|
| 3551 | + unsigned int next_pi; |
---|
3758 | 3552 | unsigned long futex_offset; |
---|
3759 | 3553 | int rc; |
---|
3760 | 3554 | |
---|
.. | .. |
---|
3947 | 3741 | return -ENOSYS; |
---|
3948 | 3742 | } |
---|
3949 | 3743 | |
---|
| 3744 | + trace_android_vh_do_futex(cmd, &flags, uaddr2); |
---|
3950 | 3745 | switch (cmd) { |
---|
3951 | 3746 | case FUTEX_WAIT: |
---|
3952 | 3747 | val3 = FUTEX_BITSET_MATCH_ANY; |
---|
3953 | | - /* fall through */ |
---|
| 3748 | + fallthrough; |
---|
3954 | 3749 | case FUTEX_WAIT_BITSET: |
---|
3955 | 3750 | return futex_wait(uaddr, flags, val, timeout, val3); |
---|
3956 | 3751 | case FUTEX_WAKE: |
---|
3957 | 3752 | val3 = FUTEX_BITSET_MATCH_ANY; |
---|
3958 | | - /* fall through */ |
---|
| 3753 | + fallthrough; |
---|
3959 | 3754 | case FUTEX_WAKE_BITSET: |
---|
3960 | 3755 | return futex_wake(uaddr, flags, val, val3); |
---|
3961 | 3756 | case FUTEX_REQUEUE: |
---|
.. | .. |
---|
3982 | 3777 | |
---|
3983 | 3778 | |
---|
3984 | 3779 | SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, |
---|
3985 | | - struct timespec __user *, utime, u32 __user *, uaddr2, |
---|
| 3780 | + struct __kernel_timespec __user *, utime, u32 __user *, uaddr2, |
---|
3986 | 3781 | u32, val3) |
---|
3987 | 3782 | { |
---|
3988 | | - struct timespec ts; |
---|
| 3783 | + struct timespec64 ts; |
---|
3989 | 3784 | ktime_t t, *tp = NULL; |
---|
3990 | 3785 | u32 val2 = 0; |
---|
3991 | 3786 | int cmd = op & FUTEX_CMD_MASK; |
---|
.. | .. |
---|
3995 | 3790 | cmd == FUTEX_WAIT_REQUEUE_PI)) { |
---|
3996 | 3791 | if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG)))) |
---|
3997 | 3792 | return -EFAULT; |
---|
3998 | | - if (copy_from_user(&ts, utime, sizeof(ts)) != 0) |
---|
| 3793 | + if (get_timespec64(&ts, utime)) |
---|
3999 | 3794 | return -EFAULT; |
---|
4000 | | - if (!timespec_valid(&ts)) |
---|
| 3795 | + if (!timespec64_valid(&ts)) |
---|
4001 | 3796 | return -EINVAL; |
---|
4002 | 3797 | |
---|
4003 | | - t = timespec_to_ktime(ts); |
---|
| 3798 | + t = timespec64_to_ktime(ts); |
---|
4004 | 3799 | if (cmd == FUTEX_WAIT) |
---|
4005 | 3800 | t = ktime_add_safe(ktime_get(), t); |
---|
| 3801 | + else if (cmd != FUTEX_LOCK_PI && !(op & FUTEX_CLOCK_REALTIME)) |
---|
| 3802 | + t = timens_ktime_to_host(CLOCK_MONOTONIC, t); |
---|
4006 | 3803 | tp = &t; |
---|
4007 | 3804 | } |
---|
4008 | 3805 | /* |
---|
.. | .. |
---|
4053 | 3850 | struct compat_robust_list_head __user *head = curr->compat_robust_list; |
---|
4054 | 3851 | struct robust_list __user *entry, *next_entry, *pending; |
---|
4055 | 3852 | unsigned int limit = ROBUST_LIST_LIMIT, pi, pip; |
---|
4056 | | - unsigned int uninitialized_var(next_pi); |
---|
| 3853 | + unsigned int next_pi; |
---|
4057 | 3854 | compat_uptr_t uentry, next_uentry, upending; |
---|
4058 | 3855 | compat_long_t futex_offset; |
---|
4059 | 3856 | int rc; |
---|
.. | .. |
---|
4172 | 3969 | |
---|
4173 | 3970 | return ret; |
---|
4174 | 3971 | } |
---|
| 3972 | +#endif /* CONFIG_COMPAT */ |
---|
4175 | 3973 | |
---|
4176 | | -COMPAT_SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, |
---|
| 3974 | +#ifdef CONFIG_COMPAT_32BIT_TIME |
---|
| 3975 | +SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val, |
---|
4177 | 3976 | struct old_timespec32 __user *, utime, u32 __user *, uaddr2, |
---|
4178 | 3977 | u32, val3) |
---|
4179 | 3978 | { |
---|
4180 | | - struct timespec ts; |
---|
| 3979 | + struct timespec64 ts; |
---|
4181 | 3980 | ktime_t t, *tp = NULL; |
---|
4182 | 3981 | int val2 = 0; |
---|
4183 | 3982 | int cmd = op & FUTEX_CMD_MASK; |
---|
.. | .. |
---|
4185 | 3984 | if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || |
---|
4186 | 3985 | cmd == FUTEX_WAIT_BITSET || |
---|
4187 | 3986 | cmd == FUTEX_WAIT_REQUEUE_PI)) { |
---|
4188 | | - if (compat_get_timespec(&ts, utime)) |
---|
| 3987 | + if (get_old_timespec32(&ts, utime)) |
---|
4189 | 3988 | return -EFAULT; |
---|
4190 | | - if (!timespec_valid(&ts)) |
---|
| 3989 | + if (!timespec64_valid(&ts)) |
---|
4191 | 3990 | return -EINVAL; |
---|
4192 | 3991 | |
---|
4193 | | - t = timespec_to_ktime(ts); |
---|
| 3992 | + t = timespec64_to_ktime(ts); |
---|
4194 | 3993 | if (cmd == FUTEX_WAIT) |
---|
4195 | 3994 | t = ktime_add_safe(ktime_get(), t); |
---|
| 3995 | + else if (cmd != FUTEX_LOCK_PI && !(op & FUTEX_CLOCK_REALTIME)) |
---|
| 3996 | + t = timens_ktime_to_host(CLOCK_MONOTONIC, t); |
---|
4196 | 3997 | tp = &t; |
---|
4197 | 3998 | } |
---|
4198 | 3999 | if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE || |
---|
.. | .. |
---|
4201 | 4002 | |
---|
4202 | 4003 | return do_futex(uaddr, op, val, tp, uaddr2, val2, val3); |
---|
4203 | 4004 | } |
---|
4204 | | -#endif /* CONFIG_COMPAT */ |
---|
| 4005 | +#endif /* CONFIG_COMPAT_32BIT_TIME */ |
---|
4205 | 4006 | |
---|
4206 | 4007 | static void __init futex_detect_cmpxchg(void) |
---|
4207 | 4008 | { |
---|