btrfs-progs: fix build warnings in btrfslabel.c
[platform/upstream/btrfs-progs.git] / cmds-qgroup.c
1 /*
2  * Copyright (C) 2012 STRATO.  All rights reserved.
3  *
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.
7  *
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.
12  *
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.
17  */
18
19 #include <sys/ioctl.h>
20 #include <unistd.h>
21 #include <getopt.h>
22
23 #include "ctree.h"
24 #include "ioctl.h"
25
26 #include "commands.h"
27 #include "qgroup.h"
28
29 static const char * const qgroup_cmd_group_usage[] = {
30         "btrfs qgroup <command> [options] <path>",
31         NULL
32 };
33
34 static int qgroup_assign(int assign, int argc, char **argv)
35 {
36         int ret = 0;
37         int fd;
38         int e;
39         char *path = argv[3];
40         struct btrfs_ioctl_qgroup_assign_args args;
41
42         if (check_argc_exact(argc, 4))
43                 return -1;
44
45         memset(&args, 0, sizeof(args));
46         args.assign = assign;
47         args.src = parse_qgroupid(argv[1]);
48         args.dst = parse_qgroupid(argv[2]);
49
50         /*
51          * FIXME src should accept subvol path
52          */
53         if ((args.src >> 48) >= (args.dst >> 48)) {
54                 fprintf(stderr, "ERROR: bad relation requested '%s'\n", path);
55                 return 12;
56         }
57         fd = open_file_or_dir(path);
58         if (fd < 0) {
59                 fprintf(stderr, "ERROR: can't access '%s'\n", path);
60                 return 12;
61         }
62
63         ret = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args);
64         e = errno;
65         close(fd);
66         if (ret < 0) {
67                 fprintf(stderr, "ERROR: unable to assign quota group: %s\n",
68                         strerror(e));
69                 return 30;
70         }
71         return 0;
72 }
73
74 static int qgroup_create(int create, int argc, char **argv)
75 {
76         int ret = 0;
77         int fd;
78         int e;
79         char *path = argv[2];
80         struct btrfs_ioctl_qgroup_create_args args;
81
82         if (check_argc_exact(argc, 3))
83                 return -1;
84
85         memset(&args, 0, sizeof(args));
86         args.create = create;
87         args.qgroupid = parse_qgroupid(argv[1]);
88
89         fd = open_file_or_dir(path);
90         if (fd < 0) {
91                 fprintf(stderr, "ERROR: can't access '%s'\n", path);
92                 return 12;
93         }
94
95         ret = ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args);
96         e = errno;
97         close(fd);
98         if (ret < 0) {
99                 fprintf(stderr, "ERROR: unable to create quota group: %s\n",
100                         strerror(e));
101                 return 30;
102         }
103         return 0;
104 }
105
106 void print_qgroup_info(u64 objectid, struct btrfs_qgroup_info_item *info)
107 {
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));
112 }
113
114 int list_qgroups(int fd)
115 {
116         int ret;
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;
121         unsigned int i;
122         int e;
123         struct btrfs_qgroup_info_item *info;
124
125         memset(&args, 0, sizeof(args));
126
127         /* search in the quota tree */
128         sk->tree_id = BTRFS_QUOTA_TREE_OBJECTID;
129
130         /*
131          * set the min and max to backref keys.  The search will
132          * only send back this type of key now.
133          */
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;
139
140         /* just a big number, doesn't matter much */
141         sk->nr_items = 4096;
142
143         while (1) {
144                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
145                 e = errno;
146                 if (ret < 0) {
147                         fprintf(stderr,
148                                 "ERROR: can't perform the search - %s\n",
149                                 strerror(e));
150                         return ret;
151                 }
152                 /* the ioctl returns the number of item it found in nr_items */
153                 if (sk->nr_items == 0)
154                         break;
155
156                 off = 0;
157
158                 /*
159                  * for each item, pull the key out of the header and then
160                  * read the root_ref item it contains
161                  */
162                 for (i = 0; i < sk->nr_items; i++) {
163                         sh = (struct btrfs_ioctl_search_header *)(args.buf +
164                                                                   off);
165                         off += sizeof(*sh);
166
167                         if (sh->objectid != 0)
168                                 goto done;
169
170                         if (sh->type != BTRFS_QGROUP_INFO_KEY)
171                                 goto done;
172
173                         info = (struct btrfs_qgroup_info_item *)
174                                         (args.buf + off);
175                         print_qgroup_info(sh->offset, info);
176
177                         off += sh->len;
178
179                         /*
180                          * record the mins in sk so we can make sure the
181                          * next search doesn't repeat this root
182                          */
183                         sk->min_offset = sh->offset;
184                 }
185                 sk->nr_items = 4096;
186                 /*
187                  * this iteration is done, step forward one qgroup for the next
188                  * ioctl
189                  */
190                 if (sk->min_offset < (u64)-1)
191                         sk->min_offset++;
192                 else
193                         break;
194         }
195
196 done:
197         return ret;
198 }
199
200 static int parse_limit(const char *p, unsigned long long *s)
201 {
202         char *endptr;
203         unsigned long long size;
204
205         if (strcasecmp(p, "none") == 0) {
206                 *s = 0;
207                 return 1;
208         }
209         size = strtoull(p, &endptr, 10);
210         switch (*endptr) {
211         case 'T':
212         case 't':
213                 size *= 1024;
214         case 'G':
215         case 'g':
216                 size *= 1024;
217         case 'M':
218         case 'm':
219                 size *= 1024;
220         case 'K':
221         case 'k':
222                 size *= 1024;
223                 ++endptr;
224                 break;
225         case 0:
226                 break;
227         default:
228                 return 0;
229         }
230
231         if (*endptr)
232                 return 0;
233
234         *s = size;
235
236         return 1;
237 }
238
239 static const char * const cmd_qgroup_assign_usage[] = {
240         "btrfs qgroup assign <src> <dst> <path>",
241         "Enable subvolume qgroup support for a filesystem.",
242         NULL
243 };
244
245 static int cmd_qgroup_assign(int argc, char **argv)
246 {
247         int ret = qgroup_assign(1, argc, argv);
248         if (ret < 0)
249                 usage(cmd_qgroup_assign_usage);
250         return ret;
251 }
252
253 static const char * const cmd_qgroup_remove_usage[] = {
254         "btrfs qgroup remove <src> <dst> <path>",
255         "Remove a subvol from a quota group.",
256         NULL
257 };
258
259 static int cmd_qgroup_remove(int argc, char **argv)
260 {
261         int ret = qgroup_assign(0, argc, argv);
262         if (ret < 0)
263                 usage(cmd_qgroup_remove_usage);
264         return ret;
265 }
266
267 static const char * const cmd_qgroup_create_usage[] = {
268         "btrfs qgroup create <qgroupid> <path>",
269         "Create a subvolume quota group.",
270         NULL
271 };
272
273 static int cmd_qgroup_create(int argc, char **argv)
274 {
275         int ret = qgroup_create(1, argc, argv);
276         if (ret < 0)
277                 usage(cmd_qgroup_create_usage);
278         return ret;
279 }
280
281 static const char * const cmd_qgroup_destroy_usage[] = {
282         "btrfs qgroup destroy <qgroupid> <path>",
283         "Destroy a subvolume quota group.",
284         NULL
285 };
286
287 static int cmd_qgroup_destroy(int argc, char **argv)
288 {
289         int ret = qgroup_create(0, argc, argv);
290         if (ret < 0)
291                 usage(cmd_qgroup_destroy_usage);
292         return ret;
293 }
294
295 static const char * const cmd_qgroup_show_usage[] = {
296         "btrfs qgroup show <path>",
297         "Show all subvolume quota groups.",
298         NULL
299 };
300
301 static int cmd_qgroup_show(int argc, char **argv)
302 {
303         int ret = 0;
304         int fd;
305         char *path = argv[1];
306
307         if (check_argc_exact(argc, 2))
308                 usage(cmd_qgroup_show_usage);
309
310         fd = open_file_or_dir(path);
311         if (fd < 0) {
312                 fprintf(stderr, "ERROR: can't access '%s'\n", path);
313                 return 12;
314         }
315
316         ret = list_qgroups(fd);
317         if (ret < 0) {
318                 fprintf(stderr, "ERROR: can't list qgroups\n");
319                 return 30;
320         }
321
322         close(fd);
323
324         return ret;
325 }
326
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.",
330         "",
331         "-c   limit amount of data after compression",
332         "-e   limit space exclusively assigned to this qgroup",
333         NULL
334 };
335
336 static int cmd_qgroup_limit(int argc, char **argv)
337 {
338         int ret = 0;
339         int fd;
340         int e;
341         char *path = NULL;
342         struct btrfs_ioctl_qgroup_limit_args args;
343         unsigned long long size;
344         int compressed = 0;
345         int exclusive = 0;
346
347         optind = 1;
348         while (1) {
349                 int c = getopt(argc, argv, "ce");
350                 if (c < 0)
351                         break;
352                 switch (c) {
353                 case 'c':
354                         compressed = 1;
355                         break;
356                 case 'e':
357                         exclusive = 1;
358                         break;
359                 default:
360                         usage(cmd_qgroup_limit_usage);
361                 }
362         }
363
364         if (check_argc_min(argc - optind, 2))
365                 usage(cmd_qgroup_limit_usage);
366
367         if (!parse_limit(argv[optind], &size)) {
368                 fprintf(stderr, "Invalid size argument given\n");
369                 return 1;
370         }
371
372         memset(&args, 0, sizeof(args));
373         if (size) {
374                 if (compressed)
375                         args.lim.flags |= BTRFS_QGROUP_LIMIT_RFER_CMPR |
376                                           BTRFS_QGROUP_LIMIT_EXCL_CMPR;
377                 if (exclusive) {
378                         args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_EXCL;
379                         args.lim.max_exclusive = size;
380                 } else {
381                         args.lim.flags |= BTRFS_QGROUP_LIMIT_MAX_RFER;
382                         args.lim.max_referenced = size;
383                 }
384         }
385
386         if (argc - optind == 2) {
387                 args.qgroupid = 0;
388                 path = argv[optind + 1];
389                 ret = test_issubvolume(path);
390                 if (ret < 0) {
391                         fprintf(stderr, "ERROR: error accessing '%s'\n", path);
392                         return 12;
393                 }
394                 if (!ret) {
395                         fprintf(stderr, "ERROR: '%s' is not a subvolume\n",
396                                 path);
397                         return 13;
398                 }
399                 /*
400                  * keep qgroupid at 0, this indicates that the subvolume the
401                  * fd refers to is to be limited
402                  */
403         } else if (argc - optind == 3) {
404                 args.qgroupid = parse_qgroupid(argv[optind + 1]);
405                 path = argv[optind + 2];
406         } else
407                 usage(cmd_qgroup_limit_usage);
408
409         fd = open_file_or_dir(path);
410         if (fd < 0) {
411                 fprintf(stderr, "ERROR: can't access '%s'\n", path);
412                 return 12;
413         }
414
415         ret = ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args);
416         e = errno;
417         close(fd);
418         if (ret < 0) {
419                 fprintf(stderr, "ERROR: unable to limit requested quota group: "
420                         "%s\n", strerror(e));
421                 return 30;
422         }
423         return 0;
424 }
425
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 },
435                 { 0, 0, 0, 0, 0 }
436         }
437 };
438
439 int cmd_qgroup(int argc, char **argv)
440 {
441         return handle_command_group(&qgroup_cmd_group, argc, argv);
442 }