Avoid removing watch across suspend/suspend_cancel cycle diff -r b358ebf1c416 drivers/xen/netfront/accel.c --- a/drivers/xen/netfront/accel.c +++ b/drivers/xen/netfront/accel.c @@ -50,6 +50,8 @@ static int netfront_load_accelerator(str static int netfront_load_accelerator(struct netfront_info *np, struct xenbus_device *dev, const char *frontend); + +static void netfront_accelerator_remove_watch(struct netfront_info *np); /* * List of all netfront accelerator plugin modules available. Each @@ -164,8 +166,11 @@ void netfront_accelerator_add_watch(stru { int err; - /* Check we're not trying to overwrite an existing watch */ - BUG_ON(np->accel_vif_state.accel_watch.node != NULL); + /* + * If old watch exists, e.g. from before suspend/resume, + * remove it now + */ + netfront_accelerator_remove_watch(np); /* Get a watch on the accelerator plugin */ err = xenbus_watch_path2(np->xbdev, np->xbdev->otherend, @@ -180,6 +185,19 @@ void netfront_accelerator_add_watch(stru } +static void +netfront_accelerator_purge_watch(struct netfront_accel_vif_state *vif_state) +{ + flush_workqueue(accel_watch_workqueue); + + /* Clean up any state left from watch */ + if (vif_state->accel_frontend != NULL) { + kfree(vif_state->accel_frontend); + vif_state->accel_frontend = NULL; + } +} + + static void netfront_accelerator_remove_watch(struct netfront_info *np) { @@ -191,13 +209,7 @@ void netfront_accelerator_remove_watch(s kfree(vif_state->accel_watch.node); vif_state->accel_watch.node = NULL; - flush_workqueue(accel_watch_workqueue); - - /* Clean up any state left from watch */ - if (vif_state->accel_frontend != NULL) { - kfree(vif_state->accel_frontend); - vif_state->accel_frontend = NULL; - } + netfront_accelerator_purge_watch(vif_state); } } @@ -670,8 +682,6 @@ int netfront_accelerator_suspend(struct { int rc = 0; - netfront_accelerator_remove_watch(np); - mutex_lock(&accelerator_mutex); /* Check that we've got a device that was accelerated */ @@ -692,13 +702,16 @@ int netfront_accelerator_suspend_cancel( int netfront_accelerator_suspend_cancel(struct netfront_info *np, struct xenbus_device *dev) { + netfront_accelerator_purge_watch(&np->accel_vif_state); + /* - * Setting the watch will cause it to fire and probe the - * accelerator, so no need to call accelerator_probe_new_vif() - * directly here + * Gratuitously fire the watch handler to reinstate the + * configured accelerator */ if (dev->state == XenbusStateConnected) - netfront_accelerator_add_watch(np); + queue_work(accel_watch_workqueue, + &np->accel_vif_state.accel_work); + return 0; }