Fix infinite 'EAGAIN' loop in futex_unlock_pi (Raytheon bug). [ 4.4.256-RedHawk is known _not_ to have this problem ] [ 4.4.262-RedHawk is known to have it ] [ This is unlikely to be caused by the rt patch ] [ or by our patches ] A customer with a rather large, secure-site application occasionally stalls indefinately, spinning in futex_unlock_pi. This cannot be cleared except by rebooting. New to 4.4 is 73d786b ("[PATCH] futex: Rework inconsistent rt_mutex/futex_q state"). This adds an EAGAIN loop which appears to be the cause of the problem. That commit has this comment: The only problem is that this breaks RT timeliness guarantees. That is, consider the following scenario: T1 and T2 are both pinned to CPU0. prio(T2) > prio(T1) CPU0 T1 lock_pi() queue_me() <- Waiter is visible preemption T2 unlock_pi() loops with -EAGAIN forever Which is undesirable for PI primitives. Future patches will rectify this. The above matches the behavor exactly. Our replicator, based on posix-thread/pthread_mutex_lock/1-1.c test shows that indeed this is the problem. We fix, for now, by introducing a one millisecond sleep in the looping code. This gives the lower priority task T1 the time it needs to clean up the condition that the higher priority task T2 is spin-waiting on. This patch is temporary until mainline linux fixes this. We suspect that some futex patch from 4.12 that actually fixes this failed to be backported. Problem-Analysed-by: Scott Shaffer while at concurrent-rt.com Developed-by: Joe Korty while at concurrent-rt.com Index: b/kernel/futex.c =================================================================== --- a/kernel/futex.c +++ b/kernel/futex.c @@ -66,6 +66,7 @@ #include #include #include +#include #include @@ -1529,8 +1530,10 @@ static void mark_wake_futex(struct wake_ q->lock_ptr = NULL; } +unsigned long futex_eagain_ctr = 0; + static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this, - struct futex_hash_bucket *hb) + struct futex_hash_bucket *hb, int *dologp) { struct task_struct *new_owner; struct futex_pi_state *pi_state = this->pi_state; @@ -1564,6 +1567,7 @@ static int wake_futex_pi(u32 __user *uad */ if (!new_owner) { raw_spin_unlock_irq(&pi_state->pi_mutex.wait_lock); + *dologp = 1; return -EAGAIN; } @@ -2967,7 +2971,8 @@ retry: */ match = futex_top_waiter(hb, &key); if (match) { - ret = wake_futex_pi(uaddr, uval, match, hb); + int log_eagain = 0; + ret = wake_futex_pi(uaddr, uval, match, hb, &log_eagain); /* * In case of success wake_futex_pi dropped the hash * bucket lock. @@ -2987,6 +2992,11 @@ retry: if (ret == -EAGAIN) { spin_unlock(&hb->lock); put_futex_key(&key); + if (log_eagain) { + printk_once("WARNING: futex_unlock_pi: in EAGAIN loop\n"); + futex_eagain_ctr++; + usleep_range(1000, 1000); /* let the guy run who will clean things up */ + } goto retry; } /*