"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-procfs.c" (15 Mar 2019, 9934 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-procfs.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.09.55_vs_0.09.56.

    1 /*
    2  * This program is free software; you can redistribute it and/or
    3  * modify it under the terms of the GNU General Public License
    4  * as published by the Free Software Foundation; either version 2
    5  * of the License, or (at your option) any later version.
    6  *
    7  * This program is distributed in the hope that it will be useful,
    8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10  * GNU General Public License for more details.
   11  *
   12  * You should have received a copy of the GNU General Public License
   13  * along with this program; if not, write to the Free Software
   14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
   15  *
   16  * This code is a complete clean re-write of the stress tool by
   17  * Colin Ian King <colin.king@canonical.com> and attempts to be
   18  * backwardly compatible with the stress tool by Amos Waterland
   19  * <apw@rossby.metr.ou.edu> but has more stress tests and more
   20  * functionality.
   21  *
   22  */
   23 #include "stress-ng.h"
   24 
   25 #if defined(HAVE_LIB_PTHREAD) && defined(__linux__)
   26 
   27 #define PROC_BUF_SZ     (4096)
   28 #define MAX_READ_THREADS    (4)
   29 
   30 typedef struct ctxt {
   31     const args_t *args;
   32     const char *path;
   33     char *badbuf;
   34     bool writeable;
   35 } ctxt_t;
   36 
   37 static sigset_t set;
   38 static shim_pthread_spinlock_t lock;
   39 static char *proc_path;
   40 static uint32_t mixup;
   41 
   42 static uint32_t path_sum(const char *path)
   43 {
   44     const char *ptr = path;
   45     register uint32_t sum = mixup;
   46 
   47     while (*ptr) {
   48         sum <<= 1;
   49         sum += *(ptr++);
   50     }
   51 
   52     return sum;
   53 }
   54 
   55 static int mixup_sort(const struct dirent **d1, const struct dirent **d2)
   56 {
   57     uint32_t s1, s2;
   58 
   59     s1 = path_sum((*d1)->d_name);
   60     s2 = path_sum((*d2)->d_name);
   61 
   62     if (s1 == s2)
   63         return 0;
   64     return (s1 < s2) ? -1 : 1;
   65 }
   66 
   67 /*
   68  *  stress_proc_rw()
   69  *  read a proc file
   70  */
   71 static inline void stress_proc_rw(
   72     const ctxt_t *ctxt,
   73     int32_t loops)
   74 {
   75     int fd;
   76     ssize_t ret, i = 0;
   77     char buffer[PROC_BUF_SZ];
   78     char path[PATH_MAX];
   79     const double threshold = 0.2;
   80     const size_t page_size = ctxt->args->page_size;
   81     off_t pos;
   82 
   83     while (loops == -1 || loops > 0) {
   84         double t_start;
   85         bool timeout = false;
   86         uint8_t *ptr;
   87 
   88         ret = shim_pthread_spin_lock(&lock);
   89         if (ret)
   90             return;
   91         (void)shim_strlcpy(path, proc_path, sizeof(path));
   92         (void)shim_pthread_spin_unlock(&lock);
   93 
   94         if (!*path || !g_keep_stressing_flag)
   95             break;
   96 
   97         t_start = time_now();
   98 
   99         if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0)
  100             return;
  101 
  102         if (time_now() - t_start > threshold) {
  103             timeout = true;
  104             (void)close(fd);
  105             goto next;
  106         }
  107 
  108         /*
  109          *  Multiple randomly sized reads
  110          */
  111         while (i < (4096 * PROC_BUF_SZ)) {
  112             ssize_t sz = 1 + (mwc32() % sizeof(buffer));
  113             if (!g_keep_stressing_flag)
  114                 break;
  115             ret = read(fd, buffer, sz);
  116             if (ret < 0)
  117                 break;
  118             if (ret < sz)
  119                 break;
  120             i += sz;
  121 
  122             if (time_now() - t_start > threshold) {
  123                 timeout = true;
  124                 (void)close(fd);
  125                 goto next;
  126             }
  127         }
  128         (void)close(fd);
  129 
  130         if ((fd = open(path, O_RDONLY | O_NONBLOCK)) < 0)
  131             return;
  132 
  133         if (time_now() - t_start > threshold) {
  134             timeout = true;
  135             (void)close(fd);
  136             goto next;
  137         }
  138         /*
  139          *  Zero sized reads
  140          */
  141         ret = read(fd, buffer, 0);
  142         if (ret < 0)
  143             goto err;
  144         /*
  145          *  Bad read buffer, should fail!
  146          */
  147         if (ctxt->badbuf) {
  148             ret = read(fd, ctxt->badbuf, PROC_BUF_SZ);
  149             if (ret == 0)
  150                 goto err;
  151         }
  152 
  153         if (time_now() - t_start > threshold) {
  154             timeout = true;
  155             (void)close(fd);
  156             goto next;
  157         }
  158 
  159         /*
  160          *  mmap it
  161          */
  162         ptr = mmap(NULL, page_size, PROT_READ,
  163             MAP_SHARED | MAP_ANONYMOUS, fd, 0);
  164         if (ptr != MAP_FAILED) {
  165             uint8_put(*ptr);
  166             (void)munmap(ptr, page_size);
  167         }
  168 
  169         if (time_now() - t_start > threshold) {
  170             timeout = true;
  171             (void)close(fd);
  172             goto next;
  173         }
  174 
  175 #if defined(FIONREAD)
  176         {
  177             int nbytes;
  178 
  179             /*
  180              *  ioctl(), bytes ready to read
  181              */
  182             ret = ioctl(fd, FIONREAD, &nbytes);
  183             (void)ret;
  184         }
  185         if (time_now() - t_start > threshold) {
  186             timeout = true;
  187             (void)close(fd);
  188             goto next;
  189         }
  190 #endif
  191 
  192 #if defined(HAVE_POLL_H)
  193         {
  194             struct pollfd fds[1];
  195 
  196             fds[0].fd = fd;
  197             fds[0].events = POLLIN;
  198             fds[0].revents = 0;
  199 
  200             ret = poll(fds, 1, 0);
  201             (void)ret;
  202         }
  203 #endif
  204 
  205         /*
  206          *  Seek and read
  207          */
  208         pos = lseek(fd, 0, SEEK_SET);
  209         if (pos == (off_t)-1)
  210             goto err;
  211         pos = lseek(fd, 1, SEEK_CUR);
  212         if (pos == (off_t)-1)
  213             goto err;
  214         pos = lseek(fd, 0, SEEK_END);
  215         if (pos == (off_t)-1)
  216             goto err;
  217         pos = lseek(fd, 1, SEEK_SET);
  218         if (pos == (off_t)-1)
  219             goto err;
  220 
  221         if (time_now() - t_start > threshold) {
  222             timeout = true;
  223             (void)close(fd);
  224             goto next;
  225         }
  226 
  227         ret = read(fd, buffer, 1);
  228         (void)ret;
  229 err:
  230         (void)close(fd);
  231         if (time_now() - t_start > threshold) {
  232             timeout = true;
  233             goto next;
  234         }
  235 
  236         if (ctxt->writeable) {
  237             /*
  238              *  Zero sized writes
  239              */
  240             if ((fd = open(path, O_WRONLY | O_NONBLOCK)) < 0)
  241                 return;
  242             ret = write(fd, buffer, 0);
  243             (void)ret;
  244             (void)close(fd);
  245 
  246             /*
  247              *  Write using badbuf, expect it to fail
  248              */
  249             if (ctxt->badbuf) {
  250                 if ((fd = open(path, O_WRONLY | O_NONBLOCK)) < 0)
  251                     return;
  252                 ret = write(fd, ctxt->badbuf, PROC_BUF_SZ);
  253                 (void)ret;
  254                 (void)close(fd);
  255             }
  256         }
  257 next:
  258         if (loops > 0) {
  259             if (timeout)
  260                 break;
  261             loops--;
  262         }
  263     }
  264 }
  265 
  266 /*
  267  *  stress_proc_rw_thread
  268  *  keep exercising a procfs entry until
  269  *  controlling thread triggers an exit
  270  */
  271 static void *stress_proc_rw_thread(void *ctxt_ptr)
  272 {
  273     static void *nowt = NULL;
  274     uint8_t stack[SIGSTKSZ + STACK_ALIGNMENT];
  275     ctxt_t *ctxt = (ctxt_t *)ctxt_ptr;
  276 
  277     /*
  278      *  Block all signals, let controlling thread
  279      *  handle these
  280      */
  281     (void)sigprocmask(SIG_BLOCK, &set, NULL);
  282 
  283     /*
  284      *  According to POSIX.1 a thread should have
  285      *  a distinct alternative signal stack.
  286      *  However, we block signals in this thread
  287      *  so this is probably just totally unncessary.
  288      */
  289     (void)memset(stack, 0, sizeof(stack));
  290     if (stress_sigaltstack(stack, SIGSTKSZ) < 0)
  291         return &nowt;
  292 
  293     while (g_keep_stressing_flag)
  294         stress_proc_rw(ctxt, -1);
  295 
  296     return &nowt;
  297 }
  298 
  299 /*
  300  *  stress_proc_dir()
  301  *  read directory
  302  */
  303 static void stress_proc_dir(
  304     const ctxt_t *ctxt,
  305     const char *path,
  306     const bool recurse,
  307     const int depth)
  308 {
  309     struct dirent **dlist;
  310     const args_t *args = ctxt->args;
  311     int32_t loops = args->instance < 8 ? args->instance + 1 : 8;
  312     int i, n;
  313 
  314     if (!g_keep_stressing_flag)
  315         return;
  316 
  317     /* Don't want to go too deep */
  318     if (depth > 20)
  319         return;
  320 
  321     mixup = mwc32();
  322     dlist = NULL;
  323     n = scandir(path, &dlist, NULL, mixup_sort);
  324     if (n <= 0)
  325         goto done;
  326 
  327     for (i = 0; i < n; i++) {
  328         int ret;
  329         char filename[PATH_MAX];
  330         char tmp[PATH_MAX];
  331         struct dirent *d = dlist[i];
  332 
  333         if (!g_keep_stressing_flag)
  334             break;
  335         if (stress_is_dot_filename(d->d_name))
  336             continue;
  337 
  338         (void)snprintf(tmp, sizeof(tmp), "%s/%s", path, d->d_name);
  339         switch (d->d_type) {
  340         case DT_DIR:
  341             if (!recurse)
  342                 continue;
  343 
  344             inc_counter(args);
  345             stress_proc_dir(ctxt, tmp, recurse, depth + 1);
  346             break;
  347         case DT_REG:
  348             ret = shim_pthread_spin_lock(&lock);
  349             if (!ret) {
  350                 (void)shim_strlcpy(filename, tmp, sizeof(filename));
  351                 proc_path = filename;
  352                 (void)shim_pthread_spin_unlock(&lock);
  353                 stress_proc_rw(ctxt, loops);
  354                 inc_counter(args);
  355             }
  356             break;
  357         default:
  358             break;
  359         }
  360     }
  361 done:
  362     if (dlist) {
  363         for (i = 0; i < n; i++)
  364             free(dlist[i]);
  365         free(dlist);
  366     }
  367 }
  368 
  369 /*
  370  *  stress_procfs
  371  *  stress reading all of /proc
  372  */
  373 static int stress_procfs(const args_t *args)
  374 {
  375     size_t i;
  376     pthread_t pthreads[MAX_READ_THREADS];
  377     int rc, ret[MAX_READ_THREADS];
  378     ctxt_t ctxt;
  379 
  380     (void)sigfillset(&set);
  381 
  382     proc_path = "/proc/self";
  383 
  384     ctxt.args = args;
  385     ctxt.writeable = (geteuid() != 0);
  386 
  387     rc = shim_pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
  388     if (rc) {
  389         pr_inf("%s: pthread_spin_init failed, errno=%d (%s)\n",
  390             args->name, rc, strerror(rc));
  391         return EXIT_NO_RESOURCE;
  392     }
  393 
  394     (void)memset(ret, 0, sizeof(ret));
  395 
  396     ctxt.badbuf = mmap(NULL, PROC_BUF_SZ, PROT_READ,
  397             MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  398     if (ctxt.badbuf == MAP_FAILED) {
  399         pr_inf("%s: mmap failed: errno=%d (%s)\n",
  400             args->name, errno, strerror(errno));
  401         return EXIT_NO_RESOURCE;
  402     }
  403 
  404     for (i = 0; i < MAX_READ_THREADS; i++) {
  405         ret[i] = pthread_create(&pthreads[i], NULL,
  406                 stress_proc_rw_thread, &ctxt);
  407     }
  408 
  409     i = args->instance;
  410     do {
  411         i %= 13;
  412         switch (i) {
  413         case 0:
  414             stress_proc_dir(&ctxt, "/proc", false, 0);
  415             break;
  416         case 1:
  417             stress_proc_dir(&ctxt, "/proc/self", true, 0);
  418             break;
  419         case 2:
  420             stress_proc_dir(&ctxt, "/proc/sys", true, 0);
  421             break;
  422         case 3:
  423             stress_proc_dir(&ctxt, "/proc/sysvipc", true, 0);
  424             break;
  425         case 4:
  426             stress_proc_dir(&ctxt, "/proc/fs", true, 0);
  427             break;
  428         case 5:
  429             stress_proc_dir(&ctxt, "/proc/bus", true, 0);
  430             break;
  431         case 6:
  432             stress_proc_dir(&ctxt, "/proc/irq", true, 0);
  433             break;
  434         case 7:
  435             stress_proc_dir(&ctxt, "/proc/scsi", true, 0);
  436             break;
  437         case 8:
  438             stress_proc_dir(&ctxt, "/proc/tty", true, 0);
  439             break;
  440         case 9:
  441             stress_proc_dir(&ctxt, "/proc/driver", true, 0);
  442             break;
  443         case 10:
  444             stress_proc_dir(&ctxt, "/proc/tty", true, 0);
  445             break;
  446         case 11:
  447             stress_proc_dir(&ctxt, "/proc/self", true, 0);
  448             break;
  449         case 12:
  450             stress_proc_dir(&ctxt, "/proc/thread_self", true, 0);
  451             break;
  452         default:
  453             break;
  454         }
  455         i++;
  456         inc_counter(args);
  457         if (!keep_stressing())
  458             break;
  459     } while (keep_stressing());
  460 
  461     rc = shim_pthread_spin_lock(&lock);
  462     if (rc) {
  463         pr_dbg("%s: failed to lock spin lock for sysfs_path\n", args->name);
  464     } else {
  465         proc_path = "";
  466         rc = shim_pthread_spin_unlock(&lock);
  467         (void)rc;
  468     }
  469 
  470     for (i = 0; i < MAX_READ_THREADS; i++) {
  471         if (ret[i] == 0)
  472             (void)pthread_join(pthreads[i], NULL);
  473     }
  474     (void)munmap(ctxt.badbuf, PROC_BUF_SZ);
  475     (void)shim_pthread_spin_destroy(&lock);
  476 
  477     return EXIT_SUCCESS;
  478 }
  479 
  480 stressor_info_t stress_procfs_info = {
  481     .stressor = stress_procfs,
  482     .class = CLASS_FILESYSTEM | CLASS_OS
  483 };
  484 #else
  485 stressor_info_t stress_procfs_info = {
  486     .stressor = stress_not_implemented,
  487     .class = CLASS_FILESYSTEM | CLASS_OS
  488 };
  489 #endif