Commit e72aee74 authored by David S. Miller's avatar David S. Miller Committed by David S. Miller

[NET]: Process hotplug list in FIFO order.

Based upon a patch from Stephen Hemminger.
parent a3072b56
...@@ -3005,14 +3005,15 @@ subsys_initcall(net_dev_init); ...@@ -3005,14 +3005,15 @@ subsys_initcall(net_dev_init);
#ifdef CONFIG_HOTPLUG #ifdef CONFIG_HOTPLUG
struct net_hotplug_todo { struct net_hotplug_todo {
struct net_hotplug_todo *next; struct list_head list;
char ifname[IFNAMSIZ]; char ifname[IFNAMSIZ];
int is_register; int is_register;
}; };
static spinlock_t net_hotplug_list_lock = SPIN_LOCK_UNLOCKED; static spinlock_t net_hotplug_list_lock = SPIN_LOCK_UNLOCKED;
static struct net_hotplug_todo *net_hotplug_list; static DECLARE_MUTEX(net_hotplug_run);
static struct list_head net_hotplug_list = LIST_HEAD_INIT(net_hotplug_list);
static void net_run_hotplug_one(struct net_hotplug_todo *ent) static inline void net_run_hotplug_one(struct net_hotplug_todo *ent)
{ {
char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action_str[32]; char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action_str[32];
int i; int i;
...@@ -3037,23 +3038,37 @@ static void net_run_hotplug_one(struct net_hotplug_todo *ent) ...@@ -3037,23 +3038,37 @@ static void net_run_hotplug_one(struct net_hotplug_todo *ent)
call_usermodehelper(argv [0], argv, envp, 0); call_usermodehelper(argv [0], argv, envp, 0);
} }
/* Run all queued hotplug requests.
* Requests are run in FIFO order.
*/
static void net_run_hotplug_todo(void) static void net_run_hotplug_todo(void)
{ {
struct net_hotplug_todo *list; struct list_head list = LIST_HEAD_INIT(list);
/* This is racy but okay since any other requests will get
* processed when the other guy does rtnl_unlock.
*/
if (list_empty(&net_hotplug_list))
return;
/* Need to guard against multiple cpu's getting out of order. */
down(&net_hotplug_run);
/* Snapshot list, allow later requests */
spin_lock(&net_hotplug_list_lock); spin_lock(&net_hotplug_list_lock);
list = net_hotplug_list; list_splice_init(&net_hotplug_list, &list);
net_hotplug_list = NULL;
spin_unlock(&net_hotplug_list_lock); spin_unlock(&net_hotplug_list_lock);
while (list != NULL) { while (!list_empty(&list)) {
struct net_hotplug_todo *next = list->next; struct net_hotplug_todo *ent;
net_run_hotplug_one(list); ent = list_entry(list.next, struct net_hotplug_todo, list);
list_del(&ent->list);
kfree(list); net_run_hotplug_one(ent);
list = next; kfree(ent);
} }
up(&net_hotplug_run);
} }
/* Notify userspace when a netdevice event occurs, /* Notify userspace when a netdevice event occurs,
...@@ -3065,15 +3080,17 @@ static void net_run_sbin_hotplug(struct net_device *dev, int is_register) ...@@ -3065,15 +3080,17 @@ static void net_run_sbin_hotplug(struct net_device *dev, int is_register)
{ {
struct net_hotplug_todo *ent = kmalloc(sizeof(*ent), GFP_KERNEL); struct net_hotplug_todo *ent = kmalloc(sizeof(*ent), GFP_KERNEL);
ASSERT_RTNL();
if (!ent) if (!ent)
return; return;
INIT_LIST_HEAD(&ent->list);
memcpy(ent->ifname, dev->name, IFNAMSIZ); memcpy(ent->ifname, dev->name, IFNAMSIZ);
ent->is_register = is_register; ent->is_register = is_register;
spin_lock(&net_hotplug_list_lock); spin_lock(&net_hotplug_list_lock);
ent->next = net_hotplug_list; list_add(&ent->list, &net_hotplug_list);
net_hotplug_list = ent;
spin_unlock(&net_hotplug_list_lock); spin_unlock(&net_hotplug_list_lock);
} }
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment