"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-mmapaddr.c" (15 Mar 2019, 6658 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-mmapaddr.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 static volatile bool page_fault = false;
   28 
   29 static void stress_fault_handler(int signum)
   30 {
   31     (void)signum;
   32 
   33     page_fault = true;
   34 }
   35 
   36 /*
   37  *  stress_mmapaddr_check()
   38  *  perform some quick sanity checks to see if page is mapped OK
   39  */
   40 static int stress_mmapaddr_check(const args_t *args, uint8_t *map_addr)
   41 {
   42     unsigned char vec[1];
   43     volatile uint8_t val;
   44     int ret;
   45 
   46     page_fault = false;
   47     /* Should not fault! */
   48     val = *map_addr;
   49     (void)val;
   50 
   51     if (page_fault) {
   52         pr_err("%s: read of mmap'd address %p SEGFAULTed\n",
   53             args->name, map_addr);
   54         return -1;
   55     }
   56 
   57     vec[0] = 0;
   58     ret = shim_mincore(map_addr, args->page_size, vec);
   59     if (ret != 0) {
   60         pr_err("%s: mincore on address %p failed, errno=%d (%s)\n",
   61             args->name, map_addr, errno, strerror(errno));
   62         return -1;
   63     }
   64     if ((vec[0] & 1) == 0) {
   65         pr_inf("%s: mincore on address %p suggests page is not resident\n",
   66             args->name, map_addr);
   67         return -1;
   68     }
   69     return 0;
   70 }
   71 
   72 /*
   73  *  stress_mmapaddr_get_addr()
   74  *  try to find an unmapp'd address
   75  */
   76 static void *stress_mmapaddr_get_addr(
   77     const args_t *args,
   78     const uintptr_t mask,
   79     const size_t page_size)
   80 {
   81     unsigned char vec[1];
   82     void *addr = NULL;
   83 
   84     while (keep_stressing()) {
   85         int ret;
   86 
   87         vec[0] = 0;
   88         addr = (void *)(intptr_t)(mwc64() & mask);
   89         ret = shim_mincore(addr, page_size, vec);
   90         if (ret == 0) {
   91             addr = NULL;
   92             continue;   /* it's mapped already */
   93         } else if (ret <= 0) {
   94             if (errno == ENOSYS) {
   95                 addr = NULL;
   96                 break;
   97             }
   98             if (errno == ENOMEM) {
   99                 break;
  100             }
  101         } else {
  102             addr = NULL;
  103             continue;
  104         }
  105     }
  106     return addr;
  107 }
  108 
  109 /*
  110  *  stress_mmapaddr()
  111  *  stress mmap with randomly chosen addresses
  112  */
  113 static int stress_mmapaddr(const args_t *args)
  114 {
  115     pid_t pid;
  116 
  117     if (stress_sighandler(args->name, SIGSEGV, stress_fault_handler, NULL) < 0)
  118         return EXIT_FAILURE;
  119 
  120 again:  pid = fork();
  121     if (pid < 0) {
  122         if (g_keep_stressing_flag &&
  123                     ((errno == EAGAIN) || (errno == ENOMEM)))
  124             goto again;
  125         pr_err("%s: fork failed: errno=%d: (%s)\n",
  126             args->name, errno, strerror(errno));
  127     } else if (pid > 0) {
  128         int status, ret;
  129 
  130         (void)setpgid(pid, g_pgrp);
  131 
  132         /* Parent, wait for child */
  133         ret = waitpid(pid, &status, 0);
  134         if (ret < 0) {
  135             if (errno != EINTR)
  136                 pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  137                     args->name, errno, strerror(errno));
  138             (void)kill(pid, SIGTERM);
  139             (void)kill(pid, SIGKILL);
  140             (void)waitpid(pid, &status, 0);
  141         } else if (WIFSIGNALED(status)) {
  142             pr_dbg("%s: child died: %s (instance %d)\n",
  143                 args->name, stress_strsignal(WTERMSIG(status)),
  144                 args->instance);
  145             /* If we got killed by OOM killer, re-start */
  146             if (WTERMSIG(status) == SIGKILL) {
  147                 if (g_opt_flags & OPT_FLAGS_OOMABLE) {
  148                     log_system_mem_info();
  149                     pr_dbg("%s: assuming killed by OOM "
  150                         "killer, bailing out "
  151                         "(instance %d)\n",
  152                         args->name, args->instance);
  153                     _exit(0);
  154                 } else {
  155                     pr_dbg("%s: assuming killed by OOM "
  156                         "killer, restarting again  "
  157                         "(instance %d)\n", args->name,
  158                         args->instance);
  159                     goto again;
  160                 }
  161             }
  162             /* If we got killed by sigsegv, re-start */
  163             if (WTERMSIG(status) == SIGSEGV) {
  164                 pr_dbg("%s: killed by SIGSEGV, "
  165                     "restarting again "
  166                     "(instance %d)\n",
  167                     args->name, args->instance);
  168                 goto again;
  169             }
  170         }
  171     } else if (pid == 0) {
  172         const size_t page_size = args->page_size;
  173         const uintptr_t page_mask = ~(page_size - 1);
  174         const uintptr_t page_mask32 = page_mask & 0xffffffff;
  175 
  176         (void)setpgid(0, g_pgrp);
  177         stress_parent_died_alarm();
  178 
  179         /* Make sure this is killable by OOM killer */
  180         set_oom_adjustment(args->name, true);
  181 
  182         do {
  183             uint8_t *addr, *map_addr, *remap_addr;
  184             int flags;
  185             uint8_t rnd = mwc8();
  186 #if defined(MAP_POPULATE)
  187             const int mmap_flags = MAP_POPULATE | MAP_PRIVATE | MAP_ANONYMOUS;
  188 #else
  189             const int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
  190 #endif
  191             /* Randomly chosen low or high address mask */
  192             const uintptr_t mask = (rnd & 0x80) ? page_mask : page_mask32;
  193 
  194             addr = stress_mmapaddr_get_addr(args, mask, page_size);
  195             if (!addr) {
  196                 if (errno == ENOSYS)
  197                     break;
  198                 continue;
  199             }
  200 
  201             /* We get here if page is not already mapped */
  202 #if defined(MAP_FIXED)
  203             flags = mmap_flags | ((rnd & 0x40) ? MAP_FIXED : 0);
  204 #endif
  205 #if defined(MAP_LOCKED)
  206             flags |= ((rnd & 0x20) ? MAP_LOCKED : 0);
  207 #endif
  208             map_addr = (uint8_t *)mmap((void *)addr, page_size, PROT_READ, flags, -1, 0);
  209             if (!map_addr || (map_addr == MAP_FAILED))
  210                 continue;
  211 
  212             if (stress_mmapaddr_check(args, map_addr) < 0)
  213                 goto unmap;
  214 
  215             /* Now attempt to mmap the newly map'd page */
  216 #if defined(MAP_32BIT)
  217             flags = mmap_flags;
  218             addr = map_addr;
  219             if (rnd & 0x10) {
  220                 addr = NULL;
  221                 flags |= MAP_32BIT;
  222             }
  223 #endif
  224             remap_addr = (uint8_t *)mmap((void *)addr, page_size, PROT_READ, flags, -1, 0);
  225             if (!remap_addr || (remap_addr == MAP_FAILED))
  226                 goto unmap;
  227 
  228             (void)stress_mmapaddr_check(args, remap_addr);
  229             (void)munmap((void *)remap_addr, page_size);
  230 
  231 #if defined(HAVE_MREMAP) && NEED_GLIBC(2,4,0) && defined(MREMAP_FIXED) && defined(MREMAP_MAYMOVE)
  232             addr = stress_mmapaddr_get_addr(args, mask, page_size);
  233             if (!addr)
  234                 goto unmap;
  235 
  236             /* Now try to remap with a new fixed address */
  237             remap_addr = mremap(map_addr, page_size, page_size, MREMAP_FIXED | MREMAP_MAYMOVE, addr);
  238             if (remap_addr && (remap_addr != MAP_FAILED))
  239                 map_addr = remap_addr;
  240 #endif
  241 unmap:
  242             (void)munmap((void *)map_addr, page_size);
  243             inc_counter(args);
  244         } while (keep_stressing());
  245     }
  246 
  247     return EXIT_SUCCESS;
  248 }
  249 
  250 stressor_info_t stress_mmapaddr_info = {
  251     .stressor = stress_mmapaddr,
  252     .class = CLASS_VM | CLASS_OS
  253 };