linux-hotplug.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: john stultz <johnstul@us.ibm.com>
To: linux-hotplug@vger.kernel.org
Subject: Re: [PATCH] PCI device list locking
Date: Tue, 05 Mar 2002 01:47:21 +0000	[thread overview]
Message-ID: <marc-linux-hotplug-101529352513722@msgid-missing> (raw)
In-Reply-To: <marc-linux-hotplug-101528672932410@msgid-missing>

[-- Attachment #1: Type: text/plain, Size: 635 bytes --]

On Mon, 2002-03-04 at 17:12, Craig Christophel wrote:
> Also if there is only infrequent useage of the list to change the list, 
> perhaps you should use a rwlock_t instead.   It's just as light as a spinlock 
> but has the advantage of allowing multiple readers.

How about rwsem? See attached.

I think I did this properly, but there may be a few boo-boos. 

particularly:
o pci_proc_attach_device()
o pdev_enable_device()
o pdev_fixup_irq()

look like reader safe to me, but I could be wrong. 

and 
o pci_fixup_device()
o pci_announce_device

are writers, as I'm not sure what drv->probe or fixup->hook are doing.


thanks,
-john


[-- Attachment #2: pcidevlist_lock.patch --]
[-- Type: text/plain, Size: 7804 bytes --]

Index: linux24/drivers/pci/pci.c
diff -u linux24/drivers/pci/pci.c:1.1.1.1 linux24/drivers/pci/pci.c:1.1.1.1.28.23
--- linux24/drivers/pci/pci.c:1.1.1.1	Tue Dec 18 15:49:16 2001
+++ linux24/drivers/pci/pci.c	Mon Mar  4 17:46:15 2002
@@ -37,6 +37,7 @@
 
 LIST_HEAD(pci_root_buses);
 LIST_HEAD(pci_devices);
+DECLARE_RWSEM(pcidevlist_sem);
 
 /**
  * pci_find_slot - locate PCI device from a given PCI slot
@@ -55,10 +56,14 @@
 {
 	struct pci_dev *dev;
 
+	down_read(&pcidevlist_sem);
 	pci_for_each_dev(dev) {
-		if (dev->bus->number == bus && dev->devfn == devfn)
+		if (dev->bus->number == bus && dev->devfn == devfn){
+			up_read(&pcidevlist_sem);
 			return dev;
+		}
 	}
+	up_read(&pcidevlist_sem);
 	return NULL;
 }
 
@@ -81,17 +86,23 @@
 		unsigned int ss_vendor, unsigned int ss_device,
 		const struct pci_dev *from)
 {
-	struct list_head *n = from ? from->global_list.next : pci_devices.next;
+	struct list_head *n;
+	
+	down_read(&pcidevlist_sem);
+	n = from ? from->global_list.next : pci_devices.next;
 
 	while (n != &pci_devices) {
 		struct pci_dev *dev = pci_dev_g(n);
 		if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
 		    (device == PCI_ANY_ID || dev->device == device) &&
 		    (ss_vendor == PCI_ANY_ID || dev->subsystem_vendor == ss_vendor) &&
-		    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device))
+		    (ss_device == PCI_ANY_ID || dev->subsystem_device == ss_device)){
+			up_read(&pcidevlist_sem);
 			return dev;
+		}
 		n = n->next;
 	}
+	up_read(&pcidevlist_sem);
 	return NULL;
 }
 
@@ -130,14 +141,19 @@
 struct pci_dev *
 pci_find_class(unsigned int class, const struct pci_dev *from)
 {
-	struct list_head *n = from ? from->global_list.next : pci_devices.next;
+	struct list_head *n;
 
+	down_read(&pcidevlist_sem);
+	n = from ? from->global_list.next : pci_devices.next;
 	while (n != &pci_devices) {
 		struct pci_dev *dev = pci_dev_g(n);
-		if (dev->class == class)
+		if (dev->class == class){
+			up_read(&pcidevlist_sem);
 			return dev;
+		}
 		n = n->next;
 	}
+	up_read(&pcidevlist_sem);
 	return NULL;
 }
 
@@ -605,10 +621,12 @@
 	int count = 0;
 
 	list_add_tail(&drv->node, &pci_drivers);
+	down_write(&pcidevlist_sem); /* XXX: unsure of what dev->probe will do*/
 	pci_for_each_dev(dev) {
 		if (!pci_dev_driver(dev))
 			count += pci_announce_device(drv, dev);
 	}
+	up_write(&pcidevlist_sem);
 	return count;
 }
 
@@ -628,6 +646,7 @@
 	struct pci_dev *dev;
 
 	list_del(&drv->node);
+	down_write(&pcidevlist_sem);
 	pci_for_each_dev(dev) {
 		if (dev->driver == drv) {
 			if (drv->remove)
@@ -635,6 +654,7 @@
 			dev->driver = NULL;
 		}
 	}
+	up_write(&pcidevlist_sem);
 }
 
 #ifdef CONFIG_HOTPLUG
