[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [linux-2.6.18-xen] netfront accel: Simplify, document, and fix a theoretical bug in use
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1238497203 -3600 # Node ID ab1d4fbbe4bf93f203e0c4d62c18bd248e4f1d4a # Parent ad4d307bf9ced378d0b49d4559ae33ecbff3c1b7 netfront accel: Simplify, document, and fix a theoretical bug in use of spin locks by netfront acceleration plugins Signed-off-by: Kieran Mansley <kmansley@xxxxxxxxxxxxxx> --- drivers/xen/netfront/accel.c | 226 +++++++++++++++++++--------------------- drivers/xen/netfront/netfront.c | 3 2 files changed, 109 insertions(+), 120 deletions(-) diff -r ad4d307bf9ce -r ab1d4fbbe4bf drivers/xen/netfront/accel.c --- a/drivers/xen/netfront/accel.c Tue Mar 31 11:59:10 2009 +0100 +++ b/drivers/xen/netfront/accel.c Tue Mar 31 12:00:03 2009 +0100 @@ -57,9 +57,6 @@ static int netfront_load_accelerator(str */ static struct list_head accelerators_list; -/* Lock to protect access to accelerators_list */ -static spinlock_t accelerators_lock; - /* Workqueue to process acceleration configuration changes */ struct workqueue_struct *accel_watch_workqueue; @@ -69,7 +66,6 @@ void netif_init_accel(void) void netif_init_accel(void) { INIT_LIST_HEAD(&accelerators_list); - spin_lock_init(&accelerators_lock); accel_watch_workqueue = create_workqueue("net_accel"); } @@ -77,13 +73,11 @@ void netif_exit_accel(void) void netif_exit_accel(void) { struct netfront_accelerator *accelerator, *tmp; - unsigned long flags; flush_workqueue(accel_watch_workqueue); destroy_workqueue(accel_watch_workqueue); - spin_lock_irqsave(&accelerators_lock, flags); - + /* No lock required as everything else should be quiet by now */ list_for_each_entry_safe(accelerator, tmp, &accelerators_list, link) { BUG_ON(!list_empty(&accelerator->vif_states)); @@ -91,8 +85,6 @@ void netif_exit_accel(void) kfree(accelerator->frontend); kfree(accelerator); } - - spin_unlock_irqrestore(&accelerators_lock, flags); } @@ -245,16 +237,12 @@ static int match_accelerator(const char /* * Add a frontend vif to the list of vifs that is using a netfront - * accelerator plugin module. + * accelerator plugin module. Must be called with the accelerator + * mutex held. */ static void add_accelerator_vif(struct netfront_accelerator *accelerator, struct netfront_info *np) { - unsigned long flags; - - /* Need lock to write list */ - spin_lock_irqsave(&accelerator->vif_states_lock, flags); - if (np->accelerator == NULL) { np->accelerator = accelerator; @@ -267,13 +255,13 @@ static void add_accelerator_vif(struct n */ BUG_ON(np->accelerator != accelerator); } - - spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); -} - - -/* - * Initialise the state to track an accelerator plugin module. +} + + +/* + * Initialise the state to track an accelerator plugin module. + * + * Must be called with the accelerator mutex held. */ static int init_accelerator(const char *frontend, struct netfront_accelerator **result, @@ -281,7 +269,6 @@ static int init_accelerator(const char * { struct netfront_accelerator *accelerator = kmalloc(sizeof(struct netfront_accelerator), GFP_KERNEL); - unsigned long flags; int frontend_len; if (!accelerator) { @@ -303,9 +290,7 @@ static int init_accelerator(const char * accelerator->hooks = hooks; - spin_lock_irqsave(&accelerators_lock, flags); list_add(&accelerator->link, &accelerators_list); - spin_unlock_irqrestore(&accelerators_lock, flags); *result = accelerator; @@ -316,11 +301,14 @@ static int init_accelerator(const char * /* * Modify the hooks stored in the per-vif state to match that in the * netfront accelerator's state. + * + * Takes the vif_states_lock spinlock and may sleep. */ static void accelerator_set_vif_state_hooks(struct netfront_accel_vif_state *vif_state) { - /* This function must be called with the vif_states_lock held */ + struct netfront_accelerator *accelerator; + unsigned long flags; DPRINTK("%p\n",vif_state); @@ -328,19 +316,25 @@ accelerator_set_vif_state_hooks(struct n netif_poll_disable(vif_state->np->netdev); netif_tx_lock_bh(vif_state->np->netdev); - vif_state->hooks = vif_state->np->accelerator->hooks; + accelerator = vif_state->np->accelerator; + spin_lock_irqsave(&accelerator->vif_states_lock, flags); + vif_state->hooks = accelerator->hooks; + spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); netif_tx_unlock_bh(vif_state->np->netdev); netif_poll_enable(vif_state->np->netdev); } +/* + * Must be called with the accelerator mutex held. Takes the + * vif_states_lock spinlock. + */ static void accelerator_probe_new_vif(struct netfront_info *np, struct xenbus_device *dev, struct netfront_accelerator *accelerator) { struct netfront_accel_hooks *hooks; - unsigned long flags; DPRINTK("\n"); @@ -349,17 +343,8 @@ static void accelerator_probe_new_vif(st hooks = accelerator->hooks; - if (hooks) { - if (hooks->new_device(np->netdev, dev) == 0) { - spin_lock_irqsave - (&accelerator->vif_states_lock, flags); - - accelerator_set_vif_state_hooks(&np->accel_vif_state); - - spin_unlock_irqrestore - (&accelerator->vif_states_lock, flags); - } - } + if (hooks && hooks->new_device(np->netdev, dev) == 0) + accelerator_set_vif_state_hooks(&np->accel_vif_state); return; } @@ -368,7 +353,10 @@ static void accelerator_probe_new_vif(st /* * Request that a particular netfront accelerator plugin is loaded. * Usually called as a result of the vif configuration specifying - * which one to use. Must be called with accelerator_mutex held + * which one to use. + * + * Must be called with accelerator_mutex held. Takes the + * vif_states_lock spinlock. */ static int netfront_load_accelerator(struct netfront_info *np, struct xenbus_device *dev, @@ -407,13 +395,15 @@ static int netfront_load_accelerator(str * this accelerator. Notify the accelerator plugin of the relevant * device if so. Called when an accelerator plugin module is first * loaded and connects to netfront. + * + * Must be called with accelerator_mutex held. Takes the + * vif_states_lock spinlock. */ static void accelerator_probe_vifs(struct netfront_accelerator *accelerator, struct netfront_accel_hooks *hooks) { struct netfront_accel_vif_state *vif_state, *tmp; - unsigned long flags; DPRINTK("%p\n", accelerator); @@ -425,29 +415,22 @@ accelerator_probe_vifs(struct netfront_a BUG_ON(hooks == NULL); accelerator->hooks = hooks; - /* - * currently hold accelerator_mutex, so don't need - * vif_states_lock to read the list - */ + /* Holds accelerator_mutex to iterate list */ list_for_each_entry_safe(vif_state, tmp, &accelerator->vif_states, link) { struct netfront_info *np = vif_state->np; - if (hooks->new_device(np->netdev, vif_state->dev) == 0) { - spin_lock_irqsave - (&accelerator->vif_states_lock, flags); - + if (hooks->new_device(np->netdev, vif_state->dev) == 0) accelerator_set_vif_state_hooks(vif_state); - - spin_unlock_irqrestore - (&accelerator->vif_states_lock, flags); - } - } -} - - -/* - * Called by the netfront accelerator plugin module when it has loaded + } +} + + +/* + * Called by the netfront accelerator plugin module when it has + * loaded. + * + * Takes the accelerator_mutex and vif_states_lock spinlock. */ int netfront_accelerator_loaded(int version, const char *frontend, struct netfront_accel_hooks *hooks) @@ -503,14 +486,20 @@ EXPORT_SYMBOL_GPL(netfront_accelerator_l /* * Remove the hooks from a single vif state. + * + * Takes the vif_states_lock spinlock and may sleep. */ static void accelerator_remove_single_hook(struct netfront_accelerator *accelerator, struct netfront_accel_vif_state *vif_state) { + unsigned long flags; + /* Make sure there are no data path operations going on */ netif_poll_disable(vif_state->np->netdev); netif_tx_lock_bh(vif_state->np->netdev); + + spin_lock_irqsave(&accelerator->vif_states_lock, flags); /* * Remove the hooks, but leave the vif_state on the @@ -520,6 +509,8 @@ accelerator_remove_single_hook(struct ne */ vif_state->hooks = NULL; + spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); + netif_tx_unlock_bh(vif_state->np->netdev); netif_poll_enable(vif_state->np->netdev); } @@ -527,25 +518,25 @@ accelerator_remove_single_hook(struct ne /* * Safely remove the accelerator function hooks from a netfront state. + * + * Must be called with the accelerator mutex held. Takes the + * vif_states_lock spinlock. */ static void accelerator_remove_hooks(struct netfront_accelerator *accelerator) { - struct netfront_accel_hooks *hooks; struct netfront_accel_vif_state *vif_state, *tmp; unsigned long flags; - /* Mutex is held so don't need vif_states_lock to iterate list */ + /* Mutex is held to iterate list */ list_for_each_entry_safe(vif_state, tmp, &accelerator->vif_states, link) { - spin_lock_irqsave(&accelerator->vif_states_lock, flags); - if(vif_state->hooks) { - hooks = vif_state->hooks; - + spin_lock_irqsave(&accelerator->vif_states_lock, flags); + /* Last chance to get statistics from the accelerator */ - hooks->get_stats(vif_state->np->netdev, - &vif_state->np->stats); + vif_state->hooks->get_stats(vif_state->np->netdev, + &vif_state->np->stats); spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); @@ -553,9 +544,6 @@ static void accelerator_remove_hooks(str accelerator_remove_single_hook(accelerator, vif_state); accelerator->hooks->remove(vif_state->dev); - } else { - spin_unlock_irqrestore(&accelerator->vif_states_lock, - flags); } } @@ -567,47 +555,47 @@ static void accelerator_remove_hooks(str * Called by a netfront accelerator when it is unloaded. This safely * removes the hooks into the plugin and blocks until all devices have * finished using it, so on return it is safe to unload. + * + * Takes the accelerator mutex, and vif_states_lock spinlock. */ void netfront_accelerator_stop(const char *frontend) { struct netfront_accelerator *accelerator; - unsigned long flags; mutex_lock(&accelerator_mutex); - spin_lock_irqsave(&accelerators_lock, flags); list_for_each_entry(accelerator, &accelerators_list, link) { if (match_accelerator(frontend, accelerator)) { - spin_unlock_irqrestore(&accelerators_lock, flags); - accelerator_remove_hooks(accelerator); - goto out; } } - spin_unlock_irqrestore(&accelerators_lock, flags); out: mutex_unlock(&accelerator_mutex); } EXPORT_SYMBOL_GPL(netfront_accelerator_stop); -/* Helper for call_remove and do_suspend */ -static int do_remove(struct netfront_info *np, struct xenbus_device *dev, - unsigned long *lock_flags) +/* + * Helper for call_remove and do_suspend + * + * Must be called with the accelerator mutex held. Takes the + * vif_states_lock spinlock. + */ +static int do_remove(struct netfront_info *np, struct xenbus_device *dev) { struct netfront_accelerator *accelerator = np->accelerator; - struct netfront_accel_hooks *hooks; + unsigned long flags; int rc = 0; if (np->accel_vif_state.hooks) { - hooks = np->accel_vif_state.hooks; + spin_lock_irqsave(&accelerator->vif_states_lock, flags); /* Last chance to get statistics from the accelerator */ - hooks->get_stats(np->netdev, &np->stats); + np->accel_vif_state.hooks->get_stats(np->netdev, &np->stats); spin_unlock_irqrestore(&accelerator->vif_states_lock, - *lock_flags); + flags); /* * Try and do the opposite of accelerator_probe_new_vif @@ -618,20 +606,21 @@ static int do_remove(struct netfront_inf &np->accel_vif_state); rc = accelerator->hooks->remove(dev); - - spin_lock_irqsave(&accelerator->vif_states_lock, *lock_flags); } return rc; } +/* + * Must be called with the accelerator mutex held. Takes the + * vif_states_lock spinlock + */ static int netfront_remove_accelerator(struct netfront_info *np, struct xenbus_device *dev) { struct netfront_accelerator *accelerator; struct netfront_accel_vif_state *tmp_vif_state; - unsigned long flags; int rc = 0; /* Check that we've got a device that was accelerated */ @@ -639,8 +628,6 @@ static int netfront_remove_accelerator(s return rc; accelerator = np->accelerator; - - spin_lock_irqsave(&accelerator->vif_states_lock, flags); list_for_each_entry(tmp_vif_state, &accelerator->vif_states, link) { @@ -650,16 +637,18 @@ static int netfront_remove_accelerator(s } } - rc = do_remove(np, dev, &flags); + rc = do_remove(np, dev); np->accelerator = NULL; - spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); - return rc; } +/* + * No lock pre-requisites. Takes the accelerator mutex and the + * vif_states_lock spinlock. + */ int netfront_accelerator_call_remove(struct netfront_info *np, struct xenbus_device *dev) { @@ -671,11 +660,14 @@ int netfront_accelerator_call_remove(str return rc; } - + +/* + * No lock pre-requisites. Takes the accelerator mutex and the + * vif_states_lock spinlock. + */ int netfront_accelerator_suspend(struct netfront_info *np, struct xenbus_device *dev) { - unsigned long flags; int rc = 0; netfront_accelerator_remove_watch(np); @@ -690,11 +682,7 @@ int netfront_accelerator_suspend(struct * Call the remove accelerator hook, but leave the vif_state * on the accelerator's list in case there is a suspend_cancel. */ - spin_lock_irqsave(&np->accelerator->vif_states_lock, flags); - - rc = do_remove(np, dev, &flags); - - spin_unlock_irqrestore(&np->accelerator->vif_states_lock, flags); + rc = do_remove(np, dev); out: mutex_unlock(&accelerator_mutex); return rc; @@ -713,15 +701,16 @@ int netfront_accelerator_suspend_cancel( netfront_accelerator_add_watch(np); return 0; } - - + + +/* + * No lock pre-requisites. Takes the accelerator mutex + */ void netfront_accelerator_resume(struct netfront_info *np, struct xenbus_device *dev) { struct netfront_accel_vif_state *accel_vif_state = NULL; - spinlock_t *vif_states_lock; - unsigned long flags; - + mutex_lock(&accelerator_mutex); /* Check that we've got a device that was accelerated */ @@ -733,9 +722,6 @@ void netfront_accelerator_resume(struct link) { if (accel_vif_state->dev == dev) { BUG_ON(accel_vif_state != &np->accel_vif_state); - - vif_states_lock = &np->accelerator->vif_states_lock; - spin_lock_irqsave(vif_states_lock, flags); /* * Remove it from the accelerator's list so @@ -744,9 +730,7 @@ void netfront_accelerator_resume(struct */ list_del(&accel_vif_state->link); np->accelerator = NULL; - - spin_unlock_irqrestore(vif_states_lock, flags); - + break; } } @@ -757,11 +741,13 @@ void netfront_accelerator_resume(struct } +/* + * No lock pre-requisites. Takes the vif_states_lock spinlock + */ int netfront_check_accelerator_queue_ready(struct net_device *dev, struct netfront_info *np) { struct netfront_accelerator *accelerator; - struct netfront_accel_hooks *hooks; int rc = 1; unsigned long flags; @@ -770,8 +756,8 @@ int netfront_check_accelerator_queue_rea /* Call the check_ready accelerator hook. */ if (np->accel_vif_state.hooks && accelerator) { spin_lock_irqsave(&accelerator->vif_states_lock, flags); - hooks = np->accel_vif_state.hooks; - if (hooks && np->accelerator == accelerator) + if (np->accel_vif_state.hooks && + np->accelerator == accelerator) rc = np->accel_vif_state.hooks->check_ready(dev); spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); } @@ -780,11 +766,13 @@ int netfront_check_accelerator_queue_rea } +/* + * No lock pre-requisites. Takes the vif_states_lock spinlock + */ void netfront_accelerator_call_stop_napi_irq(struct netfront_info *np, struct net_device *dev) { struct netfront_accelerator *accelerator; - struct netfront_accel_hooks *hooks; unsigned long flags; accelerator = np->accelerator; @@ -792,19 +780,21 @@ void netfront_accelerator_call_stop_napi /* Call the stop_napi_interrupts accelerator hook. */ if (np->accel_vif_state.hooks && accelerator != NULL) { spin_lock_irqsave(&accelerator->vif_states_lock, flags); - hooks = np->accel_vif_state.hooks; - if (hooks && np->accelerator == accelerator) + if (np->accel_vif_state.hooks && + np->accelerator == accelerator) np->accel_vif_state.hooks->stop_napi_irq(dev); spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); } } +/* + * No lock pre-requisites. Takes the vif_states_lock spinlock + */ int netfront_accelerator_call_get_stats(struct netfront_info *np, struct net_device *dev) { struct netfront_accelerator *accelerator; - struct netfront_accel_hooks *hooks; unsigned long flags; int rc = 0; @@ -813,8 +803,8 @@ int netfront_accelerator_call_get_stats( /* Call the get_stats accelerator hook. */ if (np->accel_vif_state.hooks && accelerator != NULL) { spin_lock_irqsave(&accelerator->vif_states_lock, flags); - hooks = np->accel_vif_state.hooks; - if (hooks && np->accelerator == accelerator) + if (np->accel_vif_state.hooks && + np->accelerator == accelerator) rc = np->accel_vif_state.hooks->get_stats(dev, &np->stats); spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); diff -r ad4d307bf9ce -r ab1d4fbbe4bf drivers/xen/netfront/netfront.c --- a/drivers/xen/netfront/netfront.c Tue Mar 31 11:59:10 2009 +0100 +++ b/drivers/xen/netfront/netfront.c Tue Mar 31 12:00:03 2009 +0100 @@ -2238,10 +2238,9 @@ static void __exit netif_exit(void) #ifdef CONFIG_INET unregister_inetaddr_notifier(¬ifier_inetdev); #endif + xenbus_unregister_driver(&netfront_driver); netif_exit_accel(); - - return xenbus_unregister_driver(&netfront_driver); } module_exit(netif_exit); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |