"Fossies" - the Fresh Open Source Software Archive

Member "btrfs-progs-v5.4/cmds/balance.c" (3 Dec 2019, 24681 Bytes) of package /linux/misc/btrfs-progs-v5.4.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 "balance.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: v5.3_vs_v5.4.

    1 /*
    2  * This program is free software; you can redistribute it and/or
    3  * modify it under the terms of the GNU General Public
    4  * License v2 as published by the Free Software Foundation.
    5  *
    6  * This program is distributed in the hope that it will be useful,
    7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    9  * General Public License for more details.
   10  *
   11  * You should have received a copy of the GNU General Public
   12  * License along with this program; if not, write to the
   13  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   14  * Boston, MA 021110-1307, USA.
   15  */
   16 
   17 #include <stdio.h>
   18 #include <stdlib.h>
   19 #include <string.h>
   20 #include <unistd.h>
   21 #include <getopt.h>
   22 #include <sys/ioctl.h>
   23 #include <sys/types.h>
   24 #include <sys/stat.h>
   25 #include <fcntl.h>
   26 #include <errno.h>
   27 
   28 #include "kerncompat.h"
   29 #include "ctree.h"
   30 #include "ioctl.h"
   31 #include "volumes.h"
   32 
   33 #include "cmds/commands.h"
   34 #include "common/utils.h"
   35 #include "common/help.h"
   36 
   37 static const char * const balance_cmd_group_usage[] = {
   38     "btrfs balance <command> [options] <path>",
   39     "btrfs balance <path>",
   40     NULL
   41 };
   42 
   43 static int parse_one_profile(const char *profile, u64 *flags)
   44 {
   45     if (!strcmp(profile, "raid0")) {
   46         *flags |= BTRFS_BLOCK_GROUP_RAID0;
   47     } else if (!strcmp(profile, "raid1")) {
   48         *flags |= BTRFS_BLOCK_GROUP_RAID1;
   49     } else if (!strcmp(profile, "raid1c3")) {
   50         *flags |= BTRFS_BLOCK_GROUP_RAID1C3;
   51     } else if (!strcmp(profile, "raid1c4")) {
   52         *flags |= BTRFS_BLOCK_GROUP_RAID1C4;
   53     } else if (!strcmp(profile, "raid10")) {
   54         *flags |= BTRFS_BLOCK_GROUP_RAID10;
   55     } else if (!strcmp(profile, "raid5")) {
   56         *flags |= BTRFS_BLOCK_GROUP_RAID5;
   57     } else if (!strcmp(profile, "raid6")) {
   58         *flags |= BTRFS_BLOCK_GROUP_RAID6;
   59     } else if (!strcmp(profile, "dup")) {
   60         *flags |= BTRFS_BLOCK_GROUP_DUP;
   61     } else if (!strcmp(profile, "single")) {
   62         *flags |= BTRFS_AVAIL_ALLOC_BIT_SINGLE;
   63     } else {
   64         error("unknown profile: %s", profile);
   65         return 1;
   66     }
   67 
   68     return 0;
   69 }
   70 
   71 static int parse_profiles(char *profiles, u64 *flags)
   72 {
   73     char *this_char;
   74     char *save_ptr = NULL; /* Satisfy static checkers */
   75 
   76     for (this_char = strtok_r(profiles, "|", &save_ptr);
   77          this_char != NULL;
   78          this_char = strtok_r(NULL, "|", &save_ptr)) {
   79         if (parse_one_profile(this_char, flags))
   80             return 1;
   81     }
   82 
   83     return 0;
   84 }
   85 
   86 static int parse_u64(const char *str, u64 *result)
   87 {
   88     char *endptr;
   89     u64 val;
   90 
   91     val = strtoull(str, &endptr, 10);
   92     if (*endptr)
   93         return 1;
   94 
   95     *result = val;
   96     return 0;
   97 }
   98 
   99 /*
  100  * Parse range that's missing some part that can be implicit:
  101  * a..b - exact range, a can be equal to b
  102  * a..  - implicitly unbounded maximum (end == (u64)-1)
  103  * ..b  - implicitly starting at 0
  104  * a    - invalid; unclear semantics, use parse_u64 instead
  105  *
  106  * Returned values are u64, value validation and interpretation should be done
  107  * by the caller.
  108  */
  109 static int parse_range(const char *range, u64 *start, u64 *end)
  110 {
  111     char *dots;
  112     char *endptr;
  113     const char *rest;
  114     int skipped = 0;
  115 
  116     dots = strstr(range, "..");
  117     if (!dots)
  118         return 1;
  119 
  120     rest = dots + 2;
  121 
  122     if (!*rest) {
  123         *end = (u64)-1;
  124         skipped++;
  125     } else {
  126         *end = strtoull(rest, &endptr, 10);
  127         if (*endptr)
  128             return 1;
  129     }
  130     if (dots == range) {
  131         *start = 0;
  132         skipped++;
  133     } else {
  134         *start = strtoull(range, &endptr, 10);
  135         if (*endptr != 0 && *endptr != '.')
  136             return 1;
  137     }
  138 
  139     if (*start > *end) {
  140         error("range %llu..%llu doesn't make sense",
  141             (unsigned long long)*start,
  142             (unsigned long long)*end);
  143         return 1;
  144     }
  145 
  146     if (skipped <= 1)
  147         return 0;
  148 
  149     return 1;
  150 }
  151 
  152 /*
  153  * Parse range and check if start < end
  154  */
  155 static int parse_range_strict(const char *range, u64 *start, u64 *end)
  156 {
  157     if (parse_range(range, start, end) == 0) {
  158         if (*start >= *end) {
  159             error("range %llu..%llu not allowed",
  160                 (unsigned long long)*start,
  161                 (unsigned long long)*end);
  162             return 1;
  163         }
  164         return 0;
  165     }
  166 
  167     return 1;
  168 }
  169 
  170 /*
  171  * Convert 64bit range to 32bit with boundary checks
  172  */
  173 static int range_to_u32(u64 start, u64 end, u32 *start32, u32 *end32)
  174 {
  175     if (start > (u32)-1)
  176         return 1;
  177 
  178     if (end != (u64)-1 && end > (u32)-1)
  179         return 1;
  180 
  181     *start32 = (u32)start;
  182     *end32 = (u32)end;
  183 
  184     return 0;
  185 }
  186 
  187 __attribute__ ((unused))
  188 static int parse_range_u32(const char *range, u32 *start, u32 *end)
  189 {
  190     u64 tmp_start;
  191     u64 tmp_end;
  192 
  193     if (parse_range(range, &tmp_start, &tmp_end))
  194         return 1;
  195 
  196     if (range_to_u32(tmp_start, tmp_end, start, end))
  197         return 1;
  198 
  199     return 0;
  200 }
  201 
  202 __attribute__ ((unused))
  203 static void print_range(u64 start, u64 end)
  204 {
  205     if (start)
  206         printf("%llu", (unsigned long long)start);
  207     printf("..");
  208     if (end != (u64)-1)
  209         printf("%llu", (unsigned long long)end);
  210 }
  211 
  212 __attribute__ ((unused))
  213 static void print_range_u32(u32 start, u32 end)
  214 {
  215     if (start)
  216         printf("%u", start);
  217     printf("..");
  218     if (end != (u32)-1)
  219         printf("%u", end);
  220 }
  221 
  222 static int parse_filters(char *filters, struct btrfs_balance_args *args)
  223 {
  224     char *this_char;
  225     char *value;
  226     char *save_ptr = NULL; /* Satisfy static checkers */
  227 
  228     if (!filters)
  229         return 0;
  230 
  231     for (this_char = strtok_r(filters, ",", &save_ptr);
  232          this_char != NULL;
  233          this_char = strtok_r(NULL, ",", &save_ptr)) {
  234         if ((value = strchr(this_char, '=')) != NULL)
  235             *value++ = 0;
  236         if (!strcmp(this_char, "profiles")) {
  237             if (!value || !*value) {
  238                 error("the profiles filter requires an argument");
  239                 return 1;
  240             }
  241             if (parse_profiles(value, &args->profiles)) {
  242                 error("invalid profiles argument");
  243                 return 1;
  244             }
  245             args->flags |= BTRFS_BALANCE_ARGS_PROFILES;
  246         } else if (!strcmp(this_char, "usage")) {
  247             if (!value || !*value) {
  248                 error("the usage filter requires an argument");
  249                 return 1;
  250             }
  251             if (parse_u64(value, &args->usage)) {
  252                 if (parse_range_u32(value, &args->usage_min,
  253                             &args->usage_max)) {
  254                     error("invalid usage argument: %s",
  255                         value);
  256                     return 1;
  257                 }
  258                 if (args->usage_max > 100) {
  259                     error("invalid usage argument: %s",
  260                         value);
  261                 }
  262                 args->flags &= ~BTRFS_BALANCE_ARGS_USAGE;
  263                 args->flags |= BTRFS_BALANCE_ARGS_USAGE_RANGE;
  264             } else {
  265                 if (args->usage > 100) {
  266                     error("invalid usage argument: %s",
  267                         value);
  268                     return 1;
  269                 }
  270                 args->flags &= ~BTRFS_BALANCE_ARGS_USAGE_RANGE;
  271                 args->flags |= BTRFS_BALANCE_ARGS_USAGE;
  272             }
  273             args->flags |= BTRFS_BALANCE_ARGS_USAGE;
  274         } else if (!strcmp(this_char, "devid")) {
  275             if (!value || !*value) {
  276                 error("the devid filter requires an argument");
  277                 return 1;
  278             }
  279             if (parse_u64(value, &args->devid) || args->devid == 0) {
  280                 error("invalid devid argument: %s", value);
  281                 return 1;
  282             }
  283             args->flags |= BTRFS_BALANCE_ARGS_DEVID;
  284         } else if (!strcmp(this_char, "drange")) {
  285             if (!value || !*value) {
  286                 error("the drange filter requires an argument");
  287                 return 1;
  288             }
  289             if (parse_range_strict(value, &args->pstart, &args->pend)) {
  290                 error("invalid drange argument");
  291                 return 1;
  292             }
  293             args->flags |= BTRFS_BALANCE_ARGS_DRANGE;
  294         } else if (!strcmp(this_char, "vrange")) {
  295             if (!value || !*value) {
  296                 error("the vrange filter requires an argument");
  297                 return 1;
  298             }
  299             if (parse_range_strict(value, &args->vstart, &args->vend)) {
  300                 error("invalid vrange argument");
  301                 return 1;
  302             }
  303             args->flags |= BTRFS_BALANCE_ARGS_VRANGE;
  304         } else if (!strcmp(this_char, "convert")) {
  305             if (!value || !*value) {
  306                 error("the convert option requires an argument");
  307                 return 1;
  308             }
  309             if (parse_one_profile(value, &args->target)) {
  310                 error("invalid convert argument");
  311                 return 1;
  312             }
  313             args->flags |= BTRFS_BALANCE_ARGS_CONVERT;
  314         } else if (!strcmp(this_char, "soft")) {
  315             args->flags |= BTRFS_BALANCE_ARGS_SOFT;
  316         } else if (!strcmp(this_char, "limit")) {
  317             if (!value || !*value) {
  318                 error("the limit filter requires an argument");
  319                 return 1;
  320             }
  321             if (parse_u64(value, &args->limit)) {
  322                 if (parse_range_u32(value, &args->limit_min,
  323                             &args->limit_max)) {
  324                     error("Invalid limit argument: %s",
  325                            value);
  326                     return 1;
  327                 }
  328                 args->flags &= ~BTRFS_BALANCE_ARGS_LIMIT;
  329                 args->flags |= BTRFS_BALANCE_ARGS_LIMIT_RANGE;
  330             } else {
  331                 args->flags &= ~BTRFS_BALANCE_ARGS_LIMIT_RANGE;
  332                 args->flags |= BTRFS_BALANCE_ARGS_LIMIT;
  333             }
  334         } else if (!strcmp(this_char, "stripes")) {
  335             if (!value || !*value) {
  336                 error("the stripes filter requires an argument");
  337                 return 1;
  338             }
  339             if (parse_range_u32(value, &args->stripes_min,
  340                         &args->stripes_max)) {
  341                 error("invalid stripes argument");
  342                 return 1;
  343             }
  344             args->flags |= BTRFS_BALANCE_ARGS_STRIPES_RANGE;
  345         } else {
  346             error("unrecognized balance option: %s", this_char);
  347             return 1;
  348         }
  349     }
  350 
  351     return 0;
  352 }
  353 
  354 static void dump_balance_args(struct btrfs_balance_args *args)
  355 {
  356     if (args->flags & BTRFS_BALANCE_ARGS_CONVERT) {
  357         printf("converting, target=%llu, soft is %s",
  358                (unsigned long long)args->target,
  359                (args->flags & BTRFS_BALANCE_ARGS_SOFT) ? "on" : "off");
  360     } else {
  361         printf("balancing");
  362     }
  363 
  364     if (args->flags & BTRFS_BALANCE_ARGS_PROFILES)
  365         printf(", profiles=%llu", (unsigned long long)args->profiles);
  366     if (args->flags & BTRFS_BALANCE_ARGS_USAGE)
  367         printf(", usage=%llu", (unsigned long long)args->usage);
  368     if (args->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) {
  369         printf(", usage=");
  370         print_range_u32(args->usage_min, args->usage_max);
  371     }
  372     if (args->flags & BTRFS_BALANCE_ARGS_DEVID)
  373         printf(", devid=%llu", (unsigned long long)args->devid);
  374     if (args->flags & BTRFS_BALANCE_ARGS_DRANGE)
  375         printf(", drange=%llu..%llu",
  376                (unsigned long long)args->pstart,
  377                (unsigned long long)args->pend);
  378     if (args->flags & BTRFS_BALANCE_ARGS_VRANGE)
  379         printf(", vrange=%llu..%llu",
  380                (unsigned long long)args->vstart,
  381                (unsigned long long)args->vend);
  382     if (args->flags & BTRFS_BALANCE_ARGS_LIMIT)
  383         printf(", limit=%llu", (unsigned long long)args->limit);
  384     if (args->flags & BTRFS_BALANCE_ARGS_LIMIT_RANGE) {
  385         printf(", limit=");
  386         print_range_u32(args->limit_min, args->limit_max);
  387     }
  388     if (args->flags & BTRFS_BALANCE_ARGS_STRIPES_RANGE) {
  389         printf(", stripes=");
  390         print_range_u32(args->stripes_min, args->stripes_max);
  391     }
  392 
  393     printf("\n");
  394 }
  395 
  396 static void dump_ioctl_balance_args(struct btrfs_ioctl_balance_args *args)
  397 {
  398     printf("Dumping filters: flags 0x%llx, state 0x%llx, force is %s\n",
  399            (unsigned long long)args->flags, (unsigned long long)args->state,
  400            (args->flags & BTRFS_BALANCE_FORCE) ? "on" : "off");
  401     if (args->flags & BTRFS_BALANCE_DATA) {
  402         printf("  DATA (flags 0x%llx): ",
  403                (unsigned long long)args->data.flags);
  404         dump_balance_args(&args->data);
  405     }
  406     if (args->flags & BTRFS_BALANCE_METADATA) {
  407         printf("  METADATA (flags 0x%llx): ",
  408                (unsigned long long)args->meta.flags);
  409         dump_balance_args(&args->meta);
  410     }
  411     if (args->flags & BTRFS_BALANCE_SYSTEM) {
  412         printf("  SYSTEM (flags 0x%llx): ",
  413                (unsigned long long)args->sys.flags);
  414         dump_balance_args(&args->sys);
  415     }
  416 }
  417 
  418 static int do_balance_v1(int fd)
  419 {
  420     struct btrfs_ioctl_vol_args args;
  421     int ret;
  422 
  423     memset(&args, 0, sizeof(args));
  424     ret = ioctl(fd, BTRFS_IOC_BALANCE, &args);
  425     return ret;
  426 }
  427 
  428 enum {
  429     BALANCE_START_FILTERS = 1 << 0,
  430     BALANCE_START_NOWARN  = 1 << 1
  431 };
  432 
  433 static int do_balance(const char *path, struct btrfs_ioctl_balance_args *args,
  434               unsigned flags)
  435 {
  436     int fd;
  437     int ret;
  438     DIR *dirstream = NULL;
  439 
  440     fd = btrfs_open_dir(path, &dirstream, 1);
  441     if (fd < 0)
  442         return 1;
  443 
  444     ret = ioctl(fd, BTRFS_IOC_BALANCE_V2, args);
  445     if (ret < 0) {
  446         /*
  447          * older kernels don't have the new balance ioctl, try the
  448          * old one.  But, the old one doesn't know any filters, so
  449          * don't fall back if they tried to use the fancy new things
  450          */
  451         if (errno == ENOTTY && !(flags & BALANCE_START_FILTERS)) {
  452             ret = do_balance_v1(fd);
  453             if (ret == 0)
  454                 goto out;
  455         }
  456 
  457         if (errno == ECANCELED) {
  458             if (args->state & BTRFS_BALANCE_STATE_PAUSE_REQ)
  459                 fprintf(stderr, "balance paused by user\n");
  460             if (args->state & BTRFS_BALANCE_STATE_CANCEL_REQ)
  461                 fprintf(stderr, "balance canceled by user\n");
  462             ret = 0;
  463         } else {
  464             error("error during balancing '%s': %m", path);
  465             if (errno != EINPROGRESS)
  466                 fprintf(stderr,
  467             "There may be more info in syslog - try dmesg | tail\n");
  468             ret = 1;
  469         }
  470     } else if (ret > 0) {
  471         error("balance: %s", btrfs_err_str(ret));
  472     } else {
  473         printf("Done, had to relocate %llu out of %llu chunks\n",
  474                (unsigned long long)args->stat.completed,
  475                (unsigned long long)args->stat.considered);
  476     }
  477 
  478 out:
  479     close_file_or_dir(fd, dirstream);
  480     return ret;
  481 }
  482 
  483 static const char * const cmd_balance_start_usage[] = {
  484     "btrfs balance start [options] <path>",
  485     "Balance chunks across the devices",
  486     "Balance and/or convert (change allocation profile of) chunks that",
  487     "passed all filters in a comma-separated list of filters for a",
  488     "particular chunk type.  If filter list is not given balance all",
  489     "chunks of that type.  In case none of the -d, -m or -s options is",
  490     "given balance all chunks in a filesystem. This is potentially",
  491     "long operation and the user is warned before this start, with",
  492     "a delay to stop it.",
  493     "",
  494     "-d[filters]    act on data chunks",
  495     "-m[filters]    act on metadata chunks",
  496     "-s[filters]    act on system chunks (only under -f)",
  497     "-v|--verbose   be verbose",
  498     "-f             force a reduction of metadata integrity",
  499     "--full-balance do not print warning and do not delay start",
  500     "--background|--bg",
  501     "               run the balance as a background process",
  502     NULL
  503 };
  504 
  505 static int cmd_balance_start(const struct cmd_struct *cmd,
  506                  int argc, char **argv)
  507 {
  508     struct btrfs_ioctl_balance_args args;
  509     struct btrfs_balance_args *ptrs[] = { &args.data, &args.sys,
  510                         &args.meta, NULL };
  511     int force = 0;
  512     int verbose = 0;
  513     int background = 0;
  514     unsigned start_flags = 0;
  515     int i;
  516 
  517     memset(&args, 0, sizeof(args));
  518 
  519     optind = 0;
  520     while (1) {
  521         enum { GETOPT_VAL_FULL_BALANCE = 256,
  522             GETOPT_VAL_BACKGROUND = 257 };
  523         static const struct option longopts[] = {
  524             { "data", optional_argument, NULL, 'd'},
  525             { "metadata", optional_argument, NULL, 'm' },
  526             { "system", optional_argument, NULL, 's' },
  527             { "force", no_argument, NULL, 'f' },
  528             { "verbose", no_argument, NULL, 'v' },
  529             { "full-balance", no_argument, NULL,
  530                 GETOPT_VAL_FULL_BALANCE },
  531             { "background", no_argument, NULL,
  532                 GETOPT_VAL_BACKGROUND },
  533             { "bg", no_argument, NULL, GETOPT_VAL_BACKGROUND },
  534             { NULL, 0, NULL, 0 }
  535         };
  536 
  537         int opt = getopt_long(argc, argv, "d::s::m::fv", longopts, NULL);
  538         if (opt < 0)
  539             break;
  540 
  541         switch (opt) {
  542         case 'd':
  543             start_flags |= BALANCE_START_FILTERS;
  544             args.flags |= BTRFS_BALANCE_DATA;
  545 
  546             if (parse_filters(optarg, &args.data))
  547                 return 1;
  548             break;
  549         case 's':
  550             start_flags |= BALANCE_START_FILTERS;
  551             args.flags |= BTRFS_BALANCE_SYSTEM;
  552 
  553             if (parse_filters(optarg, &args.sys))
  554                 return 1;
  555             break;
  556         case 'm':
  557             start_flags |= BALANCE_START_FILTERS;
  558             args.flags |= BTRFS_BALANCE_METADATA;
  559 
  560             if (parse_filters(optarg, &args.meta))
  561                 return 1;
  562             break;
  563         case 'f':
  564             force = 1;
  565             break;
  566         case 'v':
  567             verbose = 1;
  568             break;
  569         case GETOPT_VAL_FULL_BALANCE:
  570             start_flags |= BALANCE_START_NOWARN;
  571             break;
  572         case GETOPT_VAL_BACKGROUND:
  573             background = 1;
  574             break;
  575         default:
  576             usage_unknown_option(cmd, argv);
  577         }
  578     }
  579 
  580     if (check_argc_exact(argc - optind, 1))
  581         return 1;
  582 
  583     /*
  584      * allow -s only under --force, otherwise do with system chunks
  585      * the same thing we were ordered to do with meta chunks
  586      */
  587     if (args.flags & BTRFS_BALANCE_SYSTEM) {
  588         if (!force) {
  589             error(
  590                 "Refusing to explicitly operate on system chunks.\n"
  591                 "Pass --force if you really want to do that.");
  592             return 1;
  593         }
  594     } else if (args.flags & BTRFS_BALANCE_METADATA) {
  595         args.flags |= BTRFS_BALANCE_SYSTEM;
  596         memcpy(&args.sys, &args.meta,
  597             sizeof(struct btrfs_balance_args));
  598     }
  599 
  600     if (!(start_flags & BALANCE_START_FILTERS)) {
  601         /* relocate everything - no filters */
  602         args.flags |= BTRFS_BALANCE_TYPE_MASK;
  603     }
  604 
  605     /* drange makes sense only when devid is set */
  606     for (i = 0; ptrs[i]; i++) {
  607         if ((ptrs[i]->flags & BTRFS_BALANCE_ARGS_DRANGE) &&
  608             !(ptrs[i]->flags & BTRFS_BALANCE_ARGS_DEVID)) {
  609             error("drange filter must be used with devid filter");
  610             return 1;
  611         }
  612     }
  613 
  614     /* soft makes sense only when convert for corresponding type is set */
  615     for (i = 0; ptrs[i]; i++) {
  616         if ((ptrs[i]->flags & BTRFS_BALANCE_ARGS_SOFT) &&
  617             !(ptrs[i]->flags & BTRFS_BALANCE_ARGS_CONVERT)) {
  618             error("'soft' option can be used only when converting profiles");
  619             return 1;
  620         }
  621     }
  622 
  623     if (!(start_flags & BALANCE_START_FILTERS) && !(start_flags & BALANCE_START_NOWARN)) {
  624         int delay = 10;
  625 
  626         printf("WARNING:\n\n");
  627         printf("\tFull balance without filters requested. This operation is very\n");
  628         printf("\tintense and takes potentially very long. It is recommended to\n");
  629         printf("\tuse the balance filters to narrow down the scope of balance.\n");
  630         printf("\tUse 'btrfs balance start --full-balance' option to skip this\n");
  631         printf("\twarning. The operation will start in %d seconds.\n", delay);
  632         printf("\tUse Ctrl-C to stop it.\n");
  633         while (delay) {
  634             printf("%2d", delay--);
  635             fflush(stdout);
  636             sleep(1);
  637         }
  638         printf("\nStarting balance without any filters.\n");
  639     }
  640 
  641     if (force)
  642         args.flags |= BTRFS_BALANCE_FORCE;
  643     if (verbose)
  644         dump_ioctl_balance_args(&args);
  645     if (background) {
  646         switch (fork()) {
  647         case (-1):
  648             error("unable to fork to run balance in background");
  649             return 1;
  650         case (0):
  651             setsid();
  652             switch(fork()) {
  653             case (-1):
  654                 error(
  655                 "unable to fork to run balance in background");
  656                 exit(1);
  657             case (0):
  658                 /*
  659                  * Read the return value to silence compiler
  660                  * warning. Change to / should succeed and
  661                  * we're not in a security-sensitive context.
  662                  */
  663                 i = chdir("/");
  664                 close(0);
  665                 close(1);
  666                 close(2);
  667                 open("/dev/null", O_RDONLY);
  668                 open("/dev/null", O_WRONLY);
  669                 open("/dev/null", O_WRONLY);
  670                 break;
  671             default:
  672                 exit(0);
  673             }
  674             break;
  675         default:
  676             exit(0);
  677         }
  678     }
  679 
  680     return do_balance(argv[optind], &args, start_flags);
  681 }
  682 static DEFINE_SIMPLE_COMMAND(balance_start, "start");
  683 
  684 static const char * const cmd_balance_pause_usage[] = {
  685     "btrfs balance pause <path>",
  686     "Pause running balance",
  687     NULL
  688 };
  689 
  690 static int cmd_balance_pause(const struct cmd_struct *cmd,
  691                  int argc, char **argv)
  692 {
  693     const char *path;
  694     int fd;
  695     int ret;
  696     DIR *dirstream = NULL;
  697 
  698     clean_args_no_options(cmd, argc, argv);
  699 
  700     if (check_argc_exact(argc - optind, 1))
  701         return 1;
  702 
  703     path = argv[optind];
  704 
  705     fd = btrfs_open_dir(path, &dirstream, 1);
  706     if (fd < 0)
  707         return 1;
  708 
  709     ret = ioctl(fd, BTRFS_IOC_BALANCE_CTL, BTRFS_BALANCE_CTL_PAUSE);
  710     if (ret < 0) {
  711         error("balance pause on '%s' failed: %s", path,
  712             (errno == ENOTCONN) ? "Not running" : strerror(errno));
  713         if (errno == ENOTCONN)
  714             ret = 2;
  715         else
  716             ret = 1;
  717     }
  718 
  719     close_file_or_dir(fd, dirstream);
  720     return ret;
  721 }
  722 static DEFINE_SIMPLE_COMMAND(balance_pause, "pause");
  723 
  724 static const char * const cmd_balance_cancel_usage[] = {
  725     "btrfs balance cancel <path>",
  726     "Cancel running or paused balance",
  727     NULL
  728 };
  729 
  730 static int cmd_balance_cancel(const struct cmd_struct *cmd,
  731                   int argc, char **argv)
  732 {
  733     const char *path;
  734     int fd;
  735     int ret;
  736     DIR *dirstream = NULL;
  737 
  738     clean_args_no_options(cmd, argc, argv);
  739 
  740     if (check_argc_exact(argc - optind, 1))
  741         return 1;
  742 
  743     path = argv[optind];
  744 
  745     fd = btrfs_open_dir(path, &dirstream, 1);
  746     if (fd < 0)
  747         return 1;
  748 
  749     ret = ioctl(fd, BTRFS_IOC_BALANCE_CTL, BTRFS_BALANCE_CTL_CANCEL);
  750     if (ret < 0) {
  751         error("balance cancel on '%s' failed: %s", path,
  752             (errno == ENOTCONN) ? "Not in progress" : strerror(errno));
  753         if (errno == ENOTCONN)
  754             ret = 2;
  755         else
  756             ret = 1;
  757     }
  758 
  759     close_file_or_dir(fd, dirstream);
  760     return ret;
  761 }
  762 static DEFINE_SIMPLE_COMMAND(balance_cancel, "cancel");
  763 
  764 static const char * const cmd_balance_resume_usage[] = {
  765     "btrfs balance resume <path>",
  766     "Resume interrupted balance",
  767     NULL
  768 };
  769 
  770 static int cmd_balance_resume(const struct cmd_struct *cmd,
  771                   int argc, char **argv)
  772 {
  773     struct btrfs_ioctl_balance_args args;
  774     const char *path;
  775     DIR *dirstream = NULL;
  776     int fd;
  777     int ret;
  778 
  779     clean_args_no_options(cmd, argc, argv);
  780 
  781     if (check_argc_exact(argc - optind, 1))
  782         return 1;
  783 
  784     path = argv[optind];
  785 
  786     fd = btrfs_open_dir(path, &dirstream, 1);
  787     if (fd < 0)
  788         return 1;
  789 
  790     memset(&args, 0, sizeof(args));
  791     args.flags |= BTRFS_BALANCE_RESUME;
  792 
  793     ret = ioctl(fd, BTRFS_IOC_BALANCE_V2, &args);
  794     if (ret < 0) {
  795         if (errno == ECANCELED) {
  796             if (args.state & BTRFS_BALANCE_STATE_PAUSE_REQ)
  797                 fprintf(stderr, "balance paused by user\n");
  798             if (args.state & BTRFS_BALANCE_STATE_CANCEL_REQ)
  799                 fprintf(stderr, "balance canceled by user\n");
  800         } else if (errno == ENOTCONN || errno == EINPROGRESS) {
  801             error("balance resume on '%s' failed: %s", path,
  802                 (errno == ENOTCONN) ? "Not in progress" :
  803                           "Already running");
  804             if (errno == ENOTCONN)
  805                 ret = 2;
  806             else
  807                 ret = 1;
  808         } else {
  809             error("error during balancing '%s': %m\n"
  810               "There may be more info in syslog - try dmesg | tail",
  811                 path);
  812             ret = 1;
  813         }
  814     } else {
  815         printf("Done, had to relocate %llu out of %llu chunks\n",
  816                (unsigned long long)args.stat.completed,
  817                (unsigned long long)args.stat.considered);
  818     }
  819 
  820     close_file_or_dir(fd, dirstream);
  821     return ret;
  822 }
  823 static DEFINE_SIMPLE_COMMAND(balance_resume, "resume");
  824 
  825 static const char * const cmd_balance_status_usage[] = {
  826     "btrfs balance status [-v] <path>",
  827     "Show status of running or paused balance",
  828     "",
  829     "-v|--verbose     be verbose",
  830     NULL
  831 };
  832 
  833 /* Checks the status of the balance if any
  834  * return codes:
  835  *   2 : Error failed to know if there is any pending balance
  836  *   1 : Successful to know status of a pending balance
  837  *   0 : When there is no pending balance or completed
  838  */
  839 static int cmd_balance_status(const struct cmd_struct *cmd,
  840                   int argc, char **argv)
  841 {
  842     struct btrfs_ioctl_balance_args args;
  843     const char *path;
  844     DIR *dirstream = NULL;
  845     int fd;
  846     int verbose = 0;
  847     int ret;
  848 
  849     optind = 0;
  850     while (1) {
  851         int opt;
  852         static const struct option longopts[] = {
  853             { "verbose", no_argument, NULL, 'v' },
  854             { NULL, 0, NULL, 0 }
  855         };
  856 
  857         opt = getopt_long(argc, argv, "v", longopts, NULL);
  858         if (opt < 0)
  859             break;
  860 
  861         switch (opt) {
  862         case 'v':
  863             verbose = 1;
  864             break;
  865         default:
  866             usage_unknown_option(cmd, argv);
  867         }
  868     }
  869 
  870     if (check_argc_exact(argc - optind, 1))
  871         return 1;
  872 
  873     path = argv[optind];
  874 
  875     fd = btrfs_open_dir(path, &dirstream, 1);
  876     if (fd < 0)
  877         return 2;
  878 
  879     ret = ioctl(fd, BTRFS_IOC_BALANCE_PROGRESS, &args);
  880     if (ret < 0) {
  881         if (errno == ENOTCONN) {
  882             printf("No balance found on '%s'\n", path);
  883             ret = 0;
  884             goto out;
  885         }
  886         error("balance status on '%s' failed: %m", path);
  887         ret = 2;
  888         goto out;
  889     }
  890 
  891     if (args.state & BTRFS_BALANCE_STATE_RUNNING) {
  892         printf("Balance on '%s' is running", path);
  893         if (args.state & BTRFS_BALANCE_STATE_CANCEL_REQ)
  894             printf(", cancel requested\n");
  895         else if (args.state & BTRFS_BALANCE_STATE_PAUSE_REQ)
  896             printf(", pause requested\n");
  897         else
  898             printf("\n");
  899     } else {
  900         printf("Balance on '%s' is paused\n", path);
  901     }
  902 
  903     printf("%llu out of about %llu chunks balanced (%llu considered), "
  904            "%3.f%% left\n", (unsigned long long)args.stat.completed,
  905            (unsigned long long)args.stat.expected,
  906            (unsigned long long)args.stat.considered,
  907            100 * (1 - (float)args.stat.completed/args.stat.expected));
  908 
  909     if (verbose)
  910         dump_ioctl_balance_args(&args);
  911 
  912     ret = 1;
  913 out:
  914     close_file_or_dir(fd, dirstream);
  915     return ret;
  916 }
  917 static DEFINE_SIMPLE_COMMAND(balance_status, "status");
  918 
  919 static int cmd_balance_full(const struct cmd_struct *cmd, int argc, char **argv)
  920 {
  921     struct btrfs_ioctl_balance_args args;
  922 
  923     memset(&args, 0, sizeof(args));
  924     args.flags |= BTRFS_BALANCE_TYPE_MASK;
  925 
  926     return do_balance(argv[1], &args, BALANCE_START_NOWARN);
  927 }
  928 static DEFINE_COMMAND(balance_full, "--full-balance", cmd_balance_full,
  929               NULL, NULL, CMD_HIDDEN);
  930 
  931 static const char balance_cmd_group_info[] =
  932 "balance data across devices, or change block groups using filters";
  933 
  934 static const struct cmd_group balance_cmd_group = {
  935     balance_cmd_group_usage, balance_cmd_group_info, {
  936         &cmd_struct_balance_start,
  937         &cmd_struct_balance_pause,
  938         &cmd_struct_balance_cancel,
  939         &cmd_struct_balance_resume,
  940         &cmd_struct_balance_status,
  941         &cmd_struct_balance_full,
  942         NULL
  943     }
  944 };
  945 
  946 static int cmd_balance(const struct cmd_struct *cmd, int argc, char **argv)
  947 {
  948     if (argc == 2 && strcmp("start", argv[1]) != 0) {
  949         /* old 'btrfs filesystem balance <path>' syntax */
  950         struct btrfs_ioctl_balance_args args;
  951 
  952         memset(&args, 0, sizeof(args));
  953         args.flags |= BTRFS_BALANCE_TYPE_MASK;
  954 
  955         return do_balance(argv[1], &args, 0);
  956     }
  957 
  958     return handle_command_group(cmd, argc, argv);
  959 }
  960 
  961 DEFINE_COMMAND(balance, "balance", cmd_balance, NULL, &balance_cmd_group, 0);