6
6
7
7
#include <ctype.h>
8
8
#include <linux/isst_if.h>
9
- #include <sys/utsname.h>
10
9
11
10
#include "isst.h"
12
11
@@ -56,6 +55,8 @@ static int clos_min = -1;
56
55
static int clos_max = -1 ;
57
56
static int clos_desired = -1 ;
58
57
static int clos_priority_type ;
58
+ static int cpu_0_cgroupv2 ;
59
+ static int cpu_0_workaround (int isolate );
59
60
60
61
struct _cpu_map {
61
62
unsigned short core_id ;
@@ -475,52 +476,26 @@ static unsigned int is_cpu_online(int cpu)
475
476
return online ;
476
477
}
477
478
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
-
497
479
void set_cpu_online_offline (int cpu , int state )
498
480
{
499
481
char buffer [128 ];
500
482
int fd , ret ;
501
483
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 ;
514
488
}
515
489
516
490
snprintf (buffer , sizeof (buffer ),
517
491
"/sys/devices/system/cpu/cpu%d/online" , cpu );
518
492
519
493
fd = open (buffer , O_WRONLY );
520
494
if (fd < 0 ) {
521
- if (!cpu && state ) {
495
+ if (!cpu ) {
522
496
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 );
524
499
return ;
525
500
}
526
501
err (-1 , "%s open failed" , buffer );
@@ -907,7 +882,7 @@ int enable_cpuset_controller(void)
907
882
return 0 ;
908
883
}
909
884
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 )
911
886
{
912
887
int i , first , curr_index , index , ret , fd ;
913
888
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
950
925
curr_index = 0 ;
951
926
first = 1 ;
952
927
str [0 ] = '\0' ;
928
+
929
+ if (cpu_0_only ) {
930
+ snprintf (str , str_len , "0" );
931
+ goto create_partition ;
932
+ }
933
+
953
934
for (i = 0 ; i < get_topo_max_cpus (); ++ i ) {
954
935
if (!is_cpu_in_power_domain (i , id ))
955
936
continue ;
@@ -972,6 +953,7 @@ int isolate_cpus(struct isst_id *id, int mask_size, cpu_set_t *cpu_mask, int lev
972
953
first = 0 ;
973
954
}
974
955
956
+ create_partition :
975
957
debug_printf ("isolated CPUs list: package:%d curr_index:%d [%s]\n" , id -> pkg , curr_index ,str );
976
958
977
959
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
1012
994
return 0 ;
1013
995
}
1014
996
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
+
1015
1065
static int isst_fill_platform_info (void )
1016
1066
{
1017
1067
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
1458
1508
if (ret )
1459
1509
goto use_offline ;
1460
1510
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 );
1462
1513
if (ret )
1463
1514
goto use_offline ;
1464
1515
@@ -3054,6 +3105,7 @@ static void usage(void)
3054
3105
printf ("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n" );
3055
3106
printf ("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n" );
3056
3107
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" );
3057
3109
printf ("\nResult format\n" );
3058
3110
printf ("\tResult display uses a common format for each command:\n" );
3059
3111
printf ("\tResults are formatted in text/JSON with\n" );
@@ -3107,6 +3159,7 @@ static void cmdline(int argc, char **argv)
3107
3159
{ "no-daemon" , no_argument , 0 , 'n' },
3108
3160
{ "poll-interval" , required_argument , 0 , 'w' },
3109
3161
{ "cgroupv2" , required_argument , 0 , 'g' },
3162
+ { "cpu0-workaround" , required_argument , 0 , 'u' },
3110
3163
{ 0 , 0 , 0 , 0 }
3111
3164
};
3112
3165
@@ -3137,7 +3190,7 @@ static void cmdline(int argc, char **argv)
3137
3190
goto out ;
3138
3191
3139
3192
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 ,
3141
3194
& option_index )) != -1 ) {
3142
3195
switch (opt ) {
3143
3196
case 'a' :
@@ -3199,6 +3252,9 @@ static void cmdline(int argc, char **argv)
3199
3252
case 'g' :
3200
3253
cgroupv2 = 1 ;
3201
3254
break ;
3255
+ case 'u' :
3256
+ cpu_0_cgroupv2 = 1 ;
3257
+ break ;
3202
3258
default :
3203
3259
usage ();
3204
3260
}
0 commit comments