Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

[PATCH] x86_64: Move ondemand timer into own work queue

Taking the cpu hotplug semaphore in a normal events workqueue
is unsafe because other tasks can wait for any workqueues with
it hold. This results in a deadlock.

Move the DBS timer into its own work queue which is not
affected by other work queue flushes to avoid this.

Has been acked by Venkatesh.

Cc: venkatesh.pallipadi@intel.com
Cc: cpufreq@lists.linux.org.uk
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by

Andi Kleen and committed by
Linus Torvalds
6810b548 ac71d12c

+20 -8
+20 -8
drivers/cpufreq/cpufreq_ondemand.c
··· 74 74 static DEFINE_MUTEX (dbs_mutex); 75 75 static DECLARE_WORK (dbs_work, do_dbs_timer, NULL); 76 76 77 + static struct workqueue_struct *dbs_workq; 78 + 77 79 struct dbs_tuners { 78 80 unsigned int sampling_rate; 79 81 unsigned int sampling_down_factor; ··· 366 364 mutex_lock(&dbs_mutex); 367 365 for_each_online_cpu(i) 368 366 dbs_check_cpu(i); 369 - schedule_delayed_work(&dbs_work, 370 - usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); 367 + queue_delayed_work(dbs_workq, &dbs_work, 368 + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); 371 369 mutex_unlock(&dbs_mutex); 372 370 } 373 371 374 372 static inline void dbs_timer_init(void) 375 373 { 376 374 INIT_WORK(&dbs_work, do_dbs_timer, NULL); 377 - schedule_delayed_work(&dbs_work, 378 - usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); 375 + if (!dbs_workq) 376 + dbs_workq = create_singlethread_workqueue("ondemand"); 377 + if (!dbs_workq) { 378 + printk(KERN_ERR "ondemand: Cannot initialize kernel thread\n"); 379 + return; 380 + } 381 + queue_delayed_work(dbs_workq, &dbs_work, 382 + usecs_to_jiffies(dbs_tuners_ins.sampling_rate)); 379 383 return; 380 384 } 381 385 382 386 static inline void dbs_timer_exit(void) 383 387 { 384 - cancel_delayed_work(&dbs_work); 385 - return; 388 + if (dbs_workq) 389 + cancel_rearming_delayed_workqueue(dbs_workq, &dbs_work); 386 390 } 387 391 388 392 static int cpufreq_governor_dbs(struct cpufreq_policy *policy, ··· 497 489 498 490 static void __exit cpufreq_gov_dbs_exit(void) 499 491 { 500 - /* Make sure that the scheduled work is indeed not running */ 501 - flush_scheduled_work(); 492 + /* Make sure that the scheduled work is indeed not running. 493 + Assumes the timer has been cancelled first. */ 494 + if (dbs_workq) { 495 + flush_workqueue(dbs_workq); 496 + destroy_workqueue(dbs_workq); 497 + } 502 498 503 499 cpufreq_unregister_governor(&cpufreq_gov_dbs); 504 500 }