Skip to content

Commit 0de93cc

Browse files
committed
btrfs-progs: quota status: add new command
The quotas are missing the status command, so add it with some basic information about quotas that can be found in sysfs. The information access is unrestricted and does not use any privileged ioctls. Signed-off-by: David Sterba <dsterba@suse.com>
1 parent 5ddccad commit 0de93cc

File tree

2 files changed

+196
-0
lines changed

2 files changed

+196
-0
lines changed

Documentation/btrfs-quota.rst

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,29 @@ rescan [options] <path>
6565
-W|--wait-norescan
6666
wait for rescan to finish without starting it
6767

68+
status [options] <path>
69+
Print status information about quotas if enabled on *path*. The information
70+
is read from :file:`/sys/fs/btrfs/FSID/qgroups` and root privileges are
71+
not needed.
72+
73+
Example output for quotas enabled by :command:`btrfs quota enable /mnt`:
74+
75+
.. code-block:: none
76+
77+
Quotas on /mnt:
78+
Enabled: yes
79+
Mode: quota (full accounting)
80+
Inconsistent: no
81+
Override limits: no
82+
Drop subtree threshold: 3
83+
Total count: 1
84+
Level 0: 1
85+
86+
``Options``
87+
88+
--is-enabled
89+
only check if quotas are enabled, not not print anything
90+
6891
EXIT STATUS
6992
-----------
7093

cmds/quota.c

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,20 @@
2020
#include <sys/ioctl.h>
2121
#include <dirent.h>
2222
#include <errno.h>
23+
#include <ctype.h>
2324
#include <getopt.h>
2425
#include <stdio.h>
2526
#include <string.h>
2627
#include <stdbool.h>
2728
#include <unistd.h>
2829
#include "kernel-shared/uapi/btrfs.h"
30+
#include "kernel-shared/uapi/btrfs_tree.h"
2931
#include "common/help.h"
3032
#include "common/open-utils.h"
3133
#include "common/messages.h"
34+
#include "common/sysfs-utils.h"
35+
#include "common/parse-utils.h"
36+
#include "common/string-utils.h"
3237
#include "cmds/commands.h"
3338

3439
static const char * const quota_cmd_group_usage[] = {
@@ -238,6 +243,173 @@ static int cmd_quota_rescan(const struct cmd_struct *cmd, int argc, char **argv)
238243
}
239244
static DEFINE_SIMPLE_COMMAND(quota_rescan, "rescan");
240245

