LCOV - code coverage report
Current view: top level - app/shared/commands/configure - irq-balance.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 80 0.0 %
Date: 2026-10-22 18:10:43 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /* irq-balance is the sibling of the irq-affinity configure stage.
       2             :    See the long doc comment in irq-affinity.c. */
       3             : 
       4             : #define _DEFAULT_SOURCE
       5             : #include "configure.h"
       6             : #include "../../../../util/tile/fd_tile_private.h"
       7             : #include "fd_cpu_isolation.h"
       8             : #include "fd_irqbalance_client.h"
       9             : 
      10             : #include <errno.h>
      11             : 
      12           0 : #define MISMATCH_SAMPLE_MAX (16UL)
      13             : #define MISMATCH_STR_LEN    (128UL)
      14             : 
      15             : static void
      16             : init_perm( fd_cap_chk_t *   chk,
      17           0 :            config_t const * config FD_PARAM_UNUSED ) {
      18           0 :   fd_cap_chk_root( chk, "irq-balance", "connect to `/run/irqbalance/<sock>`" );
      19           0 : }
      20             : 
      21             : static void
      22             : fini_perm( fd_cap_chk_t *   chk,
      23           0 :            config_t const * config FD_PARAM_UNUSED ) {
      24           0 :   fd_cap_chk_root( chk, "irq-balance", "connect to `/run/irqbalance/<sock>`" );
      25           0 : }
      26             : 
      27             : static char *
      28             : cpuset_to_list_sample( char *               buf,
      29             :                        ulong                buf_sz,
      30           0 :                        fd_cpuset_t const * cpuset ) {
      31           0 :   char * p = fd_cstr_init( buf );
      32           0 :   ulong total_cnt = 0UL;
      33           0 :   for( ulong iter = fd_cpuset_const_iter_init( cpuset );
      34           0 :        !fd_cpuset_const_iter_done( iter );
      35           0 :        iter = fd_cpuset_const_iter_next( cpuset, iter ) ) {
      36           0 :     if( FD_LIKELY( total_cnt<MISMATCH_SAMPLE_MAX ) ) {
      37           0 :       if( FD_LIKELY( total_cnt ) ) p = fd_cstr_append_char( p, ',' );
      38           0 :       if( FD_UNLIKELY( (ulong)(p-buf)+32UL >= buf_sz ) ) break;
      39           0 :       p = fd_cstr_append_ulong_as_text( p, 0, 0, iter, fd_ulong_base10_dig_cnt( iter ) );
      40           0 :     }
      41           0 :     total_cnt++;
      42           0 :   }
      43           0 :   if( FD_UNLIKELY( total_cnt>MISMATCH_SAMPLE_MAX && (ulong)(p-buf)+32UL<buf_sz ) ) {
      44           0 :     p = fd_cstr_append_cstr( p, ",+" );
      45           0 :     p = fd_cstr_append_ulong_as_text( p, 0, 0, total_cnt-MISMATCH_SAMPLE_MAX, fd_ulong_base10_dig_cnt( total_cnt-MISMATCH_SAMPLE_MAX ) );
      46           0 :     p = fd_cstr_append_cstr( p, " more" );
      47           0 :   }
      48           0 :   fd_cstr_fini( p );
      49           0 :   return buf;
      50           0 : }
      51             : 
      52             : static configure_result_t
      53             : check( config_t const * config,
      54           0 :        int              check_type ) {
      55             :   /* The irqbalance daemon applies a `settings cpus` command only on its
      56             :      next periodic scan() tick (the SLEEP interval, 10s by default), and
      57             :      the `setup` query reports the committed mask, never the pending
      58             :      one. init() and fini() read the state back immediately, so the
      59             :      framework's synchronous POST_INIT / POST_FINI checks always observe
      60             :      the pre-change state and would spuriously fail ("didn't do
      61             :      anything" / "not undone"). There is no socket command to force a
      62             :      synchronous commit or to read back the pending ban, so these
      63             :      post-action checks are unverifiable; report the outcome the
      64             :      framework expects for a successful action and rely on init()/fini()
      65             :      having sent the command.  POST_INIT wants OK (configured);
      66             :      POST_FINI wants NOT_CONFIGURED (undone).  The standalone CHECK
      67             :      still reports the true committed state once the daemon has had a
      68             :      tick to apply it. */
      69           0 :   if( check_type==FD_CONFIGURE_CHECK_TYPE_POST_INIT ) CONFIGURE_OK();
      70           0 :   if( check_type==FD_CONFIGURE_CHECK_TYPE_POST_FINI ) NOT_CONFIGURED( "irqbalance commits asynchronously; undo not verifiable" );
      71             : 
      72           0 :   FD_CPUSET_DECL( actual );
      73           0 :   if( FD_UNLIKELY( -1==fd_irqbalance_ban_cpus_get( actual ) ) ) {
      74           0 :     int err = errno;
      75           0 :     switch( err ) {
      76           0 :     case ENOENT:
      77           0 :     case ECONNREFUSED:
      78             :       /* irqbalance is not installed or not running, so there is nothing
      79             :          to configure and nothing to undo. */
      80           0 :       CONFIGURE_OK();
      81           0 :     case EACCES:
      82             :       /* During the permission check phases, an EACCES means we need to
      83             :          escalate privileges before the real check; FINI_PERM treats it
      84             :          as OK so fini can proceed.  Outside those phases it is a
      85             :          genuine misconfiguration. */
      86           0 :       if( check_type==FD_CONFIGURE_CHECK_TYPE_FINI_PERM ) CONFIGURE_OK();
      87           0 :       NOT_CONFIGURED( "insufficient permissions to query irqbalance daemon banned CPU list" );
      88           0 :     default:
      89           0 :       FD_LOG_ERR(( "fd_irqbalance_ban_cpus_get() failed unexpectedly (%i-%s)", err, fd_io_strerror( err ) ));
      90           0 :     }
      91           0 :   }
      92             : 
      93           0 :   FD_CPUSET_DECL( required );
      94           0 :   fd_cpu_isolation_banned_cpus( required, &config->topo );
      95             : 
      96           0 :   if( FD_LIKELY( !fd_cpuset_cnt( actual ) ) ) {
      97           0 :     if( FD_LIKELY( !fd_cpuset_cnt( required ) ) ) CONFIGURE_OK();
      98           0 :     NOT_CONFIGURED( "irqbalance daemon has no banned CPUs" );
      99           0 :   }
     100           0 :   if( FD_LIKELY( fd_cpuset_eq( actual, required ) ) ) CONFIGURE_OK();
     101             : 
     102           0 :   FD_CPUSET_DECL( mismatched );
     103           0 :   fd_cpuset_xor( mismatched, actual, required );
     104           0 :   char cpu_str[ MISMATCH_STR_LEN ];
     105           0 :   cpuset_to_list_sample( cpu_str, sizeof(cpu_str), mismatched );
     106           0 :   NOT_CONFIGURED( "irqbalance daemon banned CPU list does not match Firedancer tile CPUs (CPUs: %s)", cpu_str );
     107           0 : }
     108             : 
     109             : static void
     110           0 : init( config_t const * config ) {
     111           0 :   FD_CPUSET_DECL( firedancer );
     112           0 :   fd_cpu_isolation_banned_cpus( firedancer, &config->topo );
     113             : 
     114           0 :   if( FD_UNLIKELY( -1==fd_irqbalance_ban_cpus_set( firedancer ) ) ) {
     115           0 :     int err = errno;
     116           0 :     if( FD_UNLIKELY( err!=ENOENT && err!=ECONNREFUSED && err!=EACCES ) ) {
     117           0 :       FD_LOG_ERR(( "fd_irqbalance_ban_cpus_set() failed unexpectedly (%i-%s)", err, fd_io_strerror( err ) ));
     118           0 :     }
     119           0 :   }
     120           0 : }
     121             : 
     122             : static int
     123             : fini( config_t const * config,
     124           0 :       int              pre_init ) {
     125           0 :   (void)config; (void)pre_init;
     126             : 
     127           0 :   FD_CPUSET_DECL( banned );
     128           0 :   fd_cpuset_new( banned );
     129             : 
     130           0 :   if( FD_UNLIKELY( -1==fd_irqbalance_ban_cpus_set( banned ) ) ) {
     131           0 :     int err = errno;
     132           0 :     if( FD_UNLIKELY( err!=ENOENT && err!=ECONNREFUSED && err!=EACCES ) ) {
     133           0 :       FD_LOG_ERR(( "fd_irqbalance_ban_cpus_set() failed unexpectedly (%i-%s)", err, fd_io_strerror( err ) ));
     134           0 :     }
     135           0 :   }
     136           0 :   return 1;
     137           0 : }
     138             : 
     139             : configure_stage_t fd_cfg_stage_irq_balance = {
     140             :   .name            = "irq-balance",
     141             :   .always_recreate = 0,
     142             :   .init_perm       = init_perm,
     143             :   .fini_perm       = fini_perm,
     144             :   .init            = init,
     145             :   .fini            = fini,
     146             :   .check           = check
     147             : };
     148             : 
     149             : #undef MISMATCH_SAMPLE_MAX
     150             : #undef MISMATCH_STR_LEN

Generated by: LCOV version 1.14