Davidlohr Bueso 5c8ef6
From 340576590dac4bb58d532a8ad5bfa806d8ab473c Mon Sep 17 00:00:00 2001
Davidlohr Bueso 5c8ef6
From: Thomas Gleixner <tglx@linutronix.de>
Davidlohr Bueso 5c8ef6
Date: Thu, 2 Sep 2021 11:48:51 +0200
Davidlohr Bueso 5c8ef6
Subject: [PATCH] futex: Avoid redundant task lookup
Davidlohr Bueso 5c8ef6
Git-commit: 340576590dac4bb58d532a8ad5bfa806d8ab473c
Davidlohr Bueso 5c8ef6
Patch-mainline: v5.15-rc1
Davidlohr Bueso 5c8ef6
References: bsc#1190137 bsc#1189998
Davidlohr Bueso 5c8ef6
Davidlohr Bueso 5c8ef6
No need to do the full VPID based task lookup and validation of the top
Davidlohr Bueso 5c8ef6
waiter when the user space futex was acquired on it's behalf during the
Davidlohr Bueso 5c8ef6
requeue_pi operation. The task is known already and it cannot go away
Davidlohr Bueso 5c8ef6
before requeue_pi_wake_futex() has been invoked.
Davidlohr Bueso 5c8ef6
Davidlohr Bueso 5c8ef6
Split out the actual attach code from attach_pi_state_owner() and use that
Davidlohr Bueso 5c8ef6
instead of the full blown variant.
Davidlohr Bueso 5c8ef6
Davidlohr Bueso 5c8ef6
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Davidlohr Bueso 5c8ef6
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Davidlohr Bueso 5c8ef6
Link: https://lore.kernel.org/r/20210902094414.676104881@linutronix.de
Davidlohr Bueso 5c8ef6
Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Davidlohr Bueso 5c8ef6
Davidlohr Bueso 5c8ef6
---
Davidlohr Bueso 5c8ef6
 kernel/futex.c | 67 ++++++++++++++++++++++++++++----------------------
Davidlohr Bueso 5c8ef6
 1 file changed, 37 insertions(+), 30 deletions(-)
Davidlohr Bueso 5c8ef6
Davidlohr Bueso 5c8ef6
diff --git a/kernel/futex.c b/kernel/futex.c
Davidlohr Bueso 5c8ef6
index 82cd270f25a0..a316dce74c3d 100644
Davidlohr Bueso 5c8ef6
--- a/kernel/futex.c
Davidlohr Bueso 5c8ef6
+++ b/kernel/futex.c
Davidlohr Bueso 5c8ef6
@@ -1263,6 +1263,36 @@ static int handle_exit_race(u32 __user *uaddr, u32 uval,
Davidlohr Bueso 5c8ef6
 	return -ESRCH;
Davidlohr Bueso 5c8ef6
 }
Davidlohr Bueso 5c8ef6
 
Davidlohr Bueso 5c8ef6
+static void __attach_to_pi_owner(struct task_struct *p, union futex_key *key,
Davidlohr Bueso 5c8ef6
+				 struct futex_pi_state **ps)
Davidlohr Bueso 5c8ef6
+{
Davidlohr Bueso 5c8ef6
+	/*
Davidlohr Bueso 5c8ef6
+	 * No existing pi state. First waiter. [2]
Davidlohr Bueso 5c8ef6
+	 *
Davidlohr Bueso 5c8ef6
+	 * This creates pi_state, we have hb->lock held, this means nothing can
Davidlohr Bueso 5c8ef6
+	 * observe this state, wait_lock is irrelevant.
Davidlohr Bueso 5c8ef6
+	 */
Davidlohr Bueso 5c8ef6
+	struct futex_pi_state *pi_state = alloc_pi_state();
Davidlohr Bueso 5c8ef6
+
Davidlohr Bueso 5c8ef6
+	/*
Davidlohr Bueso 5c8ef6
+	 * Initialize the pi_mutex in locked state and make @p
Davidlohr Bueso 5c8ef6
+	 * the owner of it:
Davidlohr Bueso 5c8ef6
+	 */
Davidlohr Bueso 5c8ef6
+	rt_mutex_init_proxy_locked(&pi_state->pi_mutex, p);
Davidlohr Bueso 5c8ef6
+
Davidlohr Bueso 5c8ef6
+	/* Store the key for possible exit cleanups: */
Davidlohr Bueso 5c8ef6
+	pi_state->key = *key;
Davidlohr Bueso 5c8ef6
+
Davidlohr Bueso 5c8ef6
+	WARN_ON(!list_empty(&pi_state->list));
Davidlohr Bueso 5c8ef6
+	list_add(&pi_state->list, &p->pi_state_list);
Davidlohr Bueso 5c8ef6
+	/*
Davidlohr Bueso 5c8ef6
+	 * Assignment without holding pi_state->pi_mutex.wait_lock is safe
Davidlohr Bueso 5c8ef6
+	 * because there is no concurrency as the object is not published yet.
Davidlohr Bueso 5c8ef6
+	 */
Davidlohr Bueso 5c8ef6
+	pi_state->owner = p;
Davidlohr Bueso 5c8ef6
+
Davidlohr Bueso 5c8ef6
+	*ps = pi_state;
Davidlohr Bueso 5c8ef6
+}
Davidlohr Bueso 5c8ef6
 /*
Davidlohr Bueso 5c8ef6
  * Lookup the task for the TID provided from user space and attach to
Davidlohr Bueso 5c8ef6
  * it after doing proper sanity checks.
Davidlohr Bueso 5c8ef6
@@ -1272,7 +1302,6 @@ static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
Davidlohr Bueso 5c8ef6
 			      struct task_struct **exiting)
Davidlohr Bueso 5c8ef6
 {
Davidlohr Bueso 5c8ef6
 	pid_t pid = uval & FUTEX_TID_MASK;
Davidlohr Bueso 5c8ef6
-	struct futex_pi_state *pi_state;
Davidlohr Bueso 5c8ef6
 	struct task_struct *p;
Davidlohr Bueso 5c8ef6
 
Davidlohr Bueso 5c8ef6
 	/*
Davidlohr Bueso 5c8ef6
@@ -1324,36 +1353,11 @@ static int attach_to_pi_owner(u32 __user *uaddr, u32 uval, union futex_key *key,
Davidlohr Bueso 5c8ef6
 		return ret;
Davidlohr Bueso 5c8ef6
 	}
Davidlohr Bueso 5c8ef6
 
Davidlohr Bueso 5c8ef6
-	/*
Davidlohr Bueso 5c8ef6
-	 * No existing pi state. First waiter. [2]
Davidlohr Bueso 5c8ef6
-	 *
Davidlohr Bueso 5c8ef6
-	 * This creates pi_state, we have hb->lock held, this means nothing can
Davidlohr Bueso 5c8ef6
-	 * observe this state, wait_lock is irrelevant.
Davidlohr Bueso 5c8ef6
-	 */
Davidlohr Bueso 5c8ef6
-	pi_state = alloc_pi_state();
Davidlohr Bueso 5c8ef6
-
Davidlohr Bueso 5c8ef6
-	/*
Davidlohr Bueso 5c8ef6
-	 * Initialize the pi_mutex in locked state and make @p
Davidlohr Bueso 5c8ef6
-	 * the owner of it:
Davidlohr Bueso 5c8ef6
-	 */
Davidlohr Bueso 5c8ef6
-	rt_mutex_init_proxy_locked(&pi_state->pi_mutex, p);
Davidlohr Bueso 5c8ef6
-
Davidlohr Bueso 5c8ef6
-	/* Store the key for possible exit cleanups: */
Davidlohr Bueso 5c8ef6
-	pi_state->key = *key;
Davidlohr Bueso 5c8ef6
-
Davidlohr Bueso 5c8ef6
-	WARN_ON(!list_empty(&pi_state->list));
Davidlohr Bueso 5c8ef6
-	list_add(&pi_state->list, &p->pi_state_list);
Davidlohr Bueso 5c8ef6
-	/*
Davidlohr Bueso 5c8ef6
-	 * Assignment without holding pi_state->pi_mutex.wait_lock is safe
Davidlohr Bueso 5c8ef6
-	 * because there is no concurrency as the object is not published yet.
Davidlohr Bueso 5c8ef6
-	 */
Davidlohr Bueso 5c8ef6
-	pi_state->owner = p;
Davidlohr Bueso 5c8ef6
+	__attach_to_pi_owner(p, key, ps);
Davidlohr Bueso 5c8ef6
 	raw_spin_unlock_irq(&p->pi_lock);
Davidlohr Bueso 5c8ef6
 
Davidlohr Bueso 5c8ef6
 	put_task_struct(p);
Davidlohr Bueso 5c8ef6
 
Davidlohr Bueso 5c8ef6
-	*ps = pi_state;
Davidlohr Bueso 5c8ef6
-
Davidlohr Bueso 5c8ef6
 	return 0;
Davidlohr Bueso 5c8ef6
 }
Davidlohr Bueso 5c8ef6
 
Davidlohr Bueso 5c8ef6
@@ -1464,11 +1468,14 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
Davidlohr Bueso 5c8ef6
 		 * @task is guaranteed to be alive and it cannot be exiting
Davidlohr Bueso 5c8ef6
 		 * because it is either sleeping or waiting in
Davidlohr Bueso 5c8ef6
 		 * futex_requeue_pi_wakeup_sync().
Davidlohr Bueso 5c8ef6
+		 *
Davidlohr Bueso 5c8ef6
+		 * No need to do the full attach_to_pi_owner() exercise
Davidlohr Bueso 5c8ef6
+		 * because @task is known and valid.
Davidlohr Bueso 5c8ef6
 		 */
Davidlohr Bueso 5c8ef6
 		if (set_waiters) {
Davidlohr Bueso 5c8ef6
-			 ret = attach_to_pi_owner(uaddr, newval, key, ps,
Davidlohr Bueso 5c8ef6
-						  exiting);
Davidlohr Bueso 5c8ef6
-			 WARN_ON(ret);
Davidlohr Bueso 5c8ef6
+			raw_spin_lock_irq(&task->pi_lock);
Davidlohr Bueso 5c8ef6
+			__attach_to_pi_owner(task, key, ps);
Davidlohr Bueso 5c8ef6
+			raw_spin_unlock_irq(&task->pi_lock);
Davidlohr Bueso 5c8ef6
 		}
Davidlohr Bueso 5c8ef6
 		return 1;
Davidlohr Bueso 5c8ef6
 	}
Davidlohr Bueso 5c8ef6
-- 
Davidlohr Bueso 5c8ef6
2.26.2
Davidlohr Bueso 5c8ef6