"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-fiemap.c" (15 Mar 2019, 7256 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-fiemap.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) 2016-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_FIEMAP_PROCS    (4)     /* Number of FIEMAP stressors */
   28 
   29 int stress_set_fiemap_bytes(const char *opt)
   30 {
   31     uint64_t fiemap_bytes;
   32 
   33     fiemap_bytes = get_uint64_byte_filesystem(opt, 1);
   34     check_range_bytes("fiemap-bytes", fiemap_bytes,
   35         MIN_FIEMAP_SIZE, MAX_FIEMAP_SIZE);
   36     return set_setting("fiemap-bytes", TYPE_ID_UINT64, &fiemap_bytes);
   37 }
   38 
   39 #if defined(HAVE_LINUX_FS_H) &&     \
   40     defined(HAVE_LINUX_FIEMAP_H) &&     \
   41     defined(FS_IOC_FIEMAP)
   42 
   43 /*
   44  *  stress_fiemap_writer()
   45  *  write data in random places and punch holes
   46  *  in data in random places to try and maximize
   47  *  extents in the file
   48  */
   49 static int stress_fiemap_writer(
   50     const args_t *args,
   51     const int fd,
   52     const uint64_t fiemap_bytes,
   53     uint64_t *counters)
   54 {
   55     uint8_t buf[1];
   56     const uint64_t len = (off_t)fiemap_bytes - sizeof(buf);
   57     uint64_t counter;
   58     int rc = EXIT_FAILURE;
   59 #if defined(FALLOC_FL_PUNCH_HOLE) && \
   60     defined(FALLOC_FL_KEEP_SIZE)
   61     bool punch_hole = true;
   62 #endif
   63 
   64     stress_strnrnd((char *)buf, sizeof(buf));
   65 
   66     do {
   67         uint64_t offset;
   68         size_t i;
   69         counter = 0;
   70 
   71         offset = (mwc64() % len) & ~0x1fff;
   72         if (lseek(fd, (off_t)offset, SEEK_SET) < 0)
   73             break;
   74         if (!keep_stressing())
   75             break;
   76         if (write(fd, buf, sizeof(buf)) < 0) {
   77             if ((errno != EAGAIN) && (errno != EINTR)) {
   78                 pr_fail_err("write");
   79                 goto tidy;
   80             }
   81         }
   82         if (!keep_stressing())
   83             break;
   84 #if defined(FALLOC_FL_PUNCH_HOLE) && \
   85     defined(FALLOC_FL_KEEP_SIZE)
   86         if (!punch_hole)
   87             continue;
   88 
   89         offset = mwc64() % len;
   90         if (shim_fallocate(fd, FALLOC_FL_PUNCH_HOLE |
   91                   FALLOC_FL_KEEP_SIZE, offset, 8192) < 0) {
   92             if (errno == EOPNOTSUPP)
   93                 punch_hole = false;
   94         }
   95         if (!keep_stressing())
   96             break;
   97 #endif
   98         for (i = 0; i < MAX_FIEMAP_PROCS; i++)
   99             counter += counters[i];
  100     } while (keep_stressing());
  101     rc = EXIT_SUCCESS;
  102 tidy:
  103     (void)close(fd);
  104 
  105     return rc;
  106 }
  107 
  108 /*
  109  *  stress_fiemap_ioctl()
  110  *  exercise the FIEMAP ioctl
  111  */
  112 static void stress_fiemap_ioctl(const args_t *args, int fd)
  113 {
  114     uint32_t c = 0;
  115     do {
  116         struct fiemap *fiemap, *tmp;
  117         size_t extents_size;
  118 
  119         /* Force periodic yields */
  120         c++;
  121         if (c >= 64) {
  122             c = 0;
  123             (void)shim_usleep(25000);
  124         }
  125         if (!keep_stressing())
  126             break;
  127 
  128         fiemap = (struct fiemap *)calloc(1, sizeof(*fiemap));
  129         if (!fiemap) {
  130             pr_err("Out of memory allocating fiemap\n");
  131             break;
  132         }
  133         fiemap->fm_length = ~0;
  134 
  135         /* Find out how many extents there are */
  136         if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) {
  137             pr_fail_err("FS_IOC_FIEMAP ioctl()");
  138             free(fiemap);
  139             break;
  140         }
  141         if (!keep_stressing()) {
  142             free(fiemap);
  143             break;
  144         }
  145 
  146         /* Read in the extents */
  147         extents_size = sizeof(struct fiemap_extent) *
  148             (fiemap->fm_mapped_extents);
  149 
  150         /* Resize fiemap to allow us to read in the extents */
  151         tmp = (struct fiemap *)realloc(fiemap,
  152             sizeof(*fiemap) + extents_size);
  153         if (!tmp) {
  154             pr_fail_err("FS_IOC_FIEMAP ioctl()");
  155             free(fiemap);
  156             break;
  157         }
  158         fiemap = tmp;
  159 
  160         (void)memset(fiemap->fm_extents, 0, extents_size);
  161         fiemap->fm_extent_count = fiemap->fm_mapped_extents;
  162         fiemap->fm_mapped_extents = 0;
  163 
  164         if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) {
  165             pr_fail_err("FS_IOC_FIEMAP ioctl()");
  166             free(fiemap);
  167             break;
  168         }
  169         free(fiemap);
  170         inc_counter(args);
  171     } while (keep_stressing());
  172 }
  173 
  174 /*
  175  *  stress_fiemap_spawn()
  176  *  helper to spawn off fiemap stressor
  177  */
  178 static inline pid_t stress_fiemap_spawn(
  179     const args_t *args,
  180     const int fd)
  181 {
  182     pid_t pid;
  183 
  184     pid = fork();
  185     if (pid < 0)
  186         return -1;
  187     if (pid == 0) {
  188         (void)setpgid(0, g_pgrp);
  189         stress_parent_died_alarm();
  190         stress_fiemap_ioctl(args, fd);
  191         _exit(EXIT_SUCCESS);
  192     }
  193     (void)setpgid(pid, g_pgrp);
  194     return pid;
  195 }
  196 
  197 /*
  198  *  stress_fiemap
  199  *  stress fiemap IOCTL
  200  */
  201 static int stress_fiemap(const args_t *args)
  202 {
  203     pid_t pids[MAX_FIEMAP_PROCS];
  204     int ret, fd, rc = EXIT_FAILURE, status;
  205     char filename[PATH_MAX];
  206     size_t i, n;
  207     const size_t counters_sz = sizeof(uint64_t) * MAX_FIEMAP_PROCS;
  208     uint64_t *counters;
  209     const uint64_t ops_per_proc = args->max_ops / MAX_FIEMAP_PROCS;
  210     const uint64_t ops_remaining = args->max_ops % MAX_FIEMAP_PROCS;
  211     uint64_t fiemap_bytes = DEFAULT_FIEMAP_SIZE;
  212 
  213     if (!get_setting("fiemap-bytes", &fiemap_bytes)) {
  214         if (g_opt_flags & OPT_FLAGS_MAXIMIZE)
  215             fiemap_bytes = MAX_SEEK_SIZE;
  216         if (g_opt_flags & OPT_FLAGS_MINIMIZE)
  217             fiemap_bytes = MIN_SEEK_SIZE;
  218     }
  219     fiemap_bytes /= args->num_instances;
  220     if (fiemap_bytes < MIN_FIEMAP_SIZE)
  221         fiemap_bytes = MIN_FIEMAP_SIZE;
  222 
  223     /* We need some share memory for counter accounting */
  224     counters = mmap(NULL, counters_sz, PROT_READ | PROT_WRITE,
  225         MAP_SHARED | MAP_ANONYMOUS, -1, 0);
  226     if (counters == MAP_FAILED) {
  227         pr_err("%s: mmap failed: errno=%d (%s)\n",
  228             args->name, errno, strerror(errno));
  229         return EXIT_NO_RESOURCE;
  230     }
  231     (void)memset(counters, 0, counters_sz);
  232 
  233     ret = stress_temp_dir_mk_args(args);
  234     if (ret < 0) {
  235         rc = exit_status(-ret);
  236         goto clean;
  237     }
  238 
  239     (void)stress_temp_filename_args(args,
  240         filename, sizeof(filename), mwc32());
  241     if ((fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
  242         rc = exit_status(errno);
  243         pr_fail_err("open");
  244         goto clean;
  245     }
  246     (void)unlink(filename);
  247 
  248     for (n = 0; n < MAX_FIEMAP_PROCS; n++) {
  249         uint64_t proc_max_ops = ops_per_proc +
  250             ((n == 0) ? ops_remaining : 0);
  251 
  252         const args_t new_args = {
  253             .counter = &counters[n],
  254             .name = args->name,
  255             .max_ops = proc_max_ops,
  256             .instance = args->instance,
  257             .num_instances = args->num_instances,
  258             .pid = args->pid,
  259             .ppid = args->ppid,
  260             .page_size = args->page_size
  261         };
  262 
  263         if (!keep_stressing()) {
  264             rc = EXIT_SUCCESS;
  265             goto reap;
  266         }
  267 
  268         pids[n] = stress_fiemap_spawn(&new_args, fd);
  269         if (pids[n] < 0)
  270             goto reap;
  271     }
  272     rc = stress_fiemap_writer(args, fd, fiemap_bytes, counters);
  273 reap:
  274     /* And reap stressors */
  275     for (i = 0; i < n; i++) {
  276         (void)kill(pids[i], SIGKILL);
  277         (void)waitpid(pids[i], &status, 0);
  278         add_counter(args, counters[i]);
  279     }
  280     (void)close(fd);
  281 clean:
  282     (void)munmap(counters, counters_sz);
  283     (void)stress_temp_dir_rm_args(args);
  284     return rc;
  285 }
  286 
  287 stressor_info_t stress_fiemap_info = {
  288     .stressor = stress_fiemap,
  289     .class = CLASS_FILESYSTEM | CLASS_OS
  290 };
  291 #else
  292 stressor_info_t stress_fiemap_info = {
  293     .stressor = stress_not_implemented,
  294     .class = CLASS_FILESYSTEM | CLASS_OS
  295 };
  296 #endif