[PATCH] Linux1394 (r893)

From: Ben Collins (bcollins@debian.org)
Date: Sun Apr 20 2003 - 00:53:18 EST


SMP folks will hate me for this one. This fixes a deadlock during
add_host.

Index: drivers/ieee1394/highlevel.c
===================================================================
--- linux/drivers/ieee1394/highlevel.c (revision 893)
+++ linux/drivers/ieee1394/highlevel.c (working copy)
@@ -48,20 +48,22 @@
 static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr;
 
 
-/* Internal usage. Must be called with hl_drivers_lock held */
 static struct hl_host_info *hl_get_hostinfo(struct hpsb_highlevel *hl,
                                               struct hpsb_host *host)
 {
- struct hl_host_info *hi;
+ struct hl_host_info *hi = NULL;
         struct list_head *lh;
 
+ read_lock(&hl->host_info_lock);
         list_for_each (lh, &hl->host_info_list) {
                 hi = list_entry(lh, struct hl_host_info, list);
                 if (hi->host == host)
- return hi;
+ break;
+ hi = NULL;
         }
+ read_unlock(&hl->host_info_lock);
 
- return NULL;
+ return hi;
 }
 
 
@@ -69,16 +71,12 @@
  * hpsb_create_hostinfo. */
 void *hpsb_get_hostinfo(struct hpsb_highlevel *hl, struct hpsb_host *host)
 {
- struct hl_host_info *hi;
- void *data = NULL;
+ struct hl_host_info *hi = hl_get_hostinfo(hl, host);
 
- read_lock(&hl_drivers_lock);
- hi = hl_get_hostinfo(hl, host);
         if (hi)
- data = hi->data;
- read_unlock(&hl_drivers_lock);
+ return hi->data;
 
- return data;
+ return NULL;
 }
 
 
@@ -88,10 +86,9 @@
 {
         struct hl_host_info *hi;
         void *data;
+ unsigned long flags;
 
- read_lock(&hl_drivers_lock);
         hi = hl_get_hostinfo(hl, host);
- read_unlock(&hl_drivers_lock);
         if (hi) {
                 HPSB_ERR("%s called hpsb_create_hostinfo when hostinfo already exists",
                          hl->name);
@@ -112,9 +109,9 @@
 
         hi->host = host;
 
- write_lock_irq(&hl_drivers_lock);
+ write_lock_irqsave(&hl->host_info_lock, flags);
         list_add_tail(&hi->list, &hl->host_info_list);
- write_unlock_irq(&hl_drivers_lock);
+ write_unlock_irqrestore(&hl->host_info_lock, flags);
 
         return data;
 }
@@ -124,23 +121,20 @@
                       void *data)
 {
         struct hl_host_info *hi;
- int ret = -EINVAL;
 
- write_lock_irq(&hl_drivers_lock);
         hi = hl_get_hostinfo(hl, host);
         if (hi) {
                 if (!hi->size && !hi->data) {
                         hi->data = data;
- ret = 0;
+ return 0;
                 } else
                         HPSB_ERR("%s called hpsb_set_hostinfo when hostinfo already has data",
                                  hl->name);
         } else
                 HPSB_ERR("%s called hpsb_set_hostinfo when no hostinfo exists",
                          hl->name);
- write_unlock_irq(&hl_drivers_lock);
 
- return ret;
+ return -EINVAL;
 }
 
 
@@ -148,13 +142,14 @@
 {
         struct hl_host_info *hi;
 
- write_lock_irq(&hl_drivers_lock);
         hi = hl_get_hostinfo(hl, host);
         if (hi) {
+ unsigned long flags;
+ write_lock_irqsave(&hl->host_info_lock, flags);
                 list_del(&hi->list);
+ write_unlock_irqrestore(&hl->host_info_lock, flags);
                 kfree(hi);
         }
- write_unlock_irq(&hl_drivers_lock);
 
         return;
 }
@@ -164,11 +159,9 @@
 {
         struct hl_host_info *hi;
 
- write_lock(&hl_drivers_lock);
         hi = hl_get_hostinfo(hl, host);
         if (hi)
                 hi->key = key;
- write_unlock(&hl_drivers_lock);
 
         return;
 }
@@ -177,15 +170,12 @@
 unsigned long hpsb_get_hostinfo_key(struct hpsb_highlevel *hl, struct hpsb_host *host)
 {
         struct hl_host_info *hi;
- unsigned long key = 0;
 
- read_lock(&hl_drivers_lock);
         hi = hl_get_hostinfo(hl, host);
         if (hi)
- key = hi->key;
- read_unlock(&hl_drivers_lock);
+ return hi->key;
 
- return key;
+ return 0;
 }
 
 
@@ -195,7 +185,7 @@
         struct hl_host_info *hi;
         void *data = NULL;
 
- read_lock(&hl_drivers_lock);
+ read_lock(&hl->host_info_lock);
         list_for_each (lh, &hl->host_info_list) {
                 hi = list_entry(lh, struct hl_host_info, list);
                 if (hi->key == key) {
@@ -203,7 +193,7 @@
                         break;
                 }
         }
- read_unlock(&hl_drivers_lock);
+ read_unlock(&hl->host_info_lock);
 
         return data;
 }
@@ -225,6 +215,8 @@
         INIT_LIST_HEAD(&hl->addr_list);
         INIT_LIST_HEAD(&hl->host_info_list);
 
+ rwlock_init(&hl->host_info_lock);
+
         hl->name = name;
         hl->op = ops;
 
Index: drivers/ieee1394/highlevel.h
===================================================================
--- linux/drivers/ieee1394/highlevel.h (revision 893)
+++ linux/drivers/ieee1394/highlevel.h (working copy)
@@ -14,6 +14,7 @@
 
         /* Used by the highlevel drivers to store data per host */
         struct list_head host_info_list;
+ rwlock_t host_info_lock;
 };
 
 
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed Apr 23 2003 - 22:00:26 EST