@@ -716,7 +736,9 @@
 pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
 {
 	list_add_tail(&dev->bus_list, &bus->devices);
+	down_write(&pcidevlist_sem);
 	list_add_tail(&dev->global_list, &pci_devices);
+	up_write(&pcidevlist_sem);
 #ifdef CONFIG_PROC_FS
 	pci_proc_attach_device(dev);
 #endif
@@ -751,7 +773,9 @@
 		dev->driver = NULL;
 	}
 	list_del(&dev->bus_list);
+	down_write(&pcidevlist_sem); 
 	list_del(&dev->global_list);
+	up_write(&pcidevlist_sem);
 	pci_free_resources(dev);
 #ifdef CONFIG_PROC_FS
 	pci_proc_detach_device(dev);
@@ -1327,7 +1351,9 @@
 		 * Link the device to both the global PCI device chain and
 		 * the per-bus list of devices.
 		 */
+		down_write(&pcidevlist_sem);
 		list_add_tail(&dev->global_list, &pci_devices);
+		up_write(&pcidevlist_sem);
 		list_add_tail(&dev->bus_list, &bus->devices);
 
 		/* Fix up broken headers */
@@ -1935,9 +1961,11 @@
 
 	pcibios_init();
 
+	down_write(&pcidevlist_sem); /*XXX: unsure what fixup->hook will do*/
 	pci_for_each_dev(dev) {
 		pci_fixup_device(PCI_FIXUP_FINAL, dev);
 	}
+	up_write(&pcidevlist_sem);
 
 #ifdef CONFIG_PM
 	pm_register(PM_PCI_DEV, 0, pci_pm_callback);
Index: linux24/drivers/pci/proc.c
diff -u linux24/drivers/pci/proc.c:1.1.1.1 linux24/drivers/pci/proc.c:1.1.1.1.28.5
--- linux24/drivers/pci/proc.c:1.1.1.1	Tue Dec 18 15:49:16 2001
+++ linux24/drivers/pci/proc.c	Mon Mar  4 17:43:22 2002
@@ -306,17 +306,26 @@
 /* iterator */
 static void *pci_seq_start(struct seq_file *m, loff_t *pos)
 {
-	struct list_head *p = &pci_devices;
-	loff_t n = *pos;
-
-	/* XXX: surely we need some locking for traversing the list? */
+	struct list_head *p;
+	loff_t n;
+	down_read(&pcidevlist_sem);
+	p = &pci_devices;
+	n = *pos;
 	while (n--) {
 		p = p->next;
-		if (p == &pci_devices)
+		if (p == &pci_devices){
+			up_read(&pcidevlist_sem);
 			return NULL;
+		}
 	}
+	up_read(&pcidevlist_sem);
 	return p;
 }
+
+/*
+XXX: pci_seq_next() doesn't use pcidevlist_sem, make sure 
+you down it before calling. (Currently unused?)
+*/
 static void *pci_seq_next(struct seq_file *m, void *v, loff_t *pos)
 {
 	struct list_head *p = v;
@@ -559,9 +568,11 @@
 		entry = create_proc_entry("devices", 0, proc_bus_pci_dir);
 		if (entry)
 			entry->proc_fops = &proc_bus_pci_dev_operations;
+		down_read(&pcidevlist_sem);
 		pci_for_each_dev(dev) {
 			pci_proc_attach_device(dev);
 		}
+		up_read(&pcidevlist_sem); 
 		entry = create_proc_entry("pci", 0, NULL);
 		if (entry)
 			entry->proc_fops = &proc_pci_operations;
Index: linux24/drivers/pci/setup-bus.c
diff -u linux24/drivers/pci/setup-bus.c:1.1.1.1 linux24/drivers/pci/setup-bus.c:1.1.1.1.28.6
--- linux24/drivers/pci/setup-bus.c:1.1.1.1	Tue Dec 18 15:49:16 2001
+++ linux24/drivers/pci/setup-bus.c	Mon Mar  4 17:43:22 2002
@@ -222,9 +222,11 @@
 		ranges.found_vga = 0;
 		pbus_assign_resources(b, &ranges);
 	}
