"Fossies" - the Fresh Open Source Software Archive

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