Btrfs-progs: enhance btrfs qgroup to print the result as a table
[platform/upstream/btrfs-progs.git] / cmds-qgroup.c
index ff2a1fa..4fe776c 100644 (file)
@@ -106,95 +106,6 @@ static int qgroup_create(int create, int argc, char **argv)
        return 0;
 }
 
-static void print_qgroup_info(u64 objectid, struct btrfs_qgroup_info_item *info)
-{
-       printf("%llu/%llu %lld %lld\n", objectid >> 48,
-               objectid & ((1ll << 48) - 1),
-               btrfs_stack_qgroup_info_referenced(info),
-               btrfs_stack_qgroup_info_exclusive(info));
-}
-
-static int list_qgroups(int fd)
-{
-       int ret;
-       struct btrfs_ioctl_search_args args;
-       struct btrfs_ioctl_search_key *sk = &args.key;
-       struct btrfs_ioctl_search_header *sh;
-       unsigned long off = 0;
-       unsigned int i;
-       struct btrfs_qgroup_info_item *info;
-
-       memset(&args, 0, sizeof(args));
-
-       /* search in the quota tree */
-       sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
-
-       /*
-        * set the min and max to backref keys.  The search will
-        * only send back this type of key now.
-        */
-       sk->max_type = BTRFS_QGROUP_INFO_KEY;
-       sk->min_type = BTRFS_QGROUP_INFO_KEY;
-       sk->max_objectid = 0;
-       sk->max_offset = (u64)-1;
-       sk->max_transid = (u64)-1;
-
-       /* just a big number, doesn't matter much */
-       sk->nr_items = 4096;
-
-       while (1) {
-               ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
-               if (ret < 0)
-                       return ret;
-
-               /* the ioctl returns the number of item it found in nr_items */
-               if (sk->nr_items == 0)
-                       break;
-
-               off = 0;
-
-               /*
-                * for each item, pull the key out of the header and then
-                * read the root_ref item it contains
-                */
-               for (i = 0; i < sk->nr_items; i++) {
-                       sh = (struct btrfs_ioctl_search_header *)(args.buf +
-                                                                 off);
-                       off += sizeof(*sh);
-
-                       if (sh->objectid != 0)
-                               goto done;
-
-                       if (sh->type != BTRFS_QGROUP_INFO_KEY)
-                               goto done;
-
-                       info = (struct btrfs_qgroup_info_item *)
-                                       (args.buf + off);
-                       print_qgroup_info(sh->offset, info);
-
-                       off += sh->len;
-
-                       /*
-                        * record the mins in sk so we can make sure the
-                        * next search doesn't repeat this root
-                        */
-                       sk->min_offset = sh->offset;
-               }
-               sk->nr_items = 4096;
-               /*
-                * this iteration is done, step forward one qgroup for the next
-                * ioctl
-                */
-               if (sk->min_offset < (u64)-1)
-                       sk->min_offset++;
-               else
-                       break;
-       }
-
-done:
-       return ret;
-}
-
 static int parse_limit(const char *p, unsigned long long *s)
 {
        char *endptr;
@@ -291,29 +202,106 @@ static int cmd_qgroup_destroy(int argc, char **argv)
 }
 
 static const char * const cmd_qgroup_show_usage[] = {
-       "btrfs qgroup show <path>",
-       "Show all subvolume quota groups.",
+       "btrfs qgroup show -pcreFf "
+       "[--sort=qgroupid,rfer,excl,max_rfer,max_excl] <path>",
+       "Show subvolume quota groups.",
+       "-p             print parent qgroup id",
+       "-c             print child qgroup id",
+       "-r             print max referenced size of qgroup",
+       "-e             print max exclusive size of qgroup",
+       "-F             list all qgroups which impact the given path"
+       "(include ancestral qgroups)",
+       "-f             list all qgroups which impact the given path"
+       "(exclude ancestral qgroups)",
+       "--sort=qgroupid,rfer,excl,max_rfer,max_excl",
+       "               list qgroups in order of qgroupid,"
+       "rfer,max_rfer or max_excl",
+       "               you can use '+' or '-' in front of each item.",
+       "               (+:ascending, -:descending, ascending default)",
        NULL
 };
 
 static int cmd_qgroup_show(int argc, char **argv)
 {
+       char *path;
        int ret = 0;
        int fd;
        int e;
-       char *path = argv[1];
        DIR *dirstream = NULL;
+       int c;
+       u64 qgroupid;
+       int filter_flag = 0;
+
+       struct btrfs_qgroup_comparer_set *comparer_set;
+       struct btrfs_qgroup_filter_set *filter_set;
+       filter_set = btrfs_qgroup_alloc_filter_set();
+       comparer_set = btrfs_qgroup_alloc_comparer_set();
+       struct option long_options[] = {
+               {"sort", 1, NULL, 'S'},
+               {0, 0, 0, 0}
+       };
 
-       if (check_argc_exact(argc, 2))
+       optind = 1;
+       while (1) {
+               c = getopt_long(argc, argv, "pcreFf",
+                               long_options, NULL);
+               if (c < 0)
+                       break;
+               switch (c) {
+               case 'p':
+                       btrfs_qgroup_setup_print_column(
+                               BTRFS_QGROUP_PARENT);
+                       break;
+               case 'c':
+                       btrfs_qgroup_setup_print_column(
+                               BTRFS_QGROUP_CHILD);
+                       break;
+               case 'r':
+                       btrfs_qgroup_setup_print_column(
+                               BTRFS_QGROUP_MAX_RFER);
+                       break;
+               case 'e':
+                       btrfs_qgroup_setup_print_column(
+                               BTRFS_QGROUP_MAX_EXCL);
+                       break;
+               case 'F':
+                       filter_flag |= 0x1;
+                       break;
+               case 'f':
+                       filter_flag |= 0x2;
+                       break;
+               case 'S':
+                       ret = btrfs_qgroup_parse_sort_string(optarg,
+                                                            &comparer_set);
+                       if (ret)
+                               usage(cmd_qgroup_show_usage);
+                       break;
+               default:
+                       usage(cmd_qgroup_show_usage);
+               }
+       }
+       if (check_argc_exact(argc - optind, 1))
                usage(cmd_qgroup_show_usage);
 
+       path = argv[optind];
        fd = open_file_or_dir(path, &dirstream);
        if (fd < 0) {
                fprintf(stderr, "ERROR: can't access '%s'\n", path);
                return 1;
        }
 
-       ret = list_qgroups(fd);
+       if (filter_flag) {
+               qgroupid = btrfs_get_path_rootid(fd);
+               if (filter_flag & 0x1)
+                       btrfs_qgroup_setup_filter(&filter_set,
+                                       BTRFS_QGROUP_FILTER_ALL_PARENT,
+                                       qgroupid);
+               if (filter_flag & 0x2)
+                       btrfs_qgroup_setup_filter(&filter_set,
+                                       BTRFS_QGROUP_FILTER_PARENT,
+                                       qgroupid);
+       }
+       ret = btrfs_show_qgroups(fd, filter_set, comparer_set);
        e = errno;
        close_file_or_dir(fd, dirstream);
        if (ret < 0)