"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-handle.c" (15 Mar 2019, 6112 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-handle.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(HAVE_NAME_TO_HANDLE_AT) &&  \
   28     defined(HAVE_OPEN_BY_HANDLE_AT) &&  \
   29     defined(AT_FDCWD)
   30 
   31 #define MAX_MOUNT_IDS   (1024)
   32 #define FILENAME    "/dev/zero"
   33 
   34 /* Stringification macros */
   35 #define XSTR(s) STR(s)
   36 #define STR(s) #s
   37 
   38 typedef struct {
   39     char    *mount_path;
   40     int mount_id;
   41 } mount_info_t;
   42 
   43 static mount_info_t mount_info[MAX_MOUNT_IDS];
   44 
   45 static void free_mount_info(const int mounts)
   46 {
   47     int i;
   48 
   49     for (i = 0; i < mounts; i++)
   50         free(mount_info[i].mount_path);
   51 }
   52 
   53 static int get_mount_info(const args_t *args)
   54 {
   55     FILE *fp;
   56     int mounts = 0;
   57 
   58     if ((fp = fopen("/proc/self/mountinfo", "r")) == NULL) {
   59         pr_dbg("%s: cannot open /proc/self/mountinfo\n", args->name);
   60         return -1;
   61     }
   62 
   63     for (;;) {
   64         char mount_path[PATH_MAX + 1];
   65         char *line = NULL;
   66         size_t line_len = 0;
   67 
   68         ssize_t nread = getline(&line, &line_len, fp);
   69         if (nread == -1) {
   70             free(line);
   71             break;
   72         }
   73 
   74         nread = sscanf(line, "%12d %*d %*s %*s %" XSTR(PATH_MAX) "s",
   75             &mount_info[mounts].mount_id,
   76             mount_path);
   77         free(line);
   78         if (nread != 2)
   79             continue;
   80 
   81         mount_info[mounts].mount_path = strdup(mount_path);
   82         if (mount_info[mounts].mount_path == NULL) {
   83             pr_dbg("%s: cannot allocate mountinfo mount path\n", args->name);
   84             free_mount_info(mounts);
   85             mounts = -1;
   86             break;
   87         }
   88         mounts++;
   89     }
   90     (void)fclose(fp);
   91     return mounts;
   92 }
   93 
   94 
   95 /*
   96  *  stress_handle()
   97  *  stress system by rapid open/close calls via
   98  *  name_to_handle_at and open_by_handle_at
   99  */
  100 static int stress_handle(const args_t *args)
  101 {
  102     int mounts;
  103     pid_t pid;
  104 
  105     if ((mounts = get_mount_info(args)) < 0) {
  106         pr_fail("%s: failed to parse /proc/self/mountinfo\n", args->name);
  107         return EXIT_FAILURE;
  108     }
  109 
  110 again:
  111     if (!g_keep_stressing_flag)
  112         goto tidy;
  113     pid = fork();
  114     if (pid < 0) {
  115         if ((errno == EAGAIN) || (errno == ENOMEM))
  116             goto again;
  117         pr_err("%s: fork failed: errno=%d: (%s)\n",
  118             args->name, errno, strerror(errno));
  119     } else if (pid > 0) {
  120         int status, ret;
  121 
  122         (void)setpgid(pid, g_pgrp);
  123         /* Parent, wait for child */
  124         ret = waitpid(pid, &status, 0);
  125         if (ret < 0) {
  126             if (errno != EINTR)
  127                 pr_dbg("%s: waitpid(): errno=%d (%s)\n",
  128                     args->name, errno, strerror(errno));
  129             (void)kill(pid, SIGTERM);
  130             (void)kill(pid, SIGKILL);
  131             (void)waitpid(pid, &status, 0);
  132         } else if (WIFSIGNALED(status)) {
  133             pr_dbg("%s: child died: %s (instance %d)\n",
  134                 args->name, stress_strsignal(WTERMSIG(status)),
  135                 args->instance);
  136             /* If we got killed by OOM killer, re-start */
  137             if (WTERMSIG(status) == SIGKILL) {
  138                 if (g_opt_flags & OPT_FLAGS_OOMABLE) {
  139                     log_system_mem_info();
  140                     pr_dbg("%s: assuming killed by OOM "
  141                         "killer, bailing out "
  142                         "(instance %d)\n",
  143                         args->name, args->instance);
  144                     _exit(0);
  145                 } else {
  146                     log_system_mem_info();
  147                     pr_dbg("%s: assuming killed by OOM "
  148                         "killer, restarting again "
  149                         "(instance %d)\n",
  150                         args->name, args->instance);
  151                     goto again;
  152                 }
  153             }
  154         }
  155     } else if (pid == 0) {
  156         (void)setpgid(0, g_pgrp);
  157         stress_parent_died_alarm();
  158 
  159         /* Make sure this is killable by OOM killer */
  160         set_oom_adjustment(args->name, true);
  161 
  162         do {
  163             struct file_handle *fhp, *tmp;
  164             int mount_id, mount_fd, fd, i;
  165 
  166             if ((fhp = malloc(sizeof(*fhp))) == NULL)
  167                 continue;
  168 
  169             fhp->handle_bytes = 0;
  170             if ((name_to_handle_at(AT_FDCWD, FILENAME, fhp, &mount_id, 0) != -1) &&
  171                 (errno != EOVERFLOW)) {
  172                 pr_fail_err("name_to_handle_at: failed to get file handle size");
  173                 free(fhp);
  174                 break;
  175             }
  176             tmp = realloc(fhp, sizeof(struct file_handle) + fhp->handle_bytes);
  177             if (tmp == NULL) {
  178                 free(fhp);
  179                 continue;
  180             }
  181             fhp = tmp;
  182             if (name_to_handle_at(AT_FDCWD, FILENAME, fhp, &mount_id, 0) < 0) {
  183                 pr_fail_err("name_to_handle_at: failed to get file handle");
  184                 free(fhp);
  185                 break;
  186             }
  187 
  188             mount_fd = -2;
  189             for (i = 0; i < mounts; i++) {
  190                 if (mount_info[i].mount_id == mount_id) {
  191                     mount_fd = open(mount_info[i].mount_path, O_RDONLY);
  192                     break;
  193                 }
  194             }
  195             if (mount_fd == -2) {
  196                 pr_fail("%s: cannot find mount id %d\n", args->name, mount_id);
  197                 free(fhp);
  198                 break;
  199             }
  200             if (mount_fd < 0) {
  201                 pr_fail("%s: failed to open mount path '%s': errno=%d (%s)\n",
  202                     args->name, mount_info[i].mount_path, errno, strerror(errno));
  203                 free(fhp);
  204                 break;
  205             }
  206             if ((fd = open_by_handle_at(mount_fd, fhp, O_RDONLY)) < 0) {
  207                 /* We don't abort if EPERM occurs, that's not a test failure */
  208                 if (errno != EPERM) {
  209                     pr_fail("%s: open_by_handle_at: failed to open: errno=%d (%s)\n",
  210                         args->name, errno, strerror(errno));
  211                     (void)close(mount_fd);
  212                     free(fhp);
  213                     break;
  214                 }
  215             } else {
  216                 (void)close(fd);
  217             }
  218             (void)close(mount_fd);
  219             free(fhp);
  220             inc_counter(args);
  221         } while (keep_stressing());
  222         _exit(EXIT_SUCCESS);
  223     }
  224 tidy:
  225     free_mount_info(mounts);
  226 
  227     return EXIT_SUCCESS;
  228 }
  229 
  230 stressor_info_t stress_handle_info = {
  231     .stressor = stress_handle,
  232     .class = CLASS_FILESYSTEM | CLASS_OS
  233 };
  234 #else
  235 stressor_info_t stress_handle_info = {
  236     .stressor = stress_not_implemented,
  237     .class = CLASS_FILESYSTEM | CLASS_OS
  238 };
  239 #endif