@@ -5363,37 +5363,154 @@ EXPORT_STATIC_CALL(preempt_schedule_notrace);
53635363 * preempt_schedule_notrace <- preempt_schedule_notrace
53645364 * irqentry_exit_cond_resched <- irqentry_exit_cond_resched
53655365 */
5366- static int __init setup_preempt_mode (char * str )
5366+
5367+ enum {
5368+ preempt_dynamic_none = 0 ,
5369+ preempt_dynamic_voluntary ,
5370+ preempt_dynamic_full ,
5371+ };
5372+
5373+ static int preempt_dynamic_mode = preempt_dynamic_full ;
5374+
5375+ static int sched_dynamic_mode (const char * str )
53675376{
5368- if (!strcmp (str , "none" )) {
5377+ if (!strcmp (str , "none" ))
5378+ return 0 ;
5379+
5380+ if (!strcmp (str , "voluntary" ))
5381+ return 1 ;
5382+
5383+ if (!strcmp (str , "full" ))
5384+ return 2 ;
5385+
5386+ return -1 ;
5387+ }
5388+
5389+ static void sched_dynamic_update (int mode )
5390+ {
5391+ /*
5392+ * Avoid {NONE,VOLUNTARY} -> FULL transitions from ever ending up in
5393+ * the ZERO state, which is invalid.
5394+ */
5395+ static_call_update (cond_resched , __cond_resched );
5396+ static_call_update (might_resched , __cond_resched );
5397+ static_call_update (preempt_schedule , __preempt_schedule_func );
5398+ static_call_update (preempt_schedule_notrace , __preempt_schedule_notrace_func );
5399+ static_call_update (irqentry_exit_cond_resched , irqentry_exit_cond_resched );
5400+
5401+ switch (mode ) {
5402+ case preempt_dynamic_none :
53695403 static_call_update (cond_resched , __cond_resched );
53705404 static_call_update (might_resched , (typeof (& __cond_resched )) __static_call_return0 );
53715405 static_call_update (preempt_schedule , (typeof (& preempt_schedule )) NULL );
53725406 static_call_update (preempt_schedule_notrace , (typeof (& preempt_schedule_notrace )) NULL );
53735407 static_call_update (irqentry_exit_cond_resched , (typeof (& irqentry_exit_cond_resched )) NULL );
5374- pr_info ("Dynamic Preempt: %s\n" , str );
5375- } else if (!strcmp (str , "voluntary" )) {
5408+ pr_info ("Dynamic Preempt: none\n" );
5409+ break ;
5410+
5411+ case preempt_dynamic_voluntary :
53765412 static_call_update (cond_resched , __cond_resched );
53775413 static_call_update (might_resched , __cond_resched );
53785414 static_call_update (preempt_schedule , (typeof (& preempt_schedule )) NULL );
53795415 static_call_update (preempt_schedule_notrace , (typeof (& preempt_schedule_notrace )) NULL );
53805416 static_call_update (irqentry_exit_cond_resched , (typeof (& irqentry_exit_cond_resched )) NULL );
5381- pr_info ("Dynamic Preempt: %s\n" , str );
5382- } else if (!strcmp (str , "full" )) {
5417+ pr_info ("Dynamic Preempt: voluntary\n" );
5418+ break ;
5419+
5420+ case preempt_dynamic_full :
53835421 static_call_update (cond_resched , (typeof (& __cond_resched )) __static_call_return0 );
53845422 static_call_update (might_resched , (typeof (& __cond_resched )) __static_call_return0 );
53855423 static_call_update (preempt_schedule , __preempt_schedule_func );
53865424 static_call_update (preempt_schedule_notrace , __preempt_schedule_notrace_func );
53875425 static_call_update (irqentry_exit_cond_resched , irqentry_exit_cond_resched );
5388- pr_info ("Dynamic Preempt: %s\n" , str );
5389- } else {
5390- pr_warn ("Dynamic Preempt: Unsupported preempt mode %s, default to full\n" , str );
5426+ pr_info ("Dynamic Preempt: full\n" );
5427+ break ;
5428+ }
5429+
5430+ preempt_dynamic_mode = mode ;
5431+ }
5432+
5433+ static int __init setup_preempt_mode (char * str )
5434+ {
5435+ int mode = sched_dynamic_mode (str );
5436+ if (mode < 0 ) {
5437+ pr_warn ("Dynamic Preempt: unsupported mode: %s\n" , str );
53915438 return 1 ;
53925439 }
5440+
5441+ sched_dynamic_update (mode );
53935442 return 0 ;
53945443}
53955444__setup ("preempt=" , setup_preempt_mode );
53965445
5446+ #ifdef CONFIG_SCHED_DEBUG
5447+
5448+ static ssize_t sched_dynamic_write (struct file * filp , const char __user * ubuf ,
5449+ size_t cnt , loff_t * ppos )
5450+ {
5451+ char buf [16 ];
5452+ int mode ;
5453+
5454+ if (cnt > 15 )
5455+ cnt = 15 ;
5456+
5457+ if (copy_from_user (& buf , ubuf , cnt ))
5458+ return - EFAULT ;
5459+
5460+ buf [cnt ] = 0 ;
5461+ mode = sched_dynamic_mode (strstrip (buf ));
5462+ if (mode < 0 )
5463+ return mode ;
5464+
5465+ sched_dynamic_update (mode );
5466+
5467+ * ppos += cnt ;
5468+
5469+ return cnt ;
5470+ }
5471+
5472+ static int sched_dynamic_show (struct seq_file * m , void * v )
5473+ {
5474+ static const char * preempt_modes [] = {
5475+ "none" , "voluntary" , "full"
5476+ };
5477+ int i ;
5478+
5479+ for (i = 0 ; i < ARRAY_SIZE (preempt_modes ); i ++ ) {
5480+ if (preempt_dynamic_mode == i )
5481+ seq_puts (m , "(" );
5482+ seq_puts (m , preempt_modes [i ]);
5483+ if (preempt_dynamic_mode == i )
5484+ seq_puts (m , ")" );
5485+
5486+ seq_puts (m , " " );
5487+ }
5488+
5489+ seq_puts (m , "\n" );
5490+ return 0 ;
5491+ }
5492+
5493+ static int sched_dynamic_open (struct inode * inode , struct file * filp )
5494+ {
5495+ return single_open (filp , sched_dynamic_show , NULL );
5496+ }
5497+
5498+ static const struct file_operations sched_dynamic_fops = {
5499+ .open = sched_dynamic_open ,
5500+ .write = sched_dynamic_write ,
5501+ .read = seq_read ,
5502+ .llseek = seq_lseek ,
5503+ .release = single_release ,
5504+ };
5505+
5506+ static __init int sched_init_debug_dynamic (void )
5507+ {
5508+ debugfs_create_file ("sched_preempt" , 0644 , NULL , NULL , & sched_dynamic_fops );
5509+ return 0 ;
5510+ }
5511+ late_initcall (sched_init_debug_dynamic );
5512+
5513+ #endif /* CONFIG_SCHED_DEBUG */
53975514#endif /* CONFIG_PREEMPT_DYNAMIC */
53985515
53995516
0 commit comments