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>
28 static const char * const qgroup_cmd_group_usage[] = {
29 "btrfs qgroup <command> [options] <path>",
33 static u64 parse_qgroupid(char *p)
35 char *s = strchr(p, '/');
44 return (level << 48) | id;
47 static int qgroup_assign(int assign, int argc, char **argv)
53 struct btrfs_ioctl_qgroup_assign_args args;
55 if (check_argc_exact(argc, 4))
58 memset(&args, 0, sizeof(args));
60 args.src = parse_qgroupid(argv[1]);
61 args.dst = parse_qgroupid(argv[2]);
64 * FIXME src should accept subvol path
66 if (args.src >= args.dst) {
67 fprintf(stderr, "ERROR: bad relation requested '%s'\n", path);
70 fd = open_file_or_dir(path);
72 fprintf(stderr, "ERROR: can't access '%s'\n", path);
76 ret = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
80 fprintf(stderr, "ERROR: unable to assign quota group: %s\n",
87 static int qgroup_create(int create, int argc, char **argv)
93 struct btrfs_ioctl_qgroup_create_args args;
95 if (check_argc_exact(argc, 3))
98 memset(&args, 0, sizeof(args));
100 args.qgroupid = parse_qgroupid(argv[1]);
102 fd = open_file_or_dir(path);
104 fprintf(stderr, "ERROR: can't access '%s'\n", path);
108 ret = ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args);
112 fprintf(stderr, "ERROR: unable to create quota group: %s\n",
119 void print_qgroup_info(u64 objectid, struct btrfs_qgroup_info_item *info)
121 printf("%llu/%llu %lld %lld\n", objectid >> 48,
122 objectid & ((1ll << 48) - 1),
123 btrfs_stack_qgroup_info_referenced(info),
124 btrfs_stack_qgroup_info_exclusive(info));
127 int list_qgroups(int fd)
130 struct btrfs_ioctl_search_args args;
131 struct btrfs_ioctl_search_key *sk = &args.key;
132 struct btrfs_ioctl_search_header *sh;
133 unsigned long off = 0;
136 struct btrfs_qgroup_info_item *info;
138 memset(&args, 0, sizeof(args));
140 /* search in the quota tree */
141 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
144 * set the min and max to backref keys. The search will
145 * only send back this type of key now.
147 sk->max_type = BTRFS_QGROUP_INFO_KEY;
148 sk->min_type = BTRFS_QGROUP_INFO_KEY;
149 sk->max_objectid = 0;
150 sk->max_offset = (u64)-1;
151 sk->max_transid = (u64)-1;
153 /* just a big number, doesn't matter much */
157 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
161 "ERROR: can't perform the search - %s\n",
165 /* the ioctl returns the number of item it found in nr_items */
166 if (sk->nr_items == 0)
172 * for each item, pull the key out of the header and then
173 * read the root_ref item it contains
175 for (i = 0; i < sk->nr_items; i++) {
176 sh = (struct btrfs_ioctl_search_header *)(args.buf +
180 if (sh->objectid != 0)
183 if (sh->type != BTRFS_QGROUP_INFO_KEY)
186 info = (struct btrfs_qgroup_info_item *)
188 print_qgroup_info(sh->offset, info);
193 * record the mins in sk so we can make sure the
194 * next search doesn't repeat this root
196 sk->min_offset = sh->offset;
200 * this iteration is done, step forward one qgroup for the next
203 if (sk->min_offset < (u64)-1)
213 static int parse_limit(const char *p, unsigned long long *s)
216 unsigned long long size;
218 if (strcasecmp(p, "none") == 0) {
222 size = strtoull(p, &endptr, 10);
252 static const char * const cmd_qgroup_assign_usage[] = {
253 "btrfs qgroup assign <src> <dst> <path>",
254 "Enable subvolume qgroup support for a filesystem.",
258 static int cmd_qgroup_assign(int argc, char **argv)
260 int ret = qgroup_assign(1, argc, argv);
262 usage(cmd_qgroup_assign_usage);
266 static const char * const cmd_qgroup_remove_usage[] = {
267 "btrfs qgroup remove <src> <dst> <path>",
268 "Remove a subvol from a quota group.",
272 static int cmd_qgroup_remove(int argc, char **argv)
274 int ret = qgroup_assign(0, argc, argv);
276 usage(cmd_qgroup_remove_usage);
280 static const char * const cmd_qgroup_create_usage[] = {
281 "btrfs qgroup create <qgroupid> <path>",
282 "Create a subvolume quota group.",
286 static int cmd_qgroup_create(int argc, char **argv)
288 int ret = qgroup_create(1, argc, argv);
290 usage(cmd_qgroup_create_usage);
294 static const char * const cmd_qgroup_destroy_usage[] = {
295 "btrfs qgroup destroy <qgroupid> <path>",
296 "Destroy a subvolume quota group.",
300 static int cmd_qgroup_destroy(int argc, char **argv)
302 int ret = qgroup_create(0, argc, argv);
304 usage(cmd_qgroup_destroy_usage);
308 static const char * const cmd_qgroup_show_usage[] = {
309 "btrfs qgroup show <path>",
310 "Show all subvolume quota groups.",
314 static int cmd_qgroup_show(int argc, char **argv)
318 char *path = argv[1];
320 if (check_argc_exact(argc, 2))
321 usage(cmd_qgroup_show_usage);
323 fd = open_file_or_dir(path);
325 fprintf(stderr, "ERROR: can't access '%s'\n", path);
329 ret = list_qgroups(fd);
331 fprintf(stderr, "ERROR: can't list qgroups\n");
340 static const char * const cmd_qgroup_limit_usage[] = {
341 "btrfs qgroup limit [options] <size>|none [<qgroupid>] <path>",
342 "Limit the size of a subvolume quota group.",
344 "-c limit amount of data after compression",
345 "-e limit space exclusively assigned to this qgroup",
349 static int cmd_qgroup_limit(int argc, char **argv)
355 struct btrfs_ioctl_qgroup_limit_args args;
356 unsigned long long size;
362 int c = getopt(argc, argv, "ce");
373 usage(cmd_qgroup_limit_usage);
377 if (check_argc_min(argc - optind, 2))
378 usage(cmd_qgroup_limit_usage);
380 if (!parse_limit(argv[optind], &size)) {
381 fprintf(stderr, "Invalid size argument given\n");
385 memset(&args, 0, sizeof(args));
388 args.lim.flags |= BTRFS_QGROUP_LIMIT_RFER_CMPR |
389 BTRFS_QGROUP_LIMIT_EXCL_CMPR;
391 args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_EXCL;
392 args.lim.max_exclusive = size;
394 args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_RFER;
395 args.lim.max_referenced = size;
399 if (argc - optind == 2) {
401 path = argv[optind + 1];
402 ret = test_issubvolume(path);
404 fprintf(stderr, "ERROR: error accessing '%s'\n", path);
408 fprintf(stderr, "ERROR: '%s' is not a subvolume\n",
413 * keep qgroupid at 0, this indicates that the subvolume the
414 * fd refers to is to be limited
416 } else if (argc - optind == 3) {
417 args.qgroupid = parse_qgroupid(argv[optind + 1]);
418 path = argv[optind + 2];
420 usage(cmd_qgroup_limit_usage);
422 fd = open_file_or_dir(path);
424 fprintf(stderr, "ERROR: can't access '%s'\n", path);
428 ret = ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args);
432 fprintf(stderr, "ERROR: unable to limit requested quota group: "
433 "%s\n", strerror(e));
439 const struct cmd_group qgroup_cmd_group = {
440 qgroup_cmd_group_usage, NULL, {
441 { "assign", cmd_qgroup_assign, cmd_qgroup_assign_usage, 0, 0 },
442 { "remove", cmd_qgroup_remove, cmd_qgroup_remove_usage, 0, 0 },
443 { "create", cmd_qgroup_create, cmd_qgroup_create_usage, 0, 0 },
444 { "destroy", cmd_qgroup_destroy,
445 cmd_qgroup_destroy_usage, 0, 0 },
446 { "show", cmd_qgroup_show, cmd_qgroup_show_usage, 0, 0 },
447 { "limit", cmd_qgroup_limit, cmd_qgroup_limit_usage, 0, 0 },
452 int cmd_qgroup(int argc, char **argv)
454 return handle_command_group(&qgroup_cmd_group, argc, argv);