diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-04 09:02:45 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-04 09:02:45 -0800 |
commit | ca50496eb487b639de1f502e77a48dde84152fb9 (patch) | |
tree | 73a2a57cb6dc9717daff0e8d7880928747e05b2d | |
parent | 609e3ff3ff797c0ddba1c61c8eb83923586ed079 (diff) | |
parent | fc4b514f2727f74a4587c31db87e0e93465518c3 (diff) | |
download | linux-ca50496eb487b639de1f502e77a48dde84152fb9.tar.bz2 |
Merge branch 'for-3.7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
Pull workqueue fixes from Tejun Heo:
"So, safe fixes my ass.
Commit 8852aac25e79 ("workqueue: mod_delayed_work_on() shouldn't queue
timer on 0 delay") had the side-effect of performing delayed_work
sanity checks even when @delay is 0, which should be fine for any sane
use cases.
Unfortunately, megaraid was being overly ingenious. It seemingly
wanted to use cancel_delayed_work_sync() before cancel_work_sync() was
introduced, but didn't want to waste the space for full delayed_work
as it was only going to use 0 @delay. So, it only allocated space for
struct work_struct and then cast it to struct delayed_work and passed
it into delayed_work functions - truly awesome engineering tradeoff to
save some bytes.
Xiaotian fixed it by making megraid allocate full delayed_work for
now. It should be converted to use work_struct and cancel_work_sync()
but I think we better do that after 3.7.
I added another commit to change BUG_ON()s in __queue_delayed_work()
to WARN_ON_ONCE()s so that the kernel doesn't crash even if there are
more such abuses."
* 'for-3.7-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq:
workqueue: convert BUG_ON()s in __queue_delayed_work() to WARN_ON_ONCE()s
megaraid: fix BUG_ON() from incorrect use of delayed work
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.h | 2 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 14 | ||||
-rw-r--r-- | kernel/workqueue.c | 4 |
3 files changed, 9 insertions, 11 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index 16b7a72a70c4..3b2365c8eab2 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -1276,7 +1276,7 @@ struct megasas_evt_detail { } __attribute__ ((packed)); struct megasas_aen_event { - struct work_struct hotplug_work; + struct delayed_work hotplug_work; struct megasas_instance *instance; }; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index d2c5366aff7f..e4f2baacf1e1 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -2060,9 +2060,9 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) } else { ev->instance = instance; instance->ev = ev; - INIT_WORK(&ev->hotplug_work, megasas_aen_polling); - schedule_delayed_work( - (struct delayed_work *)&ev->hotplug_work, 0); + INIT_DELAYED_WORK(&ev->hotplug_work, + megasas_aen_polling); + schedule_delayed_work(&ev->hotplug_work, 0); } } } @@ -4352,8 +4352,7 @@ megasas_suspend(struct pci_dev *pdev, pm_message_t state) /* cancel the delayed work if this work still in queue */ if (instance->ev != NULL) { struct megasas_aen_event *ev = instance->ev; - cancel_delayed_work_sync( - (struct delayed_work *)&ev->hotplug_work); + cancel_delayed_work_sync(&ev->hotplug_work); instance->ev = NULL; } @@ -4545,8 +4544,7 @@ static void __devexit megasas_detach_one(struct pci_dev *pdev) /* cancel the delayed work if this work still in queue*/ if (instance->ev != NULL) { struct megasas_aen_event *ev = instance->ev; - cancel_delayed_work_sync( - (struct delayed_work *)&ev->hotplug_work); + cancel_delayed_work_sync(&ev->hotplug_work); instance->ev = NULL; } @@ -5190,7 +5188,7 @@ static void megasas_aen_polling(struct work_struct *work) { struct megasas_aen_event *ev = - container_of(work, struct megasas_aen_event, hotplug_work); + container_of(work, struct megasas_aen_event, hotplug_work.work); struct megasas_instance *instance = ev->instance; union megasas_evt_class_locale class_locale; struct Scsi_Host *host; diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 084aa47bac82..1dae900df798 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -1361,8 +1361,8 @@ static void __queue_delayed_work(int cpu, struct workqueue_struct *wq, WARN_ON_ONCE(timer->function != delayed_work_timer_fn || timer->data != (unsigned long)dwork); - BUG_ON(timer_pending(timer)); - BUG_ON(!list_empty(&work->entry)); + WARN_ON_ONCE(timer_pending(timer)); + WARN_ON_ONCE(!list_empty(&work->entry)); /* * If @delay is 0, queue @dwork->work immediately. This is for |