"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-mlock.c" (15 Mar 2019, 6360 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-mlock.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 #if defined(_POSIX_MEMLOCK_RANGE) && defined(HAVE_MLOCK)
   28 
   29 #define MLOCK_MAX   (256*1024)
   30 
   31 #if defined(HAVE_MLOCK2)
   32 
   33 #ifndef MLOCK_ONFAULT
   34 #define MLOCK_ONFAULT 1
   35 #endif
   36 
   37 /*
   38  *  do_mlock()
   39  *  if mlock2 is available, randomly exercise this
   40  *  or mlock.  If not available, just fallback to
   41  *  mlock.  Also, pick random mlock2 flags
   42  */
   43 static int do_mlock(const void *addr, size_t len)
   44 {
   45     static bool use_mlock2 = true;
   46 
   47     if (use_mlock2) {
   48         uint32_t rnd = mwc32() >> 5;
   49         /* Randomly use mlock2 or mlock */
   50         if (rnd & 1) {
   51             const int flags = (rnd & 2) ?
   52                 0 : MLOCK_ONFAULT;
   53             int ret;
   54 
   55             ret = shim_mlock2(addr, len, flags);
   56             if (!ret)
   57                 return 0;
   58             if (errno != ENOSYS)
   59                 return ret;
   60 
   61             /* mlock2 not supported... */
   62             use_mlock2 = false;
   63         }
   64     }
   65 
   66     /* Just do mlock */
   67     return shim_mlock((const void *)addr, len);
   68 }
   69 #else
   70 static inline int do_mlock(const void *addr, size_t len)
   71 {
   72     return shim_mlock((const void *)addr, len);
   73 }
   74 #endif
   75 
   76 
   77 /*
   78  *  stress_mlock()
   79  *  stress mlock with pages being locked/unlocked
   80  */
   81 static int stress_mlock(const args_t *args)
   82 {
   83     const size_t page_size = args->page_size;
   84     pid_t pid;
   85     size_t max = sysconf(_SC_MAPPED_FILES);
   86     uint8_t **mappings;
   87     max = max > MLOCK_MAX ? MLOCK_MAX : max;
   88 
   89     if ((mappings = calloc(max, sizeof(*mappings))) == NULL) {
   90         pr_fail_dbg("malloc");
   91         return EXIT_NO_RESOURCE;
   92     }
   93 again:
   94     pid = fork();
   95     if (pid < 0) {
   96         if (g_keep_stressing_flag &&
   97             ((errno == EAGAIN) || (errno == ENOMEM)))
   98             goto again;
   99         pr_err("%s: fork failed: errno=%d: (%s)\n",
  100             args->name, errno, strerror(errno));
  101     } else if (pid > 0) {
  102         int status, ret;
  103 
  104         (void)setpgid(pid, g_pgrp);
  105         stress_parent_died_alarm();
  106 
  107         /* Parent, wait for child */
  108         ret = waitpid(pid, &status, 0);
  109         if (ret < 0) {
  110             if (errno != EINTR)
  111                 pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  112                     args->name, errno, strerror(errno));
  113             (void)kill(pid, SIGTERM);
  114             (void)kill(pid, SIGKILL);
  115             (void)waitpid(pid, &status, 0);
  116         } else if (WIFSIGNALED(status)) {
  117             pr_dbg("%s: child died: %s (instance %d)\n",
  118                 args->name, stress_strsignal(WTERMSIG(status)),
  119                 args->instance);
  120             /* If we got killed by OOM killer, re-start */
  121             if (WTERMSIG(status) == SIGKILL) {
  122                 if (g_opt_flags & OPT_FLAGS_OOMABLE) {
  123                     log_system_mem_info();
  124                     pr_dbg("%s: assuming killed by OOM "
  125                         "killer, bailing out "
  126                         "(instance %d)\n",
  127                         args->name, args->instance);
  128                     _exit(0);
  129                 } else {
  130                     log_system_mem_info();
  131                     pr_dbg("%s: assuming killed by OOM "
  132                         "killer, restarting again "
  133                         "(instance %d)\n", args->name,
  134                         args->instance);
  135                     goto again;
  136                 }
  137             }
  138             /* If we got killed by sigsegv, re-start */
  139             if (WTERMSIG(status) == SIGSEGV) {
  140                 pr_dbg("%s: killed by SIGSEGV, "
  141                     "restarting again "
  142                     "(instance %d)\n",
  143                     args->name, args->instance);
  144                 goto again;
  145             }
  146         }
  147     } else if (pid == 0) {
  148         size_t i, n;
  149 
  150         (void)setpgid(0, g_pgrp);
  151 
  152         /* Make sure this is killable by OOM killer */
  153         set_oom_adjustment(args->name, true);
  154 
  155         do {
  156             for (n = 0; g_keep_stressing_flag && (n < max); n++) {
  157                 int ret;
  158                 if (!keep_stressing())
  159                     break;
  160 
  161                 mappings[n] = (uint8_t *)mmap(NULL, page_size * 3,
  162                     PROT_READ | PROT_WRITE,
  163                     MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  164                 if (mappings[n] == MAP_FAILED)
  165                     break;
  166                 /*
  167                  *  Attempt a bogos mlock, ignore failure
  168                  */
  169                 (void)do_mlock((void *)(mappings[n] + page_size), 0);
  170 
  171                 /*
  172                  *  Attempt a correct mlock
  173                  */
  174                 ret = do_mlock((void *)(mappings[n] + page_size), page_size);
  175                 if (ret < 0) {
  176                     if (errno == EAGAIN)
  177                         continue;
  178                     if (errno == ENOMEM)
  179                         break;
  180                     pr_fail_err("mlock");
  181                     break;
  182                 } else {
  183                     /*
  184                      * Mappings are always page aligned so
  185                      * we can use the bottom bit to
  186                      * indicate if the page has been
  187                      * mlocked or not
  188                      */
  189                     mappings[n] = (uint8_t *)
  190                         ((ptrdiff_t)mappings[n] | 1);
  191                     inc_counter(args);
  192                 }
  193             }
  194 
  195             for (i = 0; i < n;  i++) {
  196                 ptrdiff_t addr = (ptrdiff_t)mappings[i];
  197                 ptrdiff_t mlocked = addr & 1;
  198 
  199                 addr ^= mlocked;
  200                 if (mlocked)
  201                     (void)shim_munlock((void *)((uint8_t *)addr + page_size), page_size);
  202                 /*
  203                  *  Attempt a bogos munlock, ignore failure
  204                  */
  205                 (void)shim_munlock((void *)((uint8_t *)addr + page_size), 0);
  206                 munmap((void *)addr, page_size * 3);
  207             }
  208 #if defined(HAVE_MLOCKALL)
  209 #if defined(MCL_CURRENT)
  210             (void)shim_mlockall(MCL_CURRENT);
  211 #endif
  212 #if defined(MCL_FUTURE)
  213             (void)shim_mlockall(MCL_FUTURE);
  214 #endif
  215 #if defined(MCL_ONFAULT)
  216             (void)shim_mlockall(MCL_ONFAULT);
  217 #endif
  218 #endif
  219             for (n = 0; g_keep_stressing_flag && (n < max); n++) {
  220                 if (!keep_stressing())
  221                     break;
  222 
  223                 mappings[n] = (uint8_t *)mmap(NULL, page_size,
  224                     PROT_READ | PROT_WRITE,
  225                     MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  226                 if (mappings[n] == MAP_FAILED)
  227                     break;
  228             }
  229 #if defined(HAVE_MLOCKALL)
  230             (void)shim_munlockall();
  231 #endif
  232 
  233             for (i = 0; i < n;  i++)
  234                 munmap((void *)mappings[i], page_size);
  235         } while (keep_stressing());
  236     }
  237 
  238     free(mappings);
  239 
  240     return EXIT_SUCCESS;
  241 }
  242 
  243 stressor_info_t stress_mlock_info = {
  244     .stressor = stress_mlock,
  245     .class = CLASS_VM | CLASS_OS
  246 };
  247 #else
  248 stressor_info_t stress_mlock_info = {
  249     .stressor = stress_not_implemented,
  250     .class = CLASS_VM | CLASS_OS
  251 };
  252 #endif