2 * Copyright (C) 2012 STRATO. All rights reserved.
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.
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.
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.
19 #include <sys/ioctl.h>
30 static const char * const qgroup_cmd_group_usage[] = {
31 "btrfs qgroup <command> [options] <path>",
35 static int qgroup_assign(int assign, int argc, char **argv)
41 struct btrfs_ioctl_qgroup_assign_args args;
43 if (check_argc_exact(argc, 4))
46 memset(&args, 0, sizeof(args));
48 args.src = parse_qgroupid(argv[1]);
49 args.dst = parse_qgroupid(argv[2]);
52 * FIXME src should accept subvol path
54 if ((args.src >> 48) >= (args.dst >> 48)) {
55 fprintf(stderr, "ERROR: bad relation requested '%s'\n", path);
58 fd = open_file_or_dir(path);
60 fprintf(stderr, "ERROR: can't access '%s'\n", path);
64 ret = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
68 fprintf(stderr, "ERROR: unable to assign quota group: %s\n",
75 static int qgroup_create(int create, int argc, char **argv)
81 struct btrfs_ioctl_qgroup_create_args args;
83 if (check_argc_exact(argc, 3))
86 memset(&args, 0, sizeof(args));
88 args.qgroupid = parse_qgroupid(argv[1]);
90 fd = open_file_or_dir(path);
92 fprintf(stderr, "ERROR: can't access '%s'\n", path);
96 ret = ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args);
100 fprintf(stderr, "ERROR: unable to create quota group: %s\n",
107 void print_qgroup_info(u64 objectid, struct btrfs_qgroup_info_item *info)
109 printf("%llu/%llu %lld %lld\n", objectid >> 48,
110 objectid & ((1ll << 48) - 1),
111 btrfs_stack_qgroup_info_referenced(info),
112 btrfs_stack_qgroup_info_exclusive(info));
115 int list_qgroups(int fd)
118 struct btrfs_ioctl_search_args args;
119 struct btrfs_ioctl_search_key *sk = &args.key;
120 struct btrfs_ioctl_search_header *sh;
121 unsigned long off = 0;
123 struct btrfs_qgroup_info_item *info;
125 memset(&args, 0, sizeof(args));
127 /* search in the quota tree */
128 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
131 * set the min and max to backref keys. The search will
132 * only send back this type of key now.
134 sk->max_type = BTRFS_QGROUP_INFO_KEY;
135 sk->min_type = BTRFS_QGROUP_INFO_KEY;
136 sk->max_objectid = 0;
137 sk->max_offset = (u64)-1;
138 sk->max_transid = (u64)-1;
140 /* just a big number, doesn't matter much */
144 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
148 /* the ioctl returns the number of item it found in nr_items */
149 if (sk->nr_items == 0)
155 * for each item, pull the key out of the header and then
156 * read the root_ref item it contains
158 for (i = 0; i < sk->nr_items; i++) {
159 sh = (struct btrfs_ioctl_search_header *)(args.buf +
163 if (sh->objectid != 0)
166 if (sh->type != BTRFS_QGROUP_INFO_KEY)
169 info = (struct btrfs_qgroup_info_item *)
171 print_qgroup_info(sh->offset, info);
176 * record the mins in sk so we can make sure the
177 * next search doesn't repeat this root
179 sk->min_offset = sh->offset;
183 * this iteration is done, step forward one qgroup for the next
186 if (sk->min_offset < (u64)-1)
196 static int parse_limit(const char *p, unsigned long long *s)
199 unsigned long long size;
201 if (strcasecmp(p, "none") == 0) {
205 size = strtoull(p, &endptr, 10);
235 static const char * const cmd_qgroup_assign_usage[] = {
236 "btrfs qgroup assign <src> <dst> <path>",
237 "Enable subvolume qgroup support for a filesystem.",
241 static int cmd_qgroup_assign(int argc, char **argv)
243 int ret = qgroup_assign(1, argc, argv);
245 usage(cmd_qgroup_assign_usage);
249 static const char * const cmd_qgroup_remove_usage[] = {
250 "btrfs qgroup remove <src> <dst> <path>",
251 "Remove a subvol from a quota group.",
255 static int cmd_qgroup_remove(int argc, char **argv)
257 int ret = qgroup_assign(0, argc, argv);
259 usage(cmd_qgroup_remove_usage);
263 static const char * const cmd_qgroup_create_usage[] = {
264 "btrfs qgroup create <qgroupid> <path>",
265 "Create a subvolume quota group.",
269 static int cmd_qgroup_create(int argc, char **argv)
271 int ret = qgroup_create(1, argc, argv);
273 usage(cmd_qgroup_create_usage);
277 static const char * const cmd_qgroup_destroy_usage[] = {
278 "btrfs qgroup destroy <qgroupid> <path>",
279 "Destroy a subvolume quota group.",
283 static int cmd_qgroup_destroy(int argc, char **argv)
285 int ret = qgroup_create(0, argc, argv);
287 usage(cmd_qgroup_destroy_usage);
291 static const char * const cmd_qgroup_show_usage[] = {
292 "btrfs qgroup show <path>",
293 "Show all subvolume quota groups.",
297 static int cmd_qgroup_show(int argc, char **argv)
302 char *path = argv[1];
304 if (check_argc_exact(argc, 2))
305 usage(cmd_qgroup_show_usage);
307 fd = open_file_or_dir(path);
309 fprintf(stderr, "ERROR: can't access '%s'\n", path);
313 ret = list_qgroups(fd);
317 fprintf(stderr, "ERROR: can't list qgroups: %s\n",
325 static const char * const cmd_qgroup_limit_usage[] = {
326 "btrfs qgroup limit [options] <size>|none [<qgroupid>] <path>",
327 "Limit the size of a subvolume quota group.",
329 "-c limit amount of data after compression",
330 "-e limit space exclusively assigned to this qgroup",
334 static int cmd_qgroup_limit(int argc, char **argv)
340 struct btrfs_ioctl_qgroup_limit_args args;
341 unsigned long long size;
347 int c = getopt(argc, argv, "ce");
358 usage(cmd_qgroup_limit_usage);
362 if (check_argc_min(argc - optind, 2))
363 usage(cmd_qgroup_limit_usage);
365 if (!parse_limit(argv[optind], &size)) {
366 fprintf(stderr, "Invalid size argument given\n");
370 memset(&args, 0, sizeof(args));
373 args.lim.flags |= BTRFS_QGROUP_LIMIT_RFER_CMPR |
374 BTRFS_QGROUP_LIMIT_EXCL_CMPR;
376 args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_EXCL;
377 args.lim.max_exclusive = size;
379 args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_RFER;
380 args.lim.max_referenced = size;
384 if (argc - optind == 2) {
386 path = argv[optind + 1];
387 ret = test_issubvolume(path);
389 fprintf(stderr, "ERROR: error accessing '%s'\n", path);
393 fprintf(stderr, "ERROR: '%s' is not a subvolume\n",
398 * keep qgroupid at 0, this indicates that the subvolume the
399 * fd refers to is to be limited
401 } else if (argc - optind == 3) {
402 args.qgroupid = parse_qgroupid(argv[optind + 1]);
403 path = argv[optind + 2];
405 usage(cmd_qgroup_limit_usage);
407 fd = open_file_or_dir(path);
409 fprintf(stderr, "ERROR: can't access '%s'\n", path);
413 ret = ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args);
417 fprintf(stderr, "ERROR: unable to limit requested quota group: "
418 "%s\n", strerror(e));
424 const struct cmd_group qgroup_cmd_group = {
425 qgroup_cmd_group_usage, NULL, {
426 { "assign", cmd_qgroup_assign, cmd_qgroup_assign_usage, 0, 0 },
427 { "remove", cmd_qgroup_remove, cmd_qgroup_remove_usage, 0, 0 },
428 { "create", cmd_qgroup_create, cmd_qgroup_create_usage, 0, 0 },
429 { "destroy", cmd_qgroup_destroy,
430 cmd_qgroup_destroy_usage, 0, 0 },
431 { "show", cmd_qgroup_show, cmd_qgroup_show_usage, 0, 0 },
432 { "limit", cmd_qgroup_limit, cmd_qgroup_limit_usage, 0, 0 },
437 int cmd_qgroup(int argc, char **argv)
439 return handle_command_group(&qgroup_cmd_group, argc, argv);