netdev
[Top] [All Lists]

[PATCH 2.6.8-rc3-mm1 1/1] via-velocity: more inetaddr_notifier fix

To: Alan Cox <alan@xxxxxxxxxx>
Subject: [PATCH 2.6.8-rc3-mm1 1/1] via-velocity: more inetaddr_notifier fix
From: Francois Romieu <romieu@xxxxxxxxxxxxx>
Date: Fri, 6 Aug 2004 00:01:37 +0200
Cc: Jeff Garzik <jgarzik@xxxxxxxxx>, Andrew Morton <akpm@xxxxxxxx>, Ferenc Kubinszky <ferenc.kubinszky@xxxxxxxxxxxxxx>, Kazutoshi Morioka <morioka@xxxxxxxxxxxxx>, netdev@xxxxxxxxxxx
Sender: netdev-bounce@xxxxxxxxxxx
User-agent: Mutt/1.2.5.1i
There is no guarantee that the event which gets passed is associated to
a via-velocity device, thus preventing to dereference dev->priv as if it
always was a struct velocity_info *.
The via-velocity devices are kept in a module private list for comparison.

Signed-off-by: Francois Romieu <romieu@xxxxxxxxxxxxx>

diff -puN drivers/net/via-velocity.c~via-velocity-wol-strangeness 
drivers/net/via-velocity.c
--- linux-2.6.8-rc3/drivers/net/via-velocity.c~via-velocity-wol-strangeness     
2004-08-05 23:47:54.000000000 +0200
+++ linux-2.6.8-rc3-romieu/drivers/net/via-velocity.c   2004-08-05 
23:47:54.000000000 +0200
@@ -262,6 +262,7 @@ static u32 check_connection_type(struct 
 static int velocity_set_media_mode(struct velocity_info *vptr, u32 mii_status);
 
 #ifdef CONFIG_PM
+
 static int velocity_suspend(struct pci_dev *pdev, u32 state);
 static int velocity_resume(struct pci_dev *pdev);
 
@@ -270,9 +271,26 @@ static int velocity_netdev_event(struct 
 static struct notifier_block velocity_inetaddr_notifier = {
       .notifier_call   = velocity_netdev_event,
 };
-static int velocity_notifier_registered;
 
-#endif                         /* CONFIG_PM */
+static spinlock_t velocity_dev_list_lock = SPIN_LOCK_UNLOCKED;
+static LIST_HEAD(velocity_dev_list);
+
+static void velocity_register_notifier(void)
+{
+       register_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
+
+static void velocity_unregister_notifier(void)
+{
+       unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
+}
+
+#else                          /* CONFIG_PM */
+
+#define velocity_register_notifier()   do {} while (0)
+#define velocity_unregister_notifier() do {} while (0)
+
+#endif                         /* !CONFIG_PM */
 
 /*
  *     Internal board variants. At the moment we have only one
@@ -327,6 +345,14 @@ static void __devexit velocity_remove1(s
        struct net_device *dev = pci_get_drvdata(pdev);
        struct velocity_info *vptr = dev->priv;
 
+#ifdef CONFIG_PM
+       unsigned long flags;
+
+       spin_lock_irqsave(&velocity_dev_list_lock, flags);
+       if (!list_empty(&velocity_dev_list))
+               list_del(&vptr->list);
+       spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
+#endif
        unregister_netdev(dev);
        iounmap(vptr->mac_regs);
        pci_release_regions(pdev);
@@ -782,13 +808,16 @@ static int __devinit velocity_found1(str
        /* and leave the chip powered down */
        
        pci_set_power_state(pdev, 3);
-out:
 #ifdef CONFIG_PM
-       if (ret == 0 && !velocity_notifier_registered) {
-               velocity_notifier_registered = 1;
-               register_inetaddr_notifier(&velocity_inetaddr_notifier);
+       {
+               unsigned long flags;
+
+               spin_lock_irqsave(&velocity_dev_list_lock, flags);
+               list_add(&vptr->list, &velocity_dev_list);
+               spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
        }
 #endif
+out:
        return ret;
 
 err_iounmap:
@@ -843,6 +872,8 @@ static void __devinit velocity_init_info
 
        spin_lock_init(&vptr->lock);
        spin_lock_init(&vptr->xmit_lock);
+
+       INIT_LIST_HEAD(&vptr->list);
 }
 
 /**
@@ -2211,8 +2242,11 @@ static struct pci_driver velocity_driver
 static int __init velocity_init_module(void)
 {
        int ret;
-       ret = pci_module_init(&velocity_driver);
 
+       velocity_register_notifier();
+       ret = pci_module_init(&velocity_driver);
+       if (ret < 0)
+               velocity_unregister_notifier();
        return ret;
 }
 
@@ -2227,12 +2261,7 @@ static int __init velocity_init_module(v
  
 static void __exit velocity_cleanup_module(void)
 {
-#ifdef CONFIG_PM
-       if (velocity_notifier_registered) {
-               unregister_inetaddr_notifier(&velocity_inetaddr_notifier);
-               velocity_notifier_registered = 0;
-       }
-#endif
+       velocity_unregister_notifier();
        pci_unregister_driver(&velocity_driver);
 }
 
@@ -3252,13 +3281,20 @@ static int velocity_resume(struct pci_de
 static int velocity_netdev_event(struct notifier_block *nb, unsigned long 
notification, void *ptr)
 {
        struct in_ifaddr *ifa = (struct in_ifaddr *) ptr;
-       struct net_device *dev;
-       struct velocity_info *vptr;
 
        if (ifa) {
-               dev = ifa->ifa_dev->dev;
-               vptr = dev->priv;
-               velocity_get_ip(vptr);
+               struct net_device *dev = ifa->ifa_dev->dev;
+               struct velocity_info *vptr;
+               unsigned long flags;
+
+               spin_lock_irqsave(&velocity_dev_list_lock, flags);
+               list_for_each_entry(vptr, &velocity_dev_list, list) {
+                       if (vptr->dev == dev) {
+                               velocity_get_ip(vptr);
+                               break;
+                       }
+               }
+               spin_unlock_irqrestore(&velocity_dev_list_lock, flags);
        }
        return NOTIFY_DONE;
 }
diff -puN drivers/net/via-velocity.h~via-velocity-wol-strangeness 
drivers/net/via-velocity.h
--- linux-2.6.8-rc3/drivers/net/via-velocity.h~via-velocity-wol-strangeness     
2004-08-05 23:47:54.000000000 +0200
+++ linux-2.6.8-rc3-romieu/drivers/net/via-velocity.h   2004-08-05 
23:47:54.000000000 +0200
@@ -1733,8 +1733,7 @@ struct velocity_opt {
 };
 
 struct velocity_info {
-       struct velocity_info *next;
-       struct velocity_info *prev;
+       struct list_head list;
 
        struct pci_dev *pdev;
        struct net_device *dev;

_

<Prev in Thread] Current Thread [Next in Thread>
  • [PATCH 2.6.8-rc3-mm1 1/1] via-velocity: more inetaddr_notifier fix, Francois Romieu <=