@@ -333,8 +333,165 @@ static const struct file_operations sched_debug_fops = {
333333 .release = seq_release ,
334334};
335335
336+ enum dl_param {
337+ DL_RUNTIME = 0 ,
338+ DL_PERIOD ,
339+ };
340+
341+ static unsigned long fair_server_period_max = (1 << 22 ) * NSEC_PER_USEC ; /* ~4 seconds */
342+ static unsigned long fair_server_period_min = (100 ) * NSEC_PER_USEC ; /* 100 us */
343+
344+ static ssize_t sched_fair_server_write (struct file * filp , const char __user * ubuf ,
345+ size_t cnt , loff_t * ppos , enum dl_param param )
346+ {
347+ long cpu = (long ) ((struct seq_file * ) filp -> private_data )-> private ;
348+ struct rq * rq = cpu_rq (cpu );
349+ u64 runtime , period ;
350+ size_t err ;
351+ int retval ;
352+ u64 value ;
353+
354+ err = kstrtoull_from_user (ubuf , cnt , 10 , & value );
355+ if (err )
356+ return err ;
357+
358+ scoped_guard (rq_lock_irqsave , rq ) {
359+ runtime = rq -> fair_server .dl_runtime ;
360+ period = rq -> fair_server .dl_period ;
361+
362+ switch (param ) {
363+ case DL_RUNTIME :
364+ if (runtime == value )
365+ break ;
366+ runtime = value ;
367+ break ;
368+ case DL_PERIOD :
369+ if (value == period )
370+ break ;
371+ period = value ;
372+ break ;
373+ }
374+
375+ if (runtime > period ||
376+ period > fair_server_period_max ||
377+ period < fair_server_period_min ) {
378+ return - EINVAL ;
379+ }
380+
381+ if (rq -> cfs .h_nr_running ) {
382+ update_rq_clock (rq );
383+ dl_server_stop (& rq -> fair_server );
384+ }
385+
386+ retval = dl_server_apply_params (& rq -> fair_server , runtime , period , 0 );
387+ if (retval )
388+ cnt = retval ;
389+
390+ if (!runtime )
391+ printk_deferred ("Fair server disabled in CPU %d, system may crash due to starvation.\n" ,
392+ cpu_of (rq ));
393+
394+ if (rq -> cfs .h_nr_running )
395+ dl_server_start (& rq -> fair_server );
396+ }
397+
398+ * ppos += cnt ;
399+ return cnt ;
400+ }
401+
402+ static size_t sched_fair_server_show (struct seq_file * m , void * v , enum dl_param param )
403+ {
404+ unsigned long cpu = (unsigned long ) m -> private ;
405+ struct rq * rq = cpu_rq (cpu );
406+ u64 value ;
407+
408+ switch (param ) {
409+ case DL_RUNTIME :
410+ value = rq -> fair_server .dl_runtime ;
411+ break ;
412+ case DL_PERIOD :
413+ value = rq -> fair_server .dl_period ;
414+ break ;
415+ }
416+
417+ seq_printf (m , "%llu\n" , value );
418+ return 0 ;
419+
420+ }
421+
422+ static ssize_t
423+ sched_fair_server_runtime_write (struct file * filp , const char __user * ubuf ,
424+ size_t cnt , loff_t * ppos )
425+ {
426+ return sched_fair_server_write (filp , ubuf , cnt , ppos , DL_RUNTIME );
427+ }
428+
429+ static int sched_fair_server_runtime_show (struct seq_file * m , void * v )
430+ {
431+ return sched_fair_server_show (m , v , DL_RUNTIME );
432+ }
433+
434+ static int sched_fair_server_runtime_open (struct inode * inode , struct file * filp )
435+ {
436+ return single_open (filp , sched_fair_server_runtime_show , inode -> i_private );
437+ }
438+
439+ static const struct file_operations fair_server_runtime_fops = {
440+ .open = sched_fair_server_runtime_open ,
441+ .write = sched_fair_server_runtime_write ,
442+ .read = seq_read ,
443+ .llseek = seq_lseek ,
444+ .release = single_release ,
445+ };
446+
447+ static ssize_t
448+ sched_fair_server_period_write (struct file * filp , const char __user * ubuf ,
449+ size_t cnt , loff_t * ppos )
450+ {
451+ return sched_fair_server_write (filp , ubuf , cnt , ppos , DL_PERIOD );
452+ }
453+
454+ static int sched_fair_server_period_show (struct seq_file * m , void * v )
455+ {
456+ return sched_fair_server_show (m , v , DL_PERIOD );
457+ }
458+
459+ static int sched_fair_server_period_open (struct inode * inode , struct file * filp )
460+ {
461+ return single_open (filp , sched_fair_server_period_show , inode -> i_private );
462+ }
463+
464+ static const struct file_operations fair_server_period_fops = {
465+ .open = sched_fair_server_period_open ,
466+ .write = sched_fair_server_period_write ,
467+ .read = seq_read ,
468+ .llseek = seq_lseek ,
469+ .release = single_release ,
470+ };
471+
336472static struct dentry * debugfs_sched ;
337473
474+ static void debugfs_fair_server_init (void )
475+ {
476+ struct dentry * d_fair ;
477+ unsigned long cpu ;
478+
479+ d_fair = debugfs_create_dir ("fair_server" , debugfs_sched );
480+ if (!d_fair )
481+ return ;
482+
483+ for_each_possible_cpu (cpu ) {
484+ struct dentry * d_cpu ;
485+ char buf [32 ];
486+
487+ snprintf (buf , sizeof (buf ), "cpu%lu" , cpu );
488+ d_cpu = debugfs_create_dir (buf , d_fair );
489+
490+ debugfs_create_file ("runtime" , 0644 , d_cpu , (void * ) cpu , & fair_server_runtime_fops );
491+ debugfs_create_file ("period" , 0644 , d_cpu , (void * ) cpu , & fair_server_period_fops );
492+ }
493+ }
494+
338495static __init int sched_init_debug (void )
339496{
340497 struct dentry __maybe_unused * numa ;
@@ -374,6 +531,8 @@ static __init int sched_init_debug(void)
374531
375532 debugfs_create_file ("debug" , 0444 , debugfs_sched , NULL , & sched_debug_fops );
376533
534+ debugfs_fair_server_init ();
535+
377536 return 0 ;
378537}
379538late_initcall (sched_init_debug );
0 commit comments