"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-memfd.c" (15 Mar 2019, 7674 Bytes) of package /linux/privat/stress-ng-0.09.56.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "stress-memfd.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.52_vs_0.09.54.

    1 /*
    2  * Copyright (C) 2013-2019 Canonical, Ltd.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License
    6  * as published by the Free Software Foundation; either version 2
    7  * of the License, or (at your option) any later version.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the Free Software
   16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   17  *
   18  * This code is a complete clean re-write of the stress tool by
   19  * Colin Ian King <colin.king@canonical.com> and attempts to be
   20  * backwardly compatible with the stress tool by Amos Waterland
   21  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   22  * functionality.
   23  *
   24  */
   25 #include "stress-ng.h"
   26 
   27 /*
   28  *  stress_set_memfd_bytes
   29  *  set max size of each memfd size
   30  */
   31 int stress_set_memfd_bytes(const char *opt)
   32 {
   33     size_t memfd_bytes;
   34 
   35     memfd_bytes = (size_t)get_uint64_byte_memory(opt, 1);
   36     check_range_bytes("memfd-bytes", memfd_bytes,
   37         MIN_MEMFD_BYTES, MAX_MEM_LIMIT);
   38     return set_setting("memfd-bytes", TYPE_ID_SIZE_T, &memfd_bytes);
   39 }
   40 
   41 /*
   42  *  stress_set_memfd_fds()
   43  *      set number of memfd file descriptors
   44  */
   45 int stress_set_memfd_fds(const char *opt)
   46 {
   47     uint32_t memfd_fds;
   48 
   49     memfd_fds = (uint32_t)get_uint64(opt);
   50     check_range("memfd-fds", memfd_fds,
   51         MIN_MEMFD_FDS, MAX_MEMFD_FDS);
   52     return set_setting("memfd-fds", TYPE_ID_UINT32, &memfd_fds);
   53 }
   54 
   55 #if defined(HAVE_MEMFD_CREATE)
   56 
   57 /*
   58  *  Create allocations using memfd_create, ftruncate and mmap
   59  */
   60 static void stress_memfd_allocs(
   61     const args_t *args,
   62     const size_t memfd_bytes,
   63     const uint32_t memfd_fds)
   64 {
   65     int fds[memfd_fds];
   66     void *maps[memfd_fds];
   67     uint64_t i;
   68     const size_t page_size = args->page_size;
   69     const size_t min_size = 2 * page_size;
   70     size_t size = memfd_bytes / memfd_fds;
   71 
   72     if (size < min_size)
   73         size = min_size;
   74 
   75     do {
   76         for (i = 0; i < memfd_fds; i++) {
   77             fds[i] = -1;
   78             maps[i] = MAP_FAILED;
   79         }
   80 
   81         for (i = 0; i < memfd_fds; i++) {
   82             char filename[PATH_MAX];
   83 
   84             (void)snprintf(filename, sizeof(filename), "memfd-%u-%" PRIu64, args->pid, i);
   85             fds[i] = shim_memfd_create(filename, 0);
   86             if (fds[i] < 0) {
   87                 switch (errno) {
   88                 case EMFILE:
   89                 case ENFILE:
   90                     break;
   91                 case ENOMEM:
   92                     goto clean;
   93                 case ENOSYS:
   94                 case EFAULT:
   95                 default:
   96                     pr_err("%s: memfd_create failed: errno=%d (%s)\n",
   97                         args->name, errno, strerror(errno));
   98                     g_keep_stressing_flag = false;
   99                     goto clean;
  100                 }
  101             }
  102             if (!g_keep_stressing_flag)
  103                 goto clean;
  104         }
  105 
  106         for (i = 0; i < memfd_fds; i++) {
  107             ssize_t ret;
  108 #if defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)
  109             size_t whence;
  110 #endif
  111 
  112             if (fds[i] < 0)
  113                 continue;
  114 
  115             if (!g_keep_stressing_flag)
  116                 break;
  117 
  118             /* Allocate space */
  119             ret = ftruncate(fds[i], size);
  120             if (ret < 0) {
  121                 switch (errno) {
  122                 case EINTR:
  123                     break;
  124                 default:
  125                     pr_fail_err("ftruncate");
  126                     break;
  127                 }
  128             }
  129             /*
  130              * ..and map it in, using MAP_POPULATE
  131              * to force page it in
  132              */
  133             maps[i] = mmap(NULL, size, PROT_WRITE,
  134                 MAP_FILE | MAP_SHARED | MAP_POPULATE,
  135                 fds[i], 0);
  136             mincore_touch_pages(maps[i], size);
  137             madvise_random(maps[i], size);
  138 
  139 #if defined(FALLOC_FL_PUNCH_HOLE) && defined(FALLOC_FL_KEEP_SIZE)
  140             /*
  141              *  ..and punch a hole
  142              */
  143             whence = (mwc32() % size) & ~(page_size - 1);
  144             ret = shim_fallocate(fds[i], FALLOC_FL_PUNCH_HOLE |
  145                 FALLOC_FL_KEEP_SIZE, whence, page_size);
  146             (void)ret;
  147 #endif
  148             if (!g_keep_stressing_flag)
  149                 goto clean;
  150         }
  151 
  152         for (i = 0; i < memfd_fds; i++) {
  153             if (fds[i] < 0)
  154                 continue;
  155 #if defined(SEEK_SET)
  156             if (lseek(fds[i], (off_t)size>> 1, SEEK_SET) < 0) {
  157                 if (errno != ENXIO)
  158                     pr_fail_err("lseek SEEK_SET on memfd");
  159             }
  160 #endif
  161 #if defined(SEEK_CUR)
  162             if (lseek(fds[i], (off_t)0, SEEK_CUR) < 0) {
  163                 if (errno != ENXIO)
  164                     pr_fail_err("lseek SEEK_CUR on memfd");
  165             }
  166 #endif
  167 #if defined(SEEK_END)
  168             if (lseek(fds[i], (off_t)0, SEEK_END) < 0) {
  169                 if (errno != ENXIO)
  170                     pr_fail_err("lseek SEEK_END on memfd");
  171             }
  172 #endif
  173 #if defined(SEEK_HOLE)
  174             if (lseek(fds[i], (off_t)0, SEEK_HOLE) < 0) {
  175                 if (errno != ENXIO)
  176                     pr_fail_err("lseek SEEK_HOLE on memfd");
  177             }
  178 #endif
  179 #if defined(SEEK_DATA)
  180             if (lseek(fds[i], (off_t)0, SEEK_DATA) < 0) {
  181                 if (errno != ENXIO)
  182                     pr_fail_err("lseek SEEK_DATA on memfd");
  183             }
  184 #endif
  185             if (!g_keep_stressing_flag)
  186                 goto clean;
  187         }
  188 clean:
  189         for (i = 0; i < memfd_fds; i++) {
  190             if (maps[i] != MAP_FAILED)
  191                 (void)munmap(maps[i], size);
  192             if (fds[i] >= 0)
  193                 (void)close(fds[i]);
  194         }
  195         inc_counter(args);
  196     } while (keep_stressing());
  197 }
  198 
  199 
  200 /*
  201  *  stress_memfd()
  202  *  stress memfd
  203  */
  204 static int stress_memfd(const args_t *args)
  205 {
  206     size_t memfd_bytes = DEFAULT_MEMFD_BYTES;
  207     pid_t pid;
  208     uint32_t memfd_fds = DEFAULT_MEMFD_FDS;
  209     uint32_t ooms = 0, segvs = 0, nomems = 0;
  210 
  211     if (!get_setting("memfd-bytes", &memfd_bytes)) {
  212         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  213             memfd_bytes = MAX_MEMFD_BYTES;
  214         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  215             memfd_bytes = MIN_MEMFD_BYTES;
  216     }
  217     memfd_bytes /= args->num_instances;
  218     if (memfd_bytes < MIN_MEMFD_BYTES)
  219         memfd_bytes = MIN_MEMFD_BYTES;
  220 
  221     (void)get_setting("memfd-fds", &memfd_fds);
  222 
  223 again:
  224     if (!g_keep_stressing_flag)
  225         return EXIT_SUCCESS;
  226     pid = fork();
  227     if (pid < 0) {
  228         if ((errno == EAGAIN) || (errno == ENOMEM))
  229             goto again;
  230         pr_err("%s: fork failed: errno=%d: (%s)\n",
  231             args->name, errno, strerror(errno));
  232     } else if (pid > 0) {
  233         int status, ret;
  234 
  235         (void)setpgid(pid, g_pgrp);
  236         stress_parent_died_alarm();
  237 
  238         /* Parent, wait for child */
  239         ret = waitpid(pid, &status, 0);
  240         if (ret < 0) {
  241             if (errno != EINTR)
  242                 pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  243                     args->name, errno, strerror(errno));
  244             (void)kill(pid, SIGTERM);
  245             (void)kill(pid, SIGKILL);
  246             (void)waitpid(pid, &status, 0);
  247         } else if (WIFSIGNALED(status)) {
  248             pr_dbg("%s: child died: %s (instance %d)\n",
  249                 args->name, stress_strsignal(WTERMSIG(status)), args->instance);
  250             /* If we got killed by OOM killer, re-start */
  251             if ((WTERMSIG(status) == SIGKILL) ||
  252                 (WTERMSIG(status) == SIGSEGV)) {
  253                 if (g_opt_flags & OPT_FLAGS_OOMABLE) {
  254                     log_system_mem_info();
  255                     pr_dbg("%s: assuming killed by OOM "
  256                         "killer, bailing out "
  257                         "(instance %d)\n",
  258                         args->name, args->instance);
  259                     _exit(0);
  260                 } else {
  261                     log_system_mem_info();
  262                     pr_dbg("%s: assuming killed by OOM killer, "
  263                         "restarting again (instance %d)\n",
  264                         args->name, args->instance);
  265                     ooms++;
  266                     goto again;
  267                 }
  268             }
  269 
  270         } else if (WTERMSIG(status) == SIGSEGV) {
  271             pr_dbg("%s: killed by SIGSEGV, "
  272                 "restarting again "
  273                 "(instance %d)\n",
  274                 args->name, args->instance);
  275             segvs++;
  276             goto again;
  277         }
  278     } else if (pid == 0) {
  279         (void)setpgid(0, g_pgrp);
  280 
  281         /* Make sure this is killable by OOM killer */
  282         set_oom_adjustment(args->name, true);
  283 
  284         stress_memfd_allocs(args, memfd_bytes, memfd_fds);
  285     }
  286 
  287     if (ooms + segvs + nomems > 0)
  288         pr_dbg("%s: OOM restarts: %" PRIu32
  289             ", SEGV restarts: %" PRIu32
  290             ", out of memory restarts: %" PRIu32 ".\n",
  291             args->name, ooms, segvs, nomems);
  292 
  293     return EXIT_SUCCESS;
  294 }
  295 
  296 stressor_info_t stress_memfd_info = {
  297     .stressor = stress_memfd,
  298     .class = CLASS_OS | CLASS_MEMORY
  299 };
  300 #else
  301 stressor_info_t stress_memfd_info = {
  302     .stressor = stress_not_implemented,
  303     .class = CLASS_OS | CLASS_MEMORY
  304 };
  305 #endif