"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-dirdeep.c" (15 Mar 2019, 8043 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-dirdeep.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 0.09.49_vs_0.09.50.

    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 /*
   28  *  stress_set_dirdeep_dirs()
   29  *      set number of dirdeep directories from given option string
   30  */
   31 int stress_set_dirdeep_dirs(const char *opt)
   32 {
   33     uint32_t dirdeep_dirs;
   34 
   35     dirdeep_dirs = get_uint32(opt);
   36 
   37     check_range("dirdeep-dirs", dirdeep_dirs, 1, 10);
   38     return set_setting("dirdeep-dirs", TYPE_ID_UINT32, &dirdeep_dirs);
   39 }
   40 
   41 /*
   42  *  stress_set_dirdeep_inodes()
   43  *      set max number of inodes to consume
   44  */
   45 int stress_set_dirdeep_inodes(const char *opt)
   46 {
   47     uint64_t inodes = stress_get_filesystem_available_inodes();
   48     uint64_t dirdeep_inodes;
   49 
   50     dirdeep_inodes = get_uint64_percent(opt, 1, inodes,
   51         "Cannot determine number of available free inodes");
   52     return set_setting("dirdeep-inodes", TYPE_ID_UINT64, &dirdeep_inodes);
   53 }
   54 
   55 /*
   56  *  stress_dirdeep_sync()
   57  *  attempt to sync a directory
   58  */
   59 static void stress_dirdeep_sync(const char *path)
   60 {
   61 #if defined(O_DIRECTORY)
   62     int fd;
   63 
   64     fd = open(path, O_RDONLY | O_DIRECTORY);
   65     if (fd < 0)
   66         return;
   67 
   68     /*
   69      *  The interesting part of fsync is that in
   70      *  theory we can fsync a read only file and
   71      *  this could be a directory too. So try and
   72      *  sync.
   73      */
   74     (void)shim_fsync(fd);
   75     (void)close(fd);
   76 #else
   77     (void)path;
   78 #endif
   79 }
   80 
   81 /*
   82  *  stress_dirdeep_make()
   83  *  depth-first tree creation, create lots of sub-trees with
   84  *  dirdeep_dir number of subtress per level.
   85  */
   86 static void stress_dirdeep_make(
   87     const args_t *args,
   88     const char *linkpath,
   89     char *const path,
   90     const size_t len,
   91     const size_t path_len,
   92     const uint32_t dirdeep_dirs,
   93     const uint64_t dirdeep_inodes,
   94     const uint64_t inodes_target_free,
   95     uint64_t *min_inodes_free,
   96     uint32_t depth)
   97 {
   98     uint32_t i;
   99     int ret;
  100     const uint64_t inodes_avail = stress_get_filesystem_available_inodes();
  101 
  102     if (*min_inodes_free > inodes_avail)
  103         *min_inodes_free = inodes_avail;
  104 
  105     if (inodes_avail <= inodes_target_free)
  106         return;
  107     if (len + 2 >= path_len)
  108         return;
  109     if (!keep_stressing())
  110         return;
  111 
  112     errno = 0;
  113     if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) < 0) {
  114         if ((errno == ENOSPC) || (errno == ENOMEM) ||
  115             (errno == ENAMETOOLONG) || (errno == EDQUOT) ||
  116             (errno == EMLINK)) {
  117             return;
  118         }
  119         pr_fail_err("mkdir");
  120         return;
  121     }
  122     inc_counter(args);
  123 
  124     /*
  125      *  Top level, create file to symlink and link to
  126      */
  127     if (!depth) {
  128         int fd;
  129 
  130         fd = creat(linkpath, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
  131         if (fd < 0) {
  132             pr_fail_err("create");
  133             return;
  134         }
  135         (void)close(fd);
  136     }
  137 
  138     path[len] = '/';
  139     path[len + 1] = 's';    /* symlink */
  140     path[len + 2] = '\0';
  141     ret = symlink(linkpath, path);
  142     (void)ret;
  143 
  144     path[len + 1] = 'h';    /* hardlink */
  145     ret = link(linkpath, path);
  146     (void)ret;
  147 
  148     for (i = 0; i < dirdeep_dirs; i++) {
  149         path[len + 1] = '0' + i;
  150         stress_dirdeep_make(args, linkpath, path, len + 2, path_len,
  151                 dirdeep_dirs, dirdeep_inodes, inodes_target_free,
  152                 min_inodes_free, depth + 1);
  153     }
  154     path[len] = '\0';
  155 
  156     stress_dirdeep_sync(path);
  157 }
  158 
  159 /*
  160  *  stress_dir_exercise()
  161  *  exercise files and directories in the tree
  162  */
  163 static void stress_dir_exercise(
  164     const args_t *args,
  165     char *const path,
  166     const size_t len,
  167     const size_t path_len)
  168 {
  169     struct dirent **namelist;
  170     int i, n;
  171 #if defined(HAVE_FUTIMENS)
  172     const double now = time_now();
  173     const time_t sec = (time_t)now;
  174     const long nsec = (long)((now - (double)sec) * 1000000000.0);
  175     struct timespec timespec[2] = {
  176         { sec, nsec },
  177         { sec, nsec }
  178     };
  179 #endif
  180 
  181     if (len + 2 >= path_len)
  182         return;
  183 
  184     n = scandir(path, &namelist, NULL, alphasort);
  185     if (n < 0)
  186         return;
  187 
  188     for (i = 0; (i < n) && keep_stressing(); i++) {
  189         if (namelist[i]->d_name[0] == '.')
  190             continue;
  191 
  192         path[len] = '/';
  193         path[len + 1] = namelist[i]->d_name[0];
  194         path[len + 2] = '\0';
  195 
  196         if (isdigit((int)namelist[i]->d_name[0])) {
  197             stress_dir_exercise(args, path, len + 2, path_len);
  198         } else {
  199             int fd;
  200 
  201             /* This will update atime only */
  202             fd = open(path, O_RDONLY);
  203             if (fd >= 0) {
  204                 const uint16_t rnd = mwc16();
  205 #if defined(HAVE_FUTIMENS)
  206                 int ret = futimens(fd, timespec);
  207                 (void)ret;
  208 #endif
  209                 /* Occasional flushing */
  210                 if (rnd >= 0xfff0) {
  211 #if defined(HAVE_SYNCFS)
  212                     (void)syncfs(fd);
  213 #else
  214                     (void)sync();
  215 #endif
  216                 } else if (rnd > 0xff40) {
  217                     (void)shim_fsync(fd);
  218                 }
  219                 (void)close(fd);
  220             }
  221             inc_counter(args);
  222         }
  223     }
  224     path[len] = '\0';
  225     if (namelist) {
  226         for (i = 0; i < n; i++)
  227             free(namelist[i]);
  228         free(namelist);
  229     }
  230 }
  231 
  232 
  233 /*
  234  *  stress_dir_tidy()
  235  *  clean up all files and directories in the tree
  236  */
  237 static void stress_dir_tidy(
  238     const args_t *args,
  239     char *const path,
  240     const size_t len,
  241     const size_t path_len)
  242 {
  243     struct dirent **namelist;
  244     int n;
  245 
  246     if (len + 2 >= path_len)
  247         return;
  248 
  249     n = scandir(path, &namelist, NULL, alphasort);
  250     if (n < 0)
  251         return;
  252 
  253     while (n--) {
  254         if (namelist[n]->d_name[0] == '.')
  255             continue;
  256 
  257         path[len] = '/';
  258         path[len + 1] = namelist[n]->d_name[0];
  259         path[len + 2] = '\0';
  260 
  261         if (isdigit((int)namelist[n]->d_name[0]))
  262             stress_dir_tidy(args, path, len + 2, path_len);
  263         else
  264             (void)unlink(path);
  265 
  266         free(namelist[n]);
  267     }
  268     path[len] = '\0';
  269     free(namelist);
  270 
  271     (void)rmdir(path);
  272 }
  273 
  274 
  275 /*
  276  *  stress_dir
  277  *  stress deep recursive directory mkdir and rmdir
  278  */
  279 static int stress_dirdeep(const args_t *args)
  280 {
  281     int ret = EXIT_SUCCESS;
  282     char path[PATH_MAX + 16];
  283     char linkpath[sizeof(path)];
  284     char rootpath[PATH_MAX];
  285     size_t path_len;
  286     uint32_t dirdeep_dirs = 1;
  287     uint64_t dirdeep_inodes = ~0ULL;
  288     const uint64_t inodes_avail = stress_get_filesystem_available_inodes();
  289     uint64_t inodes_target_free;
  290     uint64_t min_inodes_free = ~0ULL;
  291 
  292         (void)get_setting("dirdeep-dirs", &dirdeep_dirs);
  293         (void)get_setting("dirdeep-inodes", &dirdeep_inodes);
  294 
  295     inodes_target_free = (inodes_avail > dirdeep_inodes) ?
  296         inodes_avail - dirdeep_inodes : 0;
  297 
  298     (void)stress_temp_dir_args(args, rootpath, sizeof(rootpath));
  299     path_len = strlen(rootpath);
  300 
  301     (void)shim_strlcpy(linkpath, rootpath, sizeof(linkpath));
  302     (void)shim_strlcat(linkpath, "/f", sizeof(linkpath) - 3);
  303 
  304     pr_inf("%s: %" PRIu64 " inodes available, exercising up to %" PRIu64 " inodes\n",
  305         args->name, inodes_avail, inodes_avail - inodes_target_free);
  306 
  307     (void)shim_strlcpy(path, rootpath, sizeof(path));
  308     stress_dirdeep_make(args, linkpath, path, path_len, sizeof(path),
  309         dirdeep_dirs, dirdeep_inodes, inodes_target_free, &min_inodes_free, 0);
  310     do {
  311         (void)shim_strlcpy(path, rootpath, sizeof(path));
  312         stress_dir_exercise(args, path, path_len, sizeof(path));
  313     } while (keep_stressing());
  314 
  315     (void)shim_strlcpy(path, rootpath, sizeof(path));
  316     pr_tidy("%s: removing directories\n", args->name);
  317     stress_dir_tidy(args, path, path_len, sizeof(path));
  318 
  319     pr_inf("%s: %" PRIu64 " inodes exercised\n", args->name, inodes_avail - min_inodes_free);
  320     if ((args->instance == 0) && (inodes_target_free < min_inodes_free))
  321         pr_inf("%s: note: specifying a larger --dirdeep setting or "
  322             "running the stressor for longer will use more "
  323             "inodes\n", args->name);
  324 
  325     return ret;
  326 }
  327 
  328 stressor_info_t stress_dirdeep_info = {
  329     .stressor = stress_dirdeep,
  330     .class = CLASS_FILESYSTEM | CLASS_OS
  331 };