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
3439static 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}
239244static 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+
241413static 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