13b64d633SDamjan Marion/*
23b64d633SDamjan Marion * Copyright (c) 2017 Cisco and/or its affiliates.
33b64d633SDamjan Marion * Licensed under the Apache License, Version 2.0 (the "License");
43b64d633SDamjan Marion * you may not use this file except in compliance with the License.
53b64d633SDamjan Marion * You may obtain a copy of the License at:
63b64d633SDamjan Marion *
73b64d633SDamjan Marion *     http://www.apache.org/licenses/LICENSE-2.0
83b64d633SDamjan Marion *
93b64d633SDamjan Marion * Unless required by applicable law or agreed to in writing, software
103b64d633SDamjan Marion * distributed under the License is distributed on an "AS IS" BASIS,
113b64d633SDamjan Marion * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
123b64d633SDamjan Marion * See the License for the specific language governing permissions and
133b64d633SDamjan Marion * limitations under the License.
143b64d633SDamjan Marion */
153b64d633SDamjan Marion
1601914ce4SDamjan Marion#include <vppinfra/clib.h>
1701914ce4SDamjan Marion#include <vppinfra/clib_error.h>
1801914ce4SDamjan Marion#include <vppinfra/format.h>
193b64d633SDamjan Marion
203b64d633SDamjan Marion#include <sys/types.h>
213b64d633SDamjan Marion#include <sys/stat.h>
223b64d633SDamjan Marion#include <fcntl.h>
233b64d633SDamjan Marion#include <dirent.h>
243b64d633SDamjan Marion
253b64d633SDamjan Marionclib_error_t *
2601914ce4SDamjan Marionclib_sysfs_write (char *file_name, char *fmt, ...)
273b64d633SDamjan Marion{
283b64d633SDamjan Marion  u8 *s;
293b64d633SDamjan Marion  int fd;
303b64d633SDamjan Marion  clib_error_t *error = 0;
313b64d633SDamjan Marion
323b64d633SDamjan Marion  fd = open (file_name, O_WRONLY);
333b64d633SDamjan Marion  if (fd < 0)
343b64d633SDamjan Marion    return clib_error_return_unix (0, "open `%s'", file_name);
353b64d633SDamjan Marion
363b64d633SDamjan Marion  va_list va;
373b64d633SDamjan Marion  va_start (va, fmt);
383b64d633SDamjan Marion  s = va_format (0, fmt, &va);
393b64d633SDamjan Marion  va_end (va);
403b64d633SDamjan Marion
413b64d633SDamjan Marion  if (write (fd, s, vec_len (s)) < 0)
423b64d633SDamjan Marion    error = clib_error_return_unix (0, "write `%s'", file_name);
433b64d633SDamjan Marion
443b64d633SDamjan Marion  vec_free (s);
453b64d633SDamjan Marion  close (fd);
463b64d633SDamjan Marion  return error;
473b64d633SDamjan Marion}
483b64d633SDamjan Marion
493b64d633SDamjan Marionclib_error_t *
5001914ce4SDamjan Marionclib_sysfs_read (char *file_name, char *fmt, ...)
513b64d633SDamjan Marion{
523b64d633SDamjan Marion  unformat_input_t input;
533b64d633SDamjan Marion  u8 *s = 0;
543b64d633SDamjan Marion  int fd;
553b64d633SDamjan Marion  ssize_t sz;
563b64d633SDamjan Marion  uword result;
573b64d633SDamjan Marion
583b64d633SDamjan Marion  fd = open (file_name, O_RDONLY);
593b64d633SDamjan Marion  if (fd < 0)
603b64d633SDamjan Marion    return clib_error_return_unix (0, "open `%s'", file_name);
613b64d633SDamjan Marion
623b64d633SDamjan Marion  vec_validate (s, 4095);
633b64d633SDamjan Marion
643b64d633SDamjan Marion  sz = read (fd, s, vec_len (s));
653b64d633SDamjan Marion  if (sz < 0)
663b64d633SDamjan Marion    {
673b64d633SDamjan Marion      close (fd);
683b64d633SDamjan Marion      vec_free (s);
693b64d633SDamjan Marion      return clib_error_return_unix (0, "read `%s'", file_name);
703b64d633SDamjan Marion    }
713b64d633SDamjan Marion
723b64d633SDamjan Marion  _vec_len (s) = sz;
733b64d633SDamjan Marion  unformat_init_vector (&input, s);
743b64d633SDamjan Marion
753b64d633SDamjan Marion  va_list va;
763b64d633SDamjan Marion  va_start (va, fmt);
773b64d633SDamjan Marion  result = va_unformat (&input, fmt, &va);
783b64d633SDamjan Marion  va_end (va);
793b64d633SDamjan Marion
803b64d633SDamjan Marion  vec_free (s);
813b64d633SDamjan Marion  close (fd);
823b64d633SDamjan Marion
833b64d633SDamjan Marion  if (result == 0)
843b64d633SDamjan Marion    return clib_error_return (0, "unformat error");
853b64d633SDamjan Marion
863b64d633SDamjan Marion  return 0;
873b64d633SDamjan Marion}
883b64d633SDamjan Marion
893b64d633SDamjan Marionu8 *
9001914ce4SDamjan Marionclib_sysfs_link_to_name (char *link)
913b64d633SDamjan Marion{
923b64d633SDamjan Marion  char *p, buffer[64];
933b64d633SDamjan Marion  unformat_input_t in;
943b64d633SDamjan Marion  u8 *s = 0;
953b64d633SDamjan Marion  int r;
963b64d633SDamjan Marion
973b64d633SDamjan Marion  r = readlink (link, buffer, sizeof (buffer) - 1);
983b64d633SDamjan Marion
993b64d633SDamjan Marion  if (r < 0)
1003b64d633SDamjan Marion    return 0;
1013b64d633SDamjan Marion
1023b64d633SDamjan Marion  buffer[r] = 0;
1033b64d633SDamjan Marion  p = strrchr (buffer, '/');
1043b64d633SDamjan Marion
1053b64d633SDamjan Marion  if (!p)
1063b64d633SDamjan Marion    return 0;
1073b64d633SDamjan Marion
1083b64d633SDamjan Marion  unformat_init_string (&in, p + 1, strlen (p + 1));
1093b64d633SDamjan Marion  if (unformat (&in, "%s", &s) != 1)
1103b64d633SDamjan Marion    clib_unix_warning ("no string?");
1113b64d633SDamjan Marion  unformat_free (&in);
1123b64d633SDamjan Marion
1133b64d633SDamjan Marion  return s;
1143b64d633SDamjan Marion}
1153b64d633SDamjan Marion
1163b64d633SDamjan Marionclib_error_t *
1176f3f1cbfSDamjan Marionclib_sysfs_set_nr_hugepages (int numa_node, int log2_page_size, int nr)
1183b64d633SDamjan Marion{
1193b64d633SDamjan Marion  clib_error_t *error = 0;
1203b64d633SDamjan Marion  struct stat sb;
1213b64d633SDamjan Marion  u8 *p = 0;
1229787f5f9SDamjan Marion  uword page_size;
1239787f5f9SDamjan Marion
1249787f5f9SDamjan Marion  if (log2_page_size == 0)
1259787f5f9SDamjan Marion    log2_page_size = min_log2 (clib_mem_get_default_hugepage_size ());
1269787f5f9SDamjan Marion
1279787f5f9SDamjan Marion  page_size = 1ULL << (log2_page_size - 10);
1283b64d633SDamjan Marion
1293b64d633SDamjan Marion  p = format (p, "/sys/devices/system/node/node%u%c", numa_node, 0);
1303b64d633SDamjan Marion
1313b64d633SDamjan Marion  if (stat ((char *) p, &sb) == 0)
1323b64d633SDamjan Marion    {
1333b64d633SDamjan Marion      if (S_ISDIR (sb.st_mode) == 0)
1343b64d633SDamjan Marion	{
1353b64d633SDamjan Marion	  error = clib_error_return (0, "'%s' is not directory", p);
1363b64d633SDamjan Marion	  goto done;
1373b64d633SDamjan Marion	}
1383b64d633SDamjan Marion    }
1393b64d633SDamjan Marion  else if (numa_node == 0)
1403b64d633SDamjan Marion    {
1413b64d633SDamjan Marion      vec_reset_length (p);
1423b64d633SDamjan Marion      p = format (p, "/sys/kernel/mm%c", 0);
1433b64d633SDamjan Marion      if (stat ((char *) p, &sb) < 0 || S_ISDIR (sb.st_mode) == 0)
1443b64d633SDamjan Marion	{
1453b64d633SDamjan Marion	  error = clib_error_return (0, "'%s' does not exist or it is not "
1463b64d633SDamjan Marion				     "directory", p);
1473b64d633SDamjan Marion	  goto done;
1483b64d633SDamjan Marion	}
1493b64d633SDamjan Marion    }
1503b64d633SDamjan Marion  else
1513b64d633SDamjan Marion    {
1523b64d633SDamjan Marion      error = clib_error_return (0, "'%s' does not exist", p);
1533b64d633SDamjan Marion      goto done;
1543b64d633SDamjan Marion    }
1553b64d633SDamjan Marion
1563b64d633SDamjan Marion  _vec_len (p) -= 1;
1573b64d633SDamjan Marion  p = format (p, "/hugepages/hugepages-%ukB/nr_hugepages%c", page_size, 0);
15801914ce4SDamjan Marion  clib_sysfs_write ((char *) p, "%d", nr);
1593b64d633SDamjan Marion
1603b64d633SDamjan Mariondone:
1613b64d633SDamjan Marion  vec_free (p);
1623b64d633SDamjan Marion  return error;
1633b64d633SDamjan Marion}
1643b64d633SDamjan Marion
1653b64d633SDamjan Marion
1663b64d633SDamjan Marionstatic clib_error_t *
16701914ce4SDamjan Marionclib_sysfs_get_xxx_hugepages (char *type, int numa_node,
1686f3f1cbfSDamjan Marion			      int log2_page_size, int *val)
1693b64d633SDamjan Marion{
1703b64d633SDamjan Marion  clib_error_t *error = 0;
1713b64d633SDamjan Marion  struct stat sb;
1723b64d633SDamjan Marion  u8 *p = 0;
1739787f5f9SDamjan Marion
1749787f5f9SDamjan Marion  uword page_size;
1759787f5f9SDamjan Marion
1769787f5f9SDamjan Marion  if (log2_page_size == 0)
1779787f5f9SDamjan Marion    log2_page_size = min_log2 (clib_mem_get_default_hugepage_size ());
1789787f5f9SDamjan Marion
1799787f5f9SDamjan Marion  page_size = 1ULL << (log2_page_size - 10);
1809787f5f9SDamjan Marion
1813b64d633SDamjan Marion
1823b64d633SDamjan Marion  p = format (p, "/sys/devices/system/node/node%u%c", numa_node, 0);
1833b64d633SDamjan Marion
1843b64d633SDamjan Marion  if (stat ((char *) p, &sb) == 0)
1853b64d633SDamjan Marion    {
1863b64d633SDamjan Marion      if (S_ISDIR (sb.st_mode) == 0)
1873b64d633SDamjan Marion	{
1883b64d633SDamjan Marion	  error = clib_error_return (0, "'%s' is not directory", p);
1893b64d633SDamjan Marion	  goto done;
1903b64d633SDamjan Marion	}
1913b64d633SDamjan Marion    }
1923b64d633SDamjan Marion  else if (numa_node == 0)
1933b64d633SDamjan Marion    {
1943b64d633SDamjan Marion      vec_reset_length (p);
1953b64d633SDamjan Marion      p = format (p, "/sys/kernel/mm%c", 0);
1963b64d633SDamjan Marion      if (stat ((char *) p, &sb) < 0 || S_ISDIR (sb.st_mode) == 0)
1973b64d633SDamjan Marion	{
1983b64d633SDamjan Marion	  error = clib_error_return (0, "'%s' does not exist or it is not "
1993b64d633SDamjan Marion				     "directory", p);
2003b64d633SDamjan Marion	  goto done;
2013b64d633SDamjan Marion	}
2023b64d633SDamjan Marion    }
2033b64d633SDamjan Marion  else
2043b64d633SDamjan Marion    {
2053b64d633SDamjan Marion      error = clib_error_return (0, "'%s' does not exist", p);
2063b64d633SDamjan Marion      goto done;
2073b64d633SDamjan Marion    }
2083b64d633SDamjan Marion
2093b64d633SDamjan Marion  _vec_len (p) -= 1;
2103b64d633SDamjan Marion  p = format (p, "/hugepages/hugepages-%ukB/%s_hugepages%c", page_size,
2113b64d633SDamjan Marion	      type, 0);
21201914ce4SDamjan Marion  error = clib_sysfs_read ((char *) p, "%d", val);
2133b64d633SDamjan Marion
2143b64d633SDamjan Mariondone:
2153b64d633SDamjan Marion  vec_free (p);
2163b64d633SDamjan Marion  return error;
2173b64d633SDamjan Marion}
2183b64d633SDamjan Marion
2193b64d633SDamjan Marionclib_error_t *
2206f3f1cbfSDamjan Marionclib_sysfs_get_free_hugepages (int numa_node, int log2_page_size, int *v)
2213b64d633SDamjan Marion{
2226f3f1cbfSDamjan Marion  return clib_sysfs_get_xxx_hugepages ("free", numa_node, log2_page_size, v);
2233b64d633SDamjan Marion}
2243b64d633SDamjan Marion
2253b64d633SDamjan Marionclib_error_t *
2266f3f1cbfSDamjan Marionclib_sysfs_get_nr_hugepages (int numa_node, int log2_page_size, int *v)
2273b64d633SDamjan Marion{
2286f3f1cbfSDamjan Marion  return clib_sysfs_get_xxx_hugepages ("nr", numa_node, log2_page_size, v);
2293b64d633SDamjan Marion}
2303b64d633SDamjan Marion
2313b64d633SDamjan Marionclib_error_t *
2326f3f1cbfSDamjan Marionclib_sysfs_get_surplus_hugepages (int numa_node, int log2_page_size, int *v)
2333b64d633SDamjan Marion{
2346f3f1cbfSDamjan Marion  return clib_sysfs_get_xxx_hugepages ("surplus", numa_node, log2_page_size,
2356f3f1cbfSDamjan Marion				       v);
2363b64d633SDamjan Marion}
2373b64d633SDamjan Marion
2383b64d633SDamjan Marionclib_error_t *
2396f3f1cbfSDamjan Marionclib_sysfs_prealloc_hugepages (int numa_node, int log2_page_size, int nr)
2403b64d633SDamjan Marion{
2413b64d633SDamjan Marion  clib_error_t *error = 0;
2423b64d633SDamjan Marion  int n, needed;
2439787f5f9SDamjan Marion  uword page_size;
2449787f5f9SDamjan Marion
2459787f5f9SDamjan Marion  if (log2_page_size == 0)
2469787f5f9SDamjan Marion    log2_page_size = min_log2 (clib_mem_get_default_hugepage_size ());
2479787f5f9SDamjan Marion
2489787f5f9SDamjan Marion  page_size = 1ULL << (log2_page_size - 10);
2499787f5f9SDamjan Marion
2506f3f1cbfSDamjan Marion  error = clib_sysfs_get_free_hugepages (numa_node, log2_page_size, &n);
2513b64d633SDamjan Marion  if (error)
2523b64d633SDamjan Marion    return error;
2533b64d633SDamjan Marion  needed = nr - n;
2543b64d633SDamjan Marion  if (needed <= 0)
2553b64d633SDamjan Marion    return 0;
2563b64d633SDamjan Marion
2576f3f1cbfSDamjan Marion  error = clib_sysfs_get_nr_hugepages (numa_node, log2_page_size, &n);
2583b64d633SDamjan Marion  if (error)
2593b64d633SDamjan Marion    return error;
2603b64d633SDamjan Marion  clib_warning ("pre-allocating %u additional %uK hugepages on numa node %u",
2613b64d633SDamjan Marion		needed, page_size, numa_node);
2626f3f1cbfSDamjan Marion  return clib_sysfs_set_nr_hugepages (numa_node, log2_page_size, n + needed);
2633b64d633SDamjan Marion}
2643b64d633SDamjan Marion
2653b64d633SDamjan Marion
2663b64d633SDamjan Marion/*
2673b64d633SDamjan Marion * fd.io coding-style-patch-verification: ON
2683b64d633SDamjan Marion *
2693b64d633SDamjan Marion * Local Variables:
2703b64d633SDamjan Marion * eval: (c-set-style "gnu")
2713b64d633SDamjan Marion * End:
2723b64d633SDamjan Marion */