All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: Darren Hart <dvhltc@us.ibm.com>
Cc: "lkml, " <linux-kernel@vger.kernel.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Ingo Molnar <mingo@elte.hu>,
	Eric Dumazet <eric.dumazet@gmail.com>,
	John Kacur <jkacur@redhat.com>,
	Steven Rostedt <rostedt@goodmis.org>,
	Mike Galbraith <efault@gmx.de>,
	linux-rt-users <linux-rt-users@vger.kernel.org>
Subject: Re: [PATCH][RT] futex: protect against pi_blocked_on corruption during requeue PI
Date: Tue, 13 Jul 2010 11:25:44 +0200 (CEST)	[thread overview]
Message-ID: <alpine.LFD.2.00.1007131041230.3321@localhost.localdomain> (raw)
In-Reply-To: <4C3C1DCF.9090509@us.ibm.com>

On Tue, 13 Jul 2010, Darren Hart wrote:

> Thanks to Thomas, Steven, and Mike for hashing this over me. After an
> IRC discussion with Thomas, I put the following together. It resolves
> the issue for me, Mike please test and let us know if it fixes it for
> you. A couple of points of discussion before we commit this:
> 
> The use of the new state flag, PI_WAKEUP_INPROGRESS, is pretty ugly.
> Would a new task_pi_blocked_on_valid() method be preferred (in
> rtmutex.c)? 
> 
> The new WARN_ON() in task_blocks_on_rt_mutex() is complex. It didn't
> exist before and we've now closed this gap, should we just drop it?

We can simplify it to:

	WARN_ON(task->pi_blocked_on &&
		task->pi_blocked_on != PI_WAKEUP_INPROGRESS);

We check for !=current and PI_WAKEUP_INPROGRESS just above.   
 
> I've added a couple BUG_ON()s in futex_wait_requeue_pi() dealing with
> the race with requeue and q.lock_ptr. I'd like to leave this for the
> time being if nobody strongly objects.
> -
>  	/*
> -	 * In order for us to be here, we know our q.key == key2, and since
> -	 * we took the hb->lock above, we also know that futex_requeue() has
> -	 * completed and we no longer have to concern ourselves with a wakeup
> -	 * race with the atomic proxy lock acquition by the requeue code.
> +	 * Avoid races with requeue and trying to block on two mutexes
> +	 * (hb->lock and uaddr2's rtmutex) by serializing access to
> +	 * pi_blocked_on with pi_lock and setting PI_BLOCKED_ON_PENDING.
> +	 */
> +	raw_spin_lock(&current->pi_lock);

  Needs to be raw_spin_lock_irq()

