"Fossies" - the Fresh Open Source Software Archive

Member "stress-ng-0.09.56/stress-quota.c" (15 Mar 2019, 7396 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-quota.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 #if defined(HAVE_SYS_QUOTA_H) &&    \
   28     defined(__linux__) &&       \
   29     (defined(Q_GETQUOTA) ||     \
   30      defined(Q_GETFMT) ||       \
   31      defined(Q_GETINFO) ||      \
   32      defined(Q_GETSTATS) ||     \
   33      defined(Q_SYNC))
   34 
   35 #define MAX_DEVS    (128)
   36 
   37 typedef struct {
   38     char    *name;
   39     char    *mount;
   40     dev_t   st_dev;
   41     bool    valid;
   42     bool    enosys;
   43     bool    esrch;
   44 } dev_info_t;
   45 
   46 #define DO_Q_GETQUOTA   0x0001
   47 #define DO_Q_GETFMT 0x0002
   48 #define DO_Q_GETINFO    0x0004
   49 #define DO_Q_GETSTATS   0x0008
   50 #define DO_Q_SYNC   0x0010
   51 
   52 /*
   53  *  do_quotactl()
   54  *  do a quotactl command
   55  */
   56 static int do_quotactl(
   57     const args_t *args,
   58     const char *cmdname,
   59     int *tested,
   60     int *failed,
   61     int *enosys,
   62     int *esrch,
   63     int cmd,
   64     const char *special,
   65     int id,
   66     caddr_t addr)
   67 {
   68     int ret = quotactl(cmd, special, id, addr);
   69 
   70     (*tested)++;
   71     if (ret < 0) {
   72         /* Quota not enabled for this file system? */
   73         if (errno == ESRCH) {
   74             (*esrch)++;
   75             return 0;
   76         }
   77         /* Not a block device? - ship it */
   78         if (errno == ENOTBLK)
   79             return errno;
   80 
   81         if (errno == EPERM) {
   82             pr_inf("%s: need CAP_SYS_ADMIN capability to "
   83                 "run quota stressor, aborting stress test\n",
   84                 args->name);
   85             return errno;
   86         }
   87         if (errno == ENOSYS) {
   88             (*enosys)++;
   89         } else {
   90             (*failed)++;
   91             pr_fail("%s: quotactl command %s on %s failed: errno=%d (%s)\n",
   92                 args->name, cmdname, special, errno, strerror(errno));
   93         }
   94     }
   95     return errno;
   96 }
   97 
   98 /*
   99  *  do_quotas()
  100  *  do quotactl commands
  101  */
  102 static int do_quotas(const args_t *args, dev_info_t *const dev)
  103 {
  104     int tested = 0, failed = 0, enosys = 0, esrch = 0;
  105 #if defined(Q_GETQUOTA)
  106     if (g_keep_stressing_flag) {
  107         struct dqblk dqblk;
  108         int err = do_quotactl(args, "Q_GETQUOTA",
  109                 &tested, &failed, &enosys, &esrch,
  110                 QCMD(Q_GETQUOTA, USRQUOTA),
  111             dev->name, 0, (caddr_t)&dqblk);
  112         if (err == EPERM)
  113             return err;
  114     }
  115 #endif
  116 #if defined(Q_GETFMT)
  117     if (g_keep_stressing_flag) {
  118         uint32_t format;
  119         int err = do_quotactl(args, "Q_GETFMT",
  120                 &tested, &failed, &enosys, &esrch,
  121                 QCMD(Q_GETFMT, USRQUOTA),
  122             dev->name, 0, (caddr_t)&format);
  123         if (err == EPERM)
  124             return err;
  125     }
  126 #endif
  127 #if defined(Q_GETINFO)
  128     if (g_keep_stressing_flag) {
  129         struct dqinfo dqinfo;
  130         int err = do_quotactl(args, "Q_GETINFO",
  131                 &tested, &failed, &enosys, &esrch,
  132                 QCMD(Q_GETINFO, USRQUOTA),
  133             dev->name, 0, (caddr_t)&dqinfo);
  134         if (err == EPERM)
  135             return err;
  136     }
  137 #endif
  138 #if defined(Q_GETSTATS)
  139     /* Obsolete in recent kernels */
  140     if (g_keep_stressing_flag) {
  141         struct dqstats dqstats;
  142         int err = do_quotactl(args, "Q_GETSTATS",
  143                 &tested, &failed, &enosys, &esrch,
  144                 QCMD(Q_GETSTATS, USRQUOTA),
  145             dev->name, 0, (caddr_t)&dqstats);
  146         if (err == EPERM)
  147             return err;
  148     }
  149 #endif
  150 #if defined(Q_SYNC)
  151     if (g_keep_stressing_flag) {
  152         int err = do_quotactl(args, "Q_SYNC",
  153                 &tested, &failed, &enosys, &esrch,
  154                 QCMD(Q_SYNC, USRQUOTA),
  155             dev->name, 0, 0);
  156         if (err == EPERM)
  157             return err;
  158     }
  159 #endif
  160     if (tested == 0) {
  161         pr_err("%s: quotactl() failed, quota commands "
  162             "not available\n", args->name);
  163         return -1;
  164     }
  165     if (!dev->esrch && (esrch > 0)) {
  166         pr_dbg("%s: quotactl() failed on %s, perhaps not enabled\n",
  167             args->name, dev->name);
  168         dev->esrch = true;
  169     }
  170     if (tested == enosys) {
  171         pr_dbg("%s: quotactl() failed on %s, not available "
  172             "on this kernel or filesystem\n", args->name, dev->name);
  173         dev->enosys = true;
  174         return ENOSYS;
  175     }
  176     if (tested == failed) {
  177         pr_err("%s: quotactl() failed, all quota commands "
  178             "failed (maybe privilege issues, use -v "
  179             "to see why)\n", args->name);
  180         return -1;
  181     }
  182     return 0;
  183 }
  184 
  185 /*
  186  *  stress_quota
  187  *  stress various quota options
  188  */
  189 static int stress_quota(const args_t *args)
  190 {
  191     int i, n_mounts, n_devs = 0;
  192     int rc = EXIT_FAILURE;
  193     char *mnts[MAX_DEVS];
  194     dev_info_t devs[MAX_DEVS];
  195     DIR *dir;
  196     struct dirent *d;
  197     struct stat buf;
  198 
  199     (void)memset(mnts, 0, sizeof(mnts));
  200     (void)memset(devs, 0, sizeof(devs));
  201 
  202     n_mounts = mount_get(mnts, SIZEOF_ARRAY(mnts));
  203 
  204     dir = opendir("/dev/");
  205     if (!dir) {
  206         pr_err("%s: opendir on /dev failed: errno=%d: (%s)\n",
  207             args->name, errno, strerror(errno));
  208         return rc;
  209     }
  210 
  211     for (i = 0; i < n_mounts; i++) {
  212         if (lstat(mnts[i], &buf) == 0) {
  213             devs[i].st_dev = buf.st_dev;
  214             devs[i].valid = true;
  215         }
  216     }
  217 
  218     while ((d = readdir(dir)) != NULL) {
  219         char path[PATH_MAX];
  220 
  221         (void)snprintf(path, sizeof(path), "/dev/%s", d->d_name);
  222         if (lstat(path, &buf) < 0)
  223             continue;
  224         if ((buf.st_mode & S_IFBLK) == 0)
  225             continue;
  226         for (i = 0; i < n_mounts; i++) {
  227             if (devs[i].valid &&
  228                 !devs[i].name &&
  229                 (buf.st_rdev == devs[i].st_dev)) {
  230                 devs[i].name = strdup(path);
  231                 devs[i].mount = mnts[i];
  232                 if (!devs[i].name) {
  233                     pr_err("%s: out of memory\n",
  234                         args->name);
  235                     (void)closedir(dir);
  236                     goto tidy;
  237                 }
  238             }
  239         }
  240     }
  241     (void)closedir(dir);
  242 
  243     /* Compact up, remove duplicates too */
  244     for (i = 0; i < n_mounts; i++) {
  245         int j;
  246         bool unique = true;
  247 
  248         for (j = 0; j < n_devs; j++) {
  249             if (devs[i].st_dev == devs[j].st_dev) {
  250                 unique = false;
  251                 break;
  252             }
  253         }
  254         if (unique && devs[i].name)
  255             devs[n_devs++] = devs[i];
  256         else
  257             free(devs[i].name);
  258     }
  259     for (i = n_devs; i < n_mounts; i++)
  260         (void)memset(&devs[i], 0, sizeof(devs[i]));
  261 
  262     if (!n_devs) {
  263         pr_err("%s: cannot find any candidate block "
  264             "devices with quota enabled\n", args->name);
  265     } else {
  266         do {
  267             int failed = 0, enosys = 0;
  268 
  269             for (i = 0; g_keep_stressing_flag && (i < n_devs); i++) {
  270                 int ret;
  271 
  272                 /* This failed before, so don't retest */
  273                 if (devs[i].enosys) {
  274                     enosys++;
  275                     continue;
  276                 }
  277 
  278                 ret = do_quotas(args, &devs[i]);
  279                 switch (ret) {
  280                 case 0:
  281                     break;
  282                 case ENOSYS:
  283                     enosys++;
  284                     break;
  285                 case EPERM:
  286                     goto abort;
  287                     break;
  288                 default:
  289                     failed++;
  290                     break;
  291                 }
  292             }
  293             inc_counter(args);
  294 
  295             /*
  296              * Accounting not on for all the devices?
  297              * then do a non-fatal skip test
  298              */
  299             if (enosys == n_devs) {
  300                 rc = EXIT_SUCCESS;
  301                 goto tidy;
  302             }
  303             
  304             /* All failed, then give up */
  305             if (failed == n_devs)
  306                 goto tidy;
  307         } while (keep_stressing());
  308     }
  309 abort:
  310     rc = EXIT_SUCCESS;
  311 
  312 tidy:
  313     for (i = 0; i < n_devs; i++)
  314         free(devs[i].name);
  315 
  316     mount_free(mnts, n_mounts);
  317     return rc;
  318 }
  319 
  320 stressor_info_t stress_quota_info = {
  321     .stressor = stress_quota,
  322     .class = CLASS_OS
  323 };
  324 #else
  325 stressor_info_t stress_quota_info = {
  326     .stressor = stress_not_implemented,
  327     .class = CLASS_OS
  328 };
  329 #endif