Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 352104
b: refs/heads/master
c: ca99ca1
h: refs/heads/master
v: v3
  • Loading branch information
Neil Horman authored and David S. Miller committed Feb 6, 2013
1 parent 158ed73 commit 0a2582d
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 3 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: f458c647ea5cdd956f8055a4178072be460559f1
refs/heads/master: ca99ca14c95ae49fb4c9cd3abf5f84d11a7e8a61
11 changes: 10 additions & 1 deletion trunk/include/linux/netpoll.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ struct netpoll {
struct netpoll_info {
atomic_t refcnt;

int rx_flags;
unsigned long rx_flags;
spinlock_t rx_lock;
struct mutex dev_lock;
struct list_head rx_np; /* netpolls that registered an rx_hook */

struct sk_buff_head neigh_tx; /* list of neigh requests to reply to */
Expand All @@ -51,6 +52,14 @@ struct netpoll_info {
struct rcu_head rcu;
};

#ifdef CONFIG_NETPOLL
extern int netpoll_rx_disable(struct net_device *dev);
extern void netpoll_rx_enable(struct net_device *dev);
#else
static inline int netpoll_rx_disable(struct net_device *dev) { return 0; }
static inline void netpoll_rx_enable(struct net_device *dev) { return; }
#endif

void netpoll_send_udp(struct netpoll *np, const char *msg, int len);
void netpoll_print_options(struct netpoll *np);
int netpoll_parse_options(struct netpoll *np, char *opt);
Expand Down
27 changes: 26 additions & 1 deletion trunk/net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -1266,6 +1266,14 @@ static int __dev_open(struct net_device *dev)
if (!netif_device_present(dev))
return -ENODEV;

/* Block netpoll from trying to do any rx path servicing.
* If we don't do this there is a chance ndo_poll_controller
* or ndo_poll may be running while we open the device
*/
ret = netpoll_rx_disable(dev);
if (ret)
return ret;

ret = call_netdevice_notifiers(NETDEV_PRE_UP, dev);
ret = notifier_to_errno(ret);
if (ret)
Expand All @@ -1279,6 +1287,8 @@ static int __dev_open(struct net_device *dev)
if (!ret && ops->ndo_open)
ret = ops->ndo_open(dev);

netpoll_rx_enable(dev);

if (ret)
clear_bit(__LINK_STATE_START, &dev->state);
else {
Expand Down Expand Up @@ -1370,9 +1380,16 @@ static int __dev_close(struct net_device *dev)
int retval;
LIST_HEAD(single);

/* Temporarily disable netpoll until the interface is down */
retval = netpoll_rx_disable(dev);
if (retval)
return retval;

list_add(&dev->unreg_list, &single);
retval = __dev_close_many(&single);
list_del(&single);

netpoll_rx_enable(dev);
return retval;
}

Expand Down Expand Up @@ -1408,14 +1425,22 @@ static int dev_close_many(struct list_head *head)
*/
int dev_close(struct net_device *dev)
{
int ret = 0;
if (dev->flags & IFF_UP) {
LIST_HEAD(single);

/* Block netpoll rx while the interface is going down */
ret = netpoll_rx_disable(dev);
if (ret)
return ret;

list_add(&dev->unreg_list, &single);
dev_close_many(&single);
list_del(&single);

netpoll_rx_enable(dev);
}
return 0;
return ret;
}
EXPORT_SYMBOL(dev_close);

Expand Down
40 changes: 40 additions & 0 deletions trunk/net/core/netpoll.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ static struct sk_buff_head skb_pool;

static atomic_t trapped;

static struct srcu_struct netpoll_srcu;

#define USEC_PER_POLL 50
#define NETPOLL_RX_ENABLED 1
#define NETPOLL_RX_DROP 2
Expand Down Expand Up @@ -199,6 +201,13 @@ static void netpoll_poll_dev(struct net_device *dev)
const struct net_device_ops *ops;
struct netpoll_info *ni = rcu_dereference_bh(dev->npinfo);

/* Don't do any rx activity if the dev_lock mutex is held
* the dev_open/close paths use this to block netpoll activity
* while changing device state
*/
if (!mutex_trylock(&dev->npinfo->dev_lock))
return;

if (!dev || !netif_running(dev))
return;

Expand All @@ -211,6 +220,8 @@ static void netpoll_poll_dev(struct net_device *dev)

poll_napi(dev);

mutex_unlock(&dev->npinfo->dev_lock);

if (dev->flags & IFF_SLAVE) {
if (ni) {
struct net_device *bond_dev;
Expand All @@ -231,6 +242,31 @@ static void netpoll_poll_dev(struct net_device *dev)
zap_completion_queue();
}

int netpoll_rx_disable(struct net_device *dev)
{
struct netpoll_info *ni;
int idx;
might_sleep();
idx = srcu_read_lock(&netpoll_srcu);
ni = srcu_dereference(dev->npinfo, &netpoll_srcu);
if (ni)
mutex_lock(&ni->dev_lock);
srcu_read_unlock(&netpoll_srcu, idx);
return 0;
}
EXPORT_SYMBOL(netpoll_rx_disable);

void netpoll_rx_enable(struct net_device *dev)
{
struct netpoll_info *ni;
rcu_read_lock();
ni = rcu_dereference(dev->npinfo);
if (ni)
mutex_unlock(&ni->dev_lock);
rcu_read_unlock();
}
EXPORT_SYMBOL(netpoll_rx_enable);

static void refill_skbs(void)
{
struct sk_buff *skb;
Expand Down Expand Up @@ -1004,6 +1040,7 @@ int __netpoll_setup(struct netpoll *np, struct net_device *ndev, gfp_t gfp)
INIT_LIST_HEAD(&npinfo->rx_np);

spin_lock_init(&npinfo->rx_lock);
mutex_init(&npinfo->dev_lock);
skb_queue_head_init(&npinfo->neigh_tx);
skb_queue_head_init(&npinfo->txq);
INIT_DELAYED_WORK(&npinfo->tx_work, queue_process);
Expand Down Expand Up @@ -1169,6 +1206,7 @@ EXPORT_SYMBOL(netpoll_setup);
static int __init netpoll_init(void)
{
skb_queue_head_init(&skb_pool);
init_srcu_struct(&netpoll_srcu);
return 0;
}
core_initcall(netpoll_init);
Expand Down Expand Up @@ -1208,6 +1246,8 @@ void __netpoll_cleanup(struct netpoll *np)
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
}

synchronize_srcu(&netpoll_srcu);

if (atomic_dec_and_test(&npinfo->refcnt)) {
const struct net_device_ops *ops;

Expand Down

0 comments on commit 0a2582d

Please sign in to comment.