Sparse annotation for "context imbalance" false positives?
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
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
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
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