struct net_device allocation rules
 ==================================
 Network device structures need to persist even after module is unloaded and
-must be allocated with kmalloc.  If device has registered successfully,
-it will be freed on last use by free_netdev.  This is required to handle the
-pathologic case cleanly (example: rmmod mydriver </sys/class/net/myeth/mtu )
+must be allocated with alloc_netdev_mqs() and friends.
+If device has registered successfully, it will be freed on last use
+by free_netdev(). This is required to handle the pathologic case cleanly
+(example: rmmod mydriver </sys/class/net/myeth/mtu )
 
-There are routines in net_init.c to handle the common cases of
-alloc_etherdev, alloc_netdev.  These reserve extra space for driver
+alloc_netdev_mqs()/alloc_netdev() reserve extra space for driver
 private data which gets freed when the network device is freed. If
 separately allocated data is attached to the network device
 (netdev_priv(dev)) then it is up to the module exit handler to free that.
 
 
 int netdev_refcnt_read(const struct net_device *dev);
 void free_netdev(struct net_device *dev);
+void netdev_freemem(struct net_device *dev);
 void synchronize_net(void);
 int init_dummy_netdev(struct net_device *dev);
 
 
 }
 EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops);
 
+void netdev_freemem(struct net_device *dev)
+{
+       char *addr = (char *)dev - dev->padded;
+
+       if (is_vmalloc_addr(addr))
+               vfree(addr);
+       else
+               kfree(addr);
+}
+
 /**
  *     alloc_netdev_mqs - allocate network device
  *     @sizeof_priv:   size of private data to allocate space for
        /* ensure 32-byte alignment of whole construct */
        alloc_size += NETDEV_ALIGN - 1;
 
-       p = kzalloc(alloc_size, GFP_KERNEL);
+       p = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT);
+       if (!p)
+               p = vzalloc(alloc_size);
        if (!p)
                return NULL;
 
 
        dev->pcpu_refcnt = alloc_percpu(int);
        if (!dev->pcpu_refcnt)
-               goto free_p;
+               goto free_dev;
 
        if (dev_addr_init(dev))
                goto free_pcpu;
        kfree(dev->_rx);
 #endif
 
-free_p:
-       kfree(p);
+free_dev:
+       netdev_freemem(dev);
        return NULL;
 }
 EXPORT_SYMBOL(alloc_netdev_mqs);
 
        /*  Compatibility with error handling in drivers */
        if (dev->reg_state == NETREG_UNINITIALIZED) {
-               kfree((char *)dev - dev->padded);
+               netdev_freemem(dev);
                return;
        }
 
 
        BUG_ON(dev->reg_state != NETREG_RELEASED);
 
        kfree(dev->ifalias);
-       kfree((char *)dev - dev->padded);
+       netdev_freemem(dev);
 }
 
 static const void *net_namespace(struct device *d)