From d7530a1e767b562c7e071f559d542c132d85fff7 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 3 Jul 2006 00:58:01 +0200 Subject: [PATCH] ieee1394: fix cosmetic problem in speed probe If ieee1394.h::IEEE1394_SPEED_MAX is bigger than the actual speed of an 1394b host adapter and the speed to another 1394b node was probed, a bigger speed than actually used was kept in host->speed[n]. The only resulting problem so far was sbp2 displaying bogus values in the syslog, e.g. S3200 for actual S800 connections if IEEE1394_SPEED_MAX was S3200. But other high-level drivers which access this field could get into more trouble. (Eth1394 is the only other in-tree driver which does so. It seems it is not affected.) Nodemgr now clips this value according to the host adapter's link speed. A pointer expression in nodemgr_check_speed is also changed for clarity. Signed-off-by: Stefan Richter Signed-off-by: Ben Collins --- drivers/ieee1394/nodemgr.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers/ieee1394/nodemgr.c') diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index d541b508a15..dfed2ed2ed9 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -71,7 +71,7 @@ static int nodemgr_check_speed(struct nodemgr_csr_info *ci, u64 addr, u8 i, *speed, old_speed, good_speed; int ret; - speed = ci->host->speed + NODEID_TO_NODE(ci->nodeid); + speed = &(ci->host->speed[NODEID_TO_NODE(ci->nodeid)]); old_speed = *speed; good_speed = IEEE1394_SPEED_MAX + 1; @@ -1251,6 +1251,7 @@ static void nodemgr_node_scan_one(struct host_info *hi, octlet_t guid; struct csr1212_csr *csr; struct nodemgr_csr_info *ci; + u8 *speed; ci = kmalloc(sizeof(*ci), GFP_KERNEL); if (!ci) @@ -1259,8 +1260,12 @@ static void nodemgr_node_scan_one(struct host_info *hi, ci->host = host; ci->nodeid = nodeid; ci->generation = generation; - ci->speed_unverified = - host->speed[NODEID_TO_NODE(nodeid)] > IEEE1394_SPEED_100; + + /* Prepare for speed probe which occurs when reading the ROM */ + speed = &(host->speed[NODEID_TO_NODE(nodeid)]); + if (*speed > host->csr.lnk_spd) + *speed = host->csr.lnk_spd; + ci->speed_unverified = *speed > IEEE1394_SPEED_100; /* We need to detect when the ConfigROM's generation has changed, * so we only update the node's info when it needs to be. */ @@ -1300,8 +1305,6 @@ static void nodemgr_node_scan_one(struct host_info *hi, nodemgr_create_node(guid, csr, hi, nodeid, generation); else nodemgr_update_node(ne, csr, hi, nodeid, generation); - - return; } -- cgit v1.2.3 From de4394f13cc843fae2a3ba2df752ee20e6e779a8 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 3 Jul 2006 12:02:29 -0400 Subject: [PATCH] ieee1394: update #include directives in midlayer header files Remove unnecessary includes, add missing includes. Use forward type declarations for some structs. Signed-off-by: Stefan Richter Signed-off-by: Ben Collins --- drivers/ieee1394/nodemgr.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/ieee1394/nodemgr.c') diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index dfed2ed2ed9..b873e5d5795 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -21,13 +21,14 @@ #include #include -#include "ieee1394_types.h" +#include "csr.h" +#include "highlevel.h" +#include "hosts.h" #include "ieee1394.h" #include "ieee1394_core.h" -#include "hosts.h" +#include "ieee1394_hotplug.h" +#include "ieee1394_types.h" #include "ieee1394_transactions.h" -#include "highlevel.h" -#include "csr.h" #include "nodemgr.h" static int ignore_drivers; -- cgit v1.2.3 From 1ee0dc51fb68d2d25888250c554492c4926c5ec1 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 3 Jul 2006 12:02:33 -0400 Subject: [PATCH] ieee1394: nodemgr: remove unnecessary includes Signed-off-by: Stefan Richter Signed-off-by: Ben Collins --- drivers/ieee1394/nodemgr.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/ieee1394/nodemgr.c') diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index b873e5d5795..bfab7933d68 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -12,12 +12,8 @@ #include #include #include -#include -#include -#include #include #include -#include #include #include -- cgit v1.2.3 From 40fd89cc54a8a67c81b5aa40b22c4f40b39e47b9 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 3 Jul 2006 12:02:34 -0400 Subject: [PATCH] ieee1394: nodemgr: do not spawn kernel_thread for sysfs rescan nodemgr.c::fw_set_rescan() is used to re-run the driver core over nodemgr's representation of unit directories in order to initiate protocol driver probes. It is initiated via write access to one of nodemgr's sysfs attributes. The purpose is to attach drivers to units after switching a unit's ignore_driver attribute from 1 to 0. It is not really necessary to fork a kernel_thread for this job. The call to kernel_thread() can be eliminated to avoid the deprecated API and to simplify the code a bit. Signed-off-by: Stefan Richter Signed-off-by: Ben Collins --- drivers/ieee1394/nodemgr.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers/ieee1394/nodemgr.c') diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index bfab7933d68..1ce3d8a14ae 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -405,26 +405,11 @@ static ssize_t fw_get_destroy_node(struct bus_type *bus, char *buf) } static BUS_ATTR(destroy_node, S_IWUSR | S_IRUGO, fw_get_destroy_node, fw_set_destroy_node); -static int nodemgr_rescan_bus_thread(void *__unused) -{ - /* No userlevel access needed */ - daemonize("kfwrescan"); - - bus_rescan_devices(&ieee1394_bus_type); - - return 0; -} static ssize_t fw_set_rescan(struct bus_type *bus, const char *buf, size_t count) { - int state = simple_strtoul(buf, NULL, 10); - - /* Don't wait for this, or care about errors. Root could do - * something stupid and spawn this a lot of times, but that's - * root's fault. */ - if (state == 1) - kernel_thread(nodemgr_rescan_bus_thread, NULL, CLONE_KERNEL); - + if (simple_strtoul(buf, NULL, 10) == 1) + bus_rescan_devices(&ieee1394_bus_type); return count; } static ssize_t fw_get_rescan(struct bus_type *bus, char *buf) -- cgit v1.2.3 From 3a632fe2321f6440ea8184b99549c74b912f5cef Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 3 Jul 2006 12:02:35 -0400 Subject: [PATCH] ieee1394: nodemgr: make module parameter ignore_drivers writable Nodemgr's ignore_drivers variable is exposed as a module load parameter (therefore also as a sysfs attribute below /sys/module) and additionally as an attribute below /sys/bus/ieee1394. Since the latter is writable, make the former writable too. Note, the bus's attribute ignore_drivers is only relevant to newly added units, not to present or suspended or resuming units. Those have their own attribute ignore_driver. Signed-off-by: Stefan Richter Signed-off-by: Ben Collins --- drivers/ieee1394/nodemgr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/ieee1394/nodemgr.c') diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 1ce3d8a14ae..04b62eca647 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -28,7 +28,7 @@ #include "nodemgr.h" static int ignore_drivers; -module_param(ignore_drivers, int, 0444); +module_param(ignore_drivers, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers."); struct nodemgr_csr_info { -- cgit v1.2.3 From d2f119fe319528da8c76a1107459d6f478cbf28c Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 3 Jul 2006 12:02:35 -0400 Subject: [PATCH] ieee1394: nodemgr: switch to kthread api, replace reset semaphore Convert nodemgr's host thread from kernel_thread to kthread and its sleep/restart mechanism from a counting semaphore to a schedule()/ wake_up_process() scheme. Signed-off-by: Stefan Richter Signed-off-by: Ben Collins --- drivers/ieee1394/nodemgr.c | 120 ++++++++++++++++----------------------------- 1 file changed, 41 insertions(+), 79 deletions(-) (limited to 'drivers/ieee1394/nodemgr.c') diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 04b62eca647..2e6dc5990ce 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -12,8 +12,8 @@ #include #include #include -#include #include +#include #include #include @@ -163,11 +163,7 @@ static DECLARE_MUTEX(nodemgr_serialize); struct host_info { struct hpsb_host *host; struct list_head list; - struct completion exited; - struct semaphore reset_sem; - int pid; - char daemon_name[15]; - int kill_me; + struct task_struct *thread; }; static int nodemgr_bus_match(struct device * dev, struct device_driver * drv); @@ -1477,9 +1473,8 @@ static void nodemgr_node_probe(struct host_info *hi, int generation) /* If we had a bus reset while we were scanning the bus, it is * possible that we did not probe all nodes. In that case, we * skip the clean up for now, since we could remove nodes that - * were still on the bus. The bus reset increased hi->reset_sem, - * so there's a bus scan pending which will do the clean up - * eventually. + * were still on the bus. Another bus scan is pending which will + * do the clean up eventually. * * Now let's tell the bus to rescan our devices. This may seem * like overhead, but the driver-model core will only scan a @@ -1607,41 +1602,37 @@ static int nodemgr_host_thread(void *__hi) { struct host_info *hi = (struct host_info *)__hi; struct hpsb_host *host = hi->host; - int reset_cycles = 0; - - /* No userlevel access needed */ - daemonize(hi->daemon_name); + unsigned int g, generation = get_hpsb_generation(host) - 1; + int i, reset_cycles = 0; /* Setup our device-model entries */ nodemgr_create_host_dev_files(host); - /* Sit and wait for a signal to probe the nodes on the bus. This - * happens when we get a bus reset. */ - while (1) { - unsigned int generation = 0; - int i; + for (;;) { + /* Sleep until next bus reset */ + set_current_state(TASK_INTERRUPTIBLE); + if (get_hpsb_generation(host) == generation) + schedule(); + __set_current_state(TASK_RUNNING); + + /* Thread may have been woken up to freeze or to exit */ + if (try_to_freeze()) + continue; + if (kthread_should_stop()) + goto exit; - if (down_interruptible(&hi->reset_sem) || - down_interruptible(&nodemgr_serialize)) { + if (down_interruptible(&nodemgr_serialize)) { if (try_to_freeze()) continue; - printk("NodeMgr: received unexpected signal?!\n" ); - break; - } - - if (hi->kill_me) { - up(&nodemgr_serialize); - break; + goto exit; } /* Pause for 1/4 second in 1/16 second intervals, * to make sure things settle down. */ + g = get_hpsb_generation(host); for (i = 0; i < 4 ; i++) { - set_current_state(TASK_INTERRUPTIBLE); - if (msleep_interruptible(63)) { - up(&nodemgr_serialize); - goto caught_signal; - } + if (msleep_interruptible(63) || kthread_should_stop()) + goto unlock_exit; /* Now get the generation in which the node ID's we collect * are valid. During the bus scan we will use this generation @@ -1652,14 +1643,8 @@ static int nodemgr_host_thread(void *__hi) /* If we get a reset before we are done waiting, then * start the the waiting over again */ - while (!down_trylock(&hi->reset_sem)) - i = 0; - - /* Check the kill_me again */ - if (hi->kill_me) { - up(&nodemgr_serialize); - goto caught_signal; - } + if (generation != g) + g = generation, i = 0; } if (!nodemgr_check_irm_capability(host, reset_cycles) || @@ -1685,11 +1670,11 @@ static int nodemgr_host_thread(void *__hi) up(&nodemgr_serialize); } - -caught_signal: +unlock_exit: + up(&nodemgr_serialize); +exit: HPSB_VERBOSE("NodeMgr: Exiting thread"); - - complete_and_exit(&hi->exited, 0); + return 0; } int nodemgr_for_each_host(void *__data, int (*cb)(struct hpsb_host *, void *)) @@ -1749,41 +1734,27 @@ static void nodemgr_add_host(struct hpsb_host *host) struct host_info *hi; hi = hpsb_create_hostinfo(&nodemgr_highlevel, host, sizeof(*hi)); - if (!hi) { - HPSB_ERR ("NodeMgr: out of memory in add host"); + HPSB_ERR("NodeMgr: out of memory in add host"); return; } - hi->host = host; - init_completion(&hi->exited); - sema_init(&hi->reset_sem, 0); - - sprintf(hi->daemon_name, "knodemgrd_%d", host->id); - - hi->pid = kernel_thread(nodemgr_host_thread, hi, CLONE_KERNEL); - - if (hi->pid < 0) { - HPSB_ERR ("NodeMgr: failed to start %s thread for %s", - hi->daemon_name, host->driver->name); + hi->thread = kthread_run(nodemgr_host_thread, hi, "knodemgrd_%d", + host->id); + if (IS_ERR(hi->thread)) { + HPSB_ERR("NodeMgr: cannot start thread for host %d", host->id); hpsb_destroy_hostinfo(&nodemgr_highlevel, host); - return; } - - return; } static void nodemgr_host_reset(struct hpsb_host *host) { struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); - if (hi != NULL) { - HPSB_VERBOSE("NodeMgr: Processing host reset for %s", hi->daemon_name); - up(&hi->reset_sem); - } else - HPSB_ERR ("NodeMgr: could not process reset of unused host"); - - return; + if (hi) { + HPSB_VERBOSE("NodeMgr: Processing reset for host %d", host->id); + wake_up_process(hi->thread); + } } static void nodemgr_remove_host(struct hpsb_host *host) @@ -1791,18 +1762,9 @@ static void nodemgr_remove_host(struct hpsb_host *host) struct host_info *hi = hpsb_get_hostinfo(&nodemgr_highlevel, host); if (hi) { - if (hi->pid >= 0) { - hi->kill_me = 1; - mb(); - up(&hi->reset_sem); - wait_for_completion(&hi->exited); - nodemgr_remove_host_dev(&host->device); - } - } else - HPSB_ERR("NodeMgr: host %s does not exist, cannot remove", - host->driver->name); - - return; + kthread_stop(hi->thread); + nodemgr_remove_host_dev(&host->device); + } } static struct hpsb_highlevel nodemgr_highlevel = { -- cgit v1.2.3 From cab8d154e2ed43fe1495aa0e18103e747552891b Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Mon, 3 Jul 2006 12:02:36 -0400 Subject: [PATCH] ieee1394: nodemgr: convert nodemgr_serialize semaphore to mutex Another trivial sem2mutex conversion. Side note: nodemgr_serialize's purpose, when introduced in linux1394's revision 529 in July 2002, was to protect several data structures which are now largely handled by or together with Linux' driver core and are now protected by the LDM's own mechanisms. It may very well be possible to remove this mutex now. But fully parallelized node scanning is on our long-term TODO list anyway; the mutex will certainly go away then. Signed-off-by: Stefan Richter Signed-off-by: Ben Collins --- drivers/ieee1394/nodemgr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/ieee1394/nodemgr.c') diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 2e6dc5990ce..f8f6079cc48 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -158,7 +158,7 @@ static struct csr1212_bus_ops nodemgr_csr_ops = { * but now we are much simpler because of the LDM. */ -static DECLARE_MUTEX(nodemgr_serialize); +static DEFINE_MUTEX(nodemgr_serialize); struct host_info { struct hpsb_host *host; @@ -1621,7 +1621,7 @@ static int nodemgr_host_thread(void *__hi) if (kthread_should_stop()) goto exit; - if (down_interruptible(&nodemgr_serialize)) { + if (mutex_lock_interruptible(&nodemgr_serialize)) { if (try_to_freeze()) continue; goto exit; @@ -1650,7 +1650,7 @@ static int nodemgr_host_thread(void *__hi) if (!nodemgr_check_irm_capability(host, reset_cycles) || !nodemgr_do_irm_duties(host, reset_cycles)) { reset_cycles++; - up(&nodemgr_serialize); + mutex_unlock(&nodemgr_serialize); continue; } reset_cycles = 0; @@ -1668,10 +1668,10 @@ static int nodemgr_host_thread(void *__hi) /* Update some of our sysfs symlinks */ nodemgr_update_host_dev_links(host); - up(&nodemgr_serialize); + mutex_unlock(&nodemgr_serialize); } unlock_exit: - up(&nodemgr_serialize); + mutex_unlock(&nodemgr_serialize); exit: HPSB_VERBOSE("NodeMgr: Exiting thread"); return 0; -- cgit v1.2.3 From 9951903e616662e9a5dad5fbd296690e2ebbbc65 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Sun, 2 Jul 2006 14:17:00 +0200 Subject: ieee1394: shrink tlabel pools, remove tpool semaphores This patch reduces the size of struct hpsb_host and also removes semaphores from ieee1394_transactions.c. On i386, struct hpsb_host shrinks from 10656 bytes to 6688 bytes. This is accomplished by - using a single wait_queue for hpsb_get_tlabel instead of many instances of semaphores, - using a single lock to serialize access to all tlabel pools (the protected code regions are small, i.e. lock contention very low), - omitting the sysfs attribute tlabels_allocations. Drawback: In the rare case that a process needs to sleep because all transaction labels for the node are temporarily exhausted, it is also woken up if a tlabel for a different node became free, checks for an available tlabel, and is put to sleep again. The check is not costly and the situation occurs extremely rarely. (Tlabels are typically only exhausted if there was no context switch to the khpsbpkt thread which recycles tlables.) Therefore the benefit of reduced tpool size outweighs this drawback. The sysfs attributes tlabels_free and tlabels_mask are not compiled anymore unless CONFIG_IEEE1394_VERBOSEDEBUG is set. The by far biggest member of struct hpsb_host, the struct csr_control csr (5272 bytes on i386), is now placed at the end of struct hpsb_host. Note, hpsb_get_tlabel calls the macro wait_event_interruptible with a condition argument which has a side effect (allocation of a tlabel and manipulation of the packet). This side effect happens only if the condition is true. The patch relies on wait_event_interruptible not evaluating the condition again after it became true. Signed-off-by: Stefan Richter --- drivers/ieee1394/nodemgr.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) (limited to 'drivers/ieee1394/nodemgr.c') diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index f8f6079cc48..eabc51b23c0 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -327,34 +327,44 @@ static ssize_t fw_show_ne_bus_options(struct device *dev, struct device_attribut static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL); -/* tlabels_free, tlabels_allocations, tlabels_mask are read non-atomically - * here, therefore displayed values may be occasionally wrong. */ -static ssize_t fw_show_ne_tlabels_free(struct device *dev, struct device_attribute *attr, char *buf) +#ifdef HPSB_DEBUG_TLABELS +static ssize_t fw_show_ne_tlabels_free(struct device *dev, + struct device_attribute *attr, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); - return sprintf(buf, "%d\n", 64 - bitmap_weight(ne->tpool->pool, 64)); -} -static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL); + unsigned long flags; + unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map; + int tf; + spin_lock_irqsave(&hpsb_tlabel_lock, flags); + tf = 64 - bitmap_weight(tp, 64); + spin_unlock_irqrestore(&hpsb_tlabel_lock, flags); -static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct node_entry *ne = container_of(dev, struct node_entry, device); - return sprintf(buf, "%u\n", ne->tpool->allocations); + return sprintf(buf, "%d\n", tf); } -static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL); +static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL); -static ssize_t fw_show_ne_tlabels_mask(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t fw_show_ne_tlabels_mask(struct device *dev, + struct device_attribute *attr, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); + unsigned long flags; + unsigned long *tp = ne->host->tl_pool[NODEID_TO_NODE(ne->nodeid)].map; + u64 tm; + + spin_lock_irqsave(&hpsb_tlabel_lock, flags); #if (BITS_PER_LONG <= 32) - return sprintf(buf, "0x%08lx%08lx\n", ne->tpool->pool[0], ne->tpool->pool[1]); + tm = ((u64)tp[0] << 32) + tp[1]; #else - return sprintf(buf, "0x%016lx\n", ne->tpool->pool[0]); + tm = tp[0]; #endif + spin_unlock_irqrestore(&hpsb_tlabel_lock, flags); + + return sprintf(buf, "0x%016llx\n", tm); } static DEVICE_ATTR(tlabels_mask, S_IRUGO, fw_show_ne_tlabels_mask, NULL); +#endif /* HPSB_DEBUG_TLABELS */ static ssize_t fw_set_ignore_driver(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) @@ -461,9 +471,10 @@ static struct device_attribute *const fw_ne_attrs[] = { &dev_attr_ne_vendor_id, &dev_attr_ne_nodeid, &dev_attr_bus_options, +#ifdef HPSB_DEBUG_TLABELS &dev_attr_tlabels_free, - &dev_attr_tlabels_allocations, &dev_attr_tlabels_mask, +#endif }; @@ -782,8 +793,6 @@ static struct node_entry *nodemgr_create_node(octlet_t guid, struct csr1212_csr if (!ne) return NULL; - ne->tpool = &host->tpool[nodeid & NODE_MASK]; - ne->host = host; ne->nodeid = nodeid; ne->generation = generation; -- cgit v1.2.3 From 9b516010863195ba7db061233a3eeffe779130e8 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Wed, 6 Sep 2006 19:04:00 +0200 Subject: ieee1394: nodemgr: fix rwsem recursion nodemgr_update_pdrv grabbed an rw semaphore (as reader) which was already taken by its caller's caller, nodemgr_probe_ne (as reader too). Reported by Miles Lane, call path pointed out by Arjan van de Ven. FIXME: Shouldn't we rather use class->sem there, not class->subsys.rwsem? Signed-off-by: Stefan Richter --- drivers/ieee1394/nodemgr.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/ieee1394/nodemgr.c') diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index eabc51b23c0..f087f7e2b69 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1316,6 +1316,7 @@ static void nodemgr_node_scan(struct host_info *hi, int generation) } +/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader. */ static void nodemgr_suspend_ne(struct node_entry *ne) { struct class_device *cdev; @@ -1368,15 +1369,14 @@ static void nodemgr_resume_ne(struct node_entry *ne) } +/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader. */ static void nodemgr_update_pdrv(struct node_entry *ne) { struct unit_directory *ud; struct hpsb_protocol_driver *pdrv; - struct class *class = &nodemgr_ud_class; struct class_device *cdev; - down_read(&class->subsys.rwsem); - list_for_each_entry(cdev, &class->children, node) { + list_for_each_entry(cdev, &nodemgr_ud_class.children, node) { ud = container_of(cdev, struct unit_directory, class_dev); if (ud->ne != ne || !ud->device.driver) continue; @@ -1389,7 +1389,6 @@ static void nodemgr_update_pdrv(struct node_entry *ne) up_write(&ud->device.bus->subsys.rwsem); } } - up_read(&class->subsys.rwsem); } @@ -1420,6 +1419,8 @@ static void nodemgr_irm_write_bc(struct node_entry *ne, int generation) } +/* Caller needs to hold nodemgr_ud_class.subsys.rwsem as reader because the + * calls to nodemgr_update_pdrv() and nodemgr_suspend_ne() here require it. */ static void nodemgr_probe_ne(struct host_info *hi, struct node_entry *ne, int generation) { struct device *dev; -- cgit v1.2.3 From a1842be898a2295ef513ed0a5d26f65d6283cb11 Mon Sep 17 00:00:00 2001 From: Stefan Richter Date: Wed, 6 Sep 2006 19:04:00 +0200 Subject: ieee1394: nodemgr: grab class.subsys.rwsem in nodemgr_resume_ne nodemgr_resume_ne was iterating over nodemgr_ud_class.children without protection by nodemgr_ud_class.subsys.rwsem. FIXME: Shouldn't we rather use class->sem there, not class->subsys.rwsem? Signed-off-by: Stefan Richter --- drivers/ieee1394/nodemgr.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/ieee1394/nodemgr.c') diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index f087f7e2b69..3e7974c5744 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1352,6 +1352,7 @@ static void nodemgr_resume_ne(struct node_entry *ne) ne->in_limbo = 0; device_remove_file(&ne->device, &dev_attr_ne_in_limbo); + down_read(&nodemgr_ud_class.subsys.rwsem); down_read(&ne->device.bus->subsys.rwsem); list_for_each_entry(cdev, &nodemgr_ud_class.children, node) { ud = container_of(cdev, struct unit_directory, class_dev); @@ -1363,6 +1364,7 @@ static void nodemgr_resume_ne(struct node_entry *ne) ud->device.driver->resume(&ud->device); } up_read(&ne->device.bus->subsys.rwsem); + up_read(&nodemgr_ud_class.subsys.rwsem); HPSB_DEBUG("Node resumed: ID:BUS[" NODE_BUS_FMT "] GUID[%016Lx]", NODE_BUS_ARGS(ne->host, ne->nodeid), (unsigned long long)ne->guid); -- cgit v1.2.3