+	down_read(&pcidevlist_sem); 
 	pci_for_each_dev(dev) {
 		pdev_enable_device(dev);
 	}
+	up_read(&pcidevlist_sem); 
 }
 
 /* Check whether the bridge supports I/O forwarding.
Index: linux24/drivers/pci/setup-irq.c
diff -u linux24/drivers/pci/setup-irq.c:1.1.1.1 linux24/drivers/pci/setup-irq.c:1.1.1.1.28.4
--- linux24/drivers/pci/setup-irq.c:1.1.1.1	Tue Dec 18 15:49:16 2001
+++ linux24/drivers/pci/setup-irq.c	Mon Mar  4 17:45:13 2002
@@ -65,7 +65,9 @@
 	       int (*map_irq)(struct pci_dev *, u8, u8))
 {
 	struct pci_dev *dev;
+	down_read(&pcidevlist_sem);
 	pci_for_each_dev(dev) {
 		pdev_fixup_irq(dev, swizzle, map_irq);
 	}
+	up_read(&pcidevlist_sem);
 }
Index: linux24/drivers/pnp/isapnp.c
diff -u linux24/drivers/pnp/isapnp.c:1.1.1.2 linux24/drivers/pnp/isapnp.c:1.1.1.2.2.5
--- linux24/drivers/pnp/isapnp.c:1.1.1.2	Wed Feb 13 14:53:31 2002
+++ linux24/drivers/pnp/isapnp.c	Mon Mar  4 17:31:15 2002
@@ -1685,10 +1685,14 @@
 	}
 #ifdef CONFIG_PCI
 	if (!isapnp_skip_pci_scan) {
+		down_read(&pcidevlist_sem);
 		pci_for_each_dev(dev) {
-			if (dev->irq == irq)
+			if (dev->irq == irq){
+				up_read(&pcidevlist_sem);
 				return 1;
+			}
 		}
+		up_read(&pcidevlist_sem);
 	}
 #endif
 	if (request_irq(irq, isapnp_test_handler, SA_INTERRUPT, "isapnp", NULL))
Index: linux24/include/linux/pci.h
diff -u linux24/include/linux/pci.h:1.1.1.1 linux24/include/linux/pci.h:1.1.1.1.28.10
--- linux24/include/linux/pci.h:1.1.1.1	Tue Dec 18 15:49:00 2001
+++ linux24/include/linux/pci.h	Mon Mar  4 17:31:15 2002
@@ -16,7 +16,7 @@
 
 #ifndef LINUX_PCI_H
 #define LINUX_PCI_H
-
+#include <linux/rwsem.h>
 /*
  * Under PCI, each device has 256 bytes of configuration address space,
  * of which the first 64 bytes are standardized as follows:
@@ -435,6 +435,7 @@
 
 extern struct list_head pci_root_buses;	/* list of all known PCI buses */
 extern struct list_head pci_devices;	/* list of all devices */
+extern struct rw_semaphore pcidevlist_sem;
 
 /*
  * Error values that may be returned by PCI functions.

  parent reply	other threads:[~2002-03-05  1:47 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2002-03-04 23:54 [PATCH] PCI device list locking john stultz
2002-03-05  0:17 ` Greg KH
2002-03-05  1:05 ` john stultz
2002-03-05  1:12 ` Craig Christophel
2002-03-05  1:47 ` john stultz [this message]
2002-03-06  1:31 ` Martin Diehl
2002-03-10 12:07 ` Martin Mares

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=marc-linux-hotplug-101529352513722@msgid-missing \
    --to=johnstul@us.ibm.com \
    --cc=linux-hotplug@vger.kernel.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).