/*-------------------------------- Monitoring -------------------------------*/
 
 /* this function is called regularly to monitor each slave's link. */
-void bond_mii_monitor(struct net_device *bond_dev)
+void bond_mii_monitor(struct work_struct *work)
 {
-       struct bonding *bond = bond_dev->priv;
+       struct bonding *bond = container_of(work, struct bonding,
+                                           mii_work.work);
        struct slave *slave, *oldcurrent;
        int do_failover = 0;
        int delta_in_ticks;
                                               ": %s: link status down for %s "
                                               "interface %s, disabling it in "
                                               "%d ms.\n",
-                                              bond_dev->name,
+                                              bond->dev->name,
                                               IS_UP(slave_dev)
                                               ? ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
                                                  ? ((slave == oldcurrent)
                                               ": %s: link status definitely "
                                               "down for interface %s, "
                                               "disabling it\n",
-                                              bond_dev->name,
+                                              bond->dev->name,
                                               slave_dev->name);
 
                                        /* notify ad that the link status has changed */
                                printk(KERN_INFO DRV_NAME
                                       ": %s: link status up again after %d "
                                       "ms for interface %s.\n",
-                                      bond_dev->name,
+                                      bond->dev->name,
                                       (bond->params.downdelay - slave->delay) * bond->params.miimon,
                                       slave_dev->name);
                        }
                                               ": %s: link status up for "
                                               "interface %s, enabling it "
                                               "in %d ms.\n",
-                                              bond_dev->name,
+                                              bond->dev->name,
                                               slave_dev->name,
                                               bond->params.updelay * bond->params.miimon);
                                }
                                printk(KERN_INFO DRV_NAME
                                       ": %s: link status down again after %d "
                                       "ms for interface %s.\n",
-                                      bond_dev->name,
+                                      bond->dev->name,
                                       (bond->params.updelay - slave->delay) * bond->params.miimon,
                                       slave_dev->name);
                        } else {
                                        printk(KERN_INFO DRV_NAME
                                               ": %s: link status definitely "
                                               "up for interface %s.\n",
-                                              bond_dev->name,
+                                              bond->dev->name,
                                               slave_dev->name);
 
                                        /* notify ad that the link status has changed */
                        /* Should not happen */
                        printk(KERN_ERR DRV_NAME
                               ": %s: Error: %s Illegal value (link=%d)\n",
-                              bond_dev->name,
+                              bond->dev->name,
                               slave->dev->name,
                               slave->link);
                        goto out;
                bond_set_carrier(bond);
 
 re_arm:
-       if (bond->params.miimon) {
-               mod_timer(&bond->mii_timer, jiffies + delta_in_ticks);
-       }
+       if (bond->params.miimon)
+               queue_delayed_work(bond->wq, &bond->mii_work, delta_in_ticks);
 out:
        read_unlock(&bond->lock);
 }
  * arp is transmitted to generate traffic. see activebackup_arp_monitor for
  * arp monitoring in active backup mode.
  */
-void bond_loadbalance_arp_mon(struct net_device *bond_dev)
+void bond_loadbalance_arp_mon(struct work_struct *work)
 {
-       struct bonding *bond = bond_dev->priv;
+       struct bonding *bond = container_of(work, struct bonding,
+                                           arp_work.work);
        struct slave *slave, *oldcurrent;
        int do_failover = 0;
        int delta_in_ticks;
                                        printk(KERN_INFO DRV_NAME
                                               ": %s: link status definitely "
                                               "up for interface %s, ",
-                                              bond_dev->name,
+                                              bond->dev->name,
                                               slave->dev->name);
                                        do_failover = 1;
                                } else {
                                        printk(KERN_INFO DRV_NAME
                                               ": %s: interface %s is now up\n",
-                                              bond_dev->name,
+                                              bond->dev->name,
                                               slave->dev->name);
                                }
                        }
 
                                printk(KERN_INFO DRV_NAME
                                       ": %s: interface %s is now down.\n",
-                                      bond_dev->name,
+                                      bond->dev->name,
                                       slave->dev->name);
 
                                if (slave == oldcurrent) {
        }
 
 re_arm:
-       if (bond->params.arp_interval) {
-               mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
-       }
+       if (bond->params.arp_interval)
+               queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
 out:
        read_unlock(&bond->lock);
 }
  * may have received.
  * see loadbalance_arp_monitor for arp monitoring in load balancing mode
  */
-void bond_activebackup_arp_mon(struct net_device *bond_dev)
+void bond_activebackup_arp_mon(struct work_struct *work)
 {
-       struct bonding *bond = bond_dev->priv;
+       struct bonding *bond = container_of(work, struct bonding,
+                                           arp_work.work);
        struct slave *slave;
        int delta_in_ticks;
        int i;
                                        printk(KERN_INFO DRV_NAME
                                               ": %s: %s is up and now the "
                                               "active interface\n",
-                                              bond_dev->name,
+                                              bond->dev->name,
                                               slave->dev->name);
                                        netif_carrier_on(bond->dev);
                                } else {
                                        printk(KERN_INFO DRV_NAME
                                               ": %s: backup interface %s is "
                                               "now up\n",
-                                              bond_dev->name,
+                                              bond->dev->name,
                                               slave->dev->name);
                                }
 
 
                                printk(KERN_INFO DRV_NAME
                                       ": %s: backup interface %s is now down\n",
-                                      bond_dev->name,
+                                      bond->dev->name,
                                       slave->dev->name);
                        } else {
                                read_unlock(&bond->curr_slave_lock);
                        printk(KERN_INFO DRV_NAME
                               ": %s: link status down for active interface "
                               "%s, disabling it\n",
-                              bond_dev->name,
+                              bond->dev->name,
                               slave->dev->name);
 
                        write_lock(&bond->curr_slave_lock);
                        printk(KERN_INFO DRV_NAME
                               ": %s: changing from interface %s to primary "
                               "interface %s\n",
-                              bond_dev->name,
+                              bond->dev->name,
                               slave->dev->name,
                               bond->primary_slave->dev->name);
 
                                        printk(KERN_INFO DRV_NAME
                                               ": %s: backup interface %s is "
                                               "now down.\n",
-                                              bond_dev->name,
+                                              bond->dev->name,
                                               slave->dev->name);
                                }
                        }
 
 re_arm:
        if (bond->params.arp_interval) {
-               mod_timer(&bond->arp_timer, jiffies + delta_in_ticks);
+               queue_delayed_work(bond->wq, &bond->arp_work, delta_in_ticks);
        }
 out:
        read_unlock(&bond->lock);
 static int bond_open(struct net_device *bond_dev)
 {
        struct bonding *bond = bond_dev->priv;
-       struct timer_list *mii_timer = &bond->mii_timer;
-       struct timer_list *arp_timer = &bond->arp_timer;
 
        bond->kill_timers = 0;
 
        if ((bond->params.mode == BOND_MODE_TLB) ||
            (bond->params.mode == BOND_MODE_ALB)) {
-               struct timer_list *alb_timer = &(BOND_ALB_INFO(bond).alb_timer);
-
                /* bond_alb_initialize must be called before the timer
                 * is started.
                 */
                        return -1;
                }
 
-               init_timer(alb_timer);
-               alb_timer->expires  = jiffies + 1;
-               alb_timer->data     = (unsigned long)bond;
-               alb_timer->function = (void *)&bond_alb_monitor;
-               add_timer(alb_timer);
+               INIT_DELAYED_WORK(&bond->alb_work, bond_alb_monitor);
+               queue_delayed_work(bond->wq, &bond->alb_work, 0);
        }
 
        if (bond->params.miimon) {  /* link check interval, in milliseconds. */
-               init_timer(mii_timer);
-               mii_timer->expires  = jiffies + 1;
-               mii_timer->data     = (unsigned long)bond_dev;
-               mii_timer->function = (void *)&bond_mii_monitor;
-               add_timer(mii_timer);
+               INIT_DELAYED_WORK(&bond->mii_work, bond_mii_monitor);
+               queue_delayed_work(bond->wq, &bond->mii_work, 0);
        }
 
        if (bond->params.arp_interval) {  /* arp interval, in milliseconds. */
-               init_timer(arp_timer);
-               arp_timer->expires  = jiffies + 1;
-               arp_timer->data     = (unsigned long)bond_dev;
-               if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
-                       arp_timer->function = (void *)&bond_activebackup_arp_mon;
-               } else {
-                       arp_timer->function = (void *)&bond_loadbalance_arp_mon;
-               }
+               if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+                       INIT_DELAYED_WORK(&bond->arp_work,
+                                         bond_activebackup_arp_mon);
+               else
+                       INIT_DELAYED_WORK(&bond->arp_work,
+                                         bond_loadbalance_arp_mon);
+
+               queue_delayed_work(bond->wq, &bond->arp_work, 0);
                if (bond->params.arp_validate)
                        bond_register_arp(bond);