246+
static const char * const cmd_quota_status_usage[] = {
247+
"btrfs quota status <path>",
248+
"Show status information about quota if enabled on the <path>.",
249+
"",
250+
OPTLINE("--is-enabled", "only check if quotas are enabled, not not print anything"),
251+
NULL
252+
};
253+
254+
static bool quota_is_enabled(const char *path)
255+
{
256+
int fsfd = -1;
257+
int dirfd = -1;
258+
bool ret = true;
259+
260+
fsfd = btrfs_open_dir(path);
261+
if (fsfd < 0)
262+
return false;
263+
264+
dirfd = sysfs_open_fsid_dir(fsfd, "qgroups");
265+
if (dirfd < 0) {
266+
ret = false;
267+
goto out;
268+
}
269+
270+
out:
271+
close(fsfd);
272+
close(dirfd);
273+
return ret;
274+
}
275+
276+
static const char *describe_mode(const char *mode)
277+
{
278+
if (strcmp("qgroup", mode) == 0)
279+
return "full accounting";
280+
if (strcmp("squota", mode) == 0)
281+
return "simplified accounting";
282+
return "unknown mode";
283+
}
284+
285+
static int cmd_quota_status(const struct cmd_struct *cmd, int argc, char **argv)
286+
{
287+
int ret;
288+
int fsfd = -1;
289+
int dirfd = -1;
290+
int fd = -1;
291+
char buf[4096] = { 0 };
292+
u64 num, num2;
293+
DIR *dir = NULL;
294+
295+
optind = 0;
296+
while (1) {
297+
int c;
298+
enum { GETOPT_VAL_IS_ENABLED = GETOPT_VAL_FIRST };
299+
static const struct option long_options[] = {
300+
{ "is-enabled", no_argument, NULL, GETOPT_VAL_IS_ENABLED },
301+
{ NULL, 0, NULL, 0}
302+
};
303+
304+
c = getopt_long(argc, argv, "", long_options, NULL);
305+
if (c < 0)
306+
break;
307+
switch (c) {
308+
case GETOPT_VAL_IS_ENABLED:
309+
return quota_is_enabled(argv[optind]) ? 0 : 1;
310+
default:
311+
usage_unknown_option(cmd, argv);
312+
}
313+
}
314+
315+
if (check_argc_exact(argc - optind, 1))
316+
return 1;
317+
318+
fsfd = btrfs_open_dir(argv[1]);
319+
if (fsfd < 0)
320+
return 1;
321+
322+
dirfd = sysfs_open_fsid_dir(fsfd, "qgroups");
323+
pr_verbose(LOG_DEFAULT, "Quotas on %s:\n", argv[1]);
324+
if (dirfd < 0) {
325+
pr_verbose(LOG_DEFAULT, " Enabled: no\n");
326+
goto out;
327+
}
328+
pr_verbose(LOG_DEFAULT, " Enabled: %s\n", "yes");
329+
330+
fd = sysfs_open_fsid_file(fsfd, "qgroups/mode");
331+
if (fd < 0) {
332+
error("cannot open file qgroups/mode: %m");
333+
goto out;
334+
}
335+
ret = sysfs_read_file(fd, buf, sizeof(buf));
336+
if (fd < 0) {
337+
error("cannot read file qgroups/mode: %m");
338+
goto out;
339+
}
340+
while (isspace(buf[strlen(buf) - 1]))
341+
buf[strlen(buf) - 1] = 0;
342+
pr_verbose(LOG_DEFAULT, " Mode: %s (%s)\n", buf, describe_mode(buf));
343+
close(fd);
344+
345+
ret = sysfs_read_fsid_file_u64(fsfd, "qgroups/inconsistent", &num);
346+
if (ret < 0) {
347+
error("cannot read file qgroups/inconsistent: %m");
348+
goto out;
349+
}
350+
pr_verbose(LOG_DEFAULT, " Inconsistent: %s%s\n",
351+
(num ? "yes" : "no"), (num ? " (rescan needed)" : ""));
352+
353+
ret = sysfs_read_fsid_file_u64(fsfd, "quota_override", &num);
354+
if (ret < 0) {
355+
error("cannot read file qgroups/quota_override: %m");
356+
goto out;
357+
}
358+
pr_verbose(LOG_DEFAULT, " Override limits: %s\n", (num ? "yes" : "no"));
359+
360+
ret = sysfs_read_fsid_file_u64(fsfd, "qgroups/drop_subtree_threshold", &num);
361+
if (ret < 0) {
362+
error("cannot read file qgroups/drop_subtree_threshold");
363+
goto out;
364+
}
365+
pr_verbose(LOG_DEFAULT, " Drop subtree threshold: %llu\n", num);
366+
367+
/* Count */
368+
dir = fdopendir(dirfd);
369+
if (!dir) {
370+
error("cannot open qgroups/ directory: %m");
371+
goto out;
372+
}
373+
num = 0;
374+
num2 = 0;
375+
while (1) {
376+
struct dirent *de;
377+
u64 qgroupid;
378+
char *str;
379+
380+
de = readdir(dir);
381+
if (!de)
382+
break;
383+
384+
str = de->d_name;
385+
while (*str) {
386+
if (*str == '_') {
387+
*str = '/';
388+
break;
389+
}
390+
str++;
391+
}
392+
393+
ret = parse_qgroupid(de->d_name, &qgroupid);
394+
if (ret < 0)
395+
continue;
396+
397+
num++;
398+
if (btrfs_qgroup_level(qgroupid) == 0)
399+
num2++;
400+
}
401+
pr_verbose(LOG_DEFAULT, " Total count: %llu\n", num);
402+
pr_verbose(LOG_DEFAULT, " Level 0: %llu\n", num2);
403+
404+
out:
405+
if (dir)
406+
closedir(dir);
407+
close(dirfd);
408+
close(fsfd);
409+
return 0;
410+
}
411+
static DEFINE_SIMPLE_COMMAND(quota_status, "status");
412+
241413
static const char quota_cmd_group_info[] =
242414
"manage filesystem quota settings";
243415

@@ -246,6 +418,7 @@ static const struct cmd_group quota_cmd_group = {
246418
&cmd_struct_quota_enable,
247419
&cmd_struct_quota_disable,
248420
&cmd_struct_quota_rescan,
421+
&cmd_struct_quota_status,
249422
NULL
250423
}
251424
};

0 commit comments

Comments
 (0)