Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 171611
b: refs/heads/master
c: e014deb
h: refs/heads/master
i:
  171609: 96a77a6
  171607: 2ec250d
v: v3
  • Loading branch information
Eric Dumazet authored and David S. Miller committed Nov 18, 2009
1 parent d0f8dd8 commit bb0b658
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 39 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: e2ce146848c81af2f6d42e67990191c284bf0c33
refs/heads/master: e014debecd3ee3832e6476b3a9c948edfcfd1250
3 changes: 2 additions & 1 deletion trunk/include/linux/netdevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -896,7 +896,7 @@ struct net_device {
/* device index hash chain */
struct hlist_node index_hlist;

struct net_device *link_watch_next;
struct list_head link_watch_list;

/* register/unregister state machine */
enum { NETREG_UNINITIALIZED=0,
Expand Down Expand Up @@ -1600,6 +1600,7 @@ static inline void dev_hold(struct net_device *dev)
*/

extern void linkwatch_fire_event(struct net_device *dev);
extern void linkwatch_forget_dev(struct net_device *dev);

/**
* netif_carrier_ok - test if carrier present
Expand Down
3 changes: 3 additions & 0 deletions trunk/net/core/dev.c
Original file line number Diff line number Diff line change
Expand Up @@ -5085,6 +5085,8 @@ static void netdev_wait_allrefs(struct net_device *dev)
{
unsigned long rebroadcast_time, warning_time;

linkwatch_forget_dev(dev);

rebroadcast_time = warning_time = jiffies;
while (atomic_read(&dev->refcnt) != 0) {
if (time_after(jiffies, rebroadcast_time + 1 * HZ)) {
Expand Down Expand Up @@ -5311,6 +5313,7 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,

INIT_LIST_HEAD(&dev->napi_list);
INIT_LIST_HEAD(&dev->unreg_list);
INIT_LIST_HEAD(&dev->link_watch_list);
dev->priv_flags = IFF_XMIT_DST_RELEASE;
setup(dev);
strcpy(dev->name, name);
Expand Down
94 changes: 57 additions & 37 deletions trunk/net/core/link_watch.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ static unsigned long linkwatch_nextevent;
static void linkwatch_event(struct work_struct *dummy);
static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event);

static struct net_device *lweventlist;
static LIST_HEAD(lweventlist);
static DEFINE_SPINLOCK(lweventlist_lock);

static unsigned char default_operstate(const struct net_device *dev)
Expand Down Expand Up @@ -89,8 +89,10 @@ static void linkwatch_add_event(struct net_device *dev)
unsigned long flags;

spin_lock_irqsave(&lweventlist_lock, flags);
dev->link_watch_next = lweventlist;
lweventlist = dev;
if (list_empty(&dev->link_watch_list)) {
list_add_tail(&dev->link_watch_list, &lweventlist);
dev_hold(dev);
}
spin_unlock_irqrestore(&lweventlist_lock, flags);
}

Expand Down Expand Up @@ -133,9 +135,35 @@ static void linkwatch_schedule_work(int urgent)
}


static void linkwatch_do_dev(struct net_device *dev)
{
/*
* Make sure the above read is complete since it can be
* rewritten as soon as we clear the bit below.
*/
smp_mb__before_clear_bit();

/* We are about to handle this device,
* so new events can be accepted
*/
clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);

rfc2863_policy(dev);
if (dev->flags & IFF_UP) {
if (netif_carrier_ok(dev))
dev_activate(dev);
else
dev_deactivate(dev);

netdev_state_change(dev);
}
dev_put(dev);
}

static void __linkwatch_run_queue(int urgent_only)
{
struct net_device *next;
struct net_device *dev;
LIST_HEAD(wrk);

/*
* Limit the number of linkwatch events to one
Expand All @@ -153,46 +181,40 @@ static void __linkwatch_run_queue(int urgent_only)
clear_bit(LW_URGENT, &linkwatch_flags);

spin_lock_irq(&lweventlist_lock);
next = lweventlist;
lweventlist = NULL;
spin_unlock_irq(&lweventlist_lock);
list_splice_init(&lweventlist, &wrk);

while (next) {
struct net_device *dev = next;
while (!list_empty(&wrk)) {

next = dev->link_watch_next;
dev = list_first_entry(&wrk, struct net_device, link_watch_list);
list_del_init(&dev->link_watch_list);

if (urgent_only && !linkwatch_urgent_event(dev)) {
linkwatch_add_event(dev);
list_add_tail(&dev->link_watch_list, &lweventlist);
continue;
}

/*
* Make sure the above read is complete since it can be
* rewritten as soon as we clear the bit below.
*/
smp_mb__before_clear_bit();

/* We are about to handle this device,
* so new events can be accepted
*/
clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state);

rfc2863_policy(dev);
if (dev->flags & IFF_UP) {
if (netif_carrier_ok(dev))
dev_activate(dev);
else
dev_deactivate(dev);

netdev_state_change(dev);
}

dev_put(dev);
spin_unlock_irq(&lweventlist_lock);
linkwatch_do_dev(dev);
spin_lock_irq(&lweventlist_lock);
}

if (lweventlist)
if (!list_empty(&lweventlist))
linkwatch_schedule_work(0);
spin_unlock_irq(&lweventlist_lock);
}

void linkwatch_forget_dev(struct net_device *dev)
{
unsigned long flags;
int clean = 0;

spin_lock_irqsave(&lweventlist_lock, flags);
if (!list_empty(&dev->link_watch_list)) {
list_del_init(&dev->link_watch_list);
clean = 1;
}
spin_unlock_irqrestore(&lweventlist_lock, flags);
if (clean)
linkwatch_do_dev(dev);
}


Expand All @@ -216,8 +238,6 @@ void linkwatch_fire_event(struct net_device *dev)
bool urgent = linkwatch_urgent_event(dev);

if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
dev_hold(dev);

linkwatch_add_event(dev);
} else if (!urgent)
return;
Expand Down

0 comments on commit bb0b658

Please sign in to comment.