> +	if (current->pi_blocked_on) {
> +		raw_spin_unlock(&current->pi_lock);
> +	} else {
> +		current->pi_blocked_on = (struct rt_mutex_waiter *)PI_WAKEUP_INPROGRESS;

  #define PI_WAKEUP_INPROGRESS ((struct rt_mutex_waiter *) 1)

  perhaps ? That gets rid of all type casts

> +		raw_spin_unlock(&current->pi_lock);
> +
> +		spin_lock(&hb->lock);

  We need to cleanup current->pi_blocked_on here. If we succeed in the
  hb->lock fast path then we might leak the PI_WAKEUP_INPROGRESS to user space
  and the next requeue will fail.

> diff --git a/kernel/rtmutex.c b/kernel/rtmutex.c
> index 23dd443..0399108 100644
> --- a/kernel/rtmutex.c
> +++ b/kernel/rtmutex.c
> @@ -227,7 +227,7 @@ static int rt_mutex_adjust_prio_chain(struct task_struct *task,
>  	 * reached or the state of the chain has changed while we
>  	 * dropped the locks.
>  	 */
> -	if (!waiter || !waiter->task)
> +	if (!waiter || (long)waiter == PI_WAKEUP_INPROGRESS || !waiter->task)
>  		goto out_unlock_pi;

 Why do we need that check ? Either the requeue succeeded then
 task->pi_blocked_on is set to the real waiter or the wakeup won and
 we are in no lock chain.

 If we ever find a waiter with PI_WAKEUP_INPROGRESS set in
 rt_mutex_adjust_prio_chain() then it's a bug nothing else.

> @@ -469,7 +493,8 @@ static int task_blocks_on_rt_mutex(struct rt_mutex *lock,
>  		plist_add(&waiter->pi_list_entry, &owner->pi_waiters);
>  
>  		__rt_mutex_adjust_prio(owner);
> -		if (owner->pi_blocked_on)
> +		if (owner->pi_blocked_on &&
> +		    (long)owner->pi_blocked_on != PI_WAKEUP_INPROGRESS)

  Again, that can never happen

>  			chain_walk = 1;
>  		raw_spin_unlock(&owner->pi_lock);
>  	}
> @@ -579,9 +604,11 @@ static void wakeup_next_waiter(struct rt_mutex *lock, int savestate)
>  
>  	raw_spin_lock(&pendowner->pi_lock);
>  
> -	WARN_ON(!pendowner->pi_blocked_on);
> -	WARN_ON(pendowner->pi_blocked_on != waiter);
> -	WARN_ON(pendowner->pi_blocked_on->lock != lock);
> + 	if (!WARN_ON(!pendowner->pi_blocked_on) &&
> + 	    !WARN_ON((long)pendowner->pi_blocked_on == PI_WAKEUP_INPROGRESS)) {

  Ditto

> +  		WARN_ON(pendowner->pi_blocked_on != waiter);
> +  		WARN_ON(pendowner->pi_blocked_on->lock != lock);
> +  	}
>  
>  	pendowner->pi_blocked_on = NULL;
>  
> @@ -624,7 +651,8 @@ static void remove_waiter(struct rt_mutex *lock,
>  		}
>  		__rt_mutex_adjust_prio(owner);
>  
> -		if (owner->pi_blocked_on)
> +		if (owner->pi_blocked_on &&
> +		    (long)owner->pi_blocked_on != PI_WAKEUP_INPROGRESS)
>  			chain_walk = 1;

  Same here.			
  
>  		raw_spin_unlock(&owner->pi_lock);
> @@ -658,7 +686,8 @@ void rt_mutex_adjust_pi(struct task_struct *task)
>  	raw_spin_lock_irqsave(&task->pi_lock, flags);
>  
>  	waiter = task->pi_blocked_on;
> -	if (!waiter || waiter->list_entry.prio == task->prio) {
> +	if (!waiter || (long)waiter == PI_WAKEUP_INPROGRESS ||
> +	    waiter->list_entry.prio == task->prio) {

  And here

>  /*
>   * Convert user-nice values [ -20 ... 0 ... 19 ]
>   * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ],
> @@ -6377,7 +6379,8 @@ void task_setprio(struct task_struct *p, int prio)
>  	 */
>  	if (unlikely(p == rq->idle)) {
>  		WARN_ON(p != rq->curr);
> -		WARN_ON(p->pi_blocked_on);
> +		WARN_ON(p->pi_blocked_on &&
> +		        (long)p->pi_blocked_on != PI_WAKEUP_INPROGRESS);

  Yuck. Paranoia ? If we ever requeue idle, then .....

I'm going to cleanup the stuff and send out a new patch for Mike
to test.

Thanks,

	tglx


  reply	other threads:[~2010-07-13  9:26 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-07-07  4:46 2.6.33.[56]-rt23: howto create repeatable explosion in wakeup_next_waiter() Mike Galbraith
2010-07-07  8:03 ` Mike Galbraith
2010-07-07 11:57   ` Thomas Gleixner
2010-07-07 12:50     ` Mike Galbraith
2010-07-07 11:57 ` Thomas Gleixner
2010-07-07 14:03   ` Darren Hart
2010-07-07 14:17     ` Mike Galbraith
2010-07-08 12:05     ` Mike Galbraith
2010-07-08 14:12       ` Darren Hart
2010-07-09  2:11   ` Darren Hart
2010-07-09  4:32     ` Mike Galbraith
     [not found]     ` <4C36CD83.6070809@us.ibm.com>
2010-07-09  8:13       ` Mike Galbraith
2010-07-09 13:58       ` Mike Galbraith
2010-07-09 14:51         ` Mike Galbraith
2010-07-09 16:35         ` Darren Hart
2010-07-09 19:34           ` Mike Galbraith
2010-07-09 20:05   ` Darren Hart
2010-07-13  8:03   ` [PATCH][RT] futex: protect against pi_blocked_on corruption during requeue PI Darren Hart
2010-07-13  9:25     ` Thomas Gleixner [this message]
2010-07-13 10:28       ` Thomas Gleixner
2010-07-13 11:52         ` [PATCH][RT] futex: protect against pi_blocked_on corruption during requeue PI -V2 Thomas Gleixner
2010-07-13 15:57           ` Mike Galbraith
2010-07-13 18:59           ` Darren Hart
2010-07-18  8:32           ` Mike Galbraith
2010-07-13  9:58     ` [PATCH][RT] futex: protect against pi_blocked_on corruption during requeue PI Thomas Gleixner
2010-07-07 14:11 ` 2.6.33.[56]-rt23: howto create repeatable explosion in wakeup_next_waiter() gowrishankar
2010-07-07 14:31   ` Mike Galbraith
2010-07-07 15:05     ` Darren Hart
2010-07-07 17:45       ` Mike Galbraith

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alpine.LFD.2.00.1007131041230.3321@localhost.localdomain \
    --to=tglx@linutronix.de \
    --cc=dvhltc@us.ibm.com \
    --cc=efault@gmx.de \
    --cc=eric.dumazet@gmail.com \
    --cc=jkacur@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rt-users@vger.kernel.org \
    --cc=mingo@elte.hu \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.