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;
42 DIR *dirstream = NULL;
44 if (check_argc_exact(argc, 4))
47 memset(&args, 0, sizeof(args));
49 args.src = parse_qgroupid(argv[1]);
50 args.dst = parse_qgroupid(argv[2]);
53 * FIXME src should accept subvol path
55 if ((args.src >> 48) >= (args.dst >> 48)) {
56 fprintf(stderr, "ERROR: bad relation requested '%s'\n", path);
59 fd = open_file_or_dir(path, &dirstream);
61 fprintf(stderr, "ERROR: can't access '%s'\n", path);
65 ret = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
67 close_file_or_dir(fd, dirstream);
69 fprintf(stderr, "ERROR: unable to assign quota group: %s\n",
76 static int qgroup_create(int create, int argc, char **argv)
82 struct btrfs_ioctl_qgroup_create_args args;
83 DIR *dirstream = NULL;
85 if (check_argc_exact(argc, 3))
88 memset(&args, 0, sizeof(args));
90 args.qgroupid = parse_qgroupid(argv[1]);
92 fd = open_file_or_dir(path, &dirstream);
94 fprintf(stderr, "ERROR: can't access '%s'\n", path);
98 ret = ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args);
100 close_file_or_dir(fd, dirstream);
102 fprintf(stderr, "ERROR: unable to create quota group: %s\n",
109 static void print_qgroup_info(u64 objectid, struct btrfs_qgroup_info_item *info)
111 printf("%llu/%llu %lld %lld\n", objectid >> 48,
112 objectid & ((1ll << 48) - 1),
113 btrfs_stack_qgroup_info_referenced(info),
114 btrfs_stack_qgroup_info_exclusive(info));
117 static int list_qgroups(int fd)
120 struct btrfs_ioctl_search_args args;
121 struct btrfs_ioctl_search_key *sk = &args.key;
122 struct btrfs_ioctl_search_header *sh;
123 unsigned long off = 0;
125 struct btrfs_qgroup_info_item *info;
127 memset(&args, 0, sizeof(args));
129 /* search in the quota tree */
130 sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
133 * set the min and max to backref keys. The search will
134 * only send back this type of key now.
136 sk->max_type = BTRFS_QGROUP_INFO_KEY;
137 sk->min_type = BTRFS_QGROUP_INFO_KEY;
138 sk->max_objectid = 0;
139 sk->max_offset = (u64)-1;
140 sk->max_transid = (u64)-1;
142 /* just a big number, doesn't matter much */
146 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
150 /* the ioctl returns the number of item it found in nr_items */
151 if (sk->nr_items == 0)
157 * for each item, pull the key out of the header and then
158 * read the root_ref item it contains
160 for (i = 0; i < sk->nr_items; i++) {
161 sh = (struct btrfs_ioctl_search_header *)(args.buf +
165 if (sh->objectid != 0)
168 if (sh->type != BTRFS_QGROUP_INFO_KEY)
171 info = (struct btrfs_qgroup_info_item *)
173 print_qgroup_info(sh->offset, info);
178 * record the mins in sk so we can make sure the
179 * next search doesn't repeat this root
181 sk->min_offset = sh->offset;
185 * this iteration is done, step forward one qgroup for the next
188 if (sk->min_offset < (u64)-1)
198 static int parse_limit(const char *p, unsigned long long *s)
201 unsigned long long size;
203 if (strcasecmp(p, "none") == 0) {
207 size = strtoull(p, &endptr, 10);
237 static const char * const cmd_qgroup_assign_usage[] = {
238 "btrfs qgroup assign <src> <dst> <path>",
239 "Enable subvolume qgroup support for a filesystem.",
243 static int cmd_qgroup_assign(int argc, char **argv)
245 int ret = qgroup_assign(1, argc, argv);
247 usage(cmd_qgroup_assign_usage);
251 static const char * const cmd_qgroup_remove_usage[] = {
252 "btrfs qgroup remove <src> <dst> <path>",
253 "Remove a subvol from a quota group.",
257 static int cmd_qgroup_remove(int argc, char **argv)
259 int ret = qgroup_assign(0, argc, argv);
261 usage(cmd_qgroup_remove_usage);
265 static const char * const cmd_qgroup_create_usage[] = {
266 "btrfs qgroup create <qgroupid> <path>",
267 "Create a subvolume quota group.",
271 static int cmd_qgroup_create(int argc, char **argv)
273 int ret = qgroup_create(1, argc, argv);
275 usage(cmd_qgroup_create_usage);
279 static const char * const cmd_qgroup_destroy_usage[] = {
280 "btrfs qgroup destroy <qgroupid> <path>",
281 "Destroy a subvolume quota group.",
285 static int cmd_qgroup_destroy(int argc, char **argv)
287 int ret = qgroup_create(0, argc, argv);
289 usage(cmd_qgroup_destroy_usage);
293 static const char * const cmd_qgroup_show_usage[] = {
294 "btrfs qgroup show <path>",
295 "Show all subvolume quota groups.",
299 static int cmd_qgroup_show(int argc, char **argv)
304 char *path = argv[1];
305 DIR *dirstream = NULL;
307 if (check_argc_exact(argc, 2))
308 usage(cmd_qgroup_show_usage);
310 fd = open_file_or_dir(path, &dirstream);
312 fprintf(stderr, "ERROR: can't access '%s'\n", path);
316 ret = list_qgroups(fd);
318 close_file_or_dir(fd, dirstream);
320 fprintf(stderr, "ERROR: can't list qgroups: %s\n",
326 static const char * const cmd_qgroup_limit_usage[] = {
327 "btrfs qgroup limit [options] <size>|none [<qgroupid>] <path>",
328 "Limit the size of a subvolume quota group.",
330 "-c limit amount of data after compression. This is the default,",
331 " it is currently not possible to turn off this option.",
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;
346 DIR *dirstream = NULL;
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, &dirstream);
412 fprintf(stderr, "ERROR: can't access '%s'\n", path);
416 ret = ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args);
418 close_file_or_dir(fd, dirstream);
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,
431 { "remove", cmd_qgroup_remove, cmd_qgroup_remove_usage,
433 { "create", cmd_qgroup_create, cmd_qgroup_create_usage,
435 { "destroy", cmd_qgroup_destroy, cmd_qgroup_destroy_usage,
437 { "show", cmd_qgroup_show, cmd_qgroup_show_usage,
439 { "limit", cmd_qgroup_limit, cmd_qgroup_limit_usage,
445 int cmd_qgroup(int argc, char **argv)
447 return handle_command_group(&qgroup_cmd_group, argc, argv);