2017-03-23 19:01:41 +03:00
/*
2017-04-05 17:13:52 +03:00
* virnumamock . c : Mock some virNuma functions using sysfs
2017-03-23 19:01:41 +03:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) any later version .
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library . If not , see
* < http : //www.gnu.org/licenses/>.
*/
# include <config.h>
# include "internal.h"
# include "virnuma.h"
# include "virfile.h"
2023-03-07 17:44:41 +03:00
# include "virstring.h"
2017-03-23 19:01:41 +03:00
# define VIR_FROM_THIS VIR_FROM_NONE
2017-04-05 17:13:52 +03:00
# define SYSFS_SYSTEM_PATH " / sys / devices / system"
2017-03-23 19:01:41 +03:00
static int numa_avail = - 1 ;
/*
* Poor man ' s mocked NUMA guesser . We basically check if
* / sys / devices / system / node ( where / sys / devices / system can already be mocked or
* changed in the tests ) exists and cache the result .
*/
bool
virNumaIsAvailable ( void )
{
if ( numa_avail < 0 ) {
2021-09-04 23:37:31 +03:00
g_autofree char * sysfs_node_path = NULL ;
2017-03-23 19:01:41 +03:00
2019-10-22 16:26:14 +03:00
sysfs_node_path = g_strdup_printf ( " %s/node " , SYSFS_SYSTEM_PATH ) ;
2017-03-23 19:01:41 +03:00
numa_avail = virFileExists ( sysfs_node_path ) ;
}
/*
* Quite a few more things need to be mocked if NUMA is not available and
* you are using this file . Do not remove the abort ( ) call below unless you
* make sure all under virCapabilitiesInitNUMAFake ( ) is mocked ( and whatever
* might have changed since this comment was added . You are welcome .
*/
if ( ! numa_avail )
abort ( ) ;
return numa_avail ;
}
int
virNumaGetMaxNode ( void )
{
2021-12-06 16:10:40 +03:00
g_autoptr ( virBitmap ) map = NULL ;
2017-03-23 19:01:41 +03:00
2017-04-05 17:13:52 +03:00
if ( virFileReadValueBitmap ( & map , " %s/node/online " , SYSFS_SYSTEM_PATH ) < 0 )
2017-03-23 19:01:41 +03:00
return - 1 ;
2021-12-06 16:10:40 +03:00
return virBitmapLastSetBit ( map ) ;
2017-03-23 19:01:41 +03:00
}
bool
virNumaNodeIsAvailable ( int node )
{
2021-12-06 16:10:40 +03:00
g_autoptr ( virBitmap ) map = NULL ;
2017-03-23 19:01:41 +03:00
2017-04-05 17:13:52 +03:00
if ( virFileReadValueBitmap ( & map , " %s/node/online " , SYSFS_SYSTEM_PATH ) < 0 )
2017-03-23 19:01:41 +03:00
return false ;
2021-12-06 16:10:40 +03:00
return virBitmapIsBitSet ( map , node ) ;
2017-03-23 19:01:41 +03:00
}
int
virNumaGetNodeMemory ( int node ,
unsigned long long * memsize ,
unsigned long long * memfree )
{
const unsigned long long base = 1 < < 30 ;
if ( memsize )
* memsize = base * ( node + 1 ) ;
if ( memfree )
* memfree = base ;
return 0 ;
}
int
2019-10-14 15:45:03 +03:00
virNumaGetDistances ( int node G_GNUC_UNUSED ,
2017-03-23 19:01:41 +03:00
int * * distances ,
int * ndistances )
{
* distances = NULL ;
* ndistances = 0 ;
return 0 ;
}
/*
2017-04-05 17:13:52 +03:00
* TODO : Adapt virNumaGetHugePageInfo { Path , Dir } to use sysfs so that the
2017-03-23 19:01:41 +03:00
* paths can be modified and this function can be thrown away and instead we ' d
* have copied info from / sys ( as we do with / sys / devices / system ) .
*/
int
virNumaGetPages ( int node ,
unsigned int * * pages_size ,
2018-04-23 17:36:53 +03:00
unsigned long long * * pages_avail ,
unsigned long long * * pages_free ,
2017-03-23 19:01:41 +03:00
size_t * npages )
{
const int pages_def [ ] = { 4 , 2 * 1024 , 1 * 1024 * 1024 } ;
2019-10-15 14:55:26 +03:00
const int npages_def = G_N_ELEMENTS ( pages_def ) ;
2017-03-23 19:01:41 +03:00
size_t i = 0 ;
if ( pages_size )
2020-09-23 01:58:49 +03:00
* pages_size = g_new0 ( unsigned int , npages_def ) ;
2017-03-23 19:01:41 +03:00
if ( pages_avail )
2020-09-23 01:58:49 +03:00
* pages_avail = g_new0 ( unsigned long long , npages_def ) ;
2017-03-23 19:01:41 +03:00
if ( pages_free )
2020-09-23 01:58:49 +03:00
* pages_free = g_new0 ( unsigned long long , npages_def ) ;
2017-03-23 19:01:41 +03:00
* npages = npages_def ;
if ( pages_size )
memcpy ( * pages_size , pages_def , sizeof ( pages_def ) ) ;
node + + ;
if ( node < = 0 )
node = 32 ;
if ( pages_avail | | pages_free ) {
for ( i = 0 ; i < * npages ; i + + ) {
if ( pages_avail )
( * pages_avail ) [ i ] = ( node + i ) * 2 < < 10 ;
if ( pages_free )
( * pages_free ) [ i ] = ( node + i ) * 1 < < 10 ;
}
}
return 0 ;
}
int
2021-03-11 10:16:13 +03:00
virNumaGetNodeCPUs ( int node , virBitmap * * cpus )
2017-03-23 19:01:41 +03:00
{
2021-09-04 23:37:31 +03:00
g_autofree char * cpulist = NULL ;
2017-03-23 19:01:41 +03:00
2017-04-05 17:13:52 +03:00
if ( virFileReadValueString ( & cpulist ,
" %s/node/node%u/cpulist " ,
SYSFS_SYSTEM_PATH , node ) < 0 )
2017-03-23 19:01:41 +03:00
return - 1 ;
2021-05-17 13:40:00 +03:00
if ( STREQ ( cpulist , " " ) ) {
unsigned int max_n_cpus = virNumaGetMaxCPUs ( ) ;
* cpus = virBitmapNew ( max_n_cpus ) ;
} else {
* cpus = virBitmapParseUnlimited ( cpulist ) ;
}
2017-03-27 16:47:58 +03:00
if ( ! * cpus )
2021-09-04 23:41:36 +03:00
return - 1 ;
2017-03-23 19:01:41 +03:00
2021-09-04 23:41:36 +03:00
return virBitmapCountBits ( * cpus ) ;
2017-03-23 19:01:41 +03:00
}
2023-03-07 17:44:41 +03:00
int
virNumaGetNodeOfCPU ( int cpu )
{
g_autoptr ( DIR ) cpuDir = NULL ;
g_autofree char * sysfs_cpu_path = NULL ;
struct dirent * ent = NULL ;
int dirErr = 0 ;
sysfs_cpu_path = g_strdup_printf ( " %s/cpu/cpu%d " , SYSFS_SYSTEM_PATH , cpu ) ;
if ( virDirOpen ( & cpuDir , sysfs_cpu_path ) < 0 )
return - 1 ;
while ( ( dirErr = virDirRead ( cpuDir , & ent , sysfs_cpu_path ) ) > 0 ) {
g_autofree char * entPath = NULL ;
const char * number = NULL ;
int node ;
if ( ! ( number = STRSKIP ( ent - > d_name , " node " ) ) )
continue ;
entPath = g_strdup_printf ( " %s/%s " , sysfs_cpu_path , ent - > d_name ) ;
if ( ! virFileIsLink ( entPath ) )
continue ;
if ( virStrToLong_i ( number , NULL , 10 , & node ) < 0 ) {
errno = EINVAL ;
return - 1 ;
}
return node ;
}
if ( dirErr < 0 )
return - 1 ;
errno = EINVAL ;
return - 1 ;
}