Skip to contentSkip to conversation

Sparse annotation for "context imbalance" false positives?

DISCUSSION Roland Dreier 2 participants 4 messages May 15, 2008 Sparse checker

lore
Share & tools
lore
#0 lore raw

Now that I've gotten the sparse noise in drivers/infiniband down to a fairly low level, I'm starting to look at some of the more recalcitrant false positive warnings. One example is:

drivers/infiniband/hw/mlx4/qp.c:605:2: warning: context imbalance in 'mlx4_ib_lock_cqs' - wrong count at exit

where the function being warned about is:

	static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq)
	{
		if (send_cq == recv_cq)
			spin_lock_irq(&send_cq->lock);
		else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) {
			spin_lock_irq(&send_cq->lock);
			spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);
		} else {
			spin_lock_irq(&recv_cq->lock);
			spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
		}
	}

this function wraps up the locking rules for aquiring the completion queue (CQ) locks associated with a queue pair (QP) -- the rule is that if both the send and receive CQs are the same object, we (obviously) only lock it once, otherwise we take the lock belonging to the CQ with a numerically lower ID first (to avoid AB-BA deadlocks).

So obviously is it correct and intended that this function return holding one or two locks, but I don't know how to tell sparse that. I've tried messing around with __acquires() etc but it doesn't seem to be exactly what I want.

Is there any way to tell sparse what's going on here, or do I just live with the warnings?

Thanks,
Roland

#1 lore raw

You could, for example, insert this:

Quoted 3 lines
	static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq)
	{
		if (send_cq == recv_cq)
		{
Quoted 1 line
			spin_lock_irq(&send_cq->lock);
			 /* pretend to have acquired both for sparse */	
			__acquire(&recv_cq->lock);
		}
Quoted 8 lines
		else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) {
			spin_lock_irq(&send_cq->lock);
			spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);
		} else {
			spin_lock_irq(&recv_cq->lock);
			spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
		}
	}

and then declare that you take "both" locks. Not sure if that will bite you in the callers again though.

The exact syntax is still a bit under discussion though, whether to use &recv_cq->lock or leave out the "&" there, I'm favouring the approach with & but the kernel uses no & in some places.

johannes

#2 lore raw
Quoted 10 lines

You could, for example, insert this:

Quoted 3 lines
	static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq)
	{
		if (send_cq == recv_cq)
		{
Quoted 1 line
			spin_lock_irq(&send_cq->lock);
			 /* pretend to have acquired both for sparse */	
			__acquire(&recv_cq->lock);
		}

but the problem sparse sees is not that some paths take only one lock and some take two -- sparse is complaining that this function is returning without unlocking the locks that it takes. Even if I change the function to something as simple as:

	static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq)
	{
		spin_lock_irq(&recv_cq->lock);
	}

I still get

drivers/infiniband/hw/mlx4/qp.c:603:13: warning: context imbalance in 'mlx4_ib_lock_cqs' - wrong count at exitn

thanks,
Roland

#3 lore raw
Quoted 6 lines

but the problem sparse sees is not that some paths take only one lock and some take two -- sparse is complaining that this function is returning without unlocking the locks that it takes. Even if I change the function to something as simple as:

Quoted 8 lines
	static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq)
	{
		spin_lock_irq(&recv_cq->lock);
	}

I still get

drivers/infiniband/hw/mlx4/qp.c:603:13: warning: context imbalance in 'mlx4_ib_lock_cqs' - wrong count at exitn

Oh. Well yes, you also have to annotate the function:

static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv_cq)

	__acquires(&recv_cq->lock) __acquires(&send_cq->lock)
{
	...
}

but we're still discussing whether the & should be in there or not. I'd think right now is a bad time for you to be working on this unless you want to help with how sparse should behave too.

johannes