summaryrefslogtreecommitdiffstats
path: root/net/core/dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/dev.c')
-rw-r--r--net/core/dev.c111
1 files changed, 50 insertions, 61 deletions
diff --git a/net/core/dev.c b/net/core/dev.c
index 1e5b59c3d..cf4dcf8cd 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -154,6 +154,12 @@ static void sample_queue(unsigned long dummy);
static struct timer_list samp_timer = { function: sample_queue };
#endif
+#ifdef CONFIG_HOTPLUG
+static int net_run_sbin_hotplug(struct net_device *dev, char *action);
+#else
+#define net_run_sbin_hotplug(dev, action) ({ 0; })
+#endif
+
/*
* Our notifier list
*/
@@ -617,7 +623,7 @@ void netdev_state_change(struct net_device *dev)
void dev_load(const char *name)
{
- if (!__dev_get_by_name(name) && capable(CAP_SYS_MODULE))
+ if (!dev_get(name) && capable(CAP_SYS_MODULE))
request_module(name);
}
@@ -875,8 +881,6 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
skb2->h.raw = skb2->nh.raw;
skb2->pkt_type = PACKET_OUTGOING;
- skb2->rx_dev = skb->dev;
- dev_hold(skb2->rx_dev);
ptype->func(skb2, skb->dev, ptype);
}
}
@@ -1129,10 +1133,7 @@ int netif_rx(struct sk_buff *skb)
goto drop;
enqueue:
- if (skb->rx_dev)
- dev_put(skb->rx_dev);
- skb->rx_dev = skb->dev;
- dev_hold(skb->rx_dev);
+ dev_hold(skb->dev);
__skb_queue_tail(&queue->input_pkt_queue,skb);
__cpu_raise_softirq(this_cpu, NET_RX_SOFTIRQ);
local_irq_restore(flags);
@@ -1206,11 +1207,11 @@ static int deliver_to_old_ones(struct packet_type *pt, struct sk_buff *skb, int
*/
static __inline__ void skb_bond(struct sk_buff *skb)
{
- struct net_device *dev = skb->rx_dev;
+ struct net_device *dev = skb->dev;
if (dev->master) {
dev_hold(dev->master);
- skb->dev = skb->rx_dev = dev->master;
+ skb->dev = dev->master;
dev_put(dev);
}
}
@@ -1320,6 +1321,7 @@ static void net_rx_action(struct softirq_action *h)
for (;;) {
struct sk_buff *skb;
+ struct net_device *rx_dev;
local_irq_disable();
skb = __skb_dequeue(&queue->input_pkt_queue);
@@ -1330,10 +1332,13 @@ static void net_rx_action(struct softirq_action *h)
skb_bond(skb);
+ rx_dev = skb->dev;
+
#ifdef CONFIG_NET_FASTROUTE
if (skb->pkt_type == PACKET_FASTROUTE) {
netdev_rx_stat[this_cpu].fastroute_deferred_out++;
dev_queue_xmit(skb);
+ dev_put(rx_dev);
continue;
}
#endif
@@ -1369,6 +1374,7 @@ static void net_rx_action(struct softirq_action *h)
if (skb->dev->br_port != NULL &&
br_handle_frame_hook != NULL) {
handle_bridge(skb, pt_prev);
+ dev_put(rx_dev);
continue;
}
#endif
@@ -1399,6 +1405,8 @@ static void net_rx_action(struct softirq_action *h)
kfree_skb(skb);
}
+ dev_put(rx_dev);
+
if (bugdet-- < 0 || jiffies - start_time > 1)
goto softnet_break;
@@ -2196,9 +2204,11 @@ int dev_ioctl(unsigned int cmd, void *arg)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
dev_load(ifr.ifr_name);
+ dev_probe_lock();
rtnl_lock();
ret = dev_ifsioc(&ifr, cmd);
rtnl_unlock();
+ dev_probe_unlock();
return ret;
case SIOCGIFMEM:
@@ -2217,9 +2227,11 @@ int dev_ioctl(unsigned int cmd, void *arg)
if (cmd >= SIOCDEVPRIVATE &&
cmd <= SIOCDEVPRIVATE + 15) {
dev_load(ifr.ifr_name);
+ dev_probe_lock();
rtnl_lock();
ret = dev_ifsioc(&ifr, cmd);
rtnl_unlock();
+ dev_probe_unlock();
if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
return -EFAULT;
return ret;
@@ -2303,6 +2315,12 @@ int register_netdevice(struct net_device *dev)
#endif
if (dev_boot_phase) {
+#ifdef CONFIG_NET_DIVERT
+ ret = alloc_divert_blk(dev);
+ if (ret)
+ return ret;
+#endif /* CONFIG_NET_DIVERT */
+
/* This is NOT bug, but I am not sure, that all the
devices, initialized before netdev module is started
are sane.
@@ -2328,12 +2346,6 @@ int register_netdevice(struct net_device *dev)
dev_hold(dev);
write_unlock_bh(&dev_base_lock);
-#ifdef CONFIG_NET_DIVERT
- ret = alloc_divert_blk(dev);
- if (ret)
- return ret;
-#endif /* CONFIG_NET_DIVERT */
-
/*
* Default initial state at registry is that the
* device is present.
@@ -2344,6 +2356,12 @@ int register_netdevice(struct net_device *dev)
return 0;
}
+#ifdef CONFIG_NET_DIVERT
+ ret = alloc_divert_blk(dev);
+ if (ret)
+ return ret;
+#endif /* CONFIG_NET_DIVERT */
+
dev->iflink = -1;
/* Init, if this function is available */
@@ -2383,15 +2401,11 @@ int register_netdevice(struct net_device *dev)
dev->deadbeaf = 0;
write_unlock_bh(&dev_base_lock);
-#ifdef CONFIG_NET_DIVERT
- ret = alloc_divert_blk(dev);
- if (ret)
- return ret;
-#endif /* CONFIG_NET_DIVERT */
-
/* Notify protocols, that a new device appeared. */
notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
+ net_run_sbin_hotplug(dev, "register");
+
return 0;
}
@@ -2414,11 +2428,12 @@ int netdev_finish_unregister(struct net_device *dev)
return 0;
}
#ifdef NET_REFCNT_DEBUG
- printk(KERN_DEBUG "netdev_finish_unregister: %s%s.\n", dev->name, dev->new_style?"":", old style");
+ printk(KERN_DEBUG "netdev_finish_unregister: %s%s.\n", dev->name,
+ (dev->features & NETIF_F_DYNALLOC)?"":", old style");
#endif
if (dev->destructor)
dev->destructor(dev);
- if (dev->new_style)
+ if (dev->features & NETIF_F_DYNALLOC)
kfree(dev);
return 0;
}
@@ -2462,6 +2477,10 @@ int unregister_netdevice(struct net_device *dev)
return -ENODEV;
}
+ /* Synchronize to net_rx_action. */
+ br_write_lock_bh(BR_NETPROTO_LOCK);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
+
if (dev_boot_phase == 0) {
#ifdef CONFIG_NET_FASTROUTE
dev_clear_fastroute(dev);
@@ -2470,6 +2489,8 @@ int unregister_netdevice(struct net_device *dev)
/* Shutdown queueing discipline. */
dev_shutdown(dev);
+ net_run_sbin_hotplug(dev, "unregister");
+
/* Notify protocols, that we are about to destroy
this device. They should clean all the things.
*/
@@ -2491,7 +2512,7 @@ int unregister_netdevice(struct net_device *dev)
free_divert_blk(dev);
#endif
- if (dev->new_style) {
+ if (dev->features & NETIF_F_DYNALLOC) {
#ifdef NET_REFCNT_DEBUG
if (atomic_read(&dev->refcnt) != 1)
printk(KERN_DEBUG "unregister_netdevice: holding %s refcnt=%d\n", dev->name, atomic_read(&dev->refcnt)-1);
@@ -2709,29 +2730,15 @@ int __init net_dev_init(void)
/* Notify userspace when a netdevice event occurs,
* by running '/sbin/hotplug net' with certain
* environment variables set.
- *
- * Currently reported events are listed in netdev_event_names[].
*/
-/* /sbin/hotplug ONLY executes for events named here */
-static char *netdev_event_names[] = {
- [NETDEV_REGISTER] = "register",
- [NETDEV_UNREGISTER] = "unregister",
-};
-
-static int run_sbin_hotplug(struct notifier_block *this,
- unsigned long event, void *ptr)
+static int net_run_sbin_hotplug(struct net_device *dev, char *action)
{
- struct net_device *dev = (struct net_device *) ptr;
- char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action[32];
+ char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action_str[32];
int i;
- if ((event >= ARRAY_SIZE(netdev_event_names)) ||
- !netdev_event_names[event])
- return NOTIFY_DONE;
-
sprintf(ifname, "INTERFACE=%s", dev->name);
- sprintf(action, "ACTION=%s", netdev_event_names[event]);
+ sprintf(action_str, "ACTION=%s", action);
i = 0;
argv[i++] = hotplug_path;
@@ -2743,27 +2750,9 @@ static int run_sbin_hotplug(struct notifier_block *this,
envp [i++] = "HOME=/";
envp [i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
envp [i++] = ifname;
- envp [i++] = action;
+ envp [i++] = action_str;
envp [i] = 0;
- call_usermodehelper (argv [0], argv, envp);
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block sbin_hotplug = {
- notifier_call: run_sbin_hotplug,
-};
-
-/*
- * called from init/main.c, -after- all the initcalls are complete.
- * Registers a hook that calls /sbin/hotplug on every netdev
- * addition and removal.
- */
-void __init net_notifier_init (void)
-{
- if (register_netdevice_notifier(&sbin_hotplug))
- printk (KERN_WARNING "unable to register netdev notifier\n"
- KERN_WARNING "/sbin/hotplug will not be run.\n");
+ return call_usermodehelper(argv [0], argv, envp);
}
#endif