2009-07-08 13:19:16 -07:00
|
|
|
/*
|
|
|
|
* Distributed under the terms of the GNU GPL version 2.
|
|
|
|
* Copyright (c) 2007, 2008, 2009 Nicira Networks.
|
2009-06-15 15:11:30 -07:00
|
|
|
*
|
|
|
|
* Significant portions of this file may be copied from parts of the Linux
|
|
|
|
* kernel, by Linus Torvalds and others.
|
2009-07-08 13:19:16 -07:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Handle changes to managed devices */
|
|
|
|
|
|
|
|
#include <linux/netdevice.h>
|
|
|
|
|
|
|
|
#include "datapath.h"
|
|
|
|
|
|
|
|
|
|
|
|
static int dp_device_event(struct notifier_block *unused, unsigned long event,
|
|
|
|
void *ptr)
|
|
|
|
{
|
|
|
|
struct net_device *dev = ptr;
|
2009-08-05 14:36:21 -07:00
|
|
|
struct net_bridge_port *p;
|
|
|
|
struct datapath *dp;
|
|
|
|
|
|
|
|
p = dev->br_port;
|
|
|
|
if (!p)
|
|
|
|
return NOTIFY_DONE;
|
|
|
|
dp = p->dp;
|
|
|
|
|
|
|
|
switch (event) {
|
|
|
|
case NETDEV_UNREGISTER:
|
2009-07-08 13:19:16 -07:00
|
|
|
mutex_lock(&dp->mutex);
|
datapath: Fix race against workqueue in dp_dev and simplify code.
The dp_dev_destroy() function failed to cancel the xmit_queue work, which
allowed it to run after the device had been destroyed, accessing freed
memory. However, simply canceling the work with cancel_work_sync() would
be insufficient, since other packets could get queued while the work
function was running. Stopping the queue with netif_tx_disable() doesn't
help, because the final action in dp_dev_do_xmit() is to re-enable the TX
queue.
This issue led me to re-examine why the dp_dev needs to use a work_struct
at all. This was implemented in commit 71f13ed0b "Send of0 packets from
workqueue, to avoid recursive locking of ofN device" due to a complaint
from lockdep about recursive locking.
However, there's no actual reason that we need any locking around
dp_dev_xmit(). Until now, it has accepted the standard locking provided
by the network stack. But looking at the other software devices (veth,
loopback), those use NETIF_F_LLTX, which disables this locking, and
presumably do so for this very reason. In fact, the lwn article at
http://lwn.net/Articles/121566/ hints that NETIF_F_LLTX, which is otherwise
discouraged in the kernel, is acceptable for "certain types of software
device."
So this commit switches to using NETIF_F_LLTX for dp_dev and gets rid
of the work_struct.
In the process, I noticed that veth and loopback also take advantage of
a network device destruction "hook" using the net_device "destructor"
member. Using this we can automatically get called on network device
destruction at the point where rtnl_unlock() is called. This allows us
to stop stringing the dp_devs that are being destroyed onto a list so
that we can free them, and thus simplifies the code along all the paths
that call dp_dev_destroy().
This commit gets rid of a call to synchronize_rcu() (disguised as a call
to synchronize_net(), which is a macro that expands to synchronize_rcu()),
so it probably speeds up deleting ports, too.
2009-07-08 12:23:32 -07:00
|
|
|
dp_del_port(p);
|
2009-07-08 13:19:16 -07:00
|
|
|
mutex_unlock(&dp->mutex);
|
2009-08-05 14:36:21 -07:00
|
|
|
break;
|
|
|
|
|
|
|
|
case NETDEV_CHANGENAME:
|
|
|
|
if (p->port_no != ODPP_LOCAL) {
|
|
|
|
mutex_lock(&dp->mutex);
|
|
|
|
dp_sysfs_del_if(p);
|
|
|
|
dp_sysfs_add_if(p);
|
|
|
|
mutex_unlock(&dp->mutex);
|
|
|
|
}
|
|
|
|
break;
|
2009-07-08 13:19:16 -07:00
|
|
|
}
|
|
|
|
return NOTIFY_DONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct notifier_block dp_device_notifier = {
|
|
|
|
.notifier_call = dp_device_event
|
|
|
|
};
|