66
77#include <ctype.h>
88#include <linux/isst_if.h>
9- #include <sys/utsname.h>
109
1110#include "isst.h"
1211
@@ -56,6 +55,8 @@ static int clos_min = -1;
5655static int clos_max = -1 ;
5756static int clos_desired = -1 ;
5857static int clos_priority_type ;
58+ static int cpu_0_cgroupv2 ;
59+ static int cpu_0_workaround (int isolate );
5960
6061struct _cpu_map {
6162 unsigned short core_id ;
@@ -475,52 +476,26 @@ static unsigned int is_cpu_online(int cpu)
475476 return online ;
476477}
477478
478- static int get_kernel_version (int * major , int * minor )
479- {
480- struct utsname buf ;
481- int ret ;
482-
483- ret = uname (& buf );
484- if (ret )
485- return ret ;
486-
487- ret = sscanf (buf .release , "%d.%d" , major , minor );
488- if (ret != 2 )
489- return ret ;
490-
491- return 0 ;
492- }
493-
494- #define CPU0_HOTPLUG_DEPRECATE_MAJOR_VER 6
495- #define CPU0_HOTPLUG_DEPRECATE_MINOR_VER 5
496-
497479void set_cpu_online_offline (int cpu , int state )
498480{
499481 char buffer [128 ];
500482 int fd , ret ;
501483
502- if (!cpu ) {
503- int major , minor ;
504-
505- ret = get_kernel_version (& major , & minor );
506- if (!ret ) {
507- if (major > CPU0_HOTPLUG_DEPRECATE_MAJOR_VER || (major == CPU0_HOTPLUG_DEPRECATE_MAJOR_VER &&
508- minor >= CPU0_HOTPLUG_DEPRECATE_MINOR_VER )) {
509- debug_printf ("Ignore CPU 0 offline/online for kernel version >= %d.%d\n" , major , minor );
510- debug_printf ("Use cgroups to isolate CPU 0\n" );
511- return ;
512- }
513- }
484+ if (cpu_0_cgroupv2 && !cpu ) {
485+ fprintf (stderr , "Will use cgroup v2 for CPU 0\n" );
486+ cpu_0_workaround (!state );
487+ return ;
514488 }
515489
516490 snprintf (buffer , sizeof (buffer ),
517491 "/sys/devices/system/cpu/cpu%d/online" , cpu );
518492
519493 fd = open (buffer , O_WRONLY );
520494 if (fd < 0 ) {
521- if (!cpu && state ) {
495+ if (!cpu ) {
522496 fprintf (stderr , "This system is not configured for CPU 0 online/offline\n" );
523- fprintf (stderr , "Ignoring online request for CPU 0 as this is already online\n" );
497+ fprintf (stderr , "Will use cgroup v2\n" );
498+ cpu_0_workaround (!state );
524499 return ;
525500 }
526501 err (-1 , "%s open failed" , buffer );
@@ -907,7 +882,7 @@ int enable_cpuset_controller(void)
907882 return 0 ;
908883}
909884
910- int isolate_cpus (struct isst_id * id , int mask_size , cpu_set_t * cpu_mask , int level )
885+ int isolate_cpus (struct isst_id * id , int mask_size , cpu_set_t * cpu_mask , int level , int cpu_0_only )
911886{
912887 int i , first , curr_index , index , ret , fd ;
913888 static char str [512 ], dir_name [64 ];
@@ -950,6 +925,12 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev
950925 curr_index = 0 ;
951926 first = 1 ;
952927 str [0 ] = '\0' ;
928+
929+ if (cpu_0_only ) {
930+ snprintf (str , str_len , "0" );
931+ goto create_partition ;
932+ }
933+
953934 for (i = 0 ; i < get_topo_max_cpus (); ++ i ) {
954935 if (!is_cpu_in_power_domain (i , id ))
955936 continue ;
@@ -972,6 +953,7 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev
972953 first = 0 ;
973954 }
974955
956+ create_partition :
975957 debug_printf ("isolated CPUs list: package:%d curr_index:%d [%s]\n" , id -> pkg , curr_index ,str );
976958
977959 snprintf (cpuset_cpus , sizeof (cpuset_cpus ), "%s/cpuset.cpus" , dir_name );
@@ -1012,6 +994,74 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev
1012994 return 0 ;
1013995}
1014996
997+ static int cpu_0_workaround (int isolate )
998+ {
999+ int fd , fd1 , len , ret ;
1000+ cpu_set_t cpu_mask ;
1001+ struct isst_id id ;
1002+ char str [2 ];
1003+
1004+ debug_printf ("isolate CPU 0 state: %d\n" , isolate );
1005+
1006+ if (isolate )
1007+ goto isolate ;
1008+
1009+ /* First check if CPU 0 was isolated to remove isolation. */
1010+
1011+ /* If the cpuset.cpus doesn't exist, that means that none of the CPUs are isolated*/
1012+ fd = open ("/sys/fs/cgroup/0-0-0/cpuset.cpus" , O_RDONLY , 0 );
1013+ if (fd < 0 )
1014+ return 0 ;
1015+
1016+ len = read (fd , str , sizeof (str ));
1017+ /* Error check, but unlikely to fail. If fails that means that not isolated */
1018+ if (len == -1 )
1019+ return 0 ;
1020+
1021+
1022+ /* Is CPU 0 is in isolate list, the display is sorted so first element will be CPU 0*/
1023+ if (str [0 ] != '0' ) {
1024+ close (fd );
1025+ return 0 ;
1026+ }
1027+
1028+ fd1 = open ("/sys/fs/cgroup/0-0-0/cpuset.cpus.partition" , O_RDONLY , 0 );
1029+ /* Unlikely that, this attribute is not present, but handle error */
1030+ if (fd1 < 0 ) {
1031+ close (fd );
1032+ return 0 ;
1033+ }
1034+
1035+ /* Is CPU 0 already changed partition to "member" */
1036+ len = read (fd1 , str , sizeof (str ));
1037+ if (len != -1 && str [0 ] == 'm' ) {
1038+ close (fd1 );
1039+ close (fd );
1040+ return 0 ;
1041+ }
1042+
1043+ close (fd1 );
1044+ close (fd );
1045+
1046+ debug_printf ("CPU 0 was isolated before, so remove isolation\n" );
1047+
1048+ isolate :
1049+ ret = enable_cpuset_controller ();
1050+ if (ret )
1051+ goto isolate_fail ;
1052+
1053+ CPU_ZERO (& cpu_mask );
1054+ memset (& id , 0 , sizeof (struct isst_id ));
1055+ CPU_SET (0 , & cpu_mask );
1056+
1057+ ret = isolate_cpus (& id , sizeof (cpu_mask ), & cpu_mask , isolate , 1 );
1058+ isolate_fail :
1059+ if (ret )
1060+ fprintf (stderr , "Can't isolate CPU 0\n" );
1061+
1062+ return ret ;
1063+ }
1064+
10151065static int isst_fill_platform_info (void )
10161066{
10171067 const char * pathname = "/dev/isst_interface" ;
@@ -1458,7 +1508,8 @@ static void set_tdp_level_for_cpu(struct isst_id *id, void *arg1, void *arg2, vo
14581508 if (ret )
14591509 goto use_offline ;
14601510
1461- ret = isolate_cpus (id , ctdp_level .core_cpumask_size , ctdp_level .core_cpumask , tdp_level );
1511+ ret = isolate_cpus (id , ctdp_level .core_cpumask_size ,
1512+ ctdp_level .core_cpumask , tdp_level , 0 );
14621513 if (ret )
14631514 goto use_offline ;
14641515
@@ -3054,6 +3105,7 @@ static void usage(void)
30543105 printf ("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n" );
30553106 printf ("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n" );
30563107 printf ("\t[-g|--cgroupv2 : Try to use cgroup v2 CPU isolation instead of CPU online/offline.\n" );
3108+ printf ("\t[-u|--cpu0-workaround : Don't try to online/offline CPU0 instead use cgroup v2.\n" );
30573109 printf ("\nResult format\n" );
30583110 printf ("\tResult display uses a common format for each command:\n" );
30593111 printf ("\tResults are formatted in text/JSON with\n" );
@@ -3107,6 +3159,7 @@ static void cmdline(int argc, char **argv)
31073159 { "no-daemon" , no_argument , 0 , 'n' },
31083160 { "poll-interval" , required_argument , 0 , 'w' },
31093161 { "cgroupv2" , required_argument , 0 , 'g' },
3162+ { "cpu0-workaround" , required_argument , 0 , 'u' },
31103163 { 0 , 0 , 0 , 0 }
31113164 };
31123165
@@ -3137,7 +3190,7 @@ static void cmdline(int argc, char **argv)
31373190 goto out ;
31383191
31393192 progname = argv [0 ];
3140- while ((opt = getopt_long_only (argc , argv , "+c:df:hio:vabw:ng " , long_options ,
3193+ while ((opt = getopt_long_only (argc , argv , "+c:df:hio:vabw:ngu " , long_options ,
31413194 & option_index )) != -1 ) {
31423195 switch (opt ) {
31433196 case 'a' :
@@ -3199,6 +3252,9 @@ static void cmdline(int argc, char **argv)
31993252 case 'g' :
32003253 cgroupv2 = 1 ;
32013254 break ;
3255+ case 'u' :
3256+ cpu_0_cgroupv2 = 1 ;
3257+ break ;
32023258 default :
32033259 usage ();
32043260 }
0 commit comments