"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-fstat.c" (15 Mar 2019, 7238 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-fstat.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 #define MAX_FSTAT_THREADS   (4)
   28 #define FSTAT_LOOPS     (16)
   29 
   30 static volatile bool keep_running;
   31 static sigset_t set;
   32 
   33 /* paths we should never stat */
   34 static const char *blacklist[] = {
   35     "/dev/watchdog"
   36 };
   37 
   38 #define IGNORE_STAT 0x0001
   39 #define IGNORE_LSTAT    0x0002
   40 #define IGNORE_STATX    0x0004
   41 #define IGNORE_FSTAT    0x0008
   42 #define IGNORE_ALL  0x000f
   43 
   44 /* stat path information */
   45 typedef struct stat_info {
   46     struct stat_info *next;     /* next stat_info in list */
   47     char        *path;      /* path to stat */
   48     uint16_t    ignore;     /* true to ignore this path */
   49     bool        access;     /* false if we can't access path */
   50 } stat_info_t;
   51 
   52 /* Thread context information */
   53 typedef struct ctxt {
   54     const args_t    *args;      /* Stressor args */
   55     stat_info_t     *si;        /* path stat information */
   56     const uid_t euid;       /* euid of process */
   57 } ctxt_t;
   58 
   59 int stress_set_fstat_dir(const char *opt)
   60 {
   61     return set_setting("fstat-dir", TYPE_ID_STR, opt);
   62 }
   63 
   64 /*
   65  *  handle_fstat_sigalrm()
   66  *      catch SIGALRM
   67  */
   68 static void MLOCKED_TEXT handle_fstat_sigalrm(int signum)
   69 {
   70     (void)signum;
   71 
   72     keep_running = false;
   73     g_keep_stressing_flag = false;
   74 }
   75 
   76 /*
   77  *  do_not_stat()
   78  *  Check if file should not be stat'd
   79  */
   80 static bool do_not_stat(const char *filename)
   81 {
   82     size_t i;
   83 
   84     for (i = 0; i < SIZEOF_ARRAY(blacklist); i++) {
   85         if (!strncmp(filename, blacklist[i], strlen(blacklist[i])))
   86             return true;
   87     }
   88     return false;
   89 }
   90 
   91 static void stress_fstat_helper(const ctxt_t *ctxt)
   92 {
   93     struct stat buf;
   94 #if defined(AT_EMPTY_PATH) && defined(AT_SYMLINK_NOFOLLOW)
   95     struct shim_statx bufx;
   96 #endif
   97     stat_info_t *si = ctxt->si;
   98 
   99     if ((stat(si->path, &buf) < 0) && (errno != ENOMEM)) {
  100         si->ignore |= IGNORE_STAT;
  101     }
  102     if ((lstat(si->path, &buf) < 0) && (errno != ENOMEM)) {
  103         si->ignore |= IGNORE_LSTAT;
  104     }
  105 #if defined(AT_EMPTY_PATH) && defined(AT_SYMLINK_NOFOLLOW)
  106     /* Heavy weight statx */
  107     if ((shim_statx(AT_EMPTY_PATH, si->path, AT_SYMLINK_NOFOLLOW,
  108         SHIM_STATX_ALL, &bufx) < 0) && (errno != ENOMEM)) {
  109         si->ignore |= IGNORE_STATX;
  110     }
  111 #endif
  112     /*
  113      *  Opening /dev files such as /dev/urandom
  114      *  may block when running as root, so
  115      *  avoid this.
  116      */
  117     if ((si->access) && (ctxt->euid)) {
  118         int fd;
  119 
  120         fd = open(si->path, O_RDONLY | O_NONBLOCK);
  121         if (fd < 0) {
  122             si->access = false;
  123             return;
  124         }
  125         if ((fstat(fd, &buf) < 0) && (errno != ENOMEM))
  126             si->ignore |= IGNORE_FSTAT;
  127         (void)close(fd);
  128     }
  129 }
  130 
  131 #if defined(HAVE_LIB_PTHREAD)
  132 /*
  133  *  stress_fstat_thread
  134  *  keep exercising a file until
  135  *  controlling thread triggers an exit
  136  */
  137 static void *stress_fstat_thread(void *ctxt_ptr)
  138 {
  139     static void *nowt = NULL;
  140     uint8_t stack[SIGSTKSZ + STACK_ALIGNMENT];
  141     const ctxt_t *ctxt = (const ctxt_t *)ctxt_ptr;
  142 
  143     /*
  144      *  Block all signals, let controlling thread
  145      *  handle these
  146      */
  147 #if !defined(__APPLE__)
  148     (void)sigprocmask(SIG_BLOCK, &set, NULL);
  149 #endif
  150 
  151     /*
  152      *  According to POSIX.1 a thread should have
  153      *  a distinct alternative signal stack.
  154      *  However, we block signals in this thread
  155      *  so this is probably just totally unncessary.
  156      */
  157     (void)memset(stack, 0, sizeof(stack));
  158     if (stress_sigaltstack(stack, SIGSTKSZ) < 0)
  159         return &nowt;
  160 
  161     while (keep_running && g_keep_stressing_flag) {
  162         size_t i;
  163 
  164         for (i = 0; i < FSTAT_LOOPS; i++)  {
  165             if (!g_keep_stressing_flag)
  166                 break;
  167             stress_fstat_helper(ctxt);
  168         }
  169         (void)shim_sched_yield();
  170     }
  171 
  172     return &nowt;
  173 }
  174 #endif
  175 
  176 /*
  177  *  stress_fstat_threads()
  178  *  create a bunch of threads to thrash a file
  179  */
  180 static void stress_fstat_threads(const args_t *args, stat_info_t *si, const uid_t euid)
  181 {
  182     size_t i;
  183 #if defined(HAVE_LIB_PTHREAD)
  184     pthread_t pthreads[MAX_FSTAT_THREADS];
  185     int ret[MAX_FSTAT_THREADS];
  186 #endif
  187     ctxt_t ctxt = {
  188         .args   = args,
  189         .si     = si,
  190         .euid   = euid
  191     };
  192 
  193     keep_running = true;
  194 #if defined(HAVE_LIB_PTHREAD)
  195     (void)memset(ret, 0, sizeof(ret));
  196     (void)memset(pthreads, 0, sizeof(pthreads));
  197 
  198     for (i = 0; i < MAX_FSTAT_THREADS; i++) {
  199         ret[i] = pthread_create(&pthreads[i], NULL,
  200                 stress_fstat_thread, &ctxt);
  201     }
  202 #endif
  203     for (i = 0; i < FSTAT_LOOPS; i++) {
  204         if (!g_keep_stressing_flag)
  205             break;
  206         stress_fstat_helper(&ctxt);
  207     }
  208     keep_running = false;
  209 
  210 #if defined(HAVE_LIB_PTHREAD)
  211     for (i = 0; i < MAX_FSTAT_THREADS; i++) {
  212         if (ret[i] == 0)
  213             (void)pthread_join(pthreads[i], NULL);
  214     }
  215 #endif
  216 }
  217 
  218 /*
  219  *  stress_fstat()
  220  *  stress system with fstat
  221  */
  222 static int stress_fstat(const args_t *args)
  223 {
  224     stat_info_t *si;
  225     static stat_info_t *stat_info;
  226     struct dirent *d;
  227     NOCLOBBER int ret = EXIT_FAILURE;
  228     bool stat_some;
  229     const uid_t euid = geteuid();
  230     DIR *dp;
  231     char *fstat_dir = "/dev";
  232 
  233     (void)get_setting("fstat-dir", &fstat_dir);
  234 
  235     if (stress_sighandler(args->name, SIGALRM, handle_fstat_sigalrm, NULL) < 0)
  236         return EXIT_FAILURE;
  237 
  238     if ((dp = opendir(fstat_dir)) == NULL) {
  239         pr_err("%s: opendir on %s failed: errno=%d: (%s)\n",
  240             args->name, fstat_dir, errno, strerror(errno));
  241         return EXIT_FAILURE;
  242     }
  243 
  244     /* Cache all the directory entries */
  245     while ((d = readdir(dp)) != NULL) {
  246         char path[PATH_MAX];
  247 
  248         if (!g_keep_stressing_flag) {
  249             ret = EXIT_SUCCESS;
  250             (void)closedir(dp);
  251             goto free_cache;
  252         }
  253 
  254         (void)snprintf(path, sizeof(path), "%s/%s", fstat_dir, d->d_name);
  255         if (do_not_stat(path))
  256             continue;
  257         if ((si = calloc(1, sizeof(*si))) == NULL) {
  258             pr_err("%s: out of memory\n", args->name);
  259             (void)closedir(dp);
  260             goto free_cache;
  261         }
  262         if ((si->path = strdup(path)) == NULL) {
  263             pr_err("%s: out of memory\n", args->name);
  264             free(si);
  265             (void)closedir(dp);
  266             goto free_cache;
  267         }
  268         si->ignore = 0;
  269         si->access = true;
  270         si->next = stat_info;
  271         stat_info = si;
  272     }
  273     (void)closedir(dp);
  274 
  275     (void)sigfillset(&set);
  276     do {
  277         stat_some = false;
  278 
  279         for (si = stat_info; g_keep_stressing_flag && si; si = si->next) {
  280             if (!keep_stressing())
  281                 break;
  282             if (si->ignore == IGNORE_ALL)
  283                 continue;
  284             stress_fstat_threads(args, si, euid);
  285 
  286             stat_some = true;
  287             inc_counter(args);
  288         }
  289     } while (stat_some && keep_stressing());
  290 
  291     ret = EXIT_SUCCESS;
  292 free_cache:
  293     /* Free cache */
  294     for (si = stat_info; si; ) {
  295         stat_info_t *next = si->next;
  296 
  297         free(si->path);
  298         free(si);
  299         si = next;
  300     }
  301 
  302     return ret;
  303 }
  304 
  305 stressor_info_t stress_fstat_info = {
  306     .stressor = stress_fstat,
  307     .class = CLASS_FILESYSTEM | CLASS_OS,
  308 };