diff options
80 files changed, 289 insertions, 156 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f2742e115b0..22f10818c2b 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -566,3 +566,13 @@ Why:	This field is deprecated. I2C device drivers shouldn't change their  Who:	Jean Delvare <khali@linux-fr.org>  ---------------------------- + +What:	cancel_rearming_delayed_work[queue]() +When:	2.6.39 + +Why:	The functions have been superceded by cancel_delayed_work_sync() +	quite some time ago.  The conversion is trivial and there is no +	in-kernel user left. +Who:	Tejun Heo <tj@kernel.org> + +---------------------------- diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index 8fed027b12d..e68d46d415f 100644 --- a/arch/arm/mach-pxa/sharpsl_pm.c +++ b/arch/arm/mach-pxa/sharpsl_pm.c @@ -579,7 +579,8 @@ static int sharpsl_ac_check(void)  static int sharpsl_pm_suspend(struct platform_device *pdev, pm_message_t state)  {  	sharpsl_pm.flags |= SHARPSL_SUSPENDED; -	flush_scheduled_work(); +	flush_delayed_work_sync(&toggle_charger); +	flush_delayed_work_sync(&sharpsl_bat);  	if (sharpsl_pm.charge_mode == CHRG_ON)  		sharpsl_pm.flags |= SHARPSL_DO_OFFLINE_CHRG; diff --git a/arch/sh/drivers/push-switch.c b/arch/sh/drivers/push-switch.c index 7b42c247316..afc24556572 100644 --- a/arch/sh/drivers/push-switch.c +++ b/arch/sh/drivers/push-switch.c @@ -107,7 +107,7 @@ static int switch_drv_remove(struct platform_device *pdev)  		device_remove_file(&pdev->dev, &dev_attr_switch);  	platform_set_drvdata(pdev, NULL); -	flush_scheduled_work(); +	flush_work_sync(&psw->work);  	del_timer_sync(&psw->debounce);  	free_irq(irq, pdev); diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c index f23d6d46b95..0a6a943b377 100644 --- a/drivers/ata/libata-core.c +++ b/drivers/ata/libata-core.c @@ -6128,7 +6128,7 @@ static void ata_port_detach(struct ata_port *ap)  	/* it better be dead now */  	WARN_ON(!(ap->pflags & ATA_PFLAG_UNLOADED)); -	cancel_rearming_delayed_work(&ap->hotplug_task); +	cancel_delayed_work_sync(&ap->hotplug_task);   skip_eh:  	if (ap->pmp_link) { diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c index 484697fef38..af6141bb1ba 100644 --- a/drivers/ata/libata-sff.c +++ b/drivers/ata/libata-sff.c @@ -1320,7 +1320,7 @@ void ata_sff_flush_pio_task(struct ata_port *ap)  {  	DPRINTK("ENTER\n"); -	cancel_rearming_delayed_work(&ap->sff_pio_task); +	cancel_delayed_work_sync(&ap->sff_pio_task);  	ap->hsm_task_state = HSM_ST_IDLE;  	if (ata_msg_ctl(ap)) diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 3951020e494..25e4dffa0aa 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -4352,7 +4352,7 @@ static int __init floppy_init(void)  out_unreg_platform_dev:  	platform_device_unregister(&floppy_device[drive]);  out_flush_work: -	flush_scheduled_work(); +	flush_work_sync(&floppy_work);  	if (atomic_read(&usage_count))  		floppy_release_irq_and_dma();  out_unreg_region: @@ -4422,7 +4422,7 @@ static int floppy_grab_irq_and_dma(void)  	 * We might have scheduled a free_irq(), wait it to  	 * drain first:  	 */ -	flush_scheduled_work(); +	flush_work_sync(&floppy_work);  	if (fd_request_irq()) {  		DPRINT("Unable to grab IRQ%d for the floppy driver\n", diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 657873e4328..d7aa39e349a 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -547,7 +547,7 @@ static void xlvbd_release_gendisk(struct blkfront_info *info)  	spin_unlock_irqrestore(&blkif_io_lock, flags);  	/* Flush gnttab callback work. Must be done with no locks held. */ -	flush_scheduled_work(); +	flush_work_sync(&info->work);  	del_gendisk(info->gd); @@ -596,7 +596,7 @@ static void blkif_free(struct blkfront_info *info, int suspend)  	spin_unlock_irq(&blkif_io_lock);  	/* Flush gnttab callback work. Must be done with no locks held. */ -	flush_scheduled_work(); +	flush_work_sync(&info->work);  	/* Free resources associated with old device channel. */  	if (info->ring_ref != GRANT_INVALID_REF) { diff --git a/drivers/cdrom/gdrom.c b/drivers/cdrom/gdrom.c index de65915308f..64a21461c40 100644 --- a/drivers/cdrom/gdrom.c +++ b/drivers/cdrom/gdrom.c @@ -837,7 +837,7 @@ probe_fail_no_mem:  static int __devexit remove_gdrom(struct platform_device *devptr)  { -	flush_scheduled_work(); +	flush_work_sync(&work);  	blk_cleanup_queue(gd.gdrom_rq);  	free_irq(HW_EVENT_GDROM_CMD, &gd);  	free_irq(HW_EVENT_GDROM_DMA, &gd); diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index a2bc885ce60..67a75a502c0 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -850,8 +850,8 @@ static void hvsi_flush_output(struct hvsi_struct *hp)  	wait_event_timeout(hp->emptyq, (hp->n_outbuf <= 0), HVSI_TIMEOUT);  	/* 'writer' could still be pending if it didn't see n_outbuf = 0 yet */ -	cancel_delayed_work(&hp->writer); -	flush_scheduled_work(); +	cancel_delayed_work_sync(&hp->writer); +	flush_work_sync(&hp->handshaker);  	/*  	 * it's also possible that our timeout expired and hvsi_write_worker diff --git a/drivers/char/pcmcia/ipwireless/hardware.c b/drivers/char/pcmcia/ipwireless/hardware.c index 99cffdab105..0aeb5a38d29 100644 --- a/drivers/char/pcmcia/ipwireless/hardware.c +++ b/drivers/char/pcmcia/ipwireless/hardware.c @@ -1729,7 +1729,7 @@ void ipwireless_hardware_free(struct ipw_hardware *hw)  	ipwireless_stop_interrupts(hw); -	flush_scheduled_work(); +	flush_work_sync(&hw->work_rx);  	for (i = 0; i < NL_NUM_OF_ADDRESSES; i++)  		if (hw->packet_assembler[i] != NULL) diff --git a/drivers/char/pcmcia/ipwireless/network.c b/drivers/char/pcmcia/ipwireless/network.c index 9fe53834793..f7daeea598e 100644 --- a/drivers/char/pcmcia/ipwireless/network.c +++ b/drivers/char/pcmcia/ipwireless/network.c @@ -430,7 +430,8 @@ void ipwireless_network_free(struct ipw_network *network)  	network->shutting_down = 1;  	ipwireless_ppp_close(network); -	flush_scheduled_work(); +	flush_work_sync(&network->work_go_online); +	flush_work_sync(&network->work_go_offline);  	ipwireless_stop_interrupts(network->hardware);  	ipwireless_associate_network(network->hardware, NULL); diff --git a/drivers/char/pcmcia/ipwireless/tty.c b/drivers/char/pcmcia/ipwireless/tty.c index 1a2c2c3b068..f5eb28b6cb0 100644 --- a/drivers/char/pcmcia/ipwireless/tty.c +++ b/drivers/char/pcmcia/ipwireless/tty.c @@ -577,7 +577,7 @@ void ipwireless_tty_free(struct ipw_tty *tty)  				mutex_unlock(&ttyj->ipw_tty_mutex);  				tty_hangup(ttyj->linux_tty);  				/* Wait till the tty_hangup has completed */ -				flush_scheduled_work(); +				flush_work_sync(&ttyj->linux_tty->hangup_work);  				/* FIXME: Exactly how is the tty object locked here  				   against a parallel ioctl etc */  				mutex_lock(&ttyj->ipw_tty_mutex); diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 73f66d03624..79e36c878a4 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -1434,7 +1434,7 @@ static int __devexit sonypi_remove(struct platform_device *dev)  	sonypi_disable();  	synchronize_irq(sonypi_device.irq); -	flush_scheduled_work(); +	flush_work_sync(&sonypi_device.input_work);  	if (useinput) {  		input_unregister_device(sonypi_device.input_key_dev); diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 7c4133582db..0b3af3fe676 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c @@ -986,7 +986,7 @@ int tpm_release(struct inode *inode, struct file *file)  	struct tpm_chip *chip = file->private_data;  	del_singleshot_timer_sync(&chip->user_read_timer); -	flush_scheduled_work(); +	flush_work_sync(&chip->work);  	file->private_data = NULL;  	atomic_set(&chip->data_pending, 0);  	kfree(chip->data_buffer); @@ -1038,7 +1038,7 @@ ssize_t tpm_read(struct file *file, char __user *buf,  	ssize_t ret_size;  	del_singleshot_timer_sync(&chip->user_read_timer); -	flush_scheduled_work(); +	flush_work_sync(&chip->work);  	ret_size = atomic_read(&chip->data_pending);  	atomic_set(&chip->data_pending, 0);  	if (ret_size > 0) {	/* relay data */ diff --git a/drivers/gpu/drm/ttm/ttm_bo.c b/drivers/gpu/drm/ttm/ttm_bo.c index 148a322d8f5..934a96a7854 100644 --- a/drivers/gpu/drm/ttm/ttm_bo.c +++ b/drivers/gpu/drm/ttm/ttm_bo.c @@ -1472,8 +1472,7 @@ int ttm_bo_device_release(struct ttm_bo_device *bdev)  	list_del(&bdev->device_list);  	mutex_unlock(&glob->device_list_mutex); -	if (!cancel_delayed_work(&bdev->wq)) -		flush_scheduled_work(); +	cancel_delayed_work_sync(&bdev->wq);  	while (ttm_bo_delayed_delete(bdev, true))  		; diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c index 41d9a5b73c0..fe096a7cc0d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_fb.c @@ -659,7 +659,7 @@ int vmw_fb_off(struct vmw_private *vmw_priv)  	par->dirty.active = false;  	spin_unlock_irqrestore(&par->dirty.lock, flags); -	flush_scheduled_work(); +	flush_delayed_work_sync(&info->deferred_work);  	par->bo_ptr = NULL;  	ttm_bo_kunmap(&par->map); diff --git a/drivers/isdn/capi/capidrv.c b/drivers/isdn/capi/capidrv.c index e54e79d4e2c..92607ed25e2 100644 --- a/drivers/isdn/capi/capidrv.c +++ b/drivers/isdn/capi/capidrv.c @@ -2297,6 +2297,7 @@ static int __init capidrv_init(void)  	errcode = capi20_get_profile(0, &profile);  	if (errcode != CAPI_NOERROR) { +		unregister_capictr_notifier(&capictr_nb);  		capi20_release(&global.ap);  		return -EIO;  	} diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 3acf94cc5ac..2b33b2627fc 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -38,6 +38,7 @@  #include <linux/rcupdate.h>  static int showcapimsgs = 0; +static struct workqueue_struct *kcapi_wq;  MODULE_DESCRIPTION("CAPI4Linux: kernel CAPI layer");  MODULE_AUTHOR("Carsten Paeth"); @@ -291,7 +292,7 @@ static int notify_push(unsigned int event_type, u32 controller)  	event->type = event_type;  	event->controller = controller; -	schedule_work(&event->work); +	queue_work(kcapi_wq, &event->work);  	return 0;  } @@ -408,7 +409,7 @@ void capi_ctr_handle_message(struct capi_ctr *ctr, u16 appl,  		goto error;  	}  	skb_queue_tail(&ap->recv_queue, skb); -	schedule_work(&ap->recv_work); +	queue_work(kcapi_wq, &ap->recv_work);  	rcu_read_unlock();  	return; @@ -743,7 +744,7 @@ u16 capi20_release(struct capi20_appl *ap)  	mutex_unlock(&capi_controller_lock); -	flush_scheduled_work(); +	flush_workqueue(kcapi_wq);  	skb_queue_purge(&ap->recv_queue);  	if (showcapimsgs & 1) { @@ -1285,21 +1286,30 @@ static int __init kcapi_init(void)  {  	int err; +	kcapi_wq = alloc_workqueue("kcapi", 0, 0); +	if (!kcapi_wq) +		return -ENOMEM; +  	register_capictr_notifier(&capictr_nb);  	err = cdebug_init(); -	if (!err) -		kcapi_proc_init(); -	return err; +	if (err) { +		unregister_capictr_notifier(&capictr_nb); +		destroy_workqueue(kcapi_wq); +		return err; +	} + +	kcapi_proc_init(); +	return 0;  }  static void __exit kcapi_exit(void)  {          kcapi_proc_exit(); -	/* make sure all notifiers are finished */ -	flush_scheduled_work(); +	unregister_capictr_notifier(&capictr_nb);  	cdebug_exit(); +	destroy_workqueue(kcapi_wq);  }  module_init(kcapi_init); diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index 307bd6e8988..199f374cf9d 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -110,7 +110,7 @@ mISDN_freedchannel(struct dchannel *ch)  	}  	skb_queue_purge(&ch->squeue);  	skb_queue_purge(&ch->rqueue); -	flush_scheduled_work(); +	flush_work_sync(&ch->workq);  	return 0;  }  EXPORT_SYMBOL(mISDN_freedchannel); @@ -143,7 +143,7 @@ mISDN_freebchannel(struct bchannel *ch)  	mISDN_clear_bchannel(ch);  	skb_queue_purge(&ch->rqueue);  	ch->rcount = 0; -	flush_scheduled_work(); +	flush_work_sync(&ch->workq);  	return 0;  }  EXPORT_SYMBOL(mISDN_freebchannel); diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index 5b59796ed25..bd526f664a3 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -1269,6 +1269,8 @@ release_card(struct l1oip *hc)  	if (timer_pending(&hc->timeout_tl))  		del_timer(&hc->timeout_tl); +	cancel_work_sync(&hc->workq); +  	if (hc->socket_thread)  		l1oip_socket_close(hc); diff --git a/drivers/leds/leds-wm8350.c b/drivers/leds/leds-wm8350.c index 5aab32ce4f4..a0452327328 100644 --- a/drivers/leds/leds-wm8350.c +++ b/drivers/leds/leds-wm8350.c @@ -276,7 +276,7 @@ static int wm8350_led_remove(struct platform_device *pdev)  	struct wm8350_led *led = platform_get_drvdata(pdev);  	led_classdev_unregister(&led->cdev); -	flush_scheduled_work(); +	flush_work_sync(&led->work);  	wm8350_led_disable(led);  	regulator_put(led->dcdc);  	regulator_put(led->isink); diff --git a/drivers/macintosh/ams/ams-core.c b/drivers/macintosh/ams/ams-core.c index 2ad62c339cd..399beb1638d 100644 --- a/drivers/macintosh/ams/ams-core.c +++ b/drivers/macintosh/ams/ams-core.c @@ -226,7 +226,7 @@ void ams_sensor_detach(void)  	 * We do this after ams_info.exit(), because an interrupt might  	 * have arrived before disabling them.  	 */ -	flush_scheduled_work(); +	flush_work_sync(&ams_info.worker);  	/* Remove device */  	of_device_unregister(ams_info.of_dev); diff --git a/drivers/macintosh/rack-meter.c b/drivers/macintosh/rack-meter.c index 53cce3a5da2..39f660b2a60 100644 --- a/drivers/macintosh/rack-meter.c +++ b/drivers/macintosh/rack-meter.c @@ -285,8 +285,8 @@ static void __devinit rackmeter_init_cpu_sniffer(struct rackmeter *rm)  static void __devexit rackmeter_stop_cpu_sniffer(struct rackmeter *rm)  { -	cancel_rearming_delayed_work(&rm->cpu[0].sniffer); -	cancel_rearming_delayed_work(&rm->cpu[1].sniffer); +	cancel_delayed_work_sync(&rm->cpu[0].sniffer); +	cancel_delayed_work_sync(&rm->cpu[1].sniffer);  }  static int __devinit rackmeter_setup(struct rackmeter *rm) diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 4df42aaae7f..51752a9ef7a 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -1329,7 +1329,8 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)  		return -EBUSY;  	dvb_net_stop(net); -	flush_scheduled_work(); +	flush_work_sync(&priv->set_multicast_list_wq); +	flush_work_sync(&priv->restart_net_feed_wq);  	printk("dvb_net: removed network interface %s\n", net->name);  	unregister_netdev(net);  	dvbnet->state[num]=0; diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c index c6498f536df..23005b3cf30 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c @@ -313,8 +313,7 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)  int dvb_usb_remote_exit(struct dvb_usb_device *d)  {  	if (d->state & DVB_USB_STATE_REMOTE) { -		cancel_rearming_delayed_work(&d->rc_query_work); -		flush_scheduled_work(); +		cancel_delayed_work_sync(&d->rc_query_work);  		if (d->props.rc.mode == DVB_RC_LEGACY)  			input_unregister_device(d->input_dev);  		else diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c index a7b369a439d..9f73c2cfc9e 100644 --- a/drivers/media/dvb/mantis/mantis_evm.c +++ b/drivers/media/dvb/mantis/mantis_evm.c @@ -111,7 +111,7 @@ void mantis_evmgr_exit(struct mantis_ca *ca)  	struct mantis_pci *mantis = ca->ca_priv;  	dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting"); -	flush_scheduled_work(); +	flush_work_sync(&ca->hif_evm_work);  	mantis_hif_exit(ca);  	mantis_pcmcia_exit(ca);  } diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c index 7d2f2398fa8..97b889e8a34 100644 --- a/drivers/media/dvb/mantis/mantis_uart.c +++ b/drivers/media/dvb/mantis/mantis_uart.c @@ -182,5 +182,6 @@ void mantis_uart_exit(struct mantis_pci *mantis)  {  	/* disable interrupt */  	mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL); +	flush_work_sync(&mantis->uart_work);  }  EXPORT_SYMBOL_GPL(mantis_uart_exit); diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c index 849cd170b82..91399c94cd1 100644 --- a/drivers/media/video/bt8xx/bttv-driver.c +++ b/drivers/media/video/bt8xx/bttv-driver.c @@ -189,8 +189,14 @@ static void request_modules(struct bttv *dev)  	INIT_WORK(&dev->request_module_wk, request_module_async);  	schedule_work(&dev->request_module_wk);  } + +static void flush_request_modules(struct bttv *dev) +{ +	flush_work_sync(&dev->request_module_wk); +}  #else  #define request_modules(dev) +#define flush_request_modules(dev)  #endif /* CONFIG_MODULES */ @@ -4429,6 +4435,9 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)  	if (bttv_verbose)  		printk("bttv%d: unloading\n",btv->c.nr); +	if (bttv_tvcards[btv->c.type].has_dvb) +		flush_request_modules(btv); +  	/* shutdown everything (DMA+IRQs) */  	btand(~15, BT848_GPIO_DMA_CTL);  	btwrite(0, BT848_INT_MASK); diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c index 97793b96060..e8b64bca9db 100644 --- a/drivers/media/video/bt8xx/bttv-input.c +++ b/drivers/media/video/bt8xx/bttv-input.c @@ -319,16 +319,13 @@ static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)  static void bttv_ir_stop(struct bttv *btv)  { -	if (btv->remote->polling) { +	if (btv->remote->polling)  		del_timer_sync(&btv->remote->timer); -		flush_scheduled_work(); -	}  	if (btv->remote->rc5_gpio) {  		u32 gpio;  		del_timer_sync(&btv->remote->timer); -		flush_scheduled_work();  		gpio = bttv_gpio_read(&btv->c);  		bttv_gpio_write(&btv->c, gpio & ~(1 << 4)); diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c index 676e5bef89e..133ec2bac18 100644 --- a/drivers/media/video/cx18/cx18-driver.c +++ b/drivers/media/video/cx18/cx18-driver.c @@ -267,8 +267,14 @@ static void request_modules(struct cx18 *dev)  	INIT_WORK(&dev->request_module_wk, request_module_async);  	schedule_work(&dev->request_module_wk);  } + +static void flush_request_modules(struct cx18 *dev) +{ +	flush_work_sync(&dev->request_module_wk); +}  #else  #define request_modules(dev) +#define flush_request_modules(dev)  #endif /* CONFIG_MODULES */  /* Generic utility functions */ @@ -1233,6 +1239,8 @@ static void cx18_remove(struct pci_dev *pci_dev)  	CX18_DEBUG_INFO("Removing Card\n"); +	flush_request_modules(cx); +  	/* Stop all captures */  	CX18_DEBUG_INFO("Stopping all streams\n");  	if (atomic_read(&cx->tot_capturing) > 0) diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c index 6905607ffca..588f3e8f028 100644 --- a/drivers/media/video/cx231xx/cx231xx-cards.c +++ b/drivers/media/video/cx231xx/cx231xx-cards.c @@ -813,8 +813,14 @@ static void request_modules(struct cx231xx *dev)  	INIT_WORK(&dev->request_module_wk, request_module_async);  	schedule_work(&dev->request_module_wk);  } + +static void flush_request_modules(struct cx231xx *dev) +{ +	flush_work_sync(&dev->request_module_wk); +}  #else  #define request_modules(dev) +#define flush_request_modules(dev)  #endif /* CONFIG_MODULES */  /* @@ -1147,6 +1153,8 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)  	if (!dev->udev)  		return; +	flush_request_modules(dev); +  	/* delete v4l2 device */  	v4l2_device_unregister(&dev->v4l2_dev); diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c index 0b0d0664382..199b9964bbe 100644 --- a/drivers/media/video/cx23885/cx23885-input.c +++ b/drivers/media/video/cx23885/cx23885-input.c @@ -229,8 +229,6 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev)  		v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, ¶ms);  		v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, ¶ms);  	} - -	flush_scheduled_work();  }  static void cx23885_input_ir_close(struct rc_dev *rc) diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c index f7d71acbb07..addf9545e9b 100644 --- a/drivers/media/video/cx88/cx88-mpeg.c +++ b/drivers/media/video/cx88/cx88-mpeg.c @@ -66,8 +66,14 @@ static void request_modules(struct cx8802_dev *dev)  	INIT_WORK(&dev->request_module_wk, request_module_async);  	schedule_work(&dev->request_module_wk);  } + +static void flush_request_modules(struct cx8802_dev *dev) +{ +	flush_work_sync(&dev->request_module_wk); +}  #else  #define request_modules(dev) +#define flush_request_modules(dev)  #endif /* CONFIG_MODULES */ @@ -819,6 +825,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)  	dprintk( 1, "%s\n", __func__); +	flush_request_modules(dev); +  	if (!list_empty(&dev->drvlist)) {  		struct cx8802_driver *drv, *tmp;  		int err; diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c index 8af302b425b..099d5df8c57 100644 --- a/drivers/media/video/em28xx/em28xx-cards.c +++ b/drivers/media/video/em28xx/em28xx-cards.c @@ -2690,8 +2690,14 @@ static void request_modules(struct em28xx *dev)  	INIT_WORK(&dev->request_module_wk, request_module_async);  	schedule_work(&dev->request_module_wk);  } + +static void flush_request_modules(struct em28xx *dev) +{ +	flush_work_sync(&dev->request_module_wk); +}  #else  #define request_modules(dev) +#define flush_request_modules(dev)  #endif /* CONFIG_MODULES */  /* @@ -3118,6 +3124,8 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)  	em28xx_info("disconnecting %s\n", dev->vdev->name); +	flush_request_modules(dev); +  	/* wait until all current v4l2 io is finished then deallocate  	   resources */  	mutex_lock(&dev->lock); diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c index 29cc74441a7..ba1ba8648c8 100644 --- a/drivers/media/video/em28xx/em28xx-input.c +++ b/drivers/media/video/em28xx/em28xx-input.c @@ -551,7 +551,7 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev)  {  	if (dev->sbutton_input_dev != NULL) {  		em28xx_info("Deregistering snapshot button\n"); -		cancel_rearming_delayed_work(&dev->sbutton_query_work); +		cancel_delayed_work_sync(&dev->sbutton_query_work);  		input_unregister_device(dev->sbutton_input_dev);  		dev->sbutton_input_dev = NULL;  	} diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c index 378b094aff1..01755276290 100644 --- a/drivers/media/video/omap24xxcam.c +++ b/drivers/media/video/omap24xxcam.c @@ -1198,7 +1198,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)  	atomic_inc(&cam->reset_disable); -	flush_scheduled_work(); +	flush_work_sync(&cam->sensor_reset_work);  	rval = videobuf_streamoff(q);  	if (!rval) { @@ -1512,7 +1512,7 @@ static int omap24xxcam_release(struct file *file)  	atomic_inc(&cam->reset_disable); -	flush_scheduled_work(); +	flush_work_sync(&cam->sensor_reset_work);  	/* stop streaming capture */  	videobuf_streamoff(&fh->vbq); @@ -1536,7 +1536,7 @@ static int omap24xxcam_release(struct file *file)  	 * not be scheduled anymore since streaming is already  	 * disabled.)  	 */ -	flush_scheduled_work(); +	flush_work_sync(&cam->sensor_reset_work);  	mutex_lock(&cam->mutex);  	if (atomic_dec_return(&cam->users) == 0) { diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index 756a2781226..6abeecff6da 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -166,8 +166,14 @@ static void request_submodules(struct saa7134_dev *dev)  	schedule_work(&dev->request_module_wk);  } +static void flush_request_submodules(struct saa7134_dev *dev) +{ +	flush_work_sync(&dev->request_module_wk); +} +  #else  #define request_submodules(dev) +#define flush_request_submodules(dev)  #endif /* CONFIG_MODULES */  /* ------------------------------------------------------------------ */ @@ -1010,8 +1016,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,  		}  	} -	request_submodules(dev); -  	v4l2_prio_init(&dev->prio);  	mutex_lock(&saa7134_devlist_lock); @@ -1066,6 +1070,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,  	if (saa7134_dmasound_init && !dev->dmasound.priv_data)  		saa7134_dmasound_init(dev); +	request_submodules(dev);  	return 0;   fail4: @@ -1091,6 +1096,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)  	struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);  	struct saa7134_mpeg_ops *mops; +	flush_request_submodules(dev); +  	/* Release DMA sound modules if present */  	if (saa7134_dmasound_exit && dev->dmasound.priv_data) {  		saa7134_dmasound_exit(dev); diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c index b890aafe7d6..6b8459c7728 100644 --- a/drivers/media/video/saa7134/saa7134-empress.c +++ b/drivers/media/video/saa7134/saa7134-empress.c @@ -553,7 +553,7 @@ static int empress_fini(struct saa7134_dev *dev)  	if (NULL == dev->empress_dev)  		return 0; -	flush_scheduled_work(); +	flush_work_sync(&dev->empress_workqueue);  	video_unregister_device(dev->empress_dev);  	dev->empress_dev = NULL;  	return 0; diff --git a/drivers/mfd/menelaus.c b/drivers/mfd/menelaus.c index 4ba85bbdb4c..9cee8e7f0bc 100644 --- a/drivers/mfd/menelaus.c +++ b/drivers/mfd/menelaus.c @@ -1259,7 +1259,7 @@ static int menelaus_probe(struct i2c_client *client,  	return 0;  fail2:  	free_irq(client->irq, menelaus); -	flush_scheduled_work(); +	flush_work_sync(&menelaus->work);  fail1:  	kfree(menelaus);  	return err; @@ -1270,6 +1270,7 @@ static int __exit menelaus_remove(struct i2c_client *client)  	struct menelaus_chip	*menelaus = i2c_get_clientdata(client);  	free_irq(client->irq, menelaus); +	flush_work_sync(&menelaus->work);  	kfree(menelaus);  	the_menelaus = NULL;  	return 0; diff --git a/drivers/mfd/tps65010.c b/drivers/mfd/tps65010.c index d0016b67d12..90187fe33e0 100644 --- a/drivers/mfd/tps65010.c +++ b/drivers/mfd/tps65010.c @@ -242,7 +242,7 @@ static int dbg_show(struct seq_file *s, void *_)  	seq_printf(s, "mask2     %s\n", buf);  	/* ignore ackint2 */ -	(void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); +	schedule_delayed_work(&tps->work, POWER_POLL_DELAY);  	/* VMAIN voltage, enable lowpower, etc */ @@ -400,7 +400,7 @@ static void tps65010_interrupt(struct tps65010 *tps)  			&& (tps->chgstatus & (TPS_CHG_USB|TPS_CHG_AC)))  		poll = 1;  	if (poll) -		(void) schedule_delayed_work(&tps->work, POWER_POLL_DELAY); +		schedule_delayed_work(&tps->work, POWER_POLL_DELAY);  	/* also potentially gpio-in rise or fall */  } @@ -410,7 +410,7 @@ static void tps65010_work(struct work_struct *work)  {  	struct tps65010		*tps; -	tps = container_of(work, struct tps65010, work.work); +	tps = container_of(to_delayed_work(work), struct tps65010, work);  	mutex_lock(&tps->lock);  	tps65010_interrupt(tps); @@ -448,7 +448,7 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)  	disable_irq_nosync(irq);  	set_bit(FLAG_IRQ_ENABLE, &tps->flags); -	(void) schedule_work(&tps->work.work); +	schedule_delayed_work(&tps->work, 0);  	return IRQ_HANDLED;  } @@ -527,8 +527,7 @@ static int __exit tps65010_remove(struct i2c_client *client)  	}  	if (client->irq > 0)  		free_irq(client->irq, tps); -	cancel_delayed_work(&tps->work); -	flush_scheduled_work(); +	cancel_delayed_work_sync(&tps->work);  	debugfs_remove(tps->file);  	kfree(tps);  	the_tps = NULL; @@ -720,7 +719,7 @@ int tps65010_set_vbus_draw(unsigned mA)  			&& test_and_set_bit(  				FLAG_VBUS_CHANGED, &the_tps->flags)) {  		/* gadget drivers call this in_irq() */ -		(void) schedule_work(&the_tps->work.work); +		schedule_delayed_work(&the_tps->work, 0);  	}  	local_irq_restore(flags); diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c index 193206602d8..668d41e594a 100644 --- a/drivers/misc/ioc4.c +++ b/drivers/misc/ioc4.c @@ -273,13 +273,11 @@ ioc4_variant(struct ioc4_driver_data *idd)  static void __devinit  ioc4_load_modules(struct work_struct *work)  { -	/* arg just has to be freed */ -  	request_module("sgiioc4"); - -	kfree(work);  } +static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules); +  /* Adds a new instance of an IOC4 card */  static int __devinit  ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) @@ -396,21 +394,12 @@ ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)  	 * PCI device.  	 */  	if (idd->idd_variant != IOC4_VARIANT_PCI_RT) { -		struct work_struct *work; -		work = kzalloc(sizeof(struct work_struct), GFP_KERNEL); -		if (!work) { -			printk(KERN_WARNING -			       "%s: IOC4 unable to allocate memory for " -			       "load of sub-modules.\n", __func__); -		} else { -			/* Request the module from a work procedure as the -			 * modprobe goes out to a userland helper and that -			 * will hang if done directly from ioc4_probe(). -			 */ -			printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n"); -			INIT_WORK(work, ioc4_load_modules); -			schedule_work(work); -		} +		/* Request the module from a work procedure as the modprobe +		 * goes out to a userland helper and that will hang if done +		 * directly from ioc4_probe(). +		 */ +		printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n"); +		schedule_work(&ioc4_load_modules_work);  	}  	return 0; @@ -498,7 +487,7 @@ static void __exit  ioc4_exit(void)  {  	/* Ensure ioc4_load_modules() has completed before exiting */ -	flush_scheduled_work(); +	flush_work_sync(&ioc4_load_modules_work);  	pci_unregister_driver(&ioc4_driver);  } diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 57dcf8fa774..a3a780faf85 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -1790,7 +1790,7 @@ static int __init mmc_init(void)  {  	int ret; -	workqueue = create_singlethread_workqueue("kmmcd"); +	workqueue = alloc_ordered_workqueue("kmmcd", 0);  	if (!workqueue)  		return -ENOMEM; diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 0c7e37f496e..379d2ffe4c8 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -173,6 +173,8 @@ struct mmc_omap_host {  	struct omap_mmc_platform_data *pdata;  }; +static struct workqueue_struct *mmc_omap_wq; +  static void mmc_omap_fclk_offdelay(struct mmc_omap_slot *slot)  {  	unsigned long tick_ns; @@ -289,7 +291,7 @@ static void mmc_omap_release_slot(struct mmc_omap_slot *slot, int clk_enabled)  		host->next_slot = new_slot;  		host->mmc = new_slot->mmc;  		spin_unlock_irqrestore(&host->slot_lock, flags); -		schedule_work(&host->slot_release_work); +		queue_work(mmc_omap_wq, &host->slot_release_work);  		return;  	} @@ -457,7 +459,7 @@ mmc_omap_xfer_done(struct mmc_omap_host *host, struct mmc_data *data)  	}  	host->stop_data = data; -	schedule_work(&host->send_stop_work); +	queue_work(mmc_omap_wq, &host->send_stop_work);  }  static void @@ -637,7 +639,7 @@ mmc_omap_cmd_timer(unsigned long data)  		OMAP_MMC_WRITE(host, IE, 0);  		disable_irq(host->irq);  		host->abort = 1; -		schedule_work(&host->cmd_abort_work); +		queue_work(mmc_omap_wq, &host->cmd_abort_work);  	}  	spin_unlock_irqrestore(&host->slot_lock, flags);  } @@ -826,7 +828,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)  		host->abort = 1;  		OMAP_MMC_WRITE(host, IE, 0);  		disable_irq_nosync(host->irq); -		schedule_work(&host->cmd_abort_work); +		queue_work(mmc_omap_wq, &host->cmd_abort_work);  		return IRQ_HANDLED;  	} @@ -1387,7 +1389,7 @@ static void mmc_omap_remove_slot(struct mmc_omap_slot *slot)  	tasklet_kill(&slot->cover_tasklet);  	del_timer_sync(&slot->cover_timer); -	flush_scheduled_work(); +	flush_workqueue(mmc_omap_wq);  	mmc_remove_host(mmc);  	mmc_free_host(mmc); @@ -1608,12 +1610,22 @@ static struct platform_driver mmc_omap_driver = {  static int __init mmc_omap_init(void)  { -	return platform_driver_probe(&mmc_omap_driver, mmc_omap_probe); +	int ret; + +	mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0); +	if (!mmc_omap_wq) +		return -ENOMEM; + +	ret = platform_driver_probe(&mmc_omap_driver, mmc_omap_probe); +	if (ret) +		destroy_workqueue(mmc_omap_wq); +	return ret;  }  static void __exit mmc_omap_exit(void)  {  	platform_driver_unregister(&mmc_omap_driver); +	destroy_workqueue(mmc_omap_wq);  }  module_init(mmc_omap_init); diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 5d46021cbb5..078fdf11af0 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -2290,7 +2290,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)  		free_irq(host->irq, host);  		if (mmc_slot(host).card_detect_irq)  			free_irq(mmc_slot(host).card_detect_irq, host); -		flush_scheduled_work(); +		flush_work_sync(&host->mmc_carddetect_work);  		mmc_host_disable(host->mmc);  		clk_disable(host->iclk); diff --git a/drivers/net/chelsio/my3126.c b/drivers/net/chelsio/my3126.c index 4c6028512d1..a683fd3bb62 100644 --- a/drivers/net/chelsio/my3126.c +++ b/drivers/net/chelsio/my3126.c @@ -22,7 +22,7 @@ static int my3126_interrupt_enable(struct cphy *cphy)  static int my3126_interrupt_disable(struct cphy *cphy)  { -	cancel_rearming_delayed_work(&cphy->phy_update); +	cancel_delayed_work_sync(&cphy->phy_update);  	return 0;  } diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 8f11d29a582..6d9275c52e0 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -1279,7 +1279,7 @@ static void emac_force_link_update(struct emac_instance *dev)  	netif_carrier_off(dev->ndev);  	smp_rmb();  	if (dev->link_polling) { -		cancel_rearming_delayed_work(&dev->link_work); +		cancel_delayed_work_sync(&dev->link_work);  		if (dev->link_polling)  			schedule_delayed_work(&dev->link_work,  PHY_POLL_LINK_OFF);  	} @@ -1294,7 +1294,7 @@ static int emac_close(struct net_device *ndev)  	if (dev->phy.address >= 0) {  		dev->link_polling = 0; -		cancel_rearming_delayed_work(&dev->link_work); +		cancel_delayed_work_sync(&dev->link_work);  	}  	mutex_lock(&dev->link_lock);  	emac_netif_stop(dev); diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index 43307bd42a6..6107304cb94 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -1207,7 +1207,6 @@ static void housekeeping_enable(struct zd_mac *mac)  static void housekeeping_disable(struct zd_mac *mac)  {  	dev_dbg_f(zd_mac_dev(mac), "\n"); -	cancel_rearming_delayed_workqueue(zd_workqueue, -		&mac->housekeeping.link_led_work); +	cancel_delayed_work_sync(&mac->housekeeping.link_led_work);  	zd_chip_control_leds(&mac->chip, ZD_LED_OFF);  } diff --git a/drivers/power/ds2760_battery.c b/drivers/power/ds2760_battery.c index b3c01c16a16..e7f89785bee 100644 --- a/drivers/power/ds2760_battery.c +++ b/drivers/power/ds2760_battery.c @@ -580,10 +580,8 @@ static int ds2760_battery_remove(struct platform_device *pdev)  {  	struct ds2760_device_info *di = platform_get_drvdata(pdev); -	cancel_rearming_delayed_workqueue(di->monitor_wqueue, -					  &di->monitor_work); -	cancel_rearming_delayed_workqueue(di->monitor_wqueue, -					  &di->set_charged_work); +	cancel_delayed_work_sync(&di->monitor_work); +	cancel_delayed_work_sync(&di->set_charged_work);  	destroy_workqueue(di->monitor_wqueue);  	power_supply_unregister(&di->bat);  	kfree(di); diff --git a/drivers/power/intel_mid_battery.c b/drivers/power/intel_mid_battery.c index 2a10cd36118..36cf402c067 100644 --- a/drivers/power/intel_mid_battery.c +++ b/drivers/power/intel_mid_battery.c @@ -730,8 +730,7 @@ static __devinit int probe(int irq, struct device *dev)  power_reg_failed_1:  	power_supply_unregister(&pbi->batt);  power_reg_failed: -	cancel_rearming_delayed_workqueue(pbi->monitor_wqueue, -						&pbi->monitor_battery); +	cancel_delayed_work_sync(&pbi->monitor_battery);  requestirq_failed:  	destroy_workqueue(pbi->monitor_wqueue);  wqueue_failed: @@ -760,8 +759,7 @@ static int __devexit platform_pmic_battery_remove(struct platform_device *pdev)  	struct pmic_power_module_info *pbi = dev_get_drvdata(&pdev->dev);  	free_irq(pbi->irq, pbi); -	cancel_rearming_delayed_workqueue(pbi->monitor_wqueue, -					&pbi->monitor_battery); +	cancel_delayed_work_sync(&pbi->monitor_battery);  	destroy_workqueue(pbi->monitor_wqueue);  	power_supply_unregister(&pbi->usb); diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 62227cd5241..0cc0984d155 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -104,7 +104,7 @@ static int clear_uie(struct rtc_device *rtc)  		}  		if (rtc->uie_task_active) {  			spin_unlock_irq(&rtc->irq_lock); -			flush_scheduled_work(); +			flush_work_sync(&rtc->uie_task);  			spin_lock_irq(&rtc->irq_lock);  		}  		rtc->uie_irq_active = 0; diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 48da85e97ca..077af1d7b9e 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -813,7 +813,7 @@ static int __devexit ds1305_remove(struct spi_device *spi)  	if (spi->irq) {  		set_bit(FLAG_EXITING, &ds1305->flags);  		free_irq(spi->irq, ds1305); -		flush_scheduled_work(); +		cancel_work_sync(&ds1305->work);  	}  	rtc_device_unregister(ds1305->rtc); diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 1f0007fd443..47fb6357c34 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -417,7 +417,7 @@ static int __devexit ds1374_remove(struct i2c_client *client)  		mutex_unlock(&ds1374->mutex);  		free_irq(client->irq, client); -		flush_scheduled_work(); +		cancel_work_sync(&ds1374->work);  	}  	rtc_device_unregister(ds1374->rtc); diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 57063552d3b..23a9ee19764 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -463,7 +463,7 @@ static int __devexit ds3232_remove(struct i2c_client *client)  		mutex_unlock(&ds3232->mutex);  		free_irq(client->irq, client); -		flush_scheduled_work(); +		cancel_work_sync(&ds3232->work);  	}  	rtc_device_unregister(ds3232->rtc); diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 1146e3522d3..af32a62e12a 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -650,7 +650,7 @@ static int __devexit rx8025_remove(struct i2c_client *client)  		mutex_unlock(lock);  		free_irq(client->irq, client); -		flush_scheduled_work(); +		cancel_work_sync(&rx8025->work);  	}  	rx8025_sysfs_unregister(&client->dev); diff --git a/drivers/s390/char/tape_3590.c b/drivers/s390/char/tape_3590.c index deff2c3361e..fbe361fcd2c 100644 --- a/drivers/s390/char/tape_3590.c +++ b/drivers/s390/char/tape_3590.c @@ -24,6 +24,8 @@  #include "tape_std.h"  #include "tape_3590.h" +static struct workqueue_struct *tape_3590_wq; +  /*   * Pointer to debug area.   */ @@ -613,7 +615,7 @@ tape_3590_schedule_work(struct tape_device *device, enum tape_op op)  	p->device = tape_get_device(device);  	p->op = op; -	schedule_work(&p->work); +	queue_work(tape_3590_wq, &p->work);  	return 0;  } @@ -1629,7 +1631,7 @@ fail_kmalloc:  static void  tape_3590_cleanup_device(struct tape_device *device)  { -	flush_scheduled_work(); +	flush_workqueue(tape_3590_wq);  	tape_std_unassign(device);  	kfree(device->discdata); @@ -1733,11 +1735,17 @@ tape_3590_init(void)  #endif  	DBF_EVENT(3, "3590 init\n"); + +	tape_3590_wq = alloc_workqueue("tape_3590", 0, 0); +	if (!tape_3590_wq) +		return -ENOMEM; +  	/* Register driver for 3590 tapes. */  	rc = ccw_driver_register(&tape_3590_driver); -	if (rc) +	if (rc) { +		destroy_workqueue(tape_3590_wq);  		DBF_EVENT(3, "3590 init failed\n"); -	else +	} else  		DBF_EVENT(3, "3590 registered\n");  	return rc;  } @@ -1746,7 +1754,7 @@ static void  tape_3590_exit(void)  {  	ccw_driver_unregister(&tape_3590_driver); - +	destroy_workqueue(tape_3590_wq);  	debug_unregister(TAPE_DBF_AREA);  } diff --git a/drivers/s390/char/tape_block.c b/drivers/s390/char/tape_block.c index f0fa9ca5cb2..55d2d0f4eab 100644 --- a/drivers/s390/char/tape_block.c +++ b/drivers/s390/char/tape_block.c @@ -264,7 +264,7 @@ cleanup_queue:  void  tapeblock_cleanup_device(struct tape_device *device)  { -	flush_scheduled_work(); +	flush_work_sync(&device->blk_data.requeue_task);  	tape_put_device(device);  	if (!device->blk_data.disk) { diff --git a/drivers/staging/pohmelfs/inode.c b/drivers/staging/pohmelfs/inode.c index cc8d2840f9b..56d3a4e5622 100644 --- a/drivers/staging/pohmelfs/inode.c +++ b/drivers/staging/pohmelfs/inode.c @@ -1325,8 +1325,8 @@ static void pohmelfs_put_super(struct super_block *sb)  	}  	psb->trans_scan_timeout = psb->drop_scan_timeout = 0; -	cancel_rearming_delayed_work(&psb->dwork); -	cancel_rearming_delayed_work(&psb->drop_dwork); +	cancel_delayed_work_sync(&psb->dwork); +	cancel_delayed_work_sync(&psb->drop_dwork);  	flush_scheduled_work();  	dprintk("%s: stopped workqueues.\n", __func__); diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index f383cb42b1d..a845f8b8382 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -1247,7 +1247,7 @@ static void cxacru_unbind(struct usbatm_data *usbatm_instance,  	mutex_unlock(&instance->poll_state_serialize);  	if (is_polling) -		cancel_rearming_delayed_work(&instance->poll_work); +		cancel_delayed_work_sync(&instance->poll_work);  	usb_kill_urb(instance->snd_urb);  	usb_kill_urb(instance->rcv_urb); diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c index 4716e707de5..0842cfbf60c 100644 --- a/drivers/usb/atm/speedtch.c +++ b/drivers/usb/atm/speedtch.c @@ -139,7 +139,8 @@ struct speedtch_instance_data {  	struct speedtch_params params; /* set in probe, constant afterwards */ -	struct delayed_work status_checker; +	struct timer_list status_check_timer; +	struct work_struct status_check_work;  	unsigned char last_status; @@ -498,7 +499,7 @@ static void speedtch_check_status(struct work_struct *work)  {  	struct speedtch_instance_data *instance =  		container_of(work, struct speedtch_instance_data, -			     status_checker.work); +			     status_check_work);  	struct usbatm_data *usbatm = instance->usbatm;  	struct atm_dev *atm_dev = usbatm->atm_dev;  	unsigned char *buf = instance->scratch_buffer; @@ -575,11 +576,11 @@ static void speedtch_status_poll(unsigned long data)  {  	struct speedtch_instance_data *instance = (void *)data; -	schedule_delayed_work(&instance->status_checker, 0); +	schedule_work(&instance->status_check_work);  	/* The following check is racy, but the race is harmless */  	if (instance->poll_delay < MAX_POLL_DELAY) -		mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(instance->poll_delay)); +		mod_timer(&instance->status_check_timer, jiffies + msecs_to_jiffies(instance->poll_delay));  	else  		atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n");  } @@ -595,7 +596,7 @@ static void speedtch_resubmit_int(unsigned long data)  	if (int_urb) {  		ret = usb_submit_urb(int_urb, GFP_ATOMIC);  		if (!ret) -			schedule_delayed_work(&instance->status_checker, 0); +			schedule_work(&instance->status_check_work);  		else {  			atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);  			mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY)); @@ -624,7 +625,7 @@ static void speedtch_handle_int(struct urb *int_urb)  	}  	if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) { -		del_timer(&instance->status_checker.timer); +		del_timer(&instance->status_check_timer);  		atm_info(usbatm, "DSL line goes up\n");  	} else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) {  		atm_info(usbatm, "DSL line goes down\n"); @@ -640,7 +641,7 @@ static void speedtch_handle_int(struct urb *int_urb)  	if ((int_urb = instance->int_urb)) {  		ret = usb_submit_urb(int_urb, GFP_ATOMIC); -		schedule_delayed_work(&instance->status_checker, 0); +		schedule_work(&instance->status_check_work);  		if (ret < 0) {  			atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);  			goto fail; @@ -686,7 +687,7 @@ static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_de  	}  	/* Start status polling */ -	mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(1000)); +	mod_timer(&instance->status_check_timer, jiffies + msecs_to_jiffies(1000));  	return 0;  } @@ -698,7 +699,7 @@ static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_de  	atm_dbg(usbatm, "%s entered\n", __func__); -	del_timer_sync(&instance->status_checker.timer); +	del_timer_sync(&instance->status_check_timer);  	/*  	 * Since resubmit_timer and int_urb can schedule themselves and @@ -717,7 +718,7 @@ static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_de  	del_timer_sync(&instance->resubmit_timer);  	usb_free_urb(int_urb); -	flush_scheduled_work(); +	flush_work_sync(&instance->status_check_work);  }  static int speedtch_pre_reset(struct usb_interface *intf) @@ -869,10 +870,11 @@ static int speedtch_bind(struct usbatm_data *usbatm,  	usbatm->flags |= (use_isoc ? UDSL_USE_ISOC : 0); -	INIT_DELAYED_WORK(&instance->status_checker, speedtch_check_status); +	INIT_WORK(&instance->status_check_work, speedtch_check_status); +	init_timer(&instance->status_check_timer); -	instance->status_checker.timer.function = speedtch_status_poll; -	instance->status_checker.timer.data = (unsigned long)instance; +	instance->status_check_timer.function = speedtch_status_poll; +	instance->status_check_timer.data = (unsigned long)instance;  	instance->last_status = 0xff;  	instance->poll_delay = MIN_POLL_DELAY; diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index e3454fe46b4..1eda968b564 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -839,11 +839,9 @@ void gether_cleanup(void)  		return;  	unregister_netdev(the_dev->net); +	flush_work_sync(&the_dev->work);  	free_netdev(the_dev->net); -	/* assuming we used keventd, it must quiesce too */ -	flush_scheduled_work(); -  	the_dev = NULL;  } diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c index 9751647665d..759a12ff804 100644 --- a/drivers/usb/host/ohci-hcd.c +++ b/drivers/usb/host/ohci-hcd.c @@ -901,7 +901,8 @@ static void ohci_stop (struct usb_hcd *hcd)  	ohci_dump (ohci, 1); -	flush_scheduled_work(); +	if (quirk_nec(ohci)) +		flush_work_sync(&ohci->nec_work);  	ohci_usb_reset (ohci);  	ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable); diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c index 45696949241..e00fa1b22ec 100644 --- a/drivers/usb/otg/isp1301_omap.c +++ b/drivers/usb/otg/isp1301_omap.c @@ -1247,7 +1247,7 @@ static int __exit isp1301_remove(struct i2c_client *i2c)  	isp->timer.data = 0;  	set_bit(WORK_STOP, &isp->todo);  	del_timer_sync(&isp->timer); -	flush_scheduled_work(); +	flush_work_sync(&isp->work);  	put_device(&i2c->dev);  	the_transceiver = NULL; diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c index e199b0f4f99..5be866bb7a4 100644 --- a/drivers/usb/serial/oti6858.c +++ b/drivers/usb/serial/oti6858.c @@ -613,9 +613,8 @@ static void oti6858_close(struct usb_serial_port *port)  	dbg("%s(): after buf_clear()", __func__);  	/* cancel scheduled setup */ -	cancel_delayed_work(&priv->delayed_setup_work); -	cancel_delayed_work(&priv->delayed_write_work); -	flush_scheduled_work(); +	cancel_delayed_work_sync(&priv->delayed_setup_work); +	cancel_delayed_work_sync(&priv->delayed_write_work);  	/* shutdown our urbs */  	dbg("%s(): shutting down urbs", __func__); diff --git a/drivers/video/fb_defio.c b/drivers/video/fb_defio.c index 6b93ef93cb1..804000183c5 100644 --- a/drivers/video/fb_defio.c +++ b/drivers/video/fb_defio.c @@ -75,7 +75,7 @@ int fb_deferred_io_fsync(struct file *file, int datasync)  		return 0;  	/* Kill off the delayed work */ -	cancel_rearming_delayed_work(&info->deferred_work); +	cancel_delayed_work_sync(&info->deferred_work);  	/* Run it immediately */  	return schedule_delayed_work(&info->deferred_work, 0); diff --git a/drivers/video/omap/lcd_mipid.c b/drivers/video/omap/lcd_mipid.c index 64dcc7439c9..90e3bdd1b7a 100644 --- a/drivers/video/omap/lcd_mipid.c +++ b/drivers/video/omap/lcd_mipid.c @@ -396,7 +396,7 @@ static void mipid_esd_start_check(struct mipid_device *md)  static void mipid_esd_stop_check(struct mipid_device *md)  {  	if (md->esd_check != NULL) -		cancel_rearming_delayed_workqueue(md->esd_wq, &md->esd_work); +		cancel_delayed_work_sync(&md->esd_work);  }  static void mipid_esd_work(struct work_struct *work) diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 9531c052d7a..9b39a5dd413 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -317,7 +317,12 @@ static void ncp_stop_tasks(struct ncp_server *server) {  	sk->sk_write_space  = server->write_space;  	release_sock(sk);  	del_timer_sync(&server->timeout_tm); -	flush_scheduled_work(); + +	flush_work_sync(&server->rcv.tq); +	if (sk->sk_socket->type == SOCK_STREAM) +		flush_work_sync(&server->tx.tq); +	else +		flush_work_sync(&server->timeout_tq);  }  static int  ncp_show_options(struct seq_file *seq, struct vfsmount *mnt) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 116cab970e0..fbd18c3074b 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -4336,7 +4336,7 @@ __nfs4_state_shutdown(void)  void  nfs4_state_shutdown(void)  { -	cancel_rearming_delayed_workqueue(laundry_wq, &laundromat_work); +	cancel_delayed_work_sync(&laundromat_work);  	destroy_workqueue(laundry_wq);  	locks_end_grace(&nfsd4_manager);  	nfs4_lock_state(); diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 9f26ac9be2a..9e3d45bcb5f 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -307,8 +307,7 @@ static void o2hb_arm_write_timeout(struct o2hb_region *reg)  static void o2hb_disarm_write_timeout(struct o2hb_region *reg)  { -	cancel_delayed_work(®->hr_write_timeout_work); -	flush_scheduled_work(); +	cancel_delayed_work_sync(®->hr_write_timeout_work);  }  static inline void o2hb_bio_wait_init(struct o2hb_bio_wait_ctxt *wc) diff --git a/fs/ocfs2/cluster/quorum.c b/fs/ocfs2/cluster/quorum.c index cf3e1669621..a87366750f2 100644 --- a/fs/ocfs2/cluster/quorum.c +++ b/fs/ocfs2/cluster/quorum.c @@ -325,5 +325,7 @@ void o2quo_init(void)  void o2quo_exit(void)  { -	flush_scheduled_work(); +	struct o2quo_state *qs = &o2quo_state; + +	flush_work_sync(&qs->qs_work);  } diff --git a/fs/xfs/xfs_mru_cache.c b/fs/xfs/xfs_mru_cache.c index 45ce15dc5b2..edfa178bafb 100644 --- a/fs/xfs/xfs_mru_cache.c +++ b/fs/xfs/xfs_mru_cache.c @@ -408,7 +408,7 @@ xfs_mru_cache_flush(  	spin_lock(&mru->lock);  	if (mru->queued) {  		spin_unlock(&mru->lock); -		cancel_rearming_delayed_workqueue(xfs_mru_reap_wq, &mru->work); +		cancel_delayed_work_sync(&mru->work);  		spin_lock(&mru->lock);  	} diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h index bd257fee603..1ac11586a2f 100644 --- a/include/linux/workqueue.h +++ b/include/linux/workqueue.h @@ -409,7 +409,7 @@ static inline bool __cancel_delayed_work(struct delayed_work *work)  }  /* Obsolete. use cancel_delayed_work_sync() */ -static inline +static inline __deprecated  void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,  					struct delayed_work *work)  { @@ -417,7 +417,7 @@ void cancel_rearming_delayed_workqueue(struct workqueue_struct *wq,  }  /* Obsolete. use cancel_delayed_work_sync() */ -static inline +static inline __deprecated  void cancel_rearming_delayed_work(struct delayed_work *work)  {  	cancel_delayed_work_sync(work); diff --git a/init/main.c b/init/main.c index ea51770c017..00799c1d462 100644 --- a/init/main.c +++ b/init/main.c @@ -777,9 +777,6 @@ static void __init do_initcalls(void)  	for (fn = __early_initcall_end; fn < __initcall_end; fn++)  		do_one_initcall(*fn); - -	/* Make sure there is no pending stuff from the initcall sequence */ -	flush_scheduled_work();  }  /* diff --git a/kernel/workqueue.c b/kernel/workqueue.c index e785b0f2aea..8ee6ec82f88 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -932,6 +932,38 @@ static void insert_work(struct cpu_workqueue_struct *cwq,  		wake_up_worker(gcwq);  } +/* + * Test whether @work is being queued from another work executing on the + * same workqueue.  This is rather expensive and should only be used from + * cold paths. + */ +static bool is_chained_work(struct workqueue_struct *wq) +{ +	unsigned long flags; +	unsigned int cpu; + +	for_each_gcwq_cpu(cpu) { +		struct global_cwq *gcwq = get_gcwq(cpu); +		struct worker *worker; +		struct hlist_node *pos; +		int i; + +		spin_lock_irqsave(&gcwq->lock, flags); +		for_each_busy_worker(worker, i, pos, gcwq) { +			if (worker->task != current) +				continue; +			spin_unlock_irqrestore(&gcwq->lock, flags); +			/* +			 * I'm @worker, no locking necessary.  See if @work +			 * is headed to the same workqueue. +			 */ +			return worker->current_cwq->wq == wq; +		} +		spin_unlock_irqrestore(&gcwq->lock, flags); +	} +	return false; +} +  static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,  			 struct work_struct *work)  { @@ -943,7 +975,9 @@ static void __queue_work(unsigned int cpu, struct workqueue_struct *wq,  	debug_work_activate(work); -	if (WARN_ON_ONCE(wq->flags & WQ_DYING)) +	/* if dying, only works from the same workqueue are allowed */ +	if (unlikely(wq->flags & WQ_DYING) && +	    WARN_ON_ONCE(!is_chained_work(wq)))  		return;  	/* determine gcwq to use */ @@ -2936,11 +2970,35 @@ EXPORT_SYMBOL_GPL(__alloc_workqueue_key);   */  void destroy_workqueue(struct workqueue_struct *wq)  { +	unsigned int flush_cnt = 0;  	unsigned int cpu; +	/* +	 * Mark @wq dying and drain all pending works.  Once WQ_DYING is +	 * set, only chain queueing is allowed.  IOW, only currently +	 * pending or running work items on @wq can queue further work +	 * items on it.  @wq is flushed repeatedly until it becomes empty. +	 * The number of flushing is detemined by the depth of chaining and +	 * should be relatively short.  Whine if it takes too long. +	 */  	wq->flags |= WQ_DYING; +reflush:  	flush_workqueue(wq); +	for_each_cwq_cpu(cpu, wq) { +		struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq); + +		if (!cwq->nr_active && list_empty(&cwq->delayed_works)) +			continue; + +		if (++flush_cnt == 10 || +		    (flush_cnt % 100 == 0 && flush_cnt <= 1000)) +			printk(KERN_WARNING "workqueue %s: flush on " +			       "destruction isn't complete after %u tries\n", +			       wq->name, flush_cnt); +		goto reflush; +	} +  	/*  	 * wq list is used to freeze wq, remove from list after  	 * flushing is complete in case freeze races us. diff --git a/mm/slab.c b/mm/slab.c index 6107f2380e0..39e92c0e627 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1293,7 +1293,7 @@ static int __cpuinit cpuup_callback(struct notifier_block *nfb,  		 * anything expensive but will only modify reap_work  		 * and reschedule the timer.  		*/ -		cancel_rearming_delayed_work(&per_cpu(slab_reap_work, cpu)); +		cancel_delayed_work_sync(&per_cpu(slab_reap_work, cpu));  		/* Now the cache_reaper is guaranteed to be not running. */  		per_cpu(slab_reap_work, cpu).work.func = NULL;    		break; diff --git a/mm/vmstat.c b/mm/vmstat.c index 8f62f17ee1c..33c33e7a0f9 100644 --- a/mm/vmstat.c +++ b/mm/vmstat.c @@ -1033,7 +1033,7 @@ static int __cpuinit vmstat_cpuup_callback(struct notifier_block *nfb,  		break;  	case CPU_DOWN_PREPARE:  	case CPU_DOWN_PREPARE_FROZEN: -		cancel_rearming_delayed_work(&per_cpu(vmstat_work, cpu)); +		cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu));  		per_cpu(vmstat_work, cpu).work.func = NULL;  		break;  	case CPU_DOWN_FAILED: diff --git a/net/atm/lec.c b/net/atm/lec.c index 179e04bc99d..38754fdb88b 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -1607,7 +1607,7 @@ static void lec_arp_destroy(struct lec_priv *priv)  	struct lec_arp_table *entry;  	int i; -	cancel_rearming_delayed_work(&priv->lec_arp_work); +	cancel_delayed_work_sync(&priv->lec_arp_work);  	/*  	 * Remove all entries diff --git a/net/core/netpoll.c b/net/core/netpoll.c index 72d9b50109f..02dc2cbcbe8 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -923,7 +923,7 @@ void __netpoll_cleanup(struct netpoll *np)  		skb_queue_purge(&npinfo->arp_tx);  		skb_queue_purge(&npinfo->txq); -		cancel_rearming_delayed_work(&npinfo->tx_work); +		cancel_delayed_work_sync(&npinfo->tx_work);  		/* clean after last, unfinished work */  		__skb_queue_purge(&npinfo->txq); diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 6112a12578b..0c877a74e1f 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -390,7 +390,7 @@ static int dsa_remove(struct platform_device *pdev)  	if (dst->link_poll_needed)  		del_timer_sync(&dst->link_poll_timer); -	flush_scheduled_work(); +	flush_work_sync(&dst->link_poll_work);  	for (i = 0; i < dst->pd->nr_chips; i++) {  		struct dsa_switch *ds = dst->ds[i]; diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index c6f29363922..22f7ad5101a 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3430,7 +3430,7 @@ void ip_vs_control_cleanup(void)  {  	EnterFunction(2);  	ip_vs_trash_cleanup(); -	cancel_rearming_delayed_work(&defense_work); +	cancel_delayed_work_sync(&defense_work);  	cancel_work_sync(&defense_work.work);  	ip_vs_kill_estimator(&ip_vs_stats);  	unregister_sysctl_table(sysctl_header); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index dfcab5ac65a..96549df836e 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -770,7 +770,7 @@ static void xs_destroy(struct rpc_xprt *xprt)  	dprintk("RPC:       xs_destroy xprt %p\n", xprt); -	cancel_rearming_delayed_work(&transport->connect_worker); +	cancel_delayed_work_sync(&transport->connect_worker);  	xs_close(xprt);  	xs_free_peer_addresses(xprt);  |