"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-mremap.c" (15 Mar 2019, 8434 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-mremap.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 int stress_set_mremap_bytes(const char *opt)
   28 {
   29     size_t mremap_bytes;
   30 
   31     mremap_bytes = (size_t)get_uint64_byte_memory(opt, 1);
   32     check_range_bytes("mremap-bytes", mremap_bytes,
   33         MIN_MREMAP_BYTES, MAX_MEM_LIMIT);
   34     return set_setting("mremap-bytes", TYPE_ID_SIZE_T, &mremap_bytes);
   35 }
   36 
   37 #if defined(HAVE_MREMAP) && NEED_GLIBC(2,4,0)
   38 
   39 #if defined(MREMAP_FIXED)
   40 /*
   41  *  rand_mremap_addr()
   42  *  try and find a random unmapped region of memory
   43  */
   44 static inline void *rand_mremap_addr(const size_t sz, int flags)
   45 {
   46     void *addr;
   47 
   48     flags &= ~(MREMAP_FIXED | MAP_SHARED | MAP_POPULATE);
   49     flags |= (MAP_PRIVATE | MAP_ANONYMOUS);
   50 
   51     addr = mmap(NULL, sz, PROT_READ | PROT_WRITE, flags, -1, 0);
   52     if (addr == MAP_FAILED)
   53         return NULL;
   54 
   55     (void)munmap(addr, sz);
   56 
   57     /*
   58      * At this point, we know that we can remap to this addr
   59      * in this process if we don't do any memory mappings between
   60      * the munmap above and the remapping
   61      */
   62 
   63     return addr;
   64 }
   65 #endif
   66 
   67 
   68 
   69 /*
   70  *  try_remap()
   71  *  try and remap old size to new size
   72  */
   73 static int try_remap(
   74     const args_t *args,
   75     uint8_t **buf,
   76     const size_t old_sz,
   77     const size_t new_sz)
   78 {
   79     uint8_t *newbuf;
   80     int retry, flags = 0;
   81 #if defined(MREMAP_MAYMOVE)
   82     const int maymove = MREMAP_MAYMOVE;
   83 #else
   84     const int maymove = 0;
   85 #endif
   86 
   87 #if defined(MREMAP_FIXED) && defined(MREMAP_MAYMOVE)
   88     flags = maymove | (mwc32() & MREMAP_FIXED);
   89 #else
   90     flags = maymove;
   91 #endif
   92 
   93     for (retry = 0; retry < 100; retry++) {
   94 #if defined(MREMAP_FIXED)
   95         void *addr = rand_mremap_addr(new_sz, flags);
   96 #endif
   97         if (!g_keep_stressing_flag)
   98             return 0;
   99 #if defined(MREMAP_FIXED)
  100         if (addr) {
  101             newbuf = mremap(*buf, old_sz, new_sz, flags, addr);
  102         } else {
  103             newbuf = mremap(*buf, old_sz, new_sz, flags & ~MREMAP_FIXED);
  104         }
  105 #else
  106         newbuf = mremap(*buf, old_sz, new_sz, flags);
  107 #endif
  108         if (newbuf != MAP_FAILED) {
  109             *buf = newbuf;
  110             return 0;
  111         }
  112 
  113         switch (errno) {
  114         case ENOMEM:
  115         case EAGAIN:
  116             continue;
  117         case EINVAL:
  118 #if defined(MREMAP_FIXED)
  119             /*
  120              * Earlier kernels may not support this or we
  121              * chose a bad random address, so just fall
  122              * back to non fixed remapping
  123              */
  124             if (flags & MREMAP_FIXED) {
  125                 flags &= ~MREMAP_FIXED;
  126                 continue;
  127             }
  128 #endif
  129             break;
  130         case EFAULT:
  131         default:
  132             break;
  133         }
  134     }
  135     pr_fail_err("mremap");
  136     return -1;
  137 }
  138 
  139 static int stress_mremap_child(
  140     const args_t *args,
  141     const size_t sz,
  142     size_t new_sz,
  143     const size_t page_size,
  144     const size_t mremap_bytes,
  145     int *flags)
  146 {
  147     do {
  148         uint8_t *buf = NULL;
  149         size_t old_sz;
  150 
  151         if (!g_keep_stressing_flag)
  152             break;
  153 
  154         buf = mmap(NULL, new_sz, PROT_READ | PROT_WRITE, *flags, -1, 0);
  155         if (buf == MAP_FAILED) {
  156             /* Force MAP_POPULATE off, just in case */
  157 #if defined(MAP_POPULATE)
  158             *flags &= ~MAP_POPULATE;
  159 #endif
  160             continue;   /* Try again */
  161         }
  162         (void)madvise_random(buf, new_sz);
  163         (void)mincore_touch_pages(buf, mremap_bytes);
  164 
  165         /* Ensure we can write to the mapped pages */
  166         if (g_opt_flags & OPT_FLAGS_VERIFY) {
  167             mmap_set(buf, new_sz, page_size);
  168             if (mmap_check(buf, sz, page_size) < 0) {
  169                 pr_fail("%s: mmap'd region of %zu "
  170                     "bytes does not contain expected data\n",
  171                     args->name, sz);
  172                 (void)munmap(buf, new_sz);
  173                 return EXIT_FAILURE;
  174             }
  175         }
  176 
  177         old_sz = new_sz;
  178         new_sz >>= 1;
  179         while (new_sz > page_size) {
  180             if (try_remap(args, &buf, old_sz, new_sz) < 0) {
  181                 (void)munmap(buf, old_sz);
  182                 return EXIT_FAILURE;
  183             }
  184             (void)madvise_random(buf, new_sz);
  185             if (g_opt_flags & OPT_FLAGS_VERIFY) {
  186                 if (mmap_check(buf, new_sz, page_size) < 0) {
  187                     pr_fail("%s: mremap'd region "
  188                         "of %zu bytes does "
  189                         "not contain expected data\n",
  190                         args->name, sz);
  191                     (void)munmap(buf, new_sz);
  192                     return EXIT_FAILURE;
  193                 }
  194             }
  195             old_sz = new_sz;
  196             new_sz >>= 1;
  197         }
  198 
  199         new_sz <<= 1;
  200         while (new_sz < mremap_bytes) {
  201             if (try_remap(args, &buf, old_sz, new_sz) < 0) {
  202                 (void)munmap(buf, old_sz);
  203                 return EXIT_FAILURE;
  204             }
  205             (void)madvise_random(buf, new_sz);
  206             old_sz = new_sz;
  207             new_sz <<= 1;
  208         }
  209         (void)munmap(buf, old_sz);
  210 
  211         inc_counter(args);
  212     } while (keep_stressing());
  213 
  214     return EXIT_SUCCESS;
  215 }
  216 
  217 /*
  218  *  stress_mremap()
  219  *  stress mmap
  220  */
  221 static int stress_mremap(const args_t *args)
  222 {
  223     const size_t page_size = args->page_size;
  224     size_t sz, new_sz;
  225     int rc = EXIT_SUCCESS, flags = MAP_PRIVATE | MAP_ANONYMOUS;
  226     pid_t pid;
  227     uint32_t ooms = 0, segvs = 0, buserrs = 0;
  228     size_t mremap_bytes = DEFAULT_MREMAP_BYTES;
  229 
  230 #if defined(MAP_POPULATE)
  231     flags |= MAP_POPULATE;
  232 #endif
  233     if (!get_setting("mremap-bytes", &mremap_bytes)) {
  234         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  235             mremap_bytes = MAX_MREMAP_BYTES;
  236         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  237             mremap_bytes = MIN_MREMAP_BYTES;
  238     }
  239     mremap_bytes /= args->num_instances;
  240     if (mremap_bytes < MIN_MREMAP_BYTES)
  241         mremap_bytes = MIN_MREMAP_BYTES;
  242     if (mremap_bytes < page_size)
  243         mremap_bytes= page_size;
  244     new_sz = sz = mremap_bytes & ~(page_size - 1);
  245 
  246     /* Make sure this is killable by OOM killer */
  247     set_oom_adjustment(args->name, true);
  248 
  249 again:
  250     if (!g_keep_stressing_flag)
  251         return EXIT_SUCCESS;
  252     pid = fork();
  253     if (pid < 0) {
  254         if ((errno == EAGAIN) || (errno == ENOMEM))
  255             goto again;
  256         pr_err("%s: fork failed: errno=%d: (%s)\n",
  257             args->name, errno, strerror(errno));
  258     } else if (pid > 0) {
  259         int status, ret;
  260 
  261         (void)setpgid(pid, g_pgrp);
  262         /* Parent, wait for child */
  263         ret = waitpid(pid, &status, 0);
  264         if (ret < 0) {
  265             if (errno != EINTR)
  266                 pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  267                     args->name, errno, strerror(errno));
  268             (void)kill(pid, SIGTERM);
  269             (void)kill(pid, SIGKILL);
  270             (void)waitpid(pid, &status, 0);
  271         } else if (WIFSIGNALED(status)) {
  272             /* If we got killed by sigbus, re-start */
  273             if (WTERMSIG(status) == SIGBUS) {
  274                 /* Happens frequently, so be silent */
  275                 buserrs++;
  276                 goto again;
  277             }
  278 
  279             pr_dbg("%s: child died: %s (instance %d)\n",
  280                 args->name, stress_strsignal(WTERMSIG(status)),
  281                 args->instance);
  282             /* If we got killed by OOM killer, re-start */
  283             if (WTERMSIG(status) == SIGKILL) {
  284                 if (g_opt_flags & OPT_FLAGS_OOMABLE) {
  285                     log_system_mem_info();
  286                     pr_dbg("%s: assuming killed by OOM "
  287                         "killer, bailing out "
  288                         "(instance %d)\n",
  289                         args->name, args->instance);
  290                     _exit(0);
  291                 } else {
  292                     log_system_mem_info();
  293                     pr_dbg("%s: assuming killed by OOM "
  294                         "killer, restarting again "
  295                         "(instance %d)\n",
  296                         args->name, args->instance);
  297                     ooms++;
  298                 }
  299                 goto again;
  300             }
  301             /* If we got killed by sigsegv, re-start */
  302             if (WTERMSIG(status) == SIGSEGV) {
  303                 pr_dbg("%s: killed by SIGSEGV, "
  304                     "restarting again "
  305                     "(instance %d)\n",
  306                     args->name, args->instance);
  307                 segvs++;
  308                 goto again;
  309             }
  310         } else {
  311             rc = WEXITSTATUS(status);
  312         }
  313     } else if (pid == 0) {
  314         (void)setpgid(0, g_pgrp);
  315         stress_parent_died_alarm();
  316 
  317         /* Make sure this is killable by OOM killer */
  318         set_oom_adjustment(args->name, true);
  319 
  320         rc = stress_mremap_child(args, sz,
  321             new_sz, page_size, mremap_bytes, &flags);
  322         _exit(rc);
  323     }
  324 
  325     if (ooms + segvs + buserrs > 0)
  326         pr_dbg("%s: OOM restarts: %" PRIu32
  327             ", SEGV restarts: %" PRIu32
  328             ", SIGBUS signals: %" PRIu32 "\n",
  329             args->name, ooms, segvs, buserrs);
  330 
  331     return rc;
  332 }
  333 
  334 stressor_info_t stress_mremap_info = {
  335     .stressor = stress_mremap,
  336     .class = CLASS_VM | CLASS_OS
  337 };
  338 #else
  339 stressor_info_t stress_mremap_info = {
  340     .stressor = stress_not_implemented,
  341     .class = CLASS_VM | CLASS_OS
  342 };
  343 #endif