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;
124 struct btrfs_qgroup_info_item *info;
126 memset(&args, 0, sizeof(args));
128 /* search in the quota tree */
129 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
132 * set the min and max to backref keys. The search will
133 * only send back this type of key now.
135 sk->max_type = BTRFS_QGROUP_INFO_KEY;
136 sk->min_type = BTRFS_QGROUP_INFO_KEY;
137 sk->max_objectid = 0;
138 sk->max_offset = (u64)-1;
139 sk->max_transid = (u64)-1;
141 /* just a big number, doesn't matter much */
145 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
149 "ERROR: can't perform the search - %s\n",
153 /* the ioctl returns the number of item it found in nr_items */
154 if (sk->nr_items == 0)
160 * for each item, pull the key out of the header and then
161 * read the root_ref item it contains
163 for (i = 0; i < sk->nr_items; i++) {
164 sh = (struct btrfs_ioctl_search_header *)(args.buf +
168 if (sh->objectid != 0)
171 if (sh->type != BTRFS_QGROUP_INFO_KEY)
174 info = (struct btrfs_qgroup_info_item *)
176 print_qgroup_info(sh->offset, info);
181 * record the mins in sk so we can make sure the
182 * next search doesn't repeat this root
184 sk->min_offset = sh->offset;
188 * this iteration is done, step forward one qgroup for the next
191 if (sk->min_offset < (u64)-1)
201 static int parse_limit(const char *p, unsigned long long *s)
204 unsigned long long size;
206 if (strcasecmp(p, "none") == 0) {
210 size = strtoull(p, &endptr, 10);
240 static const char * const cmd_qgroup_assign_usage[] = {
241 "btrfs qgroup assign <src> <dst> <path>",
242 "Enable subvolume qgroup support for a filesystem.",
246 static int cmd_qgroup_assign(int argc, char **argv)
248 int ret = qgroup_assign(1, argc, argv);
250 usage(cmd_qgroup_assign_usage);
254 static const char * const cmd_qgroup_remove_usage[] = {
255 "btrfs qgroup remove <src> <dst> <path>",
256 "Remove a subvol from a quota group.",
260 static int cmd_qgroup_remove(int argc, char **argv)
262 int ret = qgroup_assign(0, argc, argv);
264 usage(cmd_qgroup_remove_usage);
268 static const char * const cmd_qgroup_create_usage[] = {
269 "btrfs qgroup create <qgroupid> <path>",
270 "Create a subvolume quota group.",
274 static int cmd_qgroup_create(int argc, char **argv)
276 int ret = qgroup_create(1, argc, argv);
278 usage(cmd_qgroup_create_usage);
282 static const char * const cmd_qgroup_destroy_usage[] = {
283 "btrfs qgroup destroy <qgroupid> <path>",
284 "Destroy a subvolume quota group.",
288 static int cmd_qgroup_destroy(int argc, char **argv)
290 int ret = qgroup_create(0, argc, argv);
292 usage(cmd_qgroup_destroy_usage);
296 static const char * const cmd_qgroup_show_usage[] = {
297 "btrfs qgroup show <path>",
298 "Show all subvolume quota groups.",
302 static int cmd_qgroup_show(int argc, char **argv)
306 char *path = argv[1];
308 if (check_argc_exact(argc, 2))
309 usage(cmd_qgroup_show_usage);
311 fd = open_file_or_dir(path);
313 fprintf(stderr, "ERROR: can't access '%s'\n", path);
317 ret = list_qgroups(fd);
319 fprintf(stderr, "ERROR: can't list qgroups\n");
328 static const char * const cmd_qgroup_limit_usage[] = {
329 "btrfs qgroup limit [options] <size>|none [<qgroupid>] <path>",
330 "Limit the size of a subvolume quota group.",
332 "-c limit amount of data after compression",
333 "-e limit space exclusively assigned to this qgroup",
337 static int cmd_qgroup_limit(int argc, char **argv)
343 struct btrfs_ioctl_qgroup_limit_args args;
344 unsigned long long size;
350 int c = getopt(argc, argv, "ce");
361 usage(cmd_qgroup_limit_usage);
365 if (check_argc_min(argc - optind, 2))
366 usage(cmd_qgroup_limit_usage);
368 if (!parse_limit(argv[optind], &size)) {
369 fprintf(stderr, "Invalid size argument given\n");
373 memset(&args, 0, sizeof(args));
376 args.lim.flags |= BTRFS_QGROUP_LIMIT_RFER_CMPR |
377 BTRFS_QGROUP_LIMIT_EXCL_CMPR;
379 args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_EXCL;
380 args.lim.max_exclusive = size;
382 args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_RFER;
383 args.lim.max_referenced = size;
387 if (argc - optind == 2) {
389 path = argv[optind + 1];
390 ret = test_issubvolume(path);
392 fprintf(stderr, "ERROR: error accessing '%s'\n", path);
396 fprintf(stderr, "ERROR: '%s' is not a subvolume\n",
401 * keep qgroupid at 0, this indicates that the subvolume the
402 * fd refers to is to be limited
404 } else if (argc - optind == 3) {
405 args.qgroupid = parse_qgroupid(argv[optind + 1]);
406 path = argv[optind + 2];
408 usage(cmd_qgroup_limit_usage);
410 fd = open_file_or_dir(path);
412 fprintf(stderr, "ERROR: can't access '%s'\n", path);
416 ret = ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args);
420 fprintf(stderr, "ERROR: unable to limit requested quota group: "
421 "%s\n", strerror(e));
427 const struct cmd_group qgroup_cmd_group = {
428 qgroup_cmd_group_usage, NULL, {
429 { "assign", cmd_qgroup_assign, cmd_qgroup_assign_usage, 0, 0 },
430 { "remove", cmd_qgroup_remove, cmd_qgroup_remove_usage, 0, 0 },
431 { "create", cmd_qgroup_create, cmd_qgroup_create_usage, 0, 0 },
432 { "destroy", cmd_qgroup_destroy,
433 cmd_qgroup_destroy_usage, 0, 0 },
434 { "show", cmd_qgroup_show, cmd_qgroup_show_usage, 0, 0 },
435 { "limit", cmd_qgroup_limit, cmd_qgroup_limit_usage, 0, 0 },
440 int cmd_qgroup(int argc, char **argv)
442 return handle_command_group(&qgroup_cmd_group, argc, argv);