-
-               add_timer(arp_timer);
        }
 
        if (bond->params.mode == BOND_MODE_8023AD) {
-               struct timer_list *ad_timer = &(BOND_AD_INFO(bond).ad_timer);
-               init_timer(ad_timer);
-               ad_timer->expires  = jiffies + 1;
-               ad_timer->data     = (unsigned long)bond;
-               ad_timer->function = (void *)&bond_3ad_state_machine_handler;
-               add_timer(ad_timer);
-
+               INIT_DELAYED_WORK(&bond->ad_work, bond_alb_monitor);
+               queue_delayed_work(bond->wq, &bond->ad_work, 0);
                /* register to receive LACPDUs */
                bond_register_lacpdu(bond);
        }
 
        write_unlock_bh(&bond->lock);
 
-       /* del_timer_sync must run without holding the bond->lock
-        * because a running timer might be trying to hold it too
-        */
-
        if (bond->params.miimon) {  /* link check interval, in milliseconds. */
-               del_timer_sync(&bond->mii_timer);
+               cancel_delayed_work(&bond->mii_work);
        }
 
        if (bond->params.arp_interval) {  /* arp interval, in milliseconds. */
-               del_timer_sync(&bond->arp_timer);
+               cancel_delayed_work(&bond->arp_work);
        }
 
        switch (bond->params.mode) {
        case BOND_MODE_8023AD:
-               del_timer_sync(&(BOND_AD_INFO(bond).ad_timer));
+               cancel_delayed_work(&bond->ad_work);
                break;
        case BOND_MODE_TLB:
        case BOND_MODE_ALB:
-               del_timer_sync(&(BOND_ALB_INFO(bond).alb_timer));
+               cancel_delayed_work(&bond->alb_work);
                break;
        default:
                break;
 
        bond->params = *params; /* copy params struct */
 
+       bond->wq = create_singlethread_workqueue(bond_dev->name);
+       if (!bond->wq)
+               return -ENOMEM;
+
        /* Initialize pointers */
        bond->first_slave = NULL;
        bond->curr_active_slave = NULL;
        return res;
 }
 
+static void bond_work_cancel_all(struct bonding *bond)
+{
+       write_lock_bh(&bond->lock);
+       bond->kill_timers = 1;
+       write_unlock_bh(&bond->lock);
+
+       if (bond->params.miimon && delayed_work_pending(&bond->mii_work))
+               cancel_delayed_work(&bond->mii_work);
+
+       if (bond->params.arp_interval && delayed_work_pending(&bond->arp_work))
+               cancel_delayed_work(&bond->arp_work);
+
+       if (bond->params.mode == BOND_MODE_ALB &&
+           delayed_work_pending(&bond->alb_work))
+               cancel_delayed_work(&bond->alb_work);
+
+       if (bond->params.mode == BOND_MODE_8023AD &&
+           delayed_work_pending(&bond->ad_work))
+               cancel_delayed_work(&bond->ad_work);
+}
+
 static int __init bonding_init(void)
 {
        int i;
        int res;
+       struct bonding *bond, *nxt;
 
        printk(KERN_INFO "%s", version);
 
 
        goto out;
 err:
+       list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
+               bond_work_cancel_all(bond);
+               destroy_workqueue(bond->wq);
+       }
+
        rtnl_lock();
        bond_free_all();
        bond_destroy_sysfs();
 
                       "%s Disabling MII monitoring.\n",
                       bond->dev->name, bond->dev->name);
                bond->params.miimon = 0;
