aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-18 07:03:51 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-18 07:03:51 -1000
commitcf20e7f96ae688dd8611dd6dce8cb4a036fecc72 (patch)
tree6a82bded6a6e5af0e548c18b5e61db4f73b7ab5d /kernel
parent32c52ec87d6245ee2d12ed5dd509e40062939b50 (diff)
parent7cbaa0f4579f48e92639c6abb761fdef8fbade47 (diff)
Merge tag 'locking-urgent-2026-10-18' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull locking fixes from Ingo Molnar: - Fix FUT_OFF_MMSHARED futex hashing bug that can cause missed wakeups or spurious wakeups on futex-waiting tasks (Jann Horn) - Fix lockdep context tracking bug in the deferred hrtimer rearming entry code, which causes a lockdep chain leak that will eventually turn lockdep off (Mikhail Gavrilov) * tag 'locking-urgent-2026-10-18' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: entry: Account the deferred hrtimer rearm as hardirq context for lockdep futex: Fix mm reuse handling for FUT_OFF_MMSHARED
Diffstat (limited to 'kernel')
-rw-r--r--kernel/futex/core.c51
1 files changed, 28 insertions, 23 deletions
diff --git a/kernel/futex/core.c b/kernel/futex/core.c
index 095f9fe440e3..a240638f69e5 100644
--- a/kernel/futex/core.c
+++ b/kernel/futex/core.c
@@ -439,45 +439,51 @@ struct hrtimer_sleeper *futex_setup_timer(ktime_t *time, struct hrtimer_sleeper
}
/*
- * Generate a machine wide unique identifier for this inode.
+ * Generate a machine wide unique identifier for this object (inode or mm).
*
* This relies on u64 not wrapping in the life-time of the machine; which with
* 1ns resolution means almost 585 years.
- *
- * This further relies on the fact that a well formed program will not unmap
- * the file while it has a (shared) futex waiting on it. This mapping will have
- * a file reference which pins the mount and inode.
- *
- * If for some reason an inode gets evicted and read back in again, it will get
- * a new sequence number and will _NOT_ match, even though it is the exact same
- * file.
- *
- * It is important that futex_match() will never have a false-positive, esp.
- * for PI futexes that can mess up the state. The above argues that false-negatives
- * are only possible for malformed programs.
*/
-static u64 get_inode_sequence_number(struct inode *inode)
+static u64 get_object_id(atomic64_t *object_seq)
{
- static atomic64_t i_seq;
+ static atomic64_t last_assigned_seq;
u64 old;
- /* Does the inode already have a sequence number? */
- old = atomic64_read(&inode->i_sequence);
+ /* Does the object already have a sequence number? */
+ old = atomic64_read(object_seq);
if (likely(old))
return old;
for (;;) {
- u64 new = atomic64_inc_return(&i_seq);
+ u64 new = atomic64_inc_return(&last_assigned_seq);
if (WARN_ON_ONCE(!new))
continue;
old = 0;
- if (!atomic64_try_cmpxchg_relaxed(&inode->i_sequence, &old, new))
+ if (!atomic64_try_cmpxchg_relaxed(object_seq, &old, new))
return old;
return new;
}
}
+/*
+ * This relies on the fact that a well formed program will not unmap
+ * the file while it has a (shared) futex waiting on it. This mapping will have
+ * a file reference which pins the mount and inode.
+ *
+ * If for some reason an inode gets evicted and read back in again, it will get
+ * a new sequence number and will _NOT_ match, even though it is the exact same
+ * file.
+ *
+ * It is important that futex_match() will never have a false-positive, esp.
+ * for PI futexes that can mess up the state. The above argues that false-negatives
+ * are only possible for malformed programs.
+ */
+static u64 get_inode_sequence_number(struct inode *inode)
+{
+ return get_object_id(&inode->i_sequence);
+}
+
/**
* get_futex_key() - Get parameters which are the keys for a futex
* @uaddr: virtual address of the futex
@@ -683,8 +689,8 @@ again:
goto out;
}
- key->both.offset |= FUT_OFF_MMSHARED; /* ref taken on mm */
- key->private.mm = mm;
+ key->both.offset |= FUT_OFF_MMSHARED;
+ key->private.mm_seq = get_object_id(&mm->futex.unique_id);
key->private.address = address;
} else {
@@ -2055,13 +2061,12 @@ static void futex_robust_unlock_init_mm(struct futex_mm_data *fd)
static inline void futex_robust_unlock_init_mm(struct futex_mm_data *fd) { }
#endif /* !CONFIG_FUTEX_ROBUST_UNLOCK */
-#if defined(CONFIG_FUTEX_PRIVATE_HASH) || defined(CONFIG_FUTEX_ROBUST_UNLOCK)
void futex_mm_init(struct mm_struct *mm)
{
+ atomic64_set(&mm->futex.unique_id, 0);
futex_hash_init_mm(&mm->futex);
futex_robust_unlock_init_mm(&mm->futex);
}
-#endif
int futex_hash_prctl(unsigned long arg2, unsigned long arg3, unsigned long arg4)
{