"Fossies" - the Fresh Open Source Software Archive

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

    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(HAVE_MNTENT_H) &&       \
   27     defined(HAVE_SYS_SELECT_H) &&   \
   28     defined(HAVE_SYS_FANOTIFY_H) && \
   29     defined(HAVE_FANOTIFY)
   30 
   31 #define MAX_MNTS    (4096)
   32 
   33 #define BUFFER_SIZE (4096)
   34 
   35 /* fanotify stats */
   36 typedef struct {
   37     uint64_t    open;
   38     uint64_t    open_exec;
   39     uint64_t    close_write;
   40     uint64_t    close_nowrite;
   41     uint64_t    access;
   42     uint64_t    modify;
   43 } fanotify_account_t;
   44 
   45 #endif
   46 
   47 #if defined(HAVE_FANOTIFY) &&   \
   48     defined(HAVE_SYS_SELECT_H)
   49 
   50 static const int FAN_STRESS_SETTINGS =
   51 #if defined(FAN_ACCESS)
   52     FAN_ACCESS |
   53 #endif
   54 #if defined(FAN_ACCESS)
   55     FAN_ACCESS |
   56 #endif
   57 #if defined(FAN_MODIFY)
   58     FAN_MODIFY |
   59 #endif
   60 #if defined(FAN_OPEN)
   61     FAN_OPEN |
   62 #endif
   63 #if defined(FAN_OPEN_EXEC)
   64     FAN_OPEN_EXEC |
   65 #endif
   66 #if defined(FAN_CLOSE)
   67     FAN_CLOSE |
   68 #endif
   69 #if defined(FAN_ONDIR)
   70     FAN_ONDIR |
   71 #endif
   72 #if defined(FAN_EVENT_ON_CHILD)
   73     FAN_EVENT_ON_CHILD |
   74 #endif
   75     0;
   76 
   77 /*
   78  *  stress_fanotify_supported()
   79  *      check if we can run this as root
   80  */
   81 static int stress_fanotify_supported(void)
   82 {
   83     if (geteuid() != 0) {
   84         pr_inf("fanotify stressor will be skipped, "
   85             "need to be running as root for this stressor\n");
   86         return -1;
   87     }
   88     return 0;
   89 }
   90 
   91 /*
   92  *  fanotify_event_init()
   93  *  initialize fanotify
   94  */
   95 static int fanotify_event_init(const char *name)
   96 {
   97     int fan_fd, count = 0, n_mnts, i;
   98     char *mnts[MAX_MNTS];
   99 
  100     if ((fan_fd = fanotify_init(0, 0)) < 0) {
  101         pr_err("%s: cannot initialize fanotify, errno=%d (%s)\n",
  102             name, errno, strerror(errno));
  103         return -1;
  104     }
  105 
  106     /* do all mount points */
  107     n_mnts = mount_get(mnts, MAX_MNTS);
  108     if (n_mnts < 1) {
  109         pr_err("%s: setmntent cannot get mount points from "
  110             "/proc/self/mounts, errno=%d (%s)\n",
  111             name, errno, strerror(errno));
  112         (void)close(fan_fd);
  113         return -1;
  114     }
  115 
  116     /*
  117      *  Gather all mounted file systems and monitor them
  118      */
  119     for (i = 0; i < n_mnts; i++) {
  120 #if defined(FAN_MARK_MOUNT) || defined(FAN_MARK_FILESYSTEM)
  121         int ret;
  122 #endif
  123 
  124 #if defined(FAN_MARK_MOUNT)
  125         ret = fanotify_mark(fan_fd, FAN_MARK_ADD | FAN_MARK_MOUNT,
  126             FAN_STRESS_SETTINGS, AT_FDCWD, mnts[i]);
  127         if (ret == 0)
  128             count++;
  129 #endif
  130 
  131 #if defined(FAN_MARK_FILESYSTEM)
  132         ret = fanotify_mark(fan_fd, FAN_MARK_ADD | FAN_MARK_FILESYSTEM,
  133             FAN_STRESS_SETTINGS, AT_FDCWD, mnts[i]);
  134         if (ret == 0)
  135             count++;
  136 #endif
  137     }
  138 
  139     mount_free(mnts, n_mnts);
  140 
  141     /* This really should not happen, / is always mounted */
  142     if (!count) {
  143         pr_err("%s: no mount points could be monitored\n",
  144             name);
  145         (void)close(fan_fd);
  146         return -1;
  147     }
  148     return fan_fd;
  149 }
  150 
  151 /*
  152  *  stress_fanotify()
  153  *  stress fanotify
  154  */
  155 static int stress_fanotify(const args_t *args)
  156 {
  157     char dirname[PATH_MAX - 16], filename[PATH_MAX];
  158     int ret, fan_fd, pid, rc = EXIT_SUCCESS;
  159     fanotify_account_t account;
  160 
  161     (void)memset(&account, 0, sizeof(account));
  162 
  163     stress_temp_dir_args(args, dirname, sizeof(dirname));
  164     (void)snprintf(filename, sizeof(filename), "%s/%s", dirname, "fanotify_file");
  165     ret = stress_temp_dir_mk_args(args);
  166     if (ret < 0)
  167         return exit_status(-ret);
  168 
  169     pid = fork();
  170     if (pid < 0) {
  171         pr_err("%s: fork failed: errno=%d (%s)\n",
  172             args->name, errno, strerror(errno));
  173         rc = EXIT_NO_RESOURCE;
  174         goto tidy;
  175     } else if (pid == 0) {
  176         /* Child */
  177 
  178         do {
  179             int fd;
  180             ssize_t n;
  181             char buffer[64];
  182 
  183             /* Force FAN_CLOSE_NOWRITE */
  184             fd = creat(filename, S_IRUSR | S_IWUSR);
  185             if (fd < 0) {
  186                 pr_fail_err("creat");
  187                 (void)kill(args->ppid, SIGALRM);
  188                 _exit(EXIT_FAILURE);
  189             }
  190             (void)close(fd);
  191 
  192             /* Force FAN_CLOSE_WRITE */
  193             fd = open(filename, O_WRONLY, S_IRUSR | S_IWUSR);
  194             if (fd < 0) {
  195                 pr_fail_err("open O_WRONLY");
  196                 (void)kill(args->ppid, SIGALRM);
  197                 _exit(EXIT_FAILURE);
  198             }
  199             n = write(fd, "test", 4);
  200             (void)n;
  201             (void)close(fd);
  202 
  203             /* Force FAN_ACCESS */
  204             fd = open(filename, O_RDONLY, S_IRUSR | S_IWUSR);
  205             if (fd < 0) {
  206                 pr_fail_err("open O_RDONLY");
  207                 (void)kill(args->ppid, SIGALRM);
  208                 _exit(EXIT_FAILURE);
  209             }
  210             n = read(fd, buffer, sizeof(buffer));
  211             (void)n;
  212             (void)close(fd);
  213 
  214             /* Force remove */
  215             (void)unlink(filename);
  216         } while (keep_stressing());
  217 
  218         _exit(EXIT_SUCCESS);
  219     } else {
  220         void *buffer;
  221 
  222         ret = posix_memalign(&buffer, BUFFER_SIZE, BUFFER_SIZE);
  223         if (ret != 0 || buffer == NULL) {
  224             pr_err("%s: posix_memalign: cannot allocate 4K "
  225                 "aligned buffer\n", args->name);
  226             rc = EXIT_NO_RESOURCE;
  227             goto tidy;
  228         }
  229 
  230         fan_fd = fanotify_event_init(args->name);
  231         if (fan_fd < 0) {
  232             free(buffer);
  233             rc = EXIT_FAILURE;
  234             goto tidy;
  235         }
  236 
  237         do {
  238             fd_set rfds;
  239             ssize_t len;
  240 
  241             FD_ZERO(&rfds);
  242             FD_SET(fan_fd, &rfds);
  243             ret = select(fan_fd + 1, &rfds, NULL, NULL, NULL);
  244             if (ret == -1) {
  245                 if (errno == EINTR)
  246                     continue;
  247                 pr_fail_err("select");
  248                 continue;
  249             }
  250             if (ret == 0)
  251                 continue;
  252 
  253 #if defined(FIONREAD)
  254             {
  255                 int isz;
  256 
  257                 /*
  258                  *  Force kernel to determine number
  259                  *  of bytes that are ready to be read
  260                  *  for some extra stress
  261                  */
  262                 ret = ioctl(fan_fd, FIONREAD, &isz);
  263                 (void)ret;
  264             }
  265 #endif
  266             if ((len = read(fan_fd, (void *)buffer, BUFFER_SIZE)) > 0) {
  267                 struct fanotify_event_metadata *metadata;
  268                 metadata = (struct fanotify_event_metadata *)buffer;
  269 
  270                 while (FAN_EVENT_OK(metadata, len)) {
  271                     if (!g_keep_stressing_flag)
  272                         break;
  273                     if ((metadata->fd != FAN_NOFD) && (metadata->fd >= 0)) {
  274 #if defined(FAN_OPEN)
  275                         if (metadata->mask & FAN_OPEN)
  276                             account.open++;
  277 #endif
  278 #if defined(FAN_OPEN_EXEC)
  279                         if (metadata->mask & FAN_OPEN_EXEC)
  280                             account.open_exec++;
  281 #endif
  282 #if defined(FAN_CLOSE_WRITE)
  283                         if (metadata->mask & FAN_CLOSE_WRITE)
  284                             account.close_write++;
  285 #endif
  286 #if defined(FAN_CLOSE_NOWRITE)
  287                         if (metadata->mask & FAN_CLOSE_NOWRITE)
  288                             account.close_nowrite++;
  289 #endif
  290 #if defined(FAN_ACCESS)
  291                         if (metadata->mask & FAN_ACCESS)
  292                             account.access++;
  293 #endif
  294 #if defined(FAN_MODIFY)
  295                         if (metadata->mask & FAN_MODIFY)
  296                             account.modify++;
  297 #endif
  298                         inc_counter(args);
  299                         (void)close(metadata->fd);
  300                     }
  301                     metadata = FAN_EVENT_NEXT(metadata, len);
  302                 }
  303             }
  304         } while (keep_stressing());
  305 
  306         free(buffer);
  307         (void)close(fan_fd);
  308         pr_inf("%s: "
  309             "%" PRIu64 " open, "
  310             "%" PRIu64 " open exec, "
  311             "%" PRIu64 " close write, "
  312             "%" PRIu64 " close nowrite, "
  313             "%" PRIu64 " access, "
  314             "%" PRIu64 " modify\n",
  315             args->name,
  316             account.open,
  317             account.open_exec,
  318             account.close_write,
  319             account.close_nowrite,
  320             account.access,
  321             account.modify);
  322     }
  323 tidy:
  324     if (pid > 0) {
  325         int status;
  326 
  327         (void)kill(pid, SIGKILL);
  328         (void)waitpid(pid, &status, 0);
  329     }
  330     (void)unlink(filename);
  331     (void)stress_temp_dir_rm_args(args);
  332 
  333     return rc;
  334 }
  335 
  336 stressor_info_t stress_fanotify_info = {
  337     .stressor = stress_fanotify,
  338     .supported = stress_fanotify_supported,
  339     .class = CLASS_FILESYSTEM | CLASS_SCHEDULER | CLASS_OS
  340 };
  341 #else
  342 stressor_info_t stress_fanotify_info = {
  343     .stressor = stress_not_implemented,
  344     .class = CLASS_FILESYSTEM | CLASS_SCHEDULER | CLASS_OS
  345 };
  346 #endif