xen/irq: Alter the locking to use a mutex instead of a spinlock.
When we allocate/change the IRQ informations, we do not need to use spinlocks. We can use a mutex (which is what the generic IRQ code does for allocations/changes). Fixes a slew of: BUG: sleeping function called from invalid context at /linux/kernel/mutex.c:271 in_atomic(): 1, irqs_disabled(): 0, pid: 3216, name: xenstored 2 locks held by xenstored/3216: #0: (&u->bind_mutex){......}, at: [<ffffffffa02e0920>] evtchn_ioctl+0x30/0x3a0 [xen_evtchn] #1: (irq_mapping_update_lock){......}, at: [<ffffffff8138b274>] bind_evtchn_to_irq+0x24/0x90 Pid: 3216, comm: xenstored Not tainted 3.1.0-rc6-00021-g437a3d1 #2 Call Trace: [<ffffffff81088d10>] __might_sleep+0x100/0x130 [<ffffffff81645c2f>] mutex_lock_nested+0x2f/0x50 [<ffffffff81627529>] __irq_alloc_descs+0x49/0x200 [<ffffffffa02e0920>] ? evtchn_ioctl+0x30/0x3a0 [xen_evtchn] [<ffffffff8138b214>] xen_allocate_irq_dynamic+0x34/0x70 [<ffffffff8138b2ad>] bind_evtchn_to_irq+0x5d/0x90 [<ffffffffa02e03c0>] ? evtchn_bind_to_user+0x60/0x60 [xen_evtchn] [<ffffffff8138c282>] bind_evtchn_to_irqhandler+0x32/0x80 [<ffffffffa02e03a9>] evtchn_bind_to_user+0x49/0x60 [xen_evtchn] [<ffffffffa02e0a34>] evtchn_ioctl+0x144/0x3a0 [xen_evtchn] [<ffffffff811b4070>] ? vfsmount_lock_local_unlock+0x50/0x80 [<ffffffff811a6a1a>] do_vfs_ioctl+0x9a/0x5e0 [<ffffffff811b476f>] ? mntput+0x1f/0x30 [<ffffffff81196259>] ? fput+0x199/0x240 [<ffffffff811a7001>] sys_ioctl+0xa1/0xb0 [<ffffffff8164ea82>] system_call_fastpath+0x16/0x1b Reported-by: Jim Burns <jim_burn@bellsouth.net> Acked-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
This commit is contained in:
parent
e3b73c4a25
commit
7736594836
|
@ -54,7 +54,7 @@
|
||||||
* This lock protects updates to the following mapping and reference-count
|
* This lock protects updates to the following mapping and reference-count
|
||||||
* arrays. The lock does not need to be acquired to read the mapping tables.
|
* arrays. The lock does not need to be acquired to read the mapping tables.
|
||||||
*/
|
*/
|
||||||
static DEFINE_SPINLOCK(irq_mapping_update_lock);
|
static DEFINE_MUTEX(irq_mapping_update_lock);
|
||||||
|
|
||||||
static LIST_HEAD(xen_irq_list_head);
|
static LIST_HEAD(xen_irq_list_head);
|
||||||
|
|
||||||
|
@ -631,7 +631,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
|
||||||
int irq = -1;
|
int irq = -1;
|
||||||
struct physdev_irq irq_op;
|
struct physdev_irq irq_op;
|
||||||
|
|
||||||
spin_lock(&irq_mapping_update_lock);
|
mutex_lock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
irq = find_irq_by_gsi(gsi);
|
irq = find_irq_by_gsi(gsi);
|
||||||
if (irq != -1) {
|
if (irq != -1) {
|
||||||
|
@ -684,7 +684,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi,
|
||||||
handle_edge_irq, name);
|
handle_edge_irq, name);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock(&irq_mapping_update_lock);
|
mutex_unlock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
return irq;
|
return irq;
|
||||||
}
|
}
|
||||||
|
@ -710,7 +710,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
|
||||||
{
|
{
|
||||||
int irq, ret;
|
int irq, ret;
|
||||||
|
|
||||||
spin_lock(&irq_mapping_update_lock);
|
mutex_lock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
irq = xen_allocate_irq_dynamic();
|
irq = xen_allocate_irq_dynamic();
|
||||||
if (irq == -1)
|
if (irq == -1)
|
||||||
|
@ -724,10 +724,10 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc,
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto error_irq;
|
goto error_irq;
|
||||||
out:
|
out:
|
||||||
spin_unlock(&irq_mapping_update_lock);
|
mutex_unlock(&irq_mapping_update_lock);
|
||||||
return irq;
|
return irq;
|
||||||
error_irq:
|
error_irq:
|
||||||
spin_unlock(&irq_mapping_update_lock);
|
mutex_unlock(&irq_mapping_update_lock);
|
||||||
xen_free_irq(irq);
|
xen_free_irq(irq);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -740,7 +740,7 @@ int xen_destroy_irq(int irq)
|
||||||
struct irq_info *info = info_for_irq(irq);
|
struct irq_info *info = info_for_irq(irq);
|
||||||
int rc = -ENOENT;
|
int rc = -ENOENT;
|
||||||
|
|
||||||
spin_lock(&irq_mapping_update_lock);
|
mutex_lock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
desc = irq_to_desc(irq);
|
desc = irq_to_desc(irq);
|
||||||
if (!desc)
|
if (!desc)
|
||||||
|
@ -766,7 +766,7 @@ int xen_destroy_irq(int irq)
|
||||||
xen_free_irq(irq);
|
xen_free_irq(irq);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock(&irq_mapping_update_lock);
|
mutex_unlock(&irq_mapping_update_lock);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -776,7 +776,7 @@ int xen_irq_from_pirq(unsigned pirq)
|
||||||
|
|
||||||
struct irq_info *info;
|
struct irq_info *info;
|
||||||
|
|
||||||
spin_lock(&irq_mapping_update_lock);
|
mutex_lock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
list_for_each_entry(info, &xen_irq_list_head, list) {
|
list_for_each_entry(info, &xen_irq_list_head, list) {
|
||||||
if (info == NULL || info->type != IRQT_PIRQ)
|
if (info == NULL || info->type != IRQT_PIRQ)
|
||||||
|
@ -787,7 +787,7 @@ int xen_irq_from_pirq(unsigned pirq)
|
||||||
}
|
}
|
||||||
irq = -1;
|
irq = -1;
|
||||||
out:
|
out:
|
||||||
spin_unlock(&irq_mapping_update_lock);
|
mutex_unlock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
return irq;
|
return irq;
|
||||||
}
|
}
|
||||||
|
@ -802,7 +802,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
|
||||||
{
|
{
|
||||||
int irq;
|
int irq;
|
||||||
|
|
||||||
spin_lock(&irq_mapping_update_lock);
|
mutex_lock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
irq = evtchn_to_irq[evtchn];
|
irq = evtchn_to_irq[evtchn];
|
||||||
|
|
||||||
|
@ -818,7 +818,7 @@ int bind_evtchn_to_irq(unsigned int evtchn)
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock(&irq_mapping_update_lock);
|
mutex_unlock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
return irq;
|
return irq;
|
||||||
}
|
}
|
||||||
|
@ -829,7 +829,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
|
||||||
struct evtchn_bind_ipi bind_ipi;
|
struct evtchn_bind_ipi bind_ipi;
|
||||||
int evtchn, irq;
|
int evtchn, irq;
|
||||||
|
|
||||||
spin_lock(&irq_mapping_update_lock);
|
mutex_lock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
irq = per_cpu(ipi_to_irq, cpu)[ipi];
|
irq = per_cpu(ipi_to_irq, cpu)[ipi];
|
||||||
|
|
||||||
|
@ -853,7 +853,7 @@ static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock(&irq_mapping_update_lock);
|
mutex_unlock(&irq_mapping_update_lock);
|
||||||
return irq;
|
return irq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -878,7 +878,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
|
||||||
struct evtchn_bind_virq bind_virq;
|
struct evtchn_bind_virq bind_virq;
|
||||||
int evtchn, irq;
|
int evtchn, irq;
|
||||||
|
|
||||||
spin_lock(&irq_mapping_update_lock);
|
mutex_lock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
irq = per_cpu(virq_to_irq, cpu)[virq];
|
irq = per_cpu(virq_to_irq, cpu)[virq];
|
||||||
|
|
||||||
|
@ -903,7 +903,7 @@ int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
spin_unlock(&irq_mapping_update_lock);
|
mutex_unlock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
return irq;
|
return irq;
|
||||||
}
|
}
|
||||||
|
@ -913,7 +913,7 @@ static void unbind_from_irq(unsigned int irq)
|
||||||
struct evtchn_close close;
|
struct evtchn_close close;
|
||||||
int evtchn = evtchn_from_irq(irq);
|
int evtchn = evtchn_from_irq(irq);
|
||||||
|
|
||||||
spin_lock(&irq_mapping_update_lock);
|
mutex_lock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
if (VALID_EVTCHN(evtchn)) {
|
if (VALID_EVTCHN(evtchn)) {
|
||||||
close.port = evtchn;
|
close.port = evtchn;
|
||||||
|
@ -943,7 +943,7 @@ static void unbind_from_irq(unsigned int irq)
|
||||||
|
|
||||||
xen_free_irq(irq);
|
xen_free_irq(irq);
|
||||||
|
|
||||||
spin_unlock(&irq_mapping_update_lock);
|
mutex_unlock(&irq_mapping_update_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bind_evtchn_to_irqhandler(unsigned int evtchn,
|
int bind_evtchn_to_irqhandler(unsigned int evtchn,
|
||||||
|
@ -1279,7 +1279,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
|
||||||
will also be masked. */
|
will also be masked. */
|
||||||
disable_irq(irq);
|
disable_irq(irq);
|
||||||
|
|
||||||
spin_lock(&irq_mapping_update_lock);
|
mutex_lock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
/* After resume the irq<->evtchn mappings are all cleared out */
|
/* After resume the irq<->evtchn mappings are all cleared out */
|
||||||
BUG_ON(evtchn_to_irq[evtchn] != -1);
|
BUG_ON(evtchn_to_irq[evtchn] != -1);
|
||||||
|
@ -1289,7 +1289,7 @@ void rebind_evtchn_irq(int evtchn, int irq)
|
||||||
|
|
||||||
xen_irq_info_evtchn_init(irq, evtchn);
|
xen_irq_info_evtchn_init(irq, evtchn);
|
||||||
|
|
||||||
spin_unlock(&irq_mapping_update_lock);
|
mutex_unlock(&irq_mapping_update_lock);
|
||||||
|
|
||||||
/* new event channels are always bound to cpu 0 */
|
/* new event channels are always bound to cpu 0 */
|
||||||
irq_set_affinity(irq, cpumask_of(0));
|
irq_set_affinity(irq, cpumask_of(0));
|
||||||
|
|
Loading…
Reference in New Issue