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>
29 static const char * const qgroup_cmd_group_usage[] = {
30 "btrfs qgroup <command> [options] <path>",
34 static int qgroup_assign(int assign, int argc, char **argv)
40 struct btrfs_ioctl_qgroup_assign_args args;
42 if (check_argc_exact(argc, 4))
45 memset(&args, 0, sizeof(args));
47 args.src = parse_qgroupid(argv[1]);
48 args.dst = parse_qgroupid(argv[2]);
51 * FIXME src should accept subvol path
53 if ((args.src >> 48) >= (args.dst >> 48)) {
54 fprintf(stderr, "ERROR: bad relation requested '%s'\n", path);
57 fd = open_file_or_dir(path);
59 fprintf(stderr, "ERROR: can't access '%s'\n", path);
63 ret = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
67 fprintf(stderr, "ERROR: unable to assign quota group: %s\n",
74 static int qgroup_create(int create, int argc, char **argv)
80 struct btrfs_ioctl_qgroup_create_args args;
82 if (check_argc_exact(argc, 3))
85 memset(&args, 0, sizeof(args));
87 args.qgroupid = parse_qgroupid(argv[1]);
89 fd = open_file_or_dir(path);
91 fprintf(stderr, "ERROR: can't access '%s'\n", path);
95 ret = ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args);
99 fprintf(stderr, "ERROR: unable to create quota group: %s\n",
106 void print_qgroup_info(u64 objectid, struct btrfs_qgroup_info_item *info)
108 printf("%llu/%llu %lld %lld\n", objectid >> 48,
109 objectid & ((1ll << 48) - 1),
110 btrfs_stack_qgroup_info_referenced(info),
111 btrfs_stack_qgroup_info_exclusive(info));
114 int list_qgroups(int fd)
117 struct btrfs_ioctl_search_args args;
118 struct btrfs_ioctl_search_key *sk = &args.key;
119 struct btrfs_ioctl_search_header *sh;
120 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 "ERROR: can't perform the search - %s\n",
152 /* the ioctl returns the number of item it found in nr_items */
153 if (sk->nr_items == 0)
159 * for each item, pull the key out of the header and then
160 * read the root_ref item it contains
162 for (i = 0; i < sk->nr_items; i++) {
163 sh = (struct btrfs_ioctl_search_header *)(args.buf +
167 if (sh->objectid != 0)
170 if (sh->type != BTRFS_QGROUP_INFO_KEY)
173 info = (struct btrfs_qgroup_info_item *)
175 print_qgroup_info(sh->offset, info);
180 * record the mins in sk so we can make sure the
181 * next search doesn't repeat this root
183 sk->min_offset = sh->offset;
187 * this iteration is done, step forward one qgroup for the next
190 if (sk->min_offset < (u64)-1)
200 static int parse_limit(const char *p, unsigned long long *s)
203 unsigned long long size;
205 if (strcasecmp(p, "none") == 0) {
209 size = strtoull(p, &endptr, 10);
239 static const char * const cmd_qgroup_assign_usage[] = {
240 "btrfs qgroup assign <src> <dst> <path>",
241 "Enable subvolume qgroup support for a filesystem.",
245 static int cmd_qgroup_assign(int argc, char **argv)
247 int ret = qgroup_assign(1, argc, argv);
249 usage(cmd_qgroup_assign_usage);
253 static const char * const cmd_qgroup_remove_usage[] = {
254 "btrfs qgroup remove <src> <dst> <path>",
255 "Remove a subvol from a quota group.",
259 static int cmd_qgroup_remove(int argc, char **argv)
261 int ret = qgroup_assign(0, argc, argv);
263 usage(cmd_qgroup_remove_usage);
267 static const char * const cmd_qgroup_create_usage[] = {
268 "btrfs qgroup create <qgroupid> <path>",
269 "Create a subvolume quota group.",
273 static int cmd_qgroup_create(int argc, char **argv)
275 int ret = qgroup_create(1, argc, argv);
277 usage(cmd_qgroup_create_usage);
281 static const char * const cmd_qgroup_destroy_usage[] = {
282 "btrfs qgroup destroy <qgroupid> <path>",
283 "Destroy a subvolume quota group.",
287 static int cmd_qgroup_destroy(int argc, char **argv)
289 int ret = qgroup_create(0, argc, argv);
291 usage(cmd_qgroup_destroy_usage);
295 static const char * const cmd_qgroup_show_usage[] = {
296 "btrfs qgroup show <path>",
297 "Show all subvolume quota groups.",
301 static int cmd_qgroup_show(int argc, char **argv)
305 char *path = argv[1];
307 if (check_argc_exact(argc, 2))
308 usage(cmd_qgroup_show_usage);
310 fd = open_file_or_dir(path);
312 fprintf(stderr, "ERROR: can't access '%s'\n", path);
316 ret = list_qgroups(fd);
318 fprintf(stderr, "ERROR: can't list qgroups\n");
327 static const char * const cmd_qgroup_limit_usage[] = {
328 "btrfs qgroup limit [options] <size>|none [<qgroupid>] <path>",
329 "Limit the size of a subvolume quota group.",
331 "-c limit amount of data after compression",
332 "-e limit space exclusively assigned to this qgroup",
336 static int cmd_qgroup_limit(int argc, char **argv)
342 struct btrfs_ioctl_qgroup_limit_args args;
343 unsigned long long size;
349 int c = getopt(argc, argv, "ce");
360 usage(cmd_qgroup_limit_usage);
364 if (check_argc_min(argc - optind, 2))
365 usage(cmd_qgroup_limit_usage);
367 if (!parse_limit(argv[optind], &size)) {
368 fprintf(stderr, "Invalid size argument given\n");
372 memset(&args, 0, sizeof(args));
375 args.lim.flags |= BTRFS_QGROUP_LIMIT_RFER_CMPR |
376 BTRFS_QGROUP_LIMIT_EXCL_CMPR;
378 args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_EXCL;
379 args.lim.max_exclusive = size;
381 args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_RFER;
382 args.lim.max_referenced = size;
386 if (argc - optind == 2) {
388 path = argv[optind + 1];
389 ret = test_issubvolume(path);
391 fprintf(stderr, "ERROR: error accessing '%s'\n", path);
395 fprintf(stderr, "ERROR: '%s' is not a subvolume\n",
400 * keep qgroupid at 0, this indicates that the subvolume the
401 * fd refers to is to be limited
403 } else if (argc - optind == 3) {
404 args.qgroupid = parse_qgroupid(argv[optind + 1]);
405 path = argv[optind + 2];
407 usage(cmd_qgroup_limit_usage);
409 fd = open_file_or_dir(path);
411 fprintf(stderr, "ERROR: can't access '%s'\n", path);
415 ret = ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args);
419 fprintf(stderr, "ERROR: unable to limit requested quota group: "
420 "%s\n", strerror(e));
426 const struct cmd_group qgroup_cmd_group = {
427 qgroup_cmd_group_usage, NULL, {
428 { "assign", cmd_qgroup_assign, cmd_qgroup_assign_usage, 0, 0 },
429 { "remove", cmd_qgroup_remove, cmd_qgroup_remove_usage, 0, 0 },
430 { "create", cmd_qgroup_create, cmd_qgroup_create_usage, 0, 0 },
431 { "destroy", cmd_qgroup_destroy,
432 cmd_qgroup_destroy_usage, 0, 0 },
433 { "show", cmd_qgroup_show, cmd_qgroup_show_usage, 0, 0 },
434 { "limit", cmd_qgroup_limit, cmd_qgroup_limit_usage, 0, 0 },
439 int cmd_qgroup(int argc, char **argv)
441 return handle_command_group(&qgroup_cmd_group, argc, argv);