-               /* Kill MII timer, else it brings bond's link down */
-               if (bond->arp_timer.function) {
-                       printk(KERN_INFO DRV_NAME
-                       ": %s: Kill MII timer, else it brings bond's link down...\n",
-                      bond->dev->name);
-                       del_timer_sync(&bond->mii_timer);
+               if (delayed_work_pending(&bond->mii_work)) {
+                       cancel_delayed_work(&bond->mii_work);
+                       flush_workqueue(bond->wq);
                }
        }
        if (!bond->params.arp_targets[0]) {
                 * timer will get fired off when the open function
                 * is called.
                 */
-               if (bond->arp_timer.function) {
-                       /* The timer's already set up, so fire it off */
-                       mod_timer(&bond->arp_timer, jiffies + 1);
-               } else {
-                       /* Set up the timer. */
-                       init_timer(&bond->arp_timer);
-                       bond->arp_timer.expires = jiffies + 1;
-                       bond->arp_timer.data =
-                               (unsigned long) bond->dev;
-                       if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
-                               bond->arp_timer.function =
-                                       (void *)
-                                       &bond_activebackup_arp_mon;
-                       } else {
-                               bond->arp_timer.function =
-                                       (void *)
-                                       &bond_loadbalance_arp_mon;
-                       }
-                       add_timer(&bond->arp_timer);
+               if (!delayed_work_pending(&bond->arp_work)) {
+                       if (bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+                               INIT_DELAYED_WORK(&bond->arp_work,
+                                                 bond_activebackup_arp_mon);
+                       else
+                               INIT_DELAYED_WORK(&bond->arp_work,
+                                                 bond_loadbalance_arp_mon);
+
+                       queue_delayed_work(bond->wq, &bond->arp_work, 0);
                }
        }
 
                                bond->params.arp_validate =
                                        BOND_ARP_VALIDATE_NONE;
                        }
-                       /* Kill ARP timer, else it brings bond's link down */
-                       if (bond->mii_timer.function) {
-                               printk(KERN_INFO DRV_NAME
-                               ": %s: Kill ARP timer, else it brings bond's link down...\n",
-                              bond->dev->name);
-                               del_timer_sync(&bond->arp_timer);
+                       if (delayed_work_pending(&bond->arp_work)) {
+                               cancel_delayed_work(&bond->arp_work);
+                               flush_workqueue(bond->wq);
                        }
                }
 
                         * timer will get fired off when the open function
                         * is called.
                         */
-                       if (bond->mii_timer.function) {
-                               /* The timer's already set up, so fire it off */
-                               mod_timer(&bond->mii_timer, jiffies + 1);
-                       } else {
-                               /* Set up the timer. */
-                               init_timer(&bond->mii_timer);
-                               bond->mii_timer.expires = jiffies + 1;
-                               bond->mii_timer.data =
-                                       (unsigned long) bond->dev;
-                               bond->mii_timer.function =
-                                       (void *) &bond_mii_monitor;
-                               add_timer(&bond->mii_timer);
+                       if (!delayed_work_pending(&bond->mii_work)) {
+                               INIT_DELAYED_WORK(&bond->mii_work,
+                                                 bond_mii_monitor);
+                               queue_delayed_work(bond->wq,
+                                                  &bond->mii_work, 0);
                        }
                }
        }