From: Linus Torvalds Date: Sat, 8 Jan 2011 00:58:04 +0000 (-0800) Subject: Merge branch 'for-2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq X-Git-Tag: v2.6.38-rc1~456 X-Git-Url: http://git.cascardo.info/?p=cascardo%2Flinux.git;a=commitdiff_plain;h=23d69b09b78c4876e134f104a3814c30747c53f1;hp=e744070fd4ff9d3114277e52d77afa21579adce2 Merge branch 'for-2.6.38' of git://git./linux/kernel/git/tj/wq * 'for-2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq: (33 commits) usb: don't use flush_scheduled_work() speedtch: don't abuse struct delayed_work media/video: don't use flush_scheduled_work() media/video: explicitly flush request_module work ioc4: use static work_struct for ioc4_load_modules() init: don't call flush_scheduled_work() from do_initcalls() s390: don't use flush_scheduled_work() rtc: don't use flush_scheduled_work() mmc: update workqueue usages mfd: update workqueue usages dvb: don't use flush_scheduled_work() leds-wm8350: don't use flush_scheduled_work() mISDN: don't use flush_scheduled_work() macintosh/ams: don't use flush_scheduled_work() vmwgfx: don't use flush_scheduled_work() tpm: don't use flush_scheduled_work() sonypi: don't use flush_scheduled_work() hvsi: don't use flush_scheduled_work() xen: don't use flush_scheduled_work() gdrom: don't use flush_scheduled_work() ... Fixed up trivial conflict in drivers/media/video/bt8xx/bttv-input.c as per Tejun. --- diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index f2742e115b09..22f10818c2b3 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 ---------------------------- + +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 + +---------------------------- diff --git a/arch/arm/mach-pxa/sharpsl_pm.c b/arch/arm/mach-pxa/sharpsl_pm.c index 8fed027b12dc..e68d46d415f3 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 7b42c247316c..afc24556572b 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 f23d6d46b95b..0a6a943b3779 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 484697fef386..af6141bb1ba3 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 3951020e494a..25e4dffa0aad 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 657873e4328d..d7aa39e349a6 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 de65915308fb..64a21461c408 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 a2bc885ce60a..67a75a502c01 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 99cffdab1056..0aeb5a38d296 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 9fe538347932..f7daeea598e4 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 1a2c2c3b068f..f5eb28b6cb0f 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 73f66d03624d..79e36c878a4c 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 7c4133582dba..0b3af3fe6766 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 148a322d8f5d..934a96a78540 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 41d9a5b73c03..fe096a7cc0d7 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 e54e79d4e2c1..92607ed25e2e 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 3acf94cc5acd..2b33b2627fce 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -38,6 +38,7 @@ #include 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 307bd6e8988b..199f374cf9da 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 5b59796ed250..bd526f664a39 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 5aab32ce4f4d..a04523273282 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 2ad62c339cd2..399beb1638d1 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 53cce3a5da23..39f660b2a60d 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 4df42aaae7f7..51752a9ef7a4 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 c6498f536dff..23005b3cf30b 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 a7b369a439d6..9f73c2cfc9ea 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 7d2f2398fa8b..97b889e8a341 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 849cd170b821..91399c94cd18 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 97793b960600..e8b64bca9db2 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 676e5bef89eb..133ec2bac180 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 6905607ffca3..588f3e8f028b 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 0b0d0664382a..199b9964bbe5 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 f7d71acbb078..addf9545e9bf 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 8af302b425b3..099d5df8c572 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 29cc74441a7d..ba1ba8648c81 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 378b094aff16..017552762902 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 756a27812260..6abeecff6da7 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 b890aafe7d64..6b8459c7728e 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 4ba85bbdb4c1..9cee8e7f0bcb 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 d0016b67d125..90187fe33e04 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 193206602d88..668d41e594a9 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 57dcf8fa774a..a3a780faf85a 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 0c7e37f496ef..379d2ffe4c87 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 5d46021cbb57..078fdf11af03 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 4c6028512d10..a683fd3bb624 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 8f11d29a5828..6d9275c52e05 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 43307bd42a69..6107304cb94c 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 b3c01c16a164..e7f89785beef 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 2a10cd361181..36cf402c0677 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 62227cd52410..0cc0984d155b 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 48da85e97ca4..077af1d7b9e4 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 1f0007fd4431..47fb6357c346 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 57063552d3b7..23a9ee19764c 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 1146e3522d3c..af32a62e12a8 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 deff2c3361e4..fbe361fcd2c0 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 f0fa9ca5cb2c..55d2d0f4eabc 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 cc8d2840f9b6..56d3a4e5622f 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 f383cb42b1d7..a845f8b8382f 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 4716e707de59..0842cfbf60cf 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 e3454fe46b47..1eda968b5644 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 9751647665df..759a12ff8048 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 456969492410..e00fa1b22ecd 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 e199b0f4f99c..5be866bb7a41 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 6b93ef93cb12..804000183c5e 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 64dcc7439c99..90e3bdd1b7ab 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 9531c052d7a4..9b39a5dd4131 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 116cab970e0f..fbd18c3074bb 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 9f26ac9be2a4..9e3d45bcb5fd 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 cf3e16696216..a87366750f23 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 45ce15dc5b2b..edfa178bafb6 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 bd257fee6031..1ac11586a2f5 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 ea51770c0170..00799c1d4628 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 e785b0f2aea5..8ee6ec82f88a 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 6107f2380e08..39e92c0e6273 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 8f62f17ee1c7..33c33e7a0f9b 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 179e04bc99dd..38754fdb88ba 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 72d9b50109fc..02dc2cbcbe86 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 6112a12578b2..0c877a74e1f4 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 c6f293639220..22f7ad5101ab 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 dfcab5ac65af..96549df836ee 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);