btrfs-progs: fix defrag threshold overflow
[platform/upstream/btrfs-progs.git] / cmds-quota.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
22 #include "ctree.h"
23 #include "ioctl.h"
24
25 #include "commands.h"
26 #include "utils.h"
27
28 static const char * const quota_cmd_group_usage[] = {
29         "btrfs quota <command> [options] <path>",
30         NULL
31 };
32
33 static int quota_ctl(int cmd, int argc, char **argv)
34 {
35         int ret = 0;
36         int fd;
37         int e;
38         char *path = argv[1];
39         struct btrfs_ioctl_quota_ctl_args args;
40         DIR *dirstream = NULL;
41
42         if (check_argc_exact(argc, 2))
43                 return -1;
44
45         memset(&args, 0, sizeof(args));
46         args.cmd = cmd;
47
48         fd = open_file_or_dir(path, &dirstream);
49         if (fd < 0) {
50                 fprintf(stderr, "ERROR: can't access '%s'\n", path);
51                 return 1;
52         }
53
54         ret = ioctl(fd, BTRFS_IOC_QUOTA_CTL, &args);
55         e = errno;
56         close_file_or_dir(fd, dirstream);
57         if (ret < 0) {
58                 fprintf(stderr, "ERROR: quota command failed: %s\n",
59                         strerror(e));
60                 return 1;
61         }
62         return 0;
63 }
64
65 static const char * const cmd_quota_enable_usage[] = {
66         "btrfs quota enable <path>",
67         "Enable subvolume quota support for a filesystem.",
68         "Any data already present on the filesystem will not count towards",
69         "the space usage numbers. It is recommended to enable quota for a",
70         "filesystem before writing any data to it.",
71         NULL
72 };
73
74 static int cmd_quota_enable(int argc, char **argv)
75 {
76         int ret = quota_ctl(BTRFS_QUOTA_CTL_ENABLE, argc, argv);
77         if (ret < 0)
78                 usage(cmd_quota_enable_usage);
79         return ret;
80 }
81
82 static const char * const cmd_quota_disable_usage[] = {
83         "btrfs quota disable <path>",
84         "Disable subvolume quota support for a filesystem.",
85         NULL
86 };
87
88 static int cmd_quota_disable(int argc, char **argv)
89 {
90         int ret = quota_ctl(BTRFS_QUOTA_CTL_DISABLE, argc, argv);
91         if (ret < 0)
92                 usage(cmd_quota_disable_usage);
93         return ret;
94 }
95
96 static const char * const cmd_quota_rescan_usage[] = {
97         "btrfs quota rescan [-sw] <path>",
98         "Trash all qgroup numbers and scan the metadata again with the current config.",
99         "",
100         "-s   show status of a running rescan operation",
101         "-w   wait for rescan operation to finish (can be already in progress)",
102         NULL
103 };
104
105 static int cmd_quota_rescan(int argc, char **argv)
106 {
107         int ret = 0;
108         int fd;
109         int e;
110         char *path = NULL;
111         struct btrfs_ioctl_quota_rescan_args args;
112         unsigned long ioctlnum = BTRFS_IOC_QUOTA_RESCAN;
113         DIR *dirstream = NULL;
114         int wait_for_completion = 0;
115
116         optind = 1;
117         while (1) {
118                 int c = getopt(argc, argv, "sw");
119                 if (c < 0)
120                         break;
121                 switch (c) {
122                 case 's':
123                         ioctlnum = BTRFS_IOC_QUOTA_RESCAN_STATUS;
124                         break;
125                 case 'w':
126                         wait_for_completion = 1;
127                         break;
128                 default:
129                         usage(cmd_quota_rescan_usage);
130                 }
131         }
132
133         if (ioctlnum != BTRFS_IOC_QUOTA_RESCAN && wait_for_completion) {
134                 fprintf(stderr, "ERROR: -w cannot be used with -s\n");
135                 return 1;
136         }
137
138         if (check_argc_exact(argc - optind, 1))
139                 usage(cmd_quota_rescan_usage);
140
141         memset(&args, 0, sizeof(args));
142
143         path = argv[optind];
144         fd = open_file_or_dir(path, &dirstream);
145         if (fd < 0) {
146                 fprintf(stderr, "ERROR: can't access '%s'\n", path);
147                 return 1;
148         }
149
150         ret = ioctl(fd, ioctlnum, &args);
151         e = errno;
152
153         if (wait_for_completion && (ret == 0 || e == EINPROGRESS)) {
154                 ret = ioctl(fd, BTRFS_IOC_QUOTA_RESCAN_WAIT, &args);
155                 e = errno;
156         }
157         close_file_or_dir(fd, dirstream);
158
159         if (ioctlnum == BTRFS_IOC_QUOTA_RESCAN) {
160                 if (ret < 0) {
161                         fprintf(stderr, "ERROR: quota rescan failed: "
162                                 "%s\n", strerror(e));
163                         return 1;
164                 }  else {
165                         printf("quota rescan started\n");
166                 }
167         } else {
168                 if (!args.flags) {
169                         printf("no rescan operation in progress\n");
170                 } else {
171                         printf("rescan operation running (current key %lld)\n",
172                                 args.progress);
173                 }
174         }
175
176         return 0;
177 }
178
179 static const char quota_cmd_group_info[] =
180 "manage filesystem quota settings";
181
182 const struct cmd_group quota_cmd_group = {
183         quota_cmd_group_usage, quota_cmd_group_info, {
184                 { "enable", cmd_quota_enable, cmd_quota_enable_usage, NULL, 0 },
185                 { "disable", cmd_quota_disable, cmd_quota_disable_usage,
186                    NULL, 0 },
187                 { "rescan", cmd_quota_rescan, cmd_quota_rescan_usage, NULL, 0 },
188                 NULL_CMD_STRUCT
189         }
190 };
191
192 int cmd_quota(int argc, char **argv)
193 {
194         return handle_command_group(&quota_cmd_group, argc, argv);
195 }