"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-dnotify.c" (15 Mar 2019, 10521 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-dnotify.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) 2012-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 #include "stress-ng.h"
   25 
   26 #if defined(F_NOTIFY) && \
   27     defined(HAVE_SYS_SELECT_H)
   28 
   29 #define DIR_FLAGS   (S_IRWXU | S_IRWXG)
   30 #define FILE_FLAGS  (S_IRUSR | S_IWUSR)
   31 
   32 #define BUF_SIZE    (4096)
   33 
   34 static volatile int dnotify_fd;
   35 
   36 static int stress_dnotify_supported(void)
   37 {
   38     char buf[64];
   39     const char path[] = "/proc/sys/fs/dir-notify-enable";
   40     int enabled;
   41 
   42     if (system_read(path, buf, sizeof(buf)) < 0) {
   43         pr_inf("dnotify stressor will be skipped, cannot "
   44             "open '%s', CONFIG_DNOTIFY is probably not set\n",
   45             path);
   46                 return -1;
   47     }
   48     if (sscanf(buf, "%d", &enabled) != 1) {
   49         pr_inf("dnotify stressor will be skipped, cannot "
   50             "parse '%s'\n", path);
   51                 return -1;
   52     }
   53     if (enabled != 1) {
   54         pr_inf("dnotify stressor will be skipped, dnotify is not enabled\n");
   55                 return -1;
   56     }
   57     return 0;
   58 }
   59 
   60 static void dnotify_handler(int sig, siginfo_t *si, void *data)
   61 {
   62     (void)sig;
   63     (void)data;
   64 
   65     dnotify_fd = si->si_fd;
   66 }
   67 
   68 typedef int (*dnotify_helper)(const args_t *args, const char *path, const void *private);
   69 typedef void (*dnotify_func)(const args_t *args, const char *path);
   70 
   71 typedef struct {
   72     const dnotify_func func;
   73     const char* description;
   74 } dnotify_stress_t;
   75 
   76 /*
   77  *  dnotify_exercise()
   78  *  run a given test helper function 'func' and see if this triggers the
   79  *  required dnotify event flags 'flags'.
   80  */
   81 static void dnotify_exercise(
   82     const args_t *args, /* Stressor args */
   83     const char *filename,   /* Filename in test */
   84     const char *watchname,  /* File or directory to watch using dnotify */
   85     const dnotify_helper func,  /* Helper func */
   86     const int flags,    /* DN_* flags to watch for */
   87     void *private)      /* Helper func private data */
   88 {
   89     int fd, i = 0;
   90 
   91     if ((fd = open(watchname, O_RDONLY)) < 0) {
   92         pr_fail_err("open");
   93         return;
   94     }
   95     if (fcntl(fd, F_SETSIG, SIGRTMIN + 1) < 0) {
   96         pr_fail_err("fcntl F_SETSIG");
   97         goto cleanup;
   98     }
   99     if (fcntl(fd, F_NOTIFY, flags) < 0) {
  100         pr_fail_err("fcntl F_NOTIFY");
  101         goto cleanup;
  102     }
  103 
  104     dnotify_fd = -1;
  105     if (func(args, filename, private) < 0)
  106         goto cleanup;
  107 
  108     /* Wait for up to 1 second for event */
  109     while ((i < 1000) && (dnotify_fd == -1)) {
  110         i++;
  111         (void)shim_usleep(1000);
  112     }
  113 
  114     if (dnotify_fd != fd) {
  115         pr_fail("%s: did not get expected dnotify "
  116             "file descriptor\n", args->name);
  117     }
  118 
  119 cleanup:
  120     (void)close(fd);
  121 
  122 }
  123 
  124 /*
  125  *  rm_file()
  126  *  remove a file
  127  */
  128 static int rm_file(const args_t *args, const char *path)
  129 {
  130     if ((unlink(path) < 0) && errno != ENOENT) {
  131         pr_err("%s: cannot remove file %s: errno=%d (%s)\n",
  132             args->name, path, errno, strerror(errno));
  133         return -1;
  134     }
  135     return 0;
  136 }
  137 
  138 /*
  139  *  mk_filename()
  140  *  simple helper to create a filename
  141  */
  142 static inline void mk_filename(
  143     char *filename,
  144     const size_t len,
  145     const char *path,
  146     const char *name)
  147 {
  148     (void)snprintf(filename, len, "%s/%s", path, name);
  149 }
  150 
  151 /*
  152  *  mk_file()
  153  *  create file of length len bytes
  154  */
  155 static int mk_file(const args_t *args, const char *filename, const size_t len)
  156 {
  157     int fd;
  158     size_t sz = len;
  159 
  160     char buffer[BUF_SIZE];
  161 
  162     if ((fd = open(filename, O_CREAT | O_RDWR, FILE_FLAGS)) < 0) {
  163         pr_err("%s: cannot create file %s: errno=%d (%s)\n",
  164             args->name, filename, errno, strerror(errno));
  165         return -1;
  166     }
  167 
  168     (void)memset(buffer, 'x', BUF_SIZE);
  169     while (sz > 0) {
  170         size_t n = (sz > BUF_SIZE) ? BUF_SIZE : sz;
  171         int ret;
  172 
  173         if ((ret = write(fd, buffer, n)) < 0) {
  174             pr_err("%s: error writing to file %s: errno=%d (%s)\n",
  175                 args->name, filename, errno, strerror(errno));
  176             (void)close(fd);
  177             return -1;
  178         }
  179         sz -= ret;
  180     }
  181 
  182     if (close(fd) < 0) {
  183         pr_err("%s: cannot close file %s: errno=%d (%s)\n",
  184             args->name, filename, errno, strerror(errno));
  185         return -1;
  186     }
  187     return 0;
  188 }
  189 
  190 static int dnotify_attrib_helper(
  191     const args_t *args,
  192     const char *path,
  193     const void *signum)
  194 {
  195     (void)signum;
  196     if (chmod(path, S_IRUSR | S_IWUSR) < 0) {
  197         pr_err("%s: cannot chmod file %s: errno=%d (%s)\n",
  198             args->name, path, errno, strerror(errno));
  199         return -1;
  200     }
  201     return 0;
  202 }
  203 
  204 static void dnotify_attrib_file(const args_t *args, const char *path)
  205 {
  206     char filepath[PATH_MAX];
  207 
  208     mk_filename(filepath, PATH_MAX, path, "dnotify_file");
  209     if (mk_file(args, filepath, 4096) < 0)
  210         return;
  211 
  212     dnotify_exercise(args, filepath, path,
  213         dnotify_attrib_helper, DN_ATTRIB, NULL);
  214     (void)rm_file(args, filepath);
  215 }
  216 
  217 static int dnotify_access_helper(
  218     const args_t *args,
  219     const char *path,
  220     const void *signum)
  221 {
  222     int fd;
  223     char buffer[1];
  224     int rc = 0;
  225 
  226     (void)signum;
  227     if ((fd = open(path, O_RDONLY)) < 0) {
  228         pr_err("%s: cannot open file %s: errno=%d (%s)\n",
  229             args->name, path, errno, strerror(errno));
  230         return -1;
  231     }
  232 
  233     /* Just want to force an access */
  234 do_access:
  235     if (g_keep_stressing_flag && (read(fd, buffer, 1) < 0)) {
  236         if ((errno == EAGAIN) || (errno == EINTR))
  237             goto do_access;
  238         pr_err("%s: cannot read file %s: errno=%d (%s)\n",
  239             args->name, path, errno, strerror(errno));
  240         rc = -1;
  241     }
  242     (void)close(fd);
  243     return rc;
  244 }
  245 
  246 static void dnotify_access_file(const args_t *args, const char *path)
  247 {
  248     char filepath[PATH_MAX];
  249 
  250     mk_filename(filepath, PATH_MAX, path, "dnotify_file");
  251     if (mk_file(args, filepath, 4096) < 0)
  252         return;
  253 
  254     dnotify_exercise(args, filepath, path,
  255         dnotify_access_helper, DN_ACCESS, NULL);
  256     (void)rm_file(args, filepath);
  257 }
  258 
  259 static int dnotify_modify_helper(
  260     const args_t *args,
  261     const char *path,
  262     const void *signum)
  263 {
  264     int fd, rc = 0;
  265     char buffer[1] = { 0 };
  266 
  267     (void)signum;
  268     if (mk_file(args, path, 4096) < 0)
  269         return -1;
  270     if ((fd = open(path, O_RDWR)) < 0) {
  271         pr_err("%s: cannot open file %s: errno=%d (%s)\n",
  272             args->name, path, errno, strerror(errno));
  273         rc = -1;
  274         goto remove;
  275     }
  276 do_modify:
  277     if (g_keep_stressing_flag && (write(fd, buffer, 1) < 0)) {
  278         if ((errno == EAGAIN) || (errno == EINTR))
  279             goto do_modify;
  280         pr_err("%s: cannot write to file %s: errno=%d (%s)\n",
  281             args->name, path, errno, strerror(errno));
  282         rc = -1;
  283     }
  284     (void)close(fd);
  285 remove:
  286     (void)rm_file(args, path);
  287     return rc;
  288 }
  289 
  290 static void dnotify_modify_file(const args_t *args, const char *path)
  291 {
  292     char filepath[PATH_MAX];
  293 
  294     mk_filename(filepath, PATH_MAX, path, "dnotify_file");
  295     dnotify_exercise(args, filepath, path,
  296         dnotify_modify_helper, DN_MODIFY, NULL);
  297 }
  298 
  299 static int dnotify_creat_helper(
  300     const args_t *args,
  301     const char *path,
  302     const void *signum)
  303 {
  304     (void)signum;
  305     int fd;
  306     if ((fd = creat(path, FILE_FLAGS)) < 0) {
  307         pr_err("%s: cannot create file %s: errno=%d (%s)\n",
  308             args->name, path, errno, strerror(errno));
  309         return -1;
  310     }
  311     (void)close(fd);
  312     return 0;
  313 }
  314 
  315 static void dnotify_creat_file(const args_t *args, const char *path)
  316 {
  317     char filepath[PATH_MAX];
  318 
  319     mk_filename(filepath, PATH_MAX, path, "dnotify_file");
  320     dnotify_exercise(args, filepath, path,
  321         dnotify_creat_helper, DN_CREATE, NULL);
  322     (void)rm_file(args, filepath);
  323 }
  324 
  325 static int dnotify_delete_helper(
  326     const args_t *args,
  327     const char *path,
  328     const void *signum)
  329 {
  330     (void)signum;
  331 
  332     return rm_file(args, path);
  333 }
  334 
  335 static void dnotify_delete_file(const args_t *args, const char *path)
  336 {
  337     char filepath[PATH_MAX];
  338 
  339     mk_filename(filepath, PATH_MAX, path, "dnotify_file");
  340     if (mk_file(args, filepath, 4096) < 0)
  341         return;
  342     dnotify_exercise(args, filepath, path,
  343         dnotify_delete_helper, DN_DELETE, NULL);
  344     /* We remove (again) it just in case the test failed */
  345     (void)rm_file(args, filepath);
  346 }
  347 
  348 static int dnotify_rename_helper(
  349     const args_t *args,
  350     const char *oldpath,
  351     const void *private)
  352 {
  353     const char *newpath = (const char *)private;
  354 
  355     if (rename(oldpath, newpath) < 0) {
  356         pr_err("%s: cannot rename %s to %s: errno=%d (%s)\n",
  357             args->name, oldpath, newpath, errno, strerror(errno));
  358         return -1;
  359     }
  360     return 0;
  361 }
  362 
  363 static void dnotify_rename_file(const args_t *args, const char *path)
  364 {
  365     char oldfile[PATH_MAX], newfile[PATH_MAX];
  366 
  367     mk_filename(oldfile, PATH_MAX, path, "dnotify_file");
  368     mk_filename(newfile, PATH_MAX, path, "dnotify_file_renamed");
  369 
  370     if (mk_file(args, oldfile, 4096) < 0)
  371         return;
  372 
  373     dnotify_exercise(args, oldfile, path,
  374         dnotify_rename_helper, DN_RENAME, newfile);
  375     (void)rm_file(args, oldfile);   /* In case rename failed */
  376     (void)rm_file(args, newfile);
  377 }
  378 
  379 static const dnotify_stress_t dnotify_stressors[] = {
  380     { dnotify_access_file,      "DN_ACCESS" },
  381     { dnotify_modify_file,      "DN_MODIFY" },
  382     { dnotify_creat_file,       "DN_CREATE" },
  383     { dnotify_delete_file,      "DN_DELETE" },
  384     { dnotify_rename_file,      "DN_RENAME" },
  385     { dnotify_attrib_file,      "DN_ATTRIB" },
  386     { NULL,             NULL }
  387 };
  388 
  389 /*
  390  *  stress_dnotify()
  391  *  stress dnotify
  392  */
  393 static int stress_dnotify(const args_t *args)
  394 {
  395     char dirname[PATH_MAX];
  396     int ret, i;
  397     struct sigaction act;
  398 
  399     act.sa_sigaction = dnotify_handler;
  400     (void)sigemptyset(&act.sa_mask);
  401     act.sa_flags = SA_SIGINFO;
  402     if (sigaction(SIGRTMIN + 1, &act, NULL) < 0) {
  403         pr_err("%s: sigaction failed: errno=%d (%s)\n",
  404             args->name, errno, strerror(errno));
  405         return EXIT_NO_RESOURCE;
  406     }
  407 
  408     stress_temp_dir_args(args, dirname, sizeof(dirname));
  409     ret = stress_temp_dir_mk_args(args);
  410     if (ret < 0)
  411         return exit_status(-ret);
  412     do {
  413         for (i = 0; g_keep_stressing_flag && dnotify_stressors[i].func; i++)
  414             dnotify_stressors[i].func(args, dirname);
  415         inc_counter(args);
  416     } while (keep_stressing());
  417     (void)stress_temp_dir_rm_args(args);
  418 
  419     return EXIT_SUCCESS;
  420 }
  421 stressor_info_t stress_dnotify_info = {
  422     .stressor = stress_dnotify,
  423     .class = CLASS_FILESYSTEM | CLASS_SCHEDULER | CLASS_OS,
  424     .supported = stress_dnotify_supported
  425 };
  426 #else
  427 stressor_info_t stress_dnotify_info = {
  428     .stressor = stress_not_implemented,
  429     .class = CLASS_FILESYSTEM | CLASS_SCHEDULER | CLASS_OS
  430 };
  431 #endif