"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-vm-rw.c" (15 Mar 2019, 8493 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-vm-rw.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.50_vs_0.09.51.

    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(HAVE_PROCESS_VM_READV) &&   \
   28     defined(HAVE_PROCESS_VM_READV) &&   \
   29     defined(HAVE_CLONE) &&      \
   30     defined(CLONE_VM)
   31 
   32 #define STACK_SIZE  (64 * 1024)
   33 
   34 typedef struct {
   35     const args_t *args;
   36     size_t sz;
   37     pid_t pid;
   38     int pipe_wr[2];
   39     int pipe_rd[2];
   40 } context_t;
   41 
   42 typedef struct {
   43     void *addr; /* Buffer to read/write to */
   44     uint8_t val;    /* Value to check */
   45 } addr_msg_t;
   46 
   47 #endif
   48 
   49 int stress_set_vm_rw_bytes(const char *opt)
   50 {
   51     size_t vm_rw_bytes;
   52 
   53     vm_rw_bytes = (size_t)get_uint64_byte_memory(opt, 1);
   54     check_range_bytes("vm-rw-bytes", vm_rw_bytes,
   55         MIN_VM_RW_BYTES, MAX_MEM_LIMIT);
   56     return set_setting("vm-rw-bytes", TYPE_ID_SIZE_T, &vm_rw_bytes);
   57 }
   58 
   59 #if defined(HAVE_PROCESS_VM_READV) &&   \
   60     defined(HAVE_PROCESS_VM_READV) &&   \
   61     defined(HAVE_CLONE) &&      \
   62     defined(CLONE_VM)
   63 
   64 static int stress_vm_child(void *arg)
   65 {
   66     const context_t *ctxt = (context_t *)arg;
   67     const args_t *args = ctxt->args;
   68 
   69     uint8_t *buf;
   70     int ret = EXIT_SUCCESS;
   71     addr_msg_t msg_rd, msg_wr;
   72 
   73     (void)setpgid(0, g_pgrp);
   74     stress_parent_died_alarm();
   75 
   76     /* Close unwanted ends */
   77     (void)close(ctxt->pipe_wr[0]);
   78     (void)close(ctxt->pipe_rd[1]);
   79 
   80     buf = mmap(NULL, ctxt->sz, PROT_READ | PROT_WRITE,
   81         MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
   82     if (buf == MAP_FAILED) {
   83         ret = exit_status(errno);
   84         pr_fail_dbg("mmap");
   85         goto cleanup;
   86     }
   87 
   88     while (g_keep_stressing_flag) {
   89         uint8_t *ptr, *end = buf + ctxt->sz;
   90         int rwret;
   91 
   92         (void)memset(&msg_wr, 0, sizeof(msg_wr));
   93         msg_wr.addr = buf;
   94         msg_wr.val = 0;
   95 
   96         /* Send address of buffer to parent */
   97 redo_wr1:
   98         rwret = write(ctxt->pipe_wr[1], &msg_wr, sizeof(msg_wr));
   99         if (rwret < 0) {
  100             if ((errno == EAGAIN) || (errno == EINTR))
  101                 goto redo_wr1;
  102             if (errno != EBADF)
  103                 pr_fail_dbg("write");
  104             break;
  105         }
  106 redo_rd1:
  107         /* Wait for parent to populate data */
  108         rwret = read(ctxt->pipe_rd[0], &msg_rd, sizeof(msg_rd));
  109         if (rwret < 0) {
  110             if ((errno == EAGAIN) || (errno == EINTR))
  111                 goto redo_rd1;
  112             pr_fail_dbg("read");
  113             break;
  114         }
  115         if (rwret == 0)
  116             break;
  117         if (rwret != sizeof(msg_rd)) {
  118             pr_fail_dbg("read");
  119             break;
  120         }
  121 
  122         if (g_opt_flags & OPT_FLAGS_VERIFY) {
  123             /* Check memory altered by parent is sane */
  124             for (ptr = buf; ptr < end; ptr += args->page_size) {
  125                 if (*ptr != msg_rd.val) {
  126                     pr_fail("%s: memory at %p: %d vs %d\n",
  127                         args->name, ptr, *ptr, msg_rd.val);
  128                     goto cleanup;
  129                 }
  130                 *ptr = 0;
  131             }
  132         }
  133     }
  134 cleanup:
  135     /* Tell parent we're done */
  136     msg_wr.addr = 0;
  137     msg_wr.val = 0;
  138     if (write(ctxt->pipe_wr[1], &msg_wr, sizeof(msg_wr)) <= 0) {
  139         if (errno != EBADF)
  140             pr_dbg("%s: failed to write termination message "
  141                 "over pipe: errno=%d (%s)\n",
  142                 args->name, errno, strerror(errno));
  143     }
  144 
  145     (void)close(ctxt->pipe_wr[1]);
  146     (void)close(ctxt->pipe_rd[0]);
  147     (void)munmap(buf, ctxt->sz);
  148     return ret;
  149 }
  150 
  151 static int stress_vm_parent(context_t *ctxt)
  152 {
  153     /* Parent */
  154     int status;
  155     uint8_t val = 0;
  156     uint8_t *localbuf;
  157     addr_msg_t msg_rd, msg_wr;
  158     const args_t *args = ctxt->args;
  159 
  160     (void)setpgid(ctxt->pid, g_pgrp);
  161 
  162     localbuf = mmap(NULL, ctxt->sz, PROT_READ | PROT_WRITE,
  163             MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
  164     if (localbuf == MAP_FAILED) {
  165         (void)close(ctxt->pipe_wr[0]);
  166         (void)close(ctxt->pipe_wr[1]);
  167         (void)close(ctxt->pipe_rd[0]);
  168         (void)close(ctxt->pipe_rd[1]);
  169         pr_fail_dbg("mmap");
  170         return EXIT_FAILURE;
  171     }
  172 
  173     /* Close unwanted ends */
  174     (void)close(ctxt->pipe_wr[1]);
  175     (void)close(ctxt->pipe_rd[0]);
  176 
  177     do {
  178         struct iovec local[1], remote[1];
  179         uint8_t *ptr, *end = localbuf + ctxt->sz;
  180         int ret;
  181 
  182         /* Wait for address of child's buffer */
  183 redo_rd2:
  184         if (!g_keep_stressing_flag)
  185             break;
  186         ret = read(ctxt->pipe_wr[0], &msg_rd, sizeof(msg_rd));
  187         if (ret < 0) {
  188             if ((errno == EAGAIN) || (errno == EINTR))
  189                 goto redo_rd2;
  190             pr_fail_dbg("read");
  191             break;
  192         }
  193         if (ret == 0)
  194             break;
  195         if (ret != sizeof(msg_rd)) {
  196             pr_fail_dbg("read");
  197             break;
  198         }
  199         /* Child telling us it's terminating? */
  200         if (!msg_rd.addr)
  201             break;
  202 
  203         /* Perform read from child's memory */
  204         local[0].iov_base = localbuf;
  205         local[0].iov_len = ctxt->sz;
  206         remote[0].iov_base = msg_rd.addr;
  207         remote[0].iov_len = ctxt->sz;
  208         if (process_vm_readv(ctxt->pid, local, 1, remote, 1, 0) < 0) {
  209             pr_fail_dbg("process_vm_readv");
  210             break;
  211         }
  212 
  213         if (g_opt_flags & OPT_FLAGS_VERIFY) {
  214             /* Check data is sane */
  215             for (ptr = localbuf; ptr < end; ptr += args->page_size) {
  216                 if (*ptr) {
  217                     pr_fail("%s: memory at %p: %d vs %d\n",
  218                         args->name, ptr, *ptr, msg_rd.val);
  219                     goto fail;
  220                 }
  221                 *ptr = 0;
  222             }
  223             /* Set memory */
  224             for (ptr = localbuf; ptr < end; ptr += args->page_size)
  225                 *ptr = val;
  226         }
  227 
  228         /* Write to child's memory */
  229         msg_wr = msg_rd;
  230         local[0].iov_base = localbuf;
  231         local[0].iov_len = ctxt->sz;
  232         remote[0].iov_base = msg_rd.addr;
  233         remote[0].iov_len = ctxt->sz;
  234         if (process_vm_writev(ctxt->pid, local, 1, remote, 1, 0) < 0) {
  235             pr_fail_dbg("process_vm_writev");
  236             break;
  237         }
  238         msg_wr.val = val;
  239         val++;
  240 redo_wr2:
  241         if (!g_keep_stressing_flag)
  242             break;
  243         /* Inform child that memory has been changed */
  244         ret = write(ctxt->pipe_rd[1], &msg_wr, sizeof(msg_wr));
  245         if (ret < 0) {
  246             if ((errno == EAGAIN) || (errno == EINTR))
  247                 goto redo_wr2;
  248             if (errno != EBADF)
  249                 pr_fail_dbg("write");
  250             break;
  251         }
  252         inc_counter(args);
  253     } while (keep_stressing());
  254 fail:
  255     /* Tell child we're done */
  256     msg_wr.addr = NULL;
  257     msg_wr.val = 0;
  258     if (write(ctxt->pipe_wr[0], &msg_wr, sizeof(msg_wr)) < 0) {
  259         if (errno != EBADF)
  260             pr_dbg("%s: failed to write "
  261                 "termination message "
  262                 "over pipe: errno=%d (%s)\n",
  263                 args->name, errno, strerror(errno));
  264     }
  265     (void)close(ctxt->pipe_wr[0]);
  266     (void)close(ctxt->pipe_rd[1]);
  267     (void)kill(ctxt->pid, SIGKILL);
  268     (void)waitpid(ctxt->pid, &status, 0);
  269     (void)munmap(localbuf, ctxt->sz);
  270 
  271     return EXIT_SUCCESS;
  272 }
  273 
  274 /*
  275  *  stress_vm_rw
  276  *  stress vm_read_v/vm_write_v
  277  */
  278 static int stress_vm_rw(const args_t *args)
  279 {
  280     context_t ctxt;
  281     uint8_t stack[64*1024];
  282     const ssize_t stack_offset =
  283         stress_get_stack_direction() * (STACK_SIZE - 64);
  284     uint8_t *stack_top = stack + stack_offset;
  285     size_t vm_rw_bytes = DEFAULT_VM_RW_BYTES;
  286 
  287     if (!get_setting("vm-rw-bytes", &vm_rw_bytes)) {
  288         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  289             vm_rw_bytes = MAX_VM_RW_BYTES;
  290         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  291             vm_rw_bytes = MIN_VM_RW_BYTES;
  292     }
  293     vm_rw_bytes /= args->num_instances;
  294     if (vm_rw_bytes < MIN_VM_RW_BYTES)
  295         vm_rw_bytes = MIN_VM_RW_BYTES;
  296     if (vm_rw_bytes < args->page_size)
  297         vm_rw_bytes = args->page_size;
  298     ctxt.args = args;
  299     ctxt.sz = vm_rw_bytes & ~(args->page_size - 1);
  300 
  301     if (pipe(ctxt.pipe_wr) < 0) {
  302         pr_fail_dbg("pipe");
  303         return EXIT_NO_RESOURCE;
  304     }
  305     if (pipe(ctxt.pipe_rd) < 0) {
  306         (void)close(ctxt.pipe_wr[0]);
  307         (void)close(ctxt.pipe_wr[1]);
  308         pr_fail_dbg("pipe");
  309         return EXIT_NO_RESOURCE;
  310     }
  311 
  312 again:
  313     ctxt.pid = clone(stress_vm_child, align_stack(stack_top),
  314         SIGCHLD | CLONE_VM, &ctxt);
  315     if (ctxt.pid < 0) {
  316         if (g_keep_stressing_flag && (errno == EAGAIN))
  317             goto again;
  318         (void)close(ctxt.pipe_wr[0]);
  319         (void)close(ctxt.pipe_wr[1]);
  320         (void)close(ctxt.pipe_rd[0]);
  321         (void)close(ctxt.pipe_rd[1]);
  322         pr_fail_dbg("clone");
  323         return EXIT_NO_RESOURCE;
  324     }
  325     return stress_vm_parent(&ctxt);
  326 }
  327 
  328 stressor_info_t stress_vm_rw_info = {
  329     .stressor = stress_vm_rw,
  330     .class = CLASS_VM | CLASS_MEMORY | CLASS_OS
  331 };
  332 #else
  333 stressor_info_t stress_vm_rw_info = {
  334     .stressor = stress_not_implemented,
  335     .class = CLASS_VM | CLASS_MEMORY | CLASS_OS
  336 };
  337 #endif