summaryrefslogtreecommitdiffstats
path: root/debian/patches-rt/0277-futex-Delay-deallocation-of-pi_state.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches-rt/0277-futex-Delay-deallocation-of-pi_state.patch')
-rw-r--r--debian/patches-rt/0277-futex-Delay-deallocation-of-pi_state.patch182
1 files changed, 182 insertions, 0 deletions
diff --git a/debian/patches-rt/0277-futex-Delay-deallocation-of-pi_state.patch b/debian/patches-rt/0277-futex-Delay-deallocation-of-pi_state.patch
new file mode 100644
index 000000000..d75a415e1
--- /dev/null
+++ b/debian/patches-rt/0277-futex-Delay-deallocation-of-pi_state.patch
@@ -0,0 +1,182 @@
+From 83bf13ff04d052ee07805956bae67c712bbb761b Mon Sep 17 00:00:00 2001
+From: Thomas Gleixner <tglx@linutronix.de>
+Date: Wed, 26 Jun 2019 13:35:36 +0200
+Subject: [PATCH 277/347] futex: Delay deallocation of pi_state
+Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/4.19/older/patches-4.19.246-rt110.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 8a49dd71b233..2fc6bedb460e 100644
+--- a/kernel/futex.c
++++ b/kernel/futex.c
+@@ -871,13 +871,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
+@@ -892,9 +892,7 @@ static void put_pi_state(struct futex_pi_state *pi_state)
+ raw_spin_unlock_irqrestore(&pi_state->pi_mutex.wait_lock, flags);
+ }
+
+- if (current->pi_state_cache) {
+- kfree(pi_state);
+- } else {
++ if (!current->pi_state_cache) {
+ /*
+ * pi_state->list is already empty.
+ * clear pi_state->owner.
+@@ -903,6 +901,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);
+ }
+ }
+
+@@ -919,6 +941,7 @@ static 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;
+@@ -963,7 +986,7 @@ static 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;
+ }
+
+@@ -982,6 +1005,8 @@ static 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);
+ }
+ #else
+ static inline void exit_pi_state_list(struct task_struct *curr) { }
+@@ -2017,6 +2042,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;
+@@ -2265,7 +2291,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.
+@@ -2282,7 +2308,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);
+@@ -2303,6 +2329,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;
+ }
+
+@@ -2439,13 +2466,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,
+@@ -3394,14 +3424,17 @@ 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);
+ /*
+ * 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);
+ spin_unlock(&hb2->lock);
++ kfree(ps_free);
+ /*
+ * Adjust the return value. It's either -EFAULT or
+ * success (1) but the caller expects 0 for success.
+--
+2.36.1
+