"Fossies" - the Fresh Open Source Software Archive

Member "btrfs-progs-v5.4.1/cmds/qgroup.c" (9 Jan 2020, 11725 Bytes) of package /linux/misc/btrfs-progs-v5.4.1.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 "qgroup.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: v5.4_vs_v5.4.1.

    1 /*
    2  * Copyright (C) 2012 STRATO.  All rights reserved.
    3  *
    4  * This program is free software; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public
    6  * License v2 as published by the Free Software Foundation.
    7  *
    8  * This program is distributed in the hope that it will be useful,
    9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   11  * General Public License for more details.
   12  *
   13  * You should have received a copy of the GNU General Public
   14  * License along with this program; if not, write to the
   15  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   16  * Boston, MA 021110-1307, USA.
   17  */
   18 
   19 #include <sys/ioctl.h>
   20 #include <unistd.h>
   21 #include <getopt.h>
   22 
   23 #include <btrfsutil.h>
   24 
   25 #include "ctree.h"
   26 #include "ioctl.h"
   27 
   28 #include "cmds/commands.h"
   29 #include "qgroup.h"
   30 #include "common/utils.h"
   31 #include "common/help.h"
   32 
   33 static const char * const qgroup_cmd_group_usage[] = {
   34     "btrfs qgroup <command> [options] <path>",
   35     NULL
   36 };
   37 
   38 static int _cmd_qgroup_assign(const struct cmd_struct *cmd, int assign,
   39                   int argc, char **argv)
   40 {
   41     int ret = 0;
   42     int fd;
   43     bool rescan = true;
   44     char *path;
   45     struct btrfs_ioctl_qgroup_assign_args args;
   46     DIR *dirstream = NULL;
   47 
   48     if (assign) {
   49         optind = 0;
   50         while (1) {
   51             enum { GETOPT_VAL_RESCAN = 256, GETOPT_VAL_NO_RESCAN };
   52             static const struct option long_options[] = {
   53                 { "rescan", no_argument, NULL,
   54                     GETOPT_VAL_RESCAN },
   55                 { "no-rescan", no_argument, NULL,
   56                     GETOPT_VAL_NO_RESCAN },
   57                 { NULL, 0, NULL, 0 }
   58             };
   59             int c = getopt_long(argc, argv, "", long_options, NULL);
   60 
   61             if (c < 0)
   62                 break;
   63             switch (c) {
   64             case GETOPT_VAL_RESCAN:
   65                 rescan = true;
   66                 break;
   67             case GETOPT_VAL_NO_RESCAN:
   68                 rescan = false;
   69                 break;
   70             default:
   71                 usage_unknown_option(cmd, argv);
   72             }
   73         }
   74     } else {
   75         clean_args_no_options(cmd, argc, argv);
   76     }
   77 
   78     if (check_argc_exact(argc - optind, 3))
   79         return 1;
   80 
   81     memset(&args, 0, sizeof(args));
   82     args.assign = assign;
   83     args.src = parse_qgroupid(argv[optind]);
   84     args.dst = parse_qgroupid(argv[optind + 1]);
   85 
   86     path = argv[optind + 2];
   87 
   88     /*
   89      * FIXME src should accept subvol path
   90      */
   91     if (btrfs_qgroup_level(args.src) >= btrfs_qgroup_level(args.dst)) {
   92         error("bad relation requested: %s", path);
   93         return 1;
   94     }
   95     fd = btrfs_open_dir(path, &dirstream, 1);
   96     if (fd < 0)
   97         return 1;
   98 
   99     ret = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
  100     if (ret < 0) {
  101         error("unable to assign quota group: %s",
  102                 errno == ENOTCONN ? "quota not enabled"
  103                         : strerror(errno));
  104         close_file_or_dir(fd, dirstream);
  105         return 1;
  106     }
  107 
  108     /*
  109      * If ret > 0, it means assign caused qgroup data inconsistent state.
  110      * Schedule a quota rescan if requested.
  111      *
  112      * The return value change only happens in newer kernel. But will not
  113      * cause problem since old kernel has a bug that will never clear
  114      * INCONSISTENT bit.
  115      */
  116     if (ret > 0) {
  117         if (rescan) {
  118             struct btrfs_ioctl_quota_rescan_args qargs;
  119 
  120             printf("Quota data changed, rescan scheduled\n");
  121             memset(&qargs, 0, sizeof(qargs));
  122             ret = ioctl(fd, BTRFS_IOC_QUOTA_RESCAN, &qargs);
  123             if (ret < 0)
  124                 error("quota rescan failed: %m");
  125         } else {
  126             warning("quotas may be inconsistent, rescan needed");
  127             ret = 0;
  128         }
  129     }
  130     close_file_or_dir(fd, dirstream);
  131     return ret;
  132 }
  133 
  134 static int _cmd_qgroup_create(int create, int argc, char **argv)
  135 {
  136     int ret = 0;
  137     int fd;
  138     char *path;
  139     struct btrfs_ioctl_qgroup_create_args args;
  140     DIR *dirstream = NULL;
  141 
  142     if (check_argc_exact(argc - optind, 2))
  143         return 1;
  144 
  145     memset(&args, 0, sizeof(args));
  146     args.create = create;
  147     args.qgroupid = parse_qgroupid(argv[optind]);
  148     path = argv[optind + 1];
  149 
  150     fd = btrfs_open_dir(path, &dirstream, 1);
  151     if (fd < 0)
  152         return 1;
  153 
  154     ret = ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args);
  155     close_file_or_dir(fd, dirstream);
  156     if (ret < 0) {
  157         error("unable to %s quota group: %s",
  158             create ? "create":"destroy",
  159                 errno == ENOTCONN ? "quota not enabled"
  160                         : strerror(errno));
  161         return 1;
  162     }
  163     return 0;
  164 }
  165 
  166 static const char * const cmd_qgroup_assign_usage[] = {
  167     "btrfs qgroup assign [options] <src> <dst> <path>",
  168     "Assign SRC as the child qgroup of DST",
  169     "",
  170     "--rescan       schedule qutoa rescan if needed",
  171     "--no-rescan    don't schedule quota rescan",
  172     NULL
  173 };
  174 
  175 static int cmd_qgroup_assign(const struct cmd_struct *cmd,
  176                  int argc, char **argv)
  177 {
  178     return _cmd_qgroup_assign(cmd, 1, argc, argv);
  179 }
  180 static DEFINE_SIMPLE_COMMAND(qgroup_assign, "assign");
  181 
  182 static const char * const cmd_qgroup_remove_usage[] = {
  183     "btrfs qgroup remove <src> <dst> <path>",
  184     "Remove a child qgroup SRC from DST.",
  185     NULL
  186 };
  187 
  188 static int cmd_qgroup_remove(const struct cmd_struct *cmd,
  189                  int argc, char **argv)
  190 {
  191     return _cmd_qgroup_assign(cmd, 0, argc, argv);
  192 }
  193 static DEFINE_SIMPLE_COMMAND(qgroup_remove, "remove");
  194 
  195 static const char * const cmd_qgroup_create_usage[] = {
  196     "btrfs qgroup create <qgroupid> <path>",
  197     "Create a subvolume quota group.",
  198     NULL
  199 };
  200 
  201 static int cmd_qgroup_create(const struct cmd_struct *cmd,
  202                  int argc, char **argv)
  203 {
  204     clean_args_no_options(cmd, argc, argv);
  205 
  206     return _cmd_qgroup_create(1, argc, argv);
  207 }
  208 static DEFINE_SIMPLE_COMMAND(qgroup_create, "create");
  209 
  210 static const char * const cmd_qgroup_destroy_usage[] = {
  211     "btrfs qgroup destroy <qgroupid> <path>",
  212     "Destroy a quota group.",
  213     NULL
  214 };
  215 
  216 static int cmd_qgroup_destroy(const struct cmd_struct *cmd,
  217                   int argc, char **argv)
  218 {
  219     clean_args_no_options(cmd, argc, argv);
  220 
  221     return _cmd_qgroup_create(0, argc, argv);
  222 }
  223 static DEFINE_SIMPLE_COMMAND(qgroup_destroy, "destroy");
  224 
  225 static const char * const cmd_qgroup_show_usage[] = {
  226     "btrfs qgroup show [options] <path>",
  227     "Show subvolume quota groups.",
  228     "",
  229     "-p             print parent qgroup id",
  230     "-c             print child qgroup id",
  231     "-r             print limit of referenced size of qgroup",
  232     "-e             print limit of exclusive size of qgroup",
  233     "-F             list all qgroups which impact the given path",
  234     "               (including ancestral qgroups)",
  235     "-f             list all qgroups which impact the given path",
  236     "               (excluding ancestral qgroups)",
  237     HELPINFO_UNITS_LONG,
  238     "--sort=qgroupid,rfer,excl,max_rfer,max_excl",
  239     "               list qgroups sorted by specified items",
  240     "               you can use '+' or '-' in front of each item.",
  241     "               (+:ascending, -:descending, ascending default)",
  242     "--sync         force sync of the filesystem before getting info",
  243     NULL
  244 };
  245 
  246 static int cmd_qgroup_show(const struct cmd_struct *cmd, int argc, char **argv)
  247 {
  248     char *path;
  249     int ret = 0;
  250     int fd;
  251     DIR *dirstream = NULL;
  252     u64 qgroupid;
  253     int filter_flag = 0;
  254     unsigned unit_mode;
  255     int sync = 0;
  256     enum btrfs_util_error err;
  257 
  258     struct btrfs_qgroup_comparer_set *comparer_set;
  259     struct btrfs_qgroup_filter_set *filter_set;
  260     filter_set = btrfs_qgroup_alloc_filter_set();
  261     comparer_set = btrfs_qgroup_alloc_comparer_set();
  262 
  263     unit_mode = get_unit_mode_from_arg(&argc, argv, 0);
  264 
  265     optind = 0;
  266     while (1) {
  267         int c;
  268         enum {
  269             GETOPT_VAL_SORT = 256,
  270             GETOPT_VAL_SYNC
  271         };
  272         static const struct option long_options[] = {
  273             {"sort", required_argument, NULL, GETOPT_VAL_SORT},
  274             {"sync", no_argument, NULL, GETOPT_VAL_SYNC},
  275             { NULL, 0, NULL, 0 }
  276         };
  277 
  278         c = getopt_long(argc, argv, "pcreFf", long_options, NULL);
  279         if (c < 0)
  280             break;
  281         switch (c) {
  282         case 'p':
  283             btrfs_qgroup_setup_print_column(
  284                 BTRFS_QGROUP_PARENT);
  285             break;
  286         case 'c':
  287             btrfs_qgroup_setup_print_column(
  288                 BTRFS_QGROUP_CHILD);
  289             break;
  290         case 'r':
  291             btrfs_qgroup_setup_print_column(
  292                 BTRFS_QGROUP_MAX_RFER);
  293             break;
  294         case 'e':
  295             btrfs_qgroup_setup_print_column(
  296                 BTRFS_QGROUP_MAX_EXCL);
  297             break;
  298         case 'F':
  299             filter_flag |= 0x1;
  300             break;
  301         case 'f':
  302             filter_flag |= 0x2;
  303             break;
  304         case GETOPT_VAL_SORT:
  305             ret = btrfs_qgroup_parse_sort_string(optarg,
  306                                  &comparer_set);
  307             if (ret < 0) {
  308                 errno = -ret;
  309                 error("cannot parse sort string: %m");
  310                 return 1;
  311             }
  312             if (ret > 0) {
  313                 error("unrecognized format of sort string");
  314                 return 1;
  315             }
  316             break;
  317         case GETOPT_VAL_SYNC:
  318             sync = 1;
  319             break;
  320         default:
  321             usage_unknown_option(cmd, argv);
  322         }
  323     }
  324     btrfs_qgroup_setup_units(unit_mode);
  325 
  326     if (check_argc_exact(argc - optind, 1))
  327         return 1;
  328 
  329     path = argv[optind];
  330     fd = btrfs_open_dir(path, &dirstream, 1);
  331     if (fd < 0) {
  332         free(filter_set);
  333         free(comparer_set);
  334         return 1;
  335     }
  336 
  337     if (sync) {
  338         err = btrfs_util_sync_fd(fd);
  339         if (err)
  340             warning("sync ioctl failed on '%s': %m", path);
  341     }
  342 
  343     if (filter_flag) {
  344         ret = lookup_path_rootid(fd, &qgroupid);
  345         if (ret < 0) {
  346             errno = -ret;
  347             error("cannot resolve rootid for %s: %m", path);
  348             close_file_or_dir(fd, dirstream);
  349             goto out;
  350         }
  351         if (filter_flag & 0x1)
  352             btrfs_qgroup_setup_filter(&filter_set,
  353                     BTRFS_QGROUP_FILTER_ALL_PARENT,
  354                     qgroupid);
  355         if (filter_flag & 0x2)
  356             btrfs_qgroup_setup_filter(&filter_set,
  357                     BTRFS_QGROUP_FILTER_PARENT,
  358                     qgroupid);
  359     }
  360     ret = btrfs_show_qgroups(fd, filter_set, comparer_set);
  361     close_file_or_dir(fd, dirstream);
  362     free(filter_set);
  363     free(comparer_set);
  364 
  365 out:
  366     return !!ret;
  367 }
  368 static DEFINE_SIMPLE_COMMAND(qgroup_show, "show");
  369 
  370 static const char * const cmd_qgroup_limit_usage[] = {
  371     "btrfs qgroup limit [options] <size>|none [<qgroupid>] <path>",
  372     "Set the limits a subvolume quota group.",
  373     "",
  374     "-c   limit amount of data after compression. This is the default,",
  375     "     it is currently not possible to turn off this option.",
  376     "-e   limit space exclusively assigned to this qgroup",
  377     NULL
  378 };
  379 
  380 static int cmd_qgroup_limit(const struct cmd_struct *cmd, int argc, char **argv)
  381 {
  382     int ret = 0;
  383     int fd;
  384     char *path = NULL;
  385     struct btrfs_ioctl_qgroup_limit_args args;
  386     unsigned long long size;
  387     int compressed = 0;
  388     int exclusive = 0;
  389     DIR *dirstream = NULL;
  390     enum btrfs_util_error err;
  391 
  392     optind = 0;
  393     while (1) {
  394         int c = getopt(argc, argv, "ce");
  395         if (c < 0)
  396             break;
  397         switch (c) {
  398         case 'c':
  399             compressed = 1;
  400             break;
  401         case 'e':
  402             exclusive = 1;
  403             break;
  404         default:
  405             usage_unknown_option(cmd, argv);
  406         }
  407     }
  408 
  409     if (check_argc_min(argc - optind, 2))
  410         return 1;
  411 
  412     if (!strcasecmp(argv[optind], "none"))
  413         size = -1ULL;
  414     else
  415         size = parse_size(argv[optind]);
  416 
  417     memset(&args, 0, sizeof(args));
  418     if (compressed)
  419         args.lim.flags |= BTRFS_QGROUP_LIMIT_RFER_CMPR |
  420                   BTRFS_QGROUP_LIMIT_EXCL_CMPR;
  421     if (exclusive) {
  422         args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_EXCL;
  423         args.lim.max_exclusive = size;
  424     } else {
  425         args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_RFER;
  426         args.lim.max_referenced = size;
  427     }
  428 
  429     if (argc - optind == 2) {
  430         args.qgroupid = 0;
  431         path = argv[optind + 1];
  432         err = btrfs_util_is_subvolume(path);
  433         if (err) {
  434             error_btrfs_util(err);
  435             return 1;
  436         }
  437         /*
  438          * keep qgroupid at 0, this indicates that the subvolume the
  439          * fd refers to is to be limited
  440          */
  441     } else if (argc - optind == 3) {
  442         args.qgroupid = parse_qgroupid(argv[optind + 1]);
  443         path = argv[optind + 2];
  444     } else
  445         usage(cmd);
  446 
  447     fd = btrfs_open_dir(path, &dirstream, 1);
  448     if (fd < 0)
  449         return 1;
  450 
  451     ret = ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args);
  452     close_file_or_dir(fd, dirstream);
  453     if (ret < 0) {
  454         error("unable to limit requested quota group: %s",
  455                 errno == ENOTCONN ? "quota not enabled"
  456                         : strerror(errno));
  457 
  458         return 1;
  459     }
  460     return 0;
  461 }
  462 static DEFINE_SIMPLE_COMMAND(qgroup_limit, "limit");
  463 
  464 static const char qgroup_cmd_group_info[] =
  465 "manage quota groups";
  466 
  467 static const struct cmd_group qgroup_cmd_group = {
  468     qgroup_cmd_group_usage, qgroup_cmd_group_info, {
  469         &cmd_struct_qgroup_assign,
  470         &cmd_struct_qgroup_remove,
  471         &cmd_struct_qgroup_create,
  472         &cmd_struct_qgroup_destroy,
  473         &cmd_struct_qgroup_show,
  474         &cmd_struct_qgroup_limit,
  475         NULL
  476     }
  477 };
  478 
  479 DEFINE_GROUP_COMMAND_TOKEN(qgroup);