187 lines
5.6 KiB
Diff
187 lines
5.6 KiB
Diff
From 183118d6b4d9dff19ec1a98dcb70bcd7fbe04adf Mon Sep 17 00:00:00 2001
|
|
Message-Id: <183118d6b4d9dff19ec1a98dcb70bcd7fbe04adf.1601675153.git.zanussi@kernel.org>
|
|
In-Reply-To: <5b5a156f9808b1acf1205606e03da117214549ea.1601675151.git.zanussi@kernel.org>
|
|
References: <5b5a156f9808b1acf1205606e03da117214549ea.1601675151.git.zanussi@kernel.org>
|
|
From: Thomas Gleixner <tglx@linutronix.de>
|
|
Date: Wed, 26 Jun 2019 13:35:36 +0200
|
|
Subject: [PATCH 277/333] futex: Delay deallocation of pi_state
|
|
Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.19/older/patches-4.19.148-rt64.tar.xz
|
|
|
|
[ Upstream commit d7c7cf8cb68b7df17e6e50be1f25f35d83e686c7 ]
|
|
|
|
On -RT we can't invoke kfree() in a non-preemptible context.
|
|
|
|
Defer the deallocation of pi_state to preemptible context.
|
|
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
|
|
---
|
|
kernel/futex.c | 55 ++++++++++++++++++++++++++++++++++++++++----------
|
|
1 file changed, 44 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/kernel/futex.c b/kernel/futex.c
|
|
index 8e8658df69d9..3c604e3eb20a 100644
|
|
--- a/kernel/futex.c
|
|
+++ b/kernel/futex.c
|
|
@@ -842,13 +842,13 @@ static void get_pi_state(struct futex_pi_state *pi_state)
|
|
* Drops a reference to the pi_state object and frees or caches it
|
|
* when the last reference is gone.
|
|
*/
|
|
-static void put_pi_state(struct futex_pi_state *pi_state)
|
|
+static struct futex_pi_state *__put_pi_state(struct futex_pi_state *pi_state)
|
|
{
|
|
if (!pi_state)
|
|
- return;
|
|
+ return NULL;
|
|
|
|
if (!atomic_dec_and_test(&pi_state->refcount))
|
|
- return;
|
|
+ return NULL;
|
|
|
|
/*
|
|
* If pi_state->owner is NULL, the owner is most probably dying
|
|
@@ -868,9 +868,7 @@ static void put_pi_state(struct futex_pi_state *pi_state)
|
|
raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock);
|
|
}
|
|
|
|
- if (current->pi_state_cache) {
|
|
- kfree(pi_state);
|
|
- } else {
|
|
+ if (!current->pi_state_cache) {
|
|
/*
|
|
* pi_state->list is already empty.
|
|
* clear pi_state->owner.
|
|
@@ -879,6 +877,30 @@ static void put_pi_state(struct futex_pi_state *pi_state)
|
|
pi_state->owner = NULL;
|
|
atomic_set(&pi_state->refcount, 1);
|
|
current->pi_state_cache = pi_state;
|
|
+ pi_state = NULL;
|
|
+ }
|
|
+ return pi_state;
|
|
+}
|
|
+
|
|
+static void put_pi_state(struct futex_pi_state *pi_state)
|
|
+{
|
|
+ kfree(__put_pi_state(pi_state));
|
|
+}
|
|
+
|
|
+static void put_pi_state_atomic(struct futex_pi_state *pi_state,
|
|
+ struct list_head *to_free)
|
|
+{
|
|
+ if (__put_pi_state(pi_state))
|
|
+ list_add(&pi_state->list, to_free);
|
|
+}
|
|
+
|
|
+static void free_pi_state_list(struct list_head *to_free)
|
|
+{
|
|
+ struct futex_pi_state *p, *next;
|
|
+
|
|
+ list_for_each_entry_safe(p, next, to_free, list) {
|
|
+ list_del(&p->list);
|
|
+ kfree(p);
|
|
}
|
|
}
|
|
|
|
@@ -895,6 +917,7 @@ void exit_pi_state_list(struct task_struct *curr)
|
|
struct futex_pi_state *pi_state;
|
|
struct futex_hash_bucket *hb;
|
|
union futex_key key = FUTEX_KEY_INIT;
|
|
+ LIST_HEAD(to_free);
|
|
|
|
if (!futex_cmpxchg_enabled)
|
|
return;
|
|
@@ -939,7 +962,7 @@ void exit_pi_state_list(struct task_struct *curr)
|
|
/* retain curr->pi_lock for the loop invariant */
|
|
raw_spin_unlock(&pi_state->pi_mutex.wait_lock);
|
|
raw_spin_unlock(&hb->lock);
|
|
- put_pi_state(pi_state);
|
|
+ put_pi_state_atomic(pi_state, &to_free);
|
|
continue;
|
|
}
|
|
|
|
@@ -958,6 +981,8 @@ void exit_pi_state_list(struct task_struct *curr)
|
|
raw_spin_lock_irq(&curr->pi_lock);
|
|
}
|
|
raw_spin_unlock_irq(&curr->pi_lock);
|
|
+
|
|
+ free_pi_state_list(&to_free);
|
|
}
|
|
|
|
#endif
|
|
@@ -1940,6 +1965,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
|
|
struct futex_hash_bucket *hb1, *hb2;
|
|
struct futex_q *this, *next;
|
|
DEFINE_WAKE_Q(wake_q);
|
|
+ LIST_HEAD(to_free);
|
|
|
|
if (nr_wake < 0 || nr_requeue < 0)
|
|
return -EINVAL;
|
|
@@ -2177,7 +2203,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
|
|
* object.
|
|
*/
|
|
this->pi_state = NULL;
|
|
- put_pi_state(pi_state);
|
|
+ put_pi_state_atomic(pi_state, &to_free);
|
|
/*
|
|
* We stop queueing more waiters and let user
|
|
* space deal with the mess.
|
|
@@ -2194,7 +2220,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
|
|
* in futex_proxy_trylock_atomic() or in lookup_pi_state(). We
|
|
* need to drop it here again.
|
|
*/
|
|
- put_pi_state(pi_state);
|
|
+ put_pi_state_atomic(pi_state, &to_free);
|
|
|
|
out_unlock:
|
|
double_unlock_hb(hb1, hb2);
|
|
@@ -2215,6 +2241,7 @@ static int futex_requeue(u32 __user *uaddr1, unsigned int flags,
|
|
out_put_key1:
|
|
put_futex_key(&key1);
|
|
out:
|
|
+ free_pi_state_list(&to_free);
|
|
return ret ? ret : task_count;
|
|
}
|
|
|
|
@@ -2351,13 +2378,16 @@ static int unqueue_me(struct futex_q *q)
|
|
static void unqueue_me_pi(struct futex_q *q)
|
|
__releases(q->lock_ptr)
|
|
{
|
|
+ struct futex_pi_state *ps;
|
|
+
|
|
__unqueue_futex(q);
|
|
|
|
BUG_ON(!q->pi_state);
|
|
- put_pi_state(q->pi_state);
|
|
+ ps = __put_pi_state(q->pi_state);
|
|
q->pi_state = NULL;
|
|
|
|
raw_spin_unlock(q->lock_ptr);
|
|
+ kfree(ps);
|
|
}
|
|
|
|
static int fixup_pi_state_owner(u32 __user *uaddr, struct futex_q *q,
|
|
@@ -3306,6 +3336,8 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
|
* did a lock-steal - fix up the PI-state in that case.
|
|
*/
|
|
if (q.pi_state && (q.pi_state->owner != current)) {
|
|
+ struct futex_pi_state *ps_free;
|
|
+
|
|
raw_spin_lock(q.lock_ptr);
|
|
ret = fixup_pi_state_owner(uaddr2, &q, current);
|
|
if (ret && rt_mutex_owner(&q.pi_state->pi_mutex) == current) {
|
|
@@ -3316,8 +3348,9 @@ static int futex_wait_requeue_pi(u32 __user *uaddr, unsigned int flags,
|
|
* Drop the reference to the pi state which
|
|
* the requeue_pi() code acquired for us.
|
|
*/
|
|
- put_pi_state(q.pi_state);
|
|
+ ps_free = __put_pi_state(q.pi_state);
|
|
raw_spin_unlock(q.lock_ptr);
|
|
+ kfree(ps_free);
|
|
}
|
|
} else {
|
|
struct rt_mutex *pi_mutex;
|
|
--
|
|
2.17.1
|
|
|