"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-locka.c" (15 Mar 2019, 6980 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-locka.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(F_GETLK) && defined(F_SETLK) && defined(F_SETLKW) && \
   28     defined(F_WRLCK) && defined(F_UNLCK)
   29 
   30 #define LOCK_FILE_SIZE  (1024 * 1024)
   31 #define LOCK_SIZE   (8)
   32 #define LOCK_MAX    (1024)
   33 
   34 typedef struct locka_info {
   35     struct locka_info *next;
   36     off_t   offset;
   37     off_t   len;
   38     pid_t   pid;
   39 } locka_info_t;
   40 
   41 typedef struct {
   42     locka_info_t *head;     /* Head of locka_info procs list */
   43     locka_info_t *tail;     /* Tail of locka_info procs list */
   44     locka_info_t *free;     /* List of free'd locka_infos */
   45     uint64_t length;        /* Length of list */
   46 } locka_info_list_t;
   47 
   48 static locka_info_list_t locka_infos;
   49 
   50 /*
   51  *  stress_locka_info_new()
   52  *  allocate a new locka_info, add to end of list
   53  */
   54 static locka_info_t *stress_locka_info_new(void)
   55 {
   56     locka_info_t *new;
   57 
   58     if (locka_infos.free) {
   59         /* Pop an old one off the free list */
   60         new = locka_infos.free;
   61         locka_infos.free = new->next;
   62         new->next = NULL;
   63     } else {
   64         new = calloc(1, sizeof(*new));
   65         if (!new)
   66             return NULL;
   67     }
   68 
   69     if (locka_infos.head)
   70         locka_infos.tail->next = new;
   71     else
   72         locka_infos.head = new;
   73 
   74     locka_infos.tail = new;
   75     locka_infos.length++;
   76 
   77     return new;
   78 }
   79 
   80 /*
   81  *  stress_locka_info_head_remove
   82  *  reap a locka_info and remove a locka_info from head of list, put it onto
   83  *  the free locka_info list
   84  */
   85 static void stress_locka_info_head_remove(void)
   86 {
   87     if (locka_infos.head) {
   88         locka_info_t *head = locka_infos.head;
   89 
   90         if (locka_infos.tail == locka_infos.head) {
   91             locka_infos.tail = NULL;
   92             locka_infos.head = NULL;
   93         } else {
   94             locka_infos.head = head->next;
   95         }
   96 
   97         /* Shove it on the free list */
   98         head->next = locka_infos.free;
   99         locka_infos.free = head;
  100 
  101         locka_infos.length--;
  102     }
  103 }
  104 
  105 /*
  106  *  stress_locka_info_free()
  107  *  free the locka_infos off the locka_info head and free lists
  108  */
  109 static void stress_locka_info_free(void)
  110 {
  111     while (locka_infos.head) {
  112         locka_info_t *next = locka_infos.head->next;
  113 
  114         free(locka_infos.head);
  115         locka_infos.head = next;
  116     }
  117 
  118     while (locka_infos.free) {
  119         locka_info_t *next = locka_infos.free->next;
  120 
  121         free(locka_infos.free);
  122         locka_infos.free = next;
  123     }
  124 }
  125 
  126 /*
  127  *  stress_locka_unlock()
  128  *  pop oldest lock record off list and unlock it
  129  */
  130 static int stress_locka_unlock(const args_t *args, const int fd)
  131 {
  132     struct flock f;
  133 
  134     /* Pop one off list */
  135     if (!locka_infos.head)
  136         return 0;
  137 
  138     f.l_type = F_UNLCK;
  139     f.l_whence = SEEK_SET;
  140     f.l_start = locka_infos.head->offset;
  141     f.l_len = locka_infos.head->len;
  142     f.l_pid = locka_infos.head->pid;
  143 
  144     stress_locka_info_head_remove();
  145 
  146     if (fcntl(fd, F_SETLK, &f) < 0) {
  147         pr_fail_err("F_SETLK");
  148         return -1;
  149     }
  150     return 0;
  151 }
  152 
  153 /*
  154  *  stress_locka_contention()
  155  *  hammer advisory lock/unlock to create some file lock contention
  156  */
  157 static int stress_locka_contention(
  158     const args_t *args,
  159     const int fd)
  160 {
  161     mwc_reseed();
  162 
  163     do {
  164         off_t offset;
  165         off_t len;
  166         int rc;
  167         locka_info_t *locka_info;
  168         struct flock f;
  169 
  170         if (locka_infos.length >= LOCK_MAX)
  171             if (stress_locka_unlock(args, fd) < 0)
  172                 return -1;
  173 
  174         len  = (mwc16() + 1) & 0xfff;
  175         offset = mwc64() % (LOCK_FILE_SIZE - len);
  176 
  177         f.l_type = F_WRLCK;
  178         f.l_whence = SEEK_SET;
  179         f.l_start = offset;
  180         f.l_len = len;
  181         f.l_pid = args->pid;
  182 
  183         rc = fcntl(fd, F_GETLK, &f);
  184         if (rc < 0)
  185             continue;
  186 
  187         /* Locked OK, add to lock list */
  188 
  189         locka_info = stress_locka_info_new();
  190         if (!locka_info) {
  191             pr_fail_err("calloc");
  192             return -1;
  193         }
  194         locka_info->offset = offset;
  195         locka_info->len = len;
  196         locka_info->pid = args->pid;
  197 
  198         inc_counter(args);
  199     } while (keep_stressing());
  200 
  201     return 0;
  202 }
  203 
  204 /*
  205  *  stress_locka
  206  *  stress file locking via advisory locking
  207  */
  208 static int stress_locka(const args_t *args)
  209 {
  210     int fd, ret = EXIT_FAILURE;
  211     pid_t cpid = -1;
  212     char filename[PATH_MAX];
  213     char dirname[PATH_MAX];
  214     char buffer[4096];
  215     off_t offset;
  216     ssize_t rc;
  217 
  218     (void)memset(buffer, 0, sizeof(buffer));
  219 
  220     /*
  221      *  There will be a race to create the directory
  222      *  so EEXIST is expected on all but one instance
  223      */
  224     (void)stress_temp_dir_args(args, dirname, sizeof(dirname));
  225     if (mkdir(dirname, S_IRWXU) < 0) {
  226         if (errno != EEXIST) {
  227             ret = exit_status(errno);
  228             pr_fail_err("mkdir");
  229             return ret;
  230         }
  231     }
  232 
  233     /*
  234      *  Lock file is based on parent pid and instance 0
  235      *  as we need to share this among all the other
  236      *  stress flock processes
  237      */
  238     (void)stress_temp_filename_args(args,
  239         filename, sizeof(filename), mwc32());
  240 
  241     if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
  242         ret = exit_status(errno);
  243         pr_fail_err("open");
  244         (void)rmdir(dirname);
  245         return ret;
  246     }
  247 
  248     if (lseek(fd, 0, SEEK_SET) < 0) {
  249         pr_fail_err("lseek");
  250         goto tidy;
  251     }
  252     for (offset = 0; offset < LOCK_FILE_SIZE; offset += sizeof(buffer)) {
  253 redo:
  254         if (!g_keep_stressing_flag) {
  255             ret = EXIT_SUCCESS;
  256             goto tidy;
  257         }
  258         rc = write(fd, buffer, sizeof(buffer));
  259         if ((rc < 0) || (rc != sizeof(buffer))) {
  260             if ((errno == EAGAIN) || (errno == EINTR))
  261                 goto redo;
  262             ret = exit_status(errno);
  263             pr_fail_err("write");
  264             goto tidy;
  265         }
  266     }
  267 
  268 again:
  269     cpid = fork();
  270     if (cpid < 0) {
  271         if (!g_keep_stressing_flag) {
  272             ret = EXIT_SUCCESS;
  273             goto tidy;
  274         }
  275         if ((errno == EAGAIN) || (errno == ENOMEM))
  276             goto again;
  277         pr_fail_err("fork");
  278         goto tidy;
  279     }
  280     if (cpid == 0) {
  281         (void)setpgid(0, g_pgrp);
  282         stress_parent_died_alarm();
  283 
  284         if (stress_locka_contention(args, fd) < 0)
  285             _exit(EXIT_FAILURE);
  286         stress_locka_info_free();
  287         _exit(EXIT_SUCCESS);
  288     }
  289     (void)setpgid(cpid, g_pgrp);
  290 
  291     if (stress_locka_contention(args, fd) == 0)
  292         ret = EXIT_SUCCESS;
  293 tidy:
  294     if (cpid > 0) {
  295         int status;
  296 
  297         (void)kill(cpid, SIGKILL);
  298         (void)waitpid(cpid, &status, 0);
  299     }
  300     stress_locka_info_free();
  301 
  302     (void)close(fd);
  303     (void)unlink(filename);
  304     (void)rmdir(dirname);
  305 
  306     return ret;
  307 }
  308 stressor_info_t stress_locka_info = {
  309     .stressor = stress_locka,
  310     .class = CLASS_FILESYSTEM | CLASS_OS
  311 };
  312 #else
  313 stressor_info_t stress_locka_info = {
  314     .stressor = stress_not_implemented,
  315     .class = CLASS_FILESYSTEM | CLASS_OS
  316 };
  317 #endif