"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.13.05/stress-link.c" (11 Oct 2021, 7586 Bytes) of package /linux/privat/stress-ng-0.13.05.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-link.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.13.04_vs_0.13.05.

    1 /*
    2  * Copyright (C) 2013-2021 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 static const stress_help_t hardlink_help[] = {
   28     { NULL, "link N",    "start N workers creating hard links" },
   29     { NULL, "link-ops N",    "stop after N link bogo operations" },
   30     { NULL, NULL,        NULL }
   31 };
   32 
   33 static const stress_help_t symlink_help[] = {
   34     { NULL, "symlink N",     "start N workers creating symbolic links" },
   35     { NULL, "symlink-ops N", "stop after N symbolic link bogo operations" },
   36     { NULL, NULL,            NULL }
   37 };
   38 
   39 #define MOUNTS_MAX  (128)
   40 
   41 /*
   42  *  stress_link_unlink()
   43  *  remove all links
   44  */
   45 static void stress_link_unlink(
   46     const stress_args_t *args,
   47     const uint64_t n)
   48 {
   49     uint64_t i;
   50 
   51     for (i = 0; i < n; i++) {
   52         char path[PATH_MAX];
   53 
   54         (void)stress_temp_filename_args(args,
   55             path, sizeof(path), i);
   56         (void)unlink(path);
   57     }
   58     (void)sync();
   59 }
   60 
   61 static inline size_t random_mount(const int mounts_max)
   62 {
   63     return (size_t)stress_mwc32() % mounts_max;
   64 }
   65 
   66 /*
   67  *  stress_link_generic
   68  *  stress links, generic case
   69  */
   70 static int stress_link_generic(
   71     const stress_args_t *args,
   72     int (*linkfunc)(const char *oldpath, const char *newpath),
   73     const char *funcname)
   74 {
   75     int rc, ret, fd, mounts_max;
   76     char oldpath[PATH_MAX], tmp_newpath[PATH_MAX];
   77     size_t oldpathlen;
   78     bool symlink_func = (linkfunc == symlink);
   79     char *mnts[MOUNTS_MAX];
   80 
   81     memset(tmp_newpath, 0, sizeof(tmp_newpath));
   82 
   83     (void)snprintf(tmp_newpath, sizeof(tmp_newpath),
   84         "/tmp/stress-ng-%s-%d-%" PRIu64 "-link",
   85         args->name, (int)getpid(), stress_mwc64());
   86 
   87     ret = stress_temp_dir_mk_args(args);
   88     if (ret < 0)
   89         return exit_status(-ret);
   90     (void)stress_temp_filename_args(args, oldpath, sizeof(oldpath), ~0UL);
   91     if ((fd = open(oldpath, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) < 0) {
   92         if ((errno == ENFILE) || (errno == ENOMEM) || (errno == ENOSPC))
   93             return EXIT_NO_RESOURCE;
   94         pr_fail("%s: open %s failed, errno=%d (%s)\n",
   95             args->name, oldpath, errno, strerror(errno));
   96         (void)stress_temp_dir_rm_args(args);
   97         return EXIT_FAILURE;
   98     }
   99     (void)close(fd);
  100 
  101     mounts_max = stress_mount_get(mnts, MOUNTS_MAX);
  102 
  103     oldpathlen = strlen(oldpath);
  104 
  105     stress_set_proc_state(args->name, STRESS_STATE_RUN);
  106 
  107     rc = EXIT_SUCCESS;
  108     do {
  109         uint64_t i, n = DEFAULT_LINKS;
  110         char testpath[PATH_MAX];
  111         ssize_t rret;
  112 
  113         for (i = 0; keep_stressing(args) && (i < n); i++) {
  114             char newpath[PATH_MAX];
  115             struct stat stbuf;
  116 
  117             (void)stress_temp_filename_args(args,
  118                 newpath, sizeof(newpath), i);
  119             if (linkfunc(oldpath, newpath) < 0) {
  120                 if ((errno == EDQUOT) ||
  121                     (errno == ENOMEM) ||
  122                     (errno == EMLINK) ||
  123                     (errno == ENOSPC)) {
  124                     /* Try again */
  125                     continue;
  126                 }
  127                 if (errno == EPERM) {
  128                     pr_inf_skip("%s: link calls not allowed on "
  129                         "the filesystem, skipping "
  130                         "stressor\n", args->name);
  131                     rc = EXIT_NO_RESOURCE;
  132                     goto err_unlink;
  133                 }
  134                 rc = exit_status(errno);
  135                 pr_fail("%s: %s failed, errno=%d (%s)\n",
  136                     args->name, funcname, errno, strerror(errno));
  137                 n = i;
  138                 break;
  139             }
  140 
  141             if (symlink_func) {
  142                 char buf[PATH_MAX];
  143 #if defined(O_DIRECTORY) && \
  144     defined(HAVE_READLINKAT)
  145                 {
  146                     char tmpfilename[PATH_MAX], *filename;
  147                     char tmpdir[PATH_MAX], *dir;
  148                     int dir_fd;
  149 
  150                     shim_strlcpy(tmpfilename, newpath, sizeof(tmpfilename));
  151                     filename = basename(tmpfilename);
  152                     shim_strlcpy(tmpdir, newpath, sizeof(tmpdir));
  153                     dir = dirname(tmpdir);
  154 
  155                     /*
  156                      *   Relatively naive readlinkat exercising
  157                      */
  158                     dir_fd = open(dir, O_DIRECTORY | O_RDONLY);
  159                     if (dir_fd >= 0) {
  160                         rret = readlinkat(dir_fd, filename, buf, sizeof(buf) - 1);
  161                         if ((rret < 0) && (errno != ENOSYS)) {
  162                             pr_fail("%s: readlinkat failed, errno=%d (%s)\n",
  163                             args->name, errno, strerror(errno));
  164                         }
  165                         (void)close(dir_fd);
  166                     }
  167                 }
  168 #endif
  169 
  170                 rret = shim_readlink(newpath, buf, sizeof(buf) - 1);
  171                 if (rret < 0) {
  172                     rc = exit_status(errno);
  173                     pr_fail("%s: readlink failed, errno=%d (%s)\n",
  174                         args->name, errno, strerror(errno));
  175                 } else {
  176                     buf[rret] = '\0';
  177                     if ((size_t)rret != oldpathlen)
  178                         pr_fail("%s: readlink length error, got %zd, expected: %zd\n",
  179                             args->name, (size_t)rret, oldpathlen);
  180                     else
  181                         if (strncmp(oldpath, buf, (size_t)rret))
  182                             pr_fail("%s: readlink path error, got %s, expected %s\n",
  183                                 args->name, buf, oldpath);
  184                 }
  185             } else {
  186                 /* Hard link, exercise illegal cross device link, EXDEV error */
  187                 if (mounts_max > 0) {
  188                     /* Try hard link on differet random mount point */
  189                     ret = linkfunc(mnts[random_mount((size_t)mounts_max)], tmp_newpath);
  190                     if (ret == 0)
  191                         (void)unlink(tmp_newpath);
  192                 }
  193             }
  194             if (lstat(newpath, &stbuf) < 0) {
  195                 rc = exit_status(errno);
  196                 pr_fail("%s: lstat failed, errno=%d (%s)\n",
  197                     args->name, errno, strerror(errno));
  198             }
  199         }
  200 
  201         /* exercise invalid newpath size, EINVAL */
  202         rret = readlink(oldpath, testpath, 0);
  203         (void)rret;
  204 
  205         /* exercise empty oldpath, ENOENT */
  206         rret = readlink("", testpath, sizeof(testpath));
  207         (void)rret;
  208 
  209         /* exercise non-link, EINVAL */
  210         rret = readlink("/", testpath, sizeof(testpath));
  211         (void)rret;
  212 
  213 #if defined(HAVE_READLINKAT) &&     \
  214     defined(AT_FDCWD)
  215         /* exercise invalid newpath size, EINVAL */
  216         rret = readlinkat(AT_FDCWD, ".", testpath, 0);
  217         (void)rret;
  218 
  219         /* exercise invalid newpath size, EINVAL */
  220         rret = readlinkat(AT_FDCWD, "", testpath, sizeof(testpath));
  221         (void)rret;
  222 
  223         /* exercise non-link, EINVAL */
  224         rret = readlinkat(AT_FDCWD, "/", testpath, sizeof(testpath));
  225         (void)rret;
  226 #endif
  227 
  228 err_unlink:
  229         stress_link_unlink(args, n);
  230 
  231         inc_counter(args);
  232     } while ((rc == EXIT_SUCCESS) && keep_stressing(args));
  233 
  234     stress_set_proc_state(args->name, STRESS_STATE_DEINIT);
  235 
  236     (void)unlink(oldpath);
  237     (void)stress_temp_dir_rm_args(args);
  238 
  239     stress_mount_free(mnts, mounts_max);
  240 
  241     return rc;
  242 }
  243 
  244 #if !defined(__HAIKU__)
  245 /*
  246  *  stress_link
  247  *  stress hard links
  248  */
  249 static int stress_link(const stress_args_t *args)
  250 {
  251     return stress_link_generic(args, link, "link");
  252 }
  253 #endif
  254 
  255 /*
  256  *  stress_symlink
  257  *  stress symbolic links
  258  */
  259 static int stress_symlink(const stress_args_t *args)
  260 {
  261     return stress_link_generic(args, symlink, "symlink");
  262 }
  263 
  264 #if !defined(__HAIKU__)
  265 stressor_info_t stress_link_info = {
  266     .stressor = stress_link,
  267     .class = CLASS_FILESYSTEM | CLASS_OS,
  268     .help = hardlink_help
  269 };
  270 #else
  271 stressor_info_t stress_link_info = {
  272     .stressor = stress_not_implemented,
  273     .class = CLASS_FILESYSTEM | CLASS_OS,
  274     .help = hardlink_help
  275 };
  276 #endif
  277 
  278 stressor_info_t stress_symlink_info = {
  279     .stressor = stress_symlink,
  280     .class = CLASS_FILESYSTEM | CLASS_OS,
  281     .help = symlink_help
  282 };