浏览代码

Merge branch 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull irq fixes from Ingo Molnar:
 "A sparse irq race/locking fix, and a MSI irq domains population fix"

* 'irq-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  genirq: Make sparse_irq_lock protect what it should protect
  genirq/msi: Fix populating multiple interrupts
Linus Torvalds 8 年之前
父节点
当前提交
33f82bda01
共有 2 个文件被更改,包括 10 次插入19 次删除
  1. 7 17
      kernel/irq/irqdesc.c
  2. 3 2
      kernel/irq/msi.c

+ 7 - 17
kernel/irq/irqdesc.c

@@ -421,10 +421,8 @@ static void free_desc(unsigned int irq)
 	 * The sysfs entry must be serialized against a concurrent
 	 * The sysfs entry must be serialized against a concurrent
 	 * irq_sysfs_init() as well.
 	 * irq_sysfs_init() as well.
 	 */
 	 */
-	mutex_lock(&sparse_irq_lock);
 	kobject_del(&desc->kobj);
 	kobject_del(&desc->kobj);
 	delete_irq_desc(irq);
 	delete_irq_desc(irq);
-	mutex_unlock(&sparse_irq_lock);
 
 
 	/*
 	/*
 	 * We free the descriptor, masks and stat fields via RCU. That
 	 * We free the descriptor, masks and stat fields via RCU. That
@@ -462,20 +460,15 @@ static int alloc_descs(unsigned int start, unsigned int cnt, int node,
 		desc = alloc_desc(start + i, node, flags, mask, owner);
 		desc = alloc_desc(start + i, node, flags, mask, owner);
 		if (!desc)
 		if (!desc)
 			goto err;
 			goto err;
-		mutex_lock(&sparse_irq_lock);
 		irq_insert_desc(start + i, desc);
 		irq_insert_desc(start + i, desc);
 		irq_sysfs_add(start + i, desc);
 		irq_sysfs_add(start + i, desc);
-		mutex_unlock(&sparse_irq_lock);
 	}
 	}
+	bitmap_set(allocated_irqs, start, cnt);
 	return start;
 	return start;
 
 
 err:
 err:
 	for (i--; i >= 0; i--)
 	for (i--; i >= 0; i--)
 		free_desc(start + i);
 		free_desc(start + i);
-
-	mutex_lock(&sparse_irq_lock);
-	bitmap_clear(allocated_irqs, start, cnt);
-	mutex_unlock(&sparse_irq_lock);
 	return -ENOMEM;
 	return -ENOMEM;
 }
 }
 
 
@@ -575,6 +568,7 @@ static inline int alloc_descs(unsigned int start, unsigned int cnt, int node,
 
 
 		desc->owner = owner;
 		desc->owner = owner;
 	}
 	}
+	bitmap_set(allocated_irqs, start, cnt);
 	return start;
 	return start;
 }
 }
 
 
@@ -670,10 +664,10 @@ void irq_free_descs(unsigned int from, unsigned int cnt)
 	if (from >= nr_irqs || (from + cnt) > nr_irqs)
 	if (from >= nr_irqs || (from + cnt) > nr_irqs)
 		return;
 		return;
 
 
+	mutex_lock(&sparse_irq_lock);
 	for (i = 0; i < cnt; i++)
 	for (i = 0; i < cnt; i++)
 		free_desc(from + i);
 		free_desc(from + i);
 
 
-	mutex_lock(&sparse_irq_lock);
 	bitmap_clear(allocated_irqs, from, cnt);
 	bitmap_clear(allocated_irqs, from, cnt);
 	mutex_unlock(&sparse_irq_lock);
 	mutex_unlock(&sparse_irq_lock);
 }
 }
@@ -720,19 +714,15 @@ __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node,
 					   from, cnt, 0);
 					   from, cnt, 0);
 	ret = -EEXIST;
 	ret = -EEXIST;
 	if (irq >=0 && start != irq)
 	if (irq >=0 && start != irq)
-		goto err;
+		goto unlock;
 
 
 	if (start + cnt > nr_irqs) {
 	if (start + cnt > nr_irqs) {
 		ret = irq_expand_nr_irqs(start + cnt);
 		ret = irq_expand_nr_irqs(start + cnt);
 		if (ret)
 		if (ret)
-			goto err;
+			goto unlock;
 	}
 	}
-
-	bitmap_set(allocated_irqs, start, cnt);
-	mutex_unlock(&sparse_irq_lock);
-	return alloc_descs(start, cnt, node, affinity, owner);
-
-err:
+	ret = alloc_descs(start, cnt, node, affinity, owner);
+unlock:
 	mutex_unlock(&sparse_irq_lock);
 	mutex_unlock(&sparse_irq_lock);
 	return ret;
 	return ret;
 }
 }

+ 3 - 2
kernel/irq/msi.c

@@ -315,11 +315,12 @@ int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev,
 
 
 		ops->set_desc(arg, desc);
 		ops->set_desc(arg, desc);
 		/* Assumes the domain mutex is held! */
 		/* Assumes the domain mutex is held! */
-		ret = irq_domain_alloc_irqs_hierarchy(domain, virq, 1, arg);
+		ret = irq_domain_alloc_irqs_hierarchy(domain, desc->irq, 1,
+						      arg);
 		if (ret)
 		if (ret)
 			break;
 			break;
 
 
-		irq_set_msi_desc_off(virq, 0, desc);
+		irq_set_msi_desc_off(desc->irq, 0, desc);
 	}
 	}
 
 
 	if (ret) {
 	if (ret) {