LCOV - code coverage report
Current view: top level - app/shared/commands/configure - hugetlbfs.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 316 0.0 %
Date: 2025-03-20 12:08:36 Functions: 0 7 0.0 %

          Line data    Source code
       1             : #include "configure.h"
       2             : 
       3             : #include "../../../shared/fd_file_util.h"
       4             : #include "../../../shared/fd_sys_util.h"
       5             : 
       6             : #include <unistd.h>
       7             : #include <errno.h>
       8             : #include <stdio.h>
       9             : #include <stdlib.h> /* strtoul */
      10             : #include <dirent.h>
      11             : #include <sys/stat.h>
      12             : #include <sys/mount.h>
      13             : #include <linux/capability.h>
      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, "hugetlbfs", "increase `/proc/sys/vm/nr_hugepages`" );
      19           0 :   fd_cap_chk_cap(  chk, "hugetlbfs", CAP_SYS_ADMIN, "mount hugetlbfs filesystems" );
      20           0 : }
      21             : 
      22             : static void
      23             : fini_perm( fd_cap_chk_t *   chk,
      24           0 :            config_t const * config FD_PARAM_UNUSED ) {
      25           0 :   fd_cap_chk_root( chk, "hugetlbfs", "remove directories from `/mnt`" );
      26           0 :   fd_cap_chk_cap(  chk, "hugetlbfs", CAP_SYS_ADMIN, "unmount hugetlbfs filesystems" );
      27           0 : }
      28             : 
      29             : static char const * TOTAL_HUGE_PAGE_PATH[ 2 ] = {
      30             :   "/sys/devices/system/node/node%lu/hugepages/hugepages-2048kB/nr_hugepages",
      31             :   "/sys/devices/system/node/node%lu/hugepages/hugepages-1048576kB/nr_hugepages",
      32             : };
      33             : 
      34             : static char const * FREE_HUGE_PAGE_PATH[ 2 ] = {
      35             :   "/sys/devices/system/node/node%lu/hugepages/hugepages-2048kB/free_hugepages",
      36             :   "/sys/devices/system/node/node%lu/hugepages/hugepages-1048576kB/free_hugepages",
      37             : };
      38             : 
      39             : static ulong PAGE_SIZE[ 2 ] = {
      40             :   2097152,
      41             :   1073741824,
      42             : };
      43             : 
      44             : static char const * PAGE_NAMES[ 2 ] = {
      45             :   "huge",
      46             :   "gigantic"
      47             : };
      48             : 
      49             : static void
      50           0 : init( config_t const * config ) {
      51           0 :   char const * mount_path[ 2 ] = {
      52           0 :     config->hugetlbfs.huge_page_mount_path,
      53           0 :     config->hugetlbfs.gigantic_page_mount_path,
      54           0 :   };
      55             : 
      56           0 :   ulong numa_node_cnt = fd_shmem_numa_cnt();
      57           0 :   for( ulong i=0UL; i<numa_node_cnt; i++ ) {
      58           0 :     ulong required_pages[ 2 ] = {
      59           0 :       fd_topo_huge_page_cnt( &config->topo, i, 0 ),
      60           0 :       fd_topo_gigantic_page_cnt( &config->topo, i ),
      61           0 :     };
      62             : 
      63           0 :     for( ulong j=0UL; j<2UL; j++ ) {
      64           0 :       char free_page_path[ PATH_MAX ];
      65           0 :       FD_TEST( fd_cstr_printf_check( free_page_path, PATH_MAX, NULL, FREE_HUGE_PAGE_PATH[ j ], i ) );
      66           0 :       uint free_pages;
      67           0 :       if( FD_UNLIKELY( -1==fd_file_util_read_uint( free_page_path, &free_pages ) ) )
      68           0 :         FD_LOG_ERR(( "could not read `%s`, please confirm your host is configured for gigantic pages (%i-%s)", free_page_path, errno, fd_io_strerror( errno ) ));
      69             : 
      70             :       /* There is a TOCTOU race condition here, but it's not avoidable. There's
      71             :          no way to atomically increment the page count. */
      72           0 :       FD_TEST( required_pages[ j ]<=UINT_MAX );
      73           0 :       if( FD_UNLIKELY( free_pages<required_pages[ j ] ) ) {
      74           0 :         char total_page_path[ PATH_MAX ];
      75           0 :         FD_TEST( fd_cstr_printf_check( total_page_path, PATH_MAX, NULL, TOTAL_HUGE_PAGE_PATH[ j ], i ) );
      76           0 :         uint total_pages;
      77           0 :         if( FD_UNLIKELY( -1==fd_file_util_read_uint( total_page_path, &total_pages ) ) )
      78           0 :           FD_LOG_ERR(( "could not read `%s`, please confirm your host is configured for gigantic pages (%i-%s)", total_page_path, errno, fd_io_strerror( errno ) ));
      79             : 
      80           0 :         ulong additional_pages_needed = required_pages[ j ]-free_pages;
      81             : 
      82           0 :         FD_LOG_NOTICE(( "RUN: `echo \"%u\" > %s`", (uint)(total_pages+additional_pages_needed), total_page_path ));
      83           0 :         if( FD_UNLIKELY( -1==fd_file_util_write_uint( total_page_path, (uint)(total_pages+additional_pages_needed) ) ) )
      84           0 :           FD_LOG_ERR(( "could not increase the number of %s pages on NUMA node %lu (%i-%s)", PAGE_NAMES[ j ], i, errno, fd_io_strerror( errno ) ));
      85             : 
      86           0 :         uint raised_free_pages;
      87           0 :         if( FD_UNLIKELY( -1==fd_file_util_read_uint( free_page_path, &raised_free_pages ) ) )
      88           0 :           FD_LOG_ERR(( "could not read `%s`, please confirm your host is configured for gigantic pages (%i-%s)", free_page_path, errno, fd_io_strerror( errno ) ));
      89             : 
      90           0 :         if( FD_UNLIKELY( raised_free_pages<required_pages[ j ] ) ) {
      91             :           /* Well.. usually this is due to memory being fragmented,
      92             :              rather than not having enough memory.  See something like
      93             :              https://tatref.github.io/blog/2023-visual-linux-memory-compact/
      94             :              for the sequence we do here. */
      95           0 :           FD_LOG_WARNING(( "ENOMEM-Out of memory when trying to reserve %s pages for Firedancer on NUMA node %lu. Compacting memory before trying again.",
      96           0 :                            PAGE_NAMES[ j ],
      97           0 :                            i ));
      98           0 :           FD_LOG_NOTICE(( "RUN: `echo \"1\" > /proc/sys/vm/compact_memory" ));
      99           0 :           if( FD_UNLIKELY( -1==fd_file_util_write_uint( "/proc/sys/vm/compact_memory", 1 ) ) )
     100           0 :             FD_LOG_ERR(( "could not write to `%s` (%i-%s)", "/proc/sys/vm/compact_memory", errno, fd_io_strerror( errno ) ));
     101             :           /* Sleep a little to give the OS some time to perform the
     102             :              compaction. */
     103           0 :           FD_TEST( -1!=fd_sys_util_nanosleep( 0, 500000000 /* 500 millis */ ) );
     104           0 :           FD_LOG_NOTICE(( "RUN: `echo \"3\" > /proc/sys/vm/drop_caches" ));
     105           0 :           if( FD_UNLIKELY( -1==fd_file_util_write_uint( "/proc/sys/vm/drop_caches", 3 ) ) )
     106           0 :             FD_LOG_ERR(( "could not write to `%s` (%i-%s)", "/proc/sys/vm/drop_caches", errno, fd_io_strerror( errno ) ));
     107           0 :           FD_TEST( -1!=fd_sys_util_nanosleep( 0, 500000000 /* 500 millis */ ) );
     108           0 :           FD_LOG_NOTICE(( "RUN: `echo \"1\" > /proc/sys/vm/compact_memory" ));
     109           0 :           if( FD_UNLIKELY( -1==fd_file_util_write_uint( "/proc/sys/vm/compact_memory", 1 ) ) )
     110           0 :             FD_LOG_ERR(( "could not write to `%s` (%i-%s)", "/proc/sys/vm/compact_memory", errno, fd_io_strerror( errno ) ));
     111           0 :           FD_TEST( -1!=fd_sys_util_nanosleep( 0, 500000000 /* 500 millis */ ) );
     112           0 :         }
     113             : 
     114           0 :         FD_LOG_NOTICE(( "RUN: `echo \"%u\" > %s`", (uint)(total_pages+additional_pages_needed), total_page_path ));
     115           0 :         if( FD_UNLIKELY( -1==fd_file_util_write_uint( total_page_path, (uint)(total_pages+additional_pages_needed) ) ) )
     116           0 :           FD_LOG_ERR(( "could not increase the number of %s pages on NUMA node %lu (%i-%s)", PAGE_NAMES[ j ], i, errno, fd_io_strerror( errno ) ));
     117           0 :         if( FD_UNLIKELY( -1==fd_file_util_read_uint( free_page_path, &raised_free_pages ) ) )
     118           0 :           FD_LOG_ERR(( "could not read `%s`, please confirm your host is configured for gigantic pages (%i-%s)", free_page_path, errno, fd_io_strerror( errno ) ));
     119           0 :         if( FD_UNLIKELY( raised_free_pages<required_pages[ j ] ) ) {
     120           0 :           FD_LOG_ERR(( "ENOMEM-Out of memory when trying to reserve %s pages for Firedancer on NUMA node %lu. Your Firedancer "
     121           0 :                        "configuration requires %lu GiB of memory total consisting of %lu gigantic (1GiB) pages and %lu huge (2MiB) "
     122           0 :                        "pages on this NUMA node but only %u %s pages were available according to `%s` (raised from %u). If your "
     123           0 :                        "system has the required amount of memory, this can be because it is not configured with %s page support, or "
     124           0 :                        "Firedancer cannot increase the value of `%s` at runtime. You might need to enable huge pages in grub at boot "
     125           0 :                        "time. This error can also happen because system uptime is high and memory is fragmented. You can fix this by "
     126           0 :                        "rebooting the machine and running the `hugetlbfs` stage immediately on boot.",
     127           0 :                        PAGE_NAMES[ j ],
     128           0 :                        i,
     129           0 :                        required_pages[ 1 ] + (required_pages[ 0 ] / 512),
     130           0 :                        required_pages[ 1 ],
     131           0 :                        required_pages[ 0 ],
     132           0 :                        raised_free_pages,
     133           0 :                        PAGE_NAMES[ j ],
     134           0 :                        free_page_path,
     135           0 :                        free_pages,
     136           0 :                        PAGE_NAMES[ j ],
     137           0 :                        total_page_path ));
     138           0 :         }
     139           0 :       }
     140           0 :     }
     141           0 :   }
     142             : 
     143             :   /* Do NOT include anonymous huge pages in the min_size count that
     144             :      we reserve here, because they do not come from the hugetlbfs.
     145             :      Counting them towards that reservation would prevent the
     146             :      anonymous mmap which maps them in from succeeding.
     147             : 
     148             :      The kernel min_size option for the hugetlbfs does not include an
     149             :      option to reserve pages from a specific NUMA node, so we simply
     150             :      take the sum here and hope they are distributed correctly.  If
     151             :      they are not, creating files in the mount on a specific node may
     152             :      fail later with ENOMEM. */
     153             : 
     154           0 :   ulong min_size[ 2 ] = {0};
     155           0 :   for( ulong i=0UL; i<numa_node_cnt; i++ ) {
     156           0 :     min_size[ 0 ] += PAGE_SIZE[ 0 ] * fd_topo_huge_page_cnt( &config->topo, i, 0 );
     157           0 :     min_size[ 1 ] += PAGE_SIZE[ 1 ] * fd_topo_gigantic_page_cnt( &config->topo, i );
     158           0 :   }
     159             : 
     160           0 :   for( ulong i=0UL; i<2UL; i++ ) {
     161           0 :     FD_LOG_NOTICE(( "RUN: `mkdir -p %s`", mount_path[ i ] ));
     162           0 :     if( FD_UNLIKELY( -1==fd_file_util_mkdir_all( mount_path[ i ], config->uid, config->gid ) ) ) {
     163           0 :       FD_LOG_ERR(( "could not create hugetlbfs mount directory `%s` (%i-%s)", mount_path[ i ], errno, fd_io_strerror( errno ) ));
     164           0 :     }
     165             : 
     166           0 :     char options[ 256 ];
     167           0 :     FD_TEST( fd_cstr_printf_check( options, sizeof(options), NULL, "pagesize=%lu,min_size=%lu", PAGE_SIZE[ i ], min_size[ i ] ) );
     168           0 :     FD_LOG_NOTICE(( "RUN: `mount -t hugetlbfs none %s -o %s`", mount_path[ i ], options ));
     169           0 :     if( FD_UNLIKELY( mount( "none", mount_path[ i ], "hugetlbfs", 0, options) ) )
     170           0 :       FD_LOG_ERR(( "mount of hugetlbfs at `%s` failed (%i-%s)", mount_path[ i ], errno, fd_io_strerror( errno ) ));
     171           0 :     if( FD_UNLIKELY( chown( mount_path[ i ], config->uid, config->gid ) ) )
     172           0 :       FD_LOG_ERR(( "chown of hugetlbfs at `%s` failed (%i-%s)", mount_path[ i ], errno, fd_io_strerror( errno ) ));
     173           0 :     if( FD_UNLIKELY( chmod( mount_path[ i ], S_IRUSR | S_IWUSR | S_IXUSR ) ) )
     174           0 :       FD_LOG_ERR(( "chmod of hugetlbfs at `%s` failed (%i-%s)", mount_path[ i ], errno, fd_io_strerror( errno ) ));
     175           0 :   }
     176           0 : }
     177             : 
     178             : static void
     179             : cmdline( char * buf,
     180           0 :          ulong  buf_sz ) {
     181           0 :   FILE * fp = fopen( "/proc/self/cmdline", "r" );
     182           0 :   if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "error opening `/proc/self/cmdline` (%i-%s)", errno, fd_io_strerror( errno ) ));
     183             : 
     184           0 :   ulong read = fread( buf, 1UL, buf_sz - 1UL, fp );
     185           0 :   if( FD_UNLIKELY( ferror( fp ) ) ) FD_LOG_ERR(( "error reading `/proc/self/cmdline` (%i-%s)", errno, fd_io_strerror( errno ) ));
     186           0 :   if( FD_UNLIKELY( fclose( fp ) ) ) FD_LOG_ERR(( "error closing `/proc/self/cmdline` (%i-%s)", errno, fd_io_strerror( errno ) ));
     187             : 
     188           0 :   buf[ read ] = '\0';
     189           0 : }
     190             : 
     191             : static void
     192           0 : warn_mount_users( char const * mount_path ) {
     193           0 :   DIR * dir = opendir( "/proc" );
     194           0 :   if( FD_UNLIKELY( !dir ) ) FD_LOG_ERR(( "error opening `/proc` (%i-%s)", errno, fd_io_strerror( errno ) ));
     195             : 
     196           0 :   struct dirent * entry;
     197           0 :   while(( FD_LIKELY( entry = readdir( dir ) ) )) {
     198           0 :     if( FD_UNLIKELY( !strcmp( entry->d_name, "." ) || !strcmp( entry->d_name, ".." ) ) ) continue;
     199           0 :     char * endptr;
     200           0 :     ulong pid = strtoul( entry->d_name, &endptr, 10 );
     201           0 :     if( FD_UNLIKELY( *endptr ) ) continue;
     202             : 
     203           0 :     char path[ PATH_MAX ];
     204           0 :     FD_TEST( fd_cstr_printf_check( path, PATH_MAX, NULL, "/proc/%lu/maps", pid ) );
     205           0 :     FILE * fp = fopen( path, "r" );
     206           0 :     if( FD_UNLIKELY( !fp && errno!=ENOENT ) ) FD_LOG_ERR(( "error opening `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     207             : 
     208           0 :     char self_cmdline[ PATH_MAX ];
     209           0 :     cmdline( self_cmdline, PATH_MAX );
     210             : 
     211           0 :     char line[ 4096 ];
     212           0 :     while( FD_LIKELY( fgets( line, 4096, fp ) ) ) {
     213           0 :       if( FD_UNLIKELY( strlen( line )==4095 ) ) FD_LOG_ERR(( "line too long in `%s`", path ));
     214           0 :       if( FD_UNLIKELY( strstr( line, mount_path ) ) ) {
     215           0 :         FD_LOG_WARNING(( "process `%lu`:`%s` has a file descriptor open in `%s`", pid, self_cmdline, mount_path ));
     216           0 :         break;
     217           0 :       }
     218           0 :     }
     219           0 :     if( FD_UNLIKELY( ferror( fp ) ) )
     220           0 :       FD_LOG_ERR(( "error reading `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     221           0 :     if( FD_LIKELY( fclose( fp ) ) )
     222           0 :       FD_LOG_ERR(( "error closing `%s` (%i-%s)", path, errno, fd_io_strerror( errno ) ));
     223           0 :   }
     224             : 
     225           0 :   if( FD_UNLIKELY( -1==closedir( dir ) ) ) FD_LOG_ERR(( "closedir (%i-%s)", errno, fd_io_strerror( errno ) ));
     226           0 : }
     227             : 
     228             : static void
     229             : fini( config_t const * config,
     230           0 :       int              pre_init ) {
     231           0 :   (void)pre_init;
     232             : 
     233             :   /* Not used by fdctl but might be created by other debugging tools
     234             :      on the system. */
     235             : 
     236           0 :   char normal_page_mount_path[ PATH_MAX ];
     237           0 :   FD_TEST( fd_cstr_printf_check( normal_page_mount_path, PATH_MAX, NULL, "%s/.normal", config->hugetlbfs.mount_path ) );
     238             : 
     239           0 :   const char * mount_path[ 3 ] = {
     240           0 :     config->hugetlbfs.huge_page_mount_path,
     241           0 :     config->hugetlbfs.gigantic_page_mount_path,
     242           0 :     normal_page_mount_path,
     243           0 :   };
     244             : 
     245           0 :   for( ulong i=0UL; i<3UL; i++ ) {
     246           0 :     FILE * fp = fopen( "/proc/self/mounts", "r" );
     247           0 :     if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "failed to open `/proc/self/mounts`" ));
     248             : 
     249           0 :     char line[ 4096 ];
     250           0 :     while( FD_LIKELY( fgets( line, 4096UL, fp ) ) ) {
     251           0 :       if( FD_UNLIKELY( strlen( line )==4095UL ) ) FD_LOG_ERR(( "line too long in `/proc/self/mounts`" ));
     252           0 :       if( FD_UNLIKELY( strstr( line, mount_path[ i ] ) ) ) {
     253           0 :         FD_LOG_NOTICE(( "RUN: `umount %s`", mount_path[ i ] ));
     254           0 :         if( FD_UNLIKELY( umount( mount_path[ i ] ) ) ) {
     255           0 :           if( FD_LIKELY( errno==EBUSY ) ) {
     256           0 :             warn_mount_users( mount_path[ i ] );
     257             : 
     258           0 :             FD_LOG_ERR(( "Unmount of hugetlbfs at `%s` failed because the mount is still in use. "
     259           0 :                          "You can unmount it by killing all processes that are actively using files in "
     260           0 :                          "the mount and running `fdctl configure fini hugetlbfs` again, or unmount "
     261           0 :                          "manually with `umount %s`", mount_path[ i ], mount_path[ i ] ));
     262           0 :           } else {
     263           0 :             FD_LOG_ERR(( "umount of hugetlbfs at `%s` failed (%i-%s)", mount_path[ i ], errno, fd_io_strerror( errno ) ));
     264           0 :           }
     265           0 :         }
     266           0 :       }
     267           0 :     }
     268             : 
     269           0 :     if( FD_UNLIKELY( ferror( fp ) ) )
     270           0 :       FD_LOG_ERR(( "error reading `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     271           0 :     if( FD_LIKELY( fclose( fp ) ) )
     272           0 :       FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     273             : 
     274           0 :     FD_LOG_NOTICE(( "RUN: `rmdir %s`", mount_path[ i ] ));
     275           0 :     if( FD_UNLIKELY( rmdir( mount_path[ i ] ) && errno!=ENOENT ) )
     276           0 :       FD_LOG_ERR(( "error removing hugetlbfs mount at `%s` (%i-%s)", mount_path[ i ], errno, fd_io_strerror( errno ) ));
     277           0 :   }
     278             : 
     279           0 :   FD_LOG_NOTICE(( "RUN: `rmdir %s`", config->hugetlbfs.mount_path ));
     280           0 :   if( FD_UNLIKELY( rmdir( config->hugetlbfs.mount_path ) && errno!=ENOENT ) )
     281           0 :     FD_LOG_ERR(( "error removing hugetlbfs directory at `%s` (%i-%s)", config->hugetlbfs.mount_path, errno, fd_io_strerror( errno ) ));
     282           0 : }
     283             : 
     284             : static configure_result_t
     285           0 : check( config_t const * config ) {
     286           0 :   char const * mount_path[ 2 ] = {
     287           0 :     config->hugetlbfs.huge_page_mount_path,
     288           0 :     config->hugetlbfs.gigantic_page_mount_path,
     289           0 :   };
     290             : 
     291           0 :   static char const * MOUNT_PAGE_SIZE[ 2 ]  = {
     292           0 :     "pagesize=2M",
     293           0 :     "pagesize=1024M",
     294           0 :   };
     295             : 
     296           0 :   ulong numa_node_cnt = fd_shmem_numa_cnt();
     297           0 :   ulong required_min_size[ 2 ] = {0};
     298           0 :   for( ulong i=0UL; i<numa_node_cnt; i++ ) {
     299           0 :     required_min_size[ 0 ] += PAGE_SIZE[ 0 ] * fd_topo_huge_page_cnt( &config->topo, i, 0 );
     300           0 :     required_min_size[ 1 ] += PAGE_SIZE[ 1 ] * fd_topo_gigantic_page_cnt( &config->topo, i );
     301           0 :   }
     302             : 
     303           0 :   struct stat st;
     304           0 :   int result1 = stat( mount_path[ 0 ], &st );
     305           0 :   if( FD_UNLIKELY( result1 && errno!=ENOENT ) )
     306           0 :     PARTIALLY_CONFIGURED( "failed to stat `%s` (%i-%s)", mount_path[ 0 ], errno, fd_io_strerror( errno ) );
     307           0 :   int result2 = stat( mount_path[ 1 ], &st );
     308           0 :   if( FD_UNLIKELY( result2 && errno!=ENOENT ) )
     309           0 :     PARTIALLY_CONFIGURED( "failed to stat `%s` (%i-%s)", mount_path[ 1 ], errno, fd_io_strerror( errno ) );
     310             : 
     311           0 :   if( FD_UNLIKELY( result1 && result2 ) )
     312           0 :     NOT_CONFIGURED( "mounts `%s` and `%s` do not exist", mount_path[ 0 ], mount_path[ 1 ] );
     313           0 :   else if( FD_UNLIKELY( result1 ) )
     314           0 :     PARTIALLY_CONFIGURED( "mount `%s` does not exist", mount_path[ 0 ] );
     315           0 :   else if( FD_UNLIKELY( result2 ) )
     316           0 :     PARTIALLY_CONFIGURED( "mount `%s` does not exist", mount_path[ 1 ] );
     317             : 
     318           0 :   CHECK( check_dir( config->hugetlbfs.mount_path, config->uid, config->gid, S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR ) );
     319           0 :   for( ulong i=0UL; i<2UL; i++ ) {
     320           0 :     CHECK( check_dir( mount_path[ i ], config->uid, config->gid, S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR ) );
     321             : 
     322           0 :     FILE * fp = fopen( "/proc/self/mounts", "r" );
     323           0 :     if( FD_UNLIKELY( !fp ) ) FD_LOG_ERR(( "failed to open `/proc/self/mounts`" ));
     324             : 
     325           0 :     char line[ 4096 ];
     326           0 :     int found = 0;
     327           0 :     while( FD_LIKELY( fgets( line, 4096UL, fp ) ) ) {
     328           0 :       if( FD_UNLIKELY( strlen( line )==4095UL ) ) FD_LOG_ERR(( "line too long in `/proc/self/mounts`" ));
     329           0 :       if( FD_UNLIKELY( strstr( line, mount_path[ i ] ) ) ) {
     330           0 :         found = 1;
     331             : 
     332           0 :         char * saveptr;
     333           0 :         char * device = strtok_r( line, " ", &saveptr );
     334           0 :         if( FD_UNLIKELY( !device ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     335           0 :         if( FD_UNLIKELY( strcmp( device, "none" ) ) ) {
     336           0 :           if( FD_UNLIKELY( fclose( fp ) ) )
     337           0 :             FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     338           0 :           PARTIALLY_CONFIGURED( "mount `%s` is on unrecognized device, expected `none`", mount_path[ i ] );
     339           0 :         }
     340             : 
     341           0 :         char * path1 = strtok_r( NULL, " ", &saveptr );
     342           0 :         if( FD_UNLIKELY( !path1 ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     343           0 :         if( FD_UNLIKELY( strcmp( path1, mount_path[ i ] ) ) ) {
     344           0 :           if( FD_UNLIKELY( fclose( fp ) ) )
     345           0 :             FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     346           0 :           PARTIALLY_CONFIGURED( "mount `%s` is on unrecognized path, expected `%s`", path1, mount_path[ i ] );
     347           0 :         }
     348             : 
     349           0 :         char * type = strtok_r( NULL, " ", &saveptr );
     350           0 :         if( FD_UNLIKELY( !type ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     351           0 :         if( FD_UNLIKELY( strcmp( type, "hugetlbfs" ) ) ) {
     352           0 :           if( FD_UNLIKELY( fclose( fp ) ) )
     353           0 :             FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     354           0 :           PARTIALLY_CONFIGURED( "mount `%s` has unrecognized type, expected `hugetlbfs`", mount_path[ i ] );
     355           0 :         }
     356             : 
     357           0 :         char * options = strtok_r( NULL, " ", &saveptr );
     358           0 :         if( FD_UNLIKELY( !options ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     359             : 
     360           0 :         char * saveptr2;
     361           0 :         char * rw = strtok_r( options, ",", &saveptr2 );
     362           0 :         if( FD_UNLIKELY( !rw ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     363           0 :         if( FD_UNLIKELY( strcmp( rw, "rw" ) ) ) {
     364           0 :           if( FD_UNLIKELY( fclose( fp ) ) )
     365           0 :             FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     366           0 :           PARTIALLY_CONFIGURED( "mount `%s` is not mounted read/write, expected `rw`", mount_path[ i ] );
     367           0 :         }
     368             : 
     369           0 :         char * seclabel = strtok_r( NULL, ",", &saveptr2 );
     370           0 :         if( FD_UNLIKELY( !seclabel ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     371             : 
     372           0 :         char * relatime;
     373           0 :         if( FD_LIKELY( !strcmp( seclabel, "seclabel" ) ) ) {
     374           0 :           relatime = strtok_r( NULL, ",", &saveptr2 );
     375           0 :           if( FD_UNLIKELY( !relatime ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     376           0 :         } else {
     377           0 :           relatime = seclabel;
     378           0 :         }
     379             : 
     380           0 :         if( FD_UNLIKELY( strcmp( relatime, "relatime" ) ) ) {
     381           0 :           if( FD_UNLIKELY( fclose( fp ) ) )
     382           0 :             FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     383           0 :           PARTIALLY_CONFIGURED( "mount `%s` is not mounted with `relatime`, expected `relatime`", mount_path[ i ] );
     384           0 :         }
     385             : 
     386           0 :         char * gid = strtok_r( NULL, ",", &saveptr2 );
     387           0 :         if( FD_UNLIKELY( !gid ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     388             : 
     389           0 :         char * pagesize;
     390           0 :         if( FD_UNLIKELY( !strncmp( "gid=", gid, 4UL ) ) ) {
     391           0 :           pagesize = strtok_r( NULL, ",", &saveptr2 );
     392           0 :           if( FD_UNLIKELY( !pagesize ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     393           0 :         } else {
     394           0 :           pagesize = gid;
     395           0 :         }
     396             : 
     397           0 :         if( FD_UNLIKELY( !pagesize ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     398           0 :         if( FD_UNLIKELY( strcmp( pagesize, MOUNT_PAGE_SIZE[ i ] ) ) ) {
     399           0 :           if( FD_UNLIKELY( fclose( fp ) ) )
     400           0 :             FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     401           0 :           PARTIALLY_CONFIGURED( "mount `%s` has unrecognized pagesize, expected `%s` %s", mount_path[ i ], MOUNT_PAGE_SIZE[ i ], pagesize );
     402           0 :         }
     403             : 
     404           0 :         char * _min_size = strtok_r( NULL, ",", &saveptr2 );
     405           0 :         if( FD_UNLIKELY( !_min_size ) ) FD_LOG_ERR(( "error parsing `/proc/self/mounts`, line `%s`", line ));
     406           0 :         if( FD_UNLIKELY( strncmp( "min_size=", _min_size, 9UL ) ) ) {
     407           0 :           if( FD_UNLIKELY( fclose( fp ) ) )
     408           0 :             FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     409           0 :           PARTIALLY_CONFIGURED( "mount `%s` has unrecognized min_size, expected at least `min_size=%lu`", mount_path[ i ], required_min_size[ i ] );
     410           0 :         }
     411             : 
     412           0 :         char * endptr;
     413           0 :         ulong min_size = strtoul( _min_size+9, &endptr, 10 );
     414           0 :         if( FD_UNLIKELY( *endptr ) ) {
     415           0 :           if( FD_UNLIKELY( fclose( fp ) ) )
     416           0 :             FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     417           0 :           PARTIALLY_CONFIGURED( "mount `%s` has malformed min_size, expected `min_size=%lu`", mount_path[ i ], required_min_size[ i ] );
     418           0 :         }
     419             : 
     420           0 :         if( FD_UNLIKELY( min_size<required_min_size[ i ] ) ) {
     421           0 :           if( FD_UNLIKELY( fclose( fp ) ) )
     422           0 :             FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     423           0 :           PARTIALLY_CONFIGURED( "mount `%s` has min_size `%lu`, expected at least `min_size=%lu`", mount_path[ i ], min_size, required_min_size[ i ] );
     424           0 :         }
     425             : 
     426           0 :         break;
     427           0 :       }
     428           0 :     }
     429             : 
     430           0 :     if( FD_UNLIKELY( ferror( fp ) ) )
     431           0 :       FD_LOG_ERR(( "error reading `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     432           0 :     if( FD_LIKELY( fclose( fp ) ) )
     433           0 :       FD_LOG_ERR(( "error closing `/proc/self/mounts` (%i-%s)", errno, fd_io_strerror( errno ) ));
     434             : 
     435           0 :     if( FD_UNLIKELY( !found ) )
     436           0 :       PARTIALLY_CONFIGURED( "mount `%s` not found in `/proc/self/mounts`", mount_path[ i ] );
     437           0 :   }
     438             : 
     439           0 :   CONFIGURE_OK();
     440           0 : }
     441             : 
     442             : configure_stage_t fd_cfg_stage_hugetlbfs = {
     443             :   .name            = "hugetlbfs",
     444             :   .always_recreate = 0,
     445             :   .enabled         = NULL,
     446             :   .init_perm       = init_perm,
     447             :   .fini_perm       = fini_perm,
     448             :   .init            = init,
     449             :   .fini            = fini,
     450             :   .check           = check,
     451             : };

Generated by: LCOV version 1.14