btrfs-progs: output the correct path when fi-usage failed
[platform/upstream/btrfs-progs.git] / cmds-fi-disk_usage.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public
4  * License v2 as published by the Free Software Foundation.
5  *
6  * This program is distributed in the hope that it will be useful,
7  * but WITHOUT ANY WARRANTY; without even the implied warranty of
8  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9  * General Public License for more details.
10  *
11  * You should have received a copy of the GNU General Public
12  * License along with this program; if not, write to the
13  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
14  * Boston, MA 021110-1307, USA.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/ioctl.h>
22 #include <errno.h>
23 #include <stdarg.h>
24
25 #include "utils.h"
26 #include "kerncompat.h"
27 #include "ctree.h"
28 #include "string-table.h"
29 #include "cmds-fi-disk_usage.h"
30 #include "commands.h"
31
32 #include "version.h"
33
34 /*
35  * Add the chunk info to the chunk_info list
36  */
37 static int add_info_to_list(struct chunk_info **info_ptr,
38                         int *info_count,
39                         struct btrfs_chunk *chunk)
40 {
41
42         u64 type = btrfs_stack_chunk_type(chunk);
43         u64 size = btrfs_stack_chunk_length(chunk);
44         int num_stripes = btrfs_stack_chunk_num_stripes(chunk);
45         int j;
46
47         for (j = 0 ; j < num_stripes ; j++) {
48                 int i;
49                 struct chunk_info *p = 0;
50                 struct btrfs_stripe *stripe;
51                 u64    devid;
52
53                 stripe = btrfs_stripe_nr(chunk, j);
54                 devid = btrfs_stack_stripe_devid(stripe);
55
56                 for (i = 0 ; i < *info_count ; i++)
57                         if ((*info_ptr)[i].type == type &&
58                             (*info_ptr)[i].devid == devid &&
59                             (*info_ptr)[i].num_stripes == num_stripes ) {
60                                 p = (*info_ptr) + i;
61                                 break;
62                         }
63
64                 if (!p) {
65                         int size = sizeof(struct btrfs_chunk) * (*info_count+1);
66                         struct chunk_info *res = realloc(*info_ptr, size);
67
68                         if (!res) {
69                                 free(*info_ptr);
70                                 fprintf(stderr, "ERROR: not enough memory\n");
71                                 return -ENOMEM;
72                         }
73
74                         *info_ptr = res;
75                         p = res + *info_count;
76                         (*info_count)++;
77
78                         p->devid = devid;
79                         p->type = type;
80                         p->size = 0;
81                         p->num_stripes = num_stripes;
82                 }
83
84                 p->size += size;
85
86         }
87
88         return 0;
89
90 }
91
92 /*
93  *  Helper to sort the chunk type
94  */
95 static int cmp_chunk_block_group(u64 f1, u64 f2)
96 {
97
98         u64 mask;
99
100         if ((f1 & BTRFS_BLOCK_GROUP_TYPE_MASK) ==
101                 (f2 & BTRFS_BLOCK_GROUP_TYPE_MASK))
102                         mask = BTRFS_BLOCK_GROUP_PROFILE_MASK;
103         else if (f2 & BTRFS_BLOCK_GROUP_SYSTEM)
104                         return -1;
105         else if (f1 & BTRFS_BLOCK_GROUP_SYSTEM)
106                         return +1;
107         else
108                         mask = BTRFS_BLOCK_GROUP_TYPE_MASK;
109
110         if ((f1 & mask) > (f2 & mask))
111                 return +1;
112         else if ((f1 & mask) < (f2 & mask))
113                 return -1;
114         else
115                 return 0;
116 }
117
118 /*
119  * Helper to sort the chunk
120  */
121 static int cmp_chunk_info(const void *a, const void *b)
122 {
123         return cmp_chunk_block_group(
124                 ((struct chunk_info *)a)->type,
125                 ((struct chunk_info *)b)->type);
126 }
127
128 static int load_chunk_info(int fd, struct chunk_info **info_ptr, int *info_count)
129 {
130         int ret;
131         struct btrfs_ioctl_search_args args;
132         struct btrfs_ioctl_search_key *sk = &args.key;
133         struct btrfs_ioctl_search_header *sh;
134         unsigned long off = 0;
135         int i, e;
136
137         memset(&args, 0, sizeof(args));
138
139         /*
140          * there may be more than one ROOT_ITEM key if there are
141          * snapshots pending deletion, we have to loop through
142          * them.
143          */
144         sk->tree_id = BTRFS_CHUNK_TREE_OBJECTID;
145
146         sk->min_objectid = 0;
147         sk->max_objectid = (u64)-1;
148         sk->max_type = 0;
149         sk->min_type = (u8)-1;
150         sk->min_offset = 0;
151         sk->max_offset = (u64)-1;
152         sk->min_transid = 0;
153         sk->max_transid = (u64)-1;
154         sk->nr_items = 4096;
155
156         while (1) {
157                 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
158                 e = errno;
159                 if (ret == -EPERM)
160                         return ret;
161
162                 if (ret < 0) {
163                         fprintf(stderr,
164                                 "ERROR: can't perform the search - %s\n",
165                                 strerror(e));
166                         return ret;
167                 }
168                 /* the ioctl returns the number of item it found in nr_items */
169
170                 if (sk->nr_items == 0)
171                         break;
172
173                 off = 0;
174                 for (i = 0; i < sk->nr_items; i++) {
175                         struct btrfs_chunk *item;
176                         sh = (struct btrfs_ioctl_search_header *)(args.buf +
177                                                                   off);
178
179                         off += sizeof(*sh);
180                         item = (struct btrfs_chunk *)(args.buf + off);
181
182                         ret = add_info_to_list(info_ptr, info_count, item);
183                         if (ret) {
184                                 *info_ptr = 0;
185                                 return ret;
186                         }
187
188                         off += sh->len;
189
190                         sk->min_objectid = sh->objectid;
191                         sk->min_type = sh->type;
192                         sk->min_offset = sh->offset+1;
193
194                 }
195                 if (!sk->min_offset)    /* overflow */
196                         sk->min_type++;
197                 else
198                         continue;
199
200                 if (!sk->min_type)
201                         sk->min_objectid++;
202                  else
203                         continue;
204
205                 if (!sk->min_objectid)
206                         break;
207         }
208
209         qsort(*info_ptr, *info_count, sizeof(struct chunk_info),
210                 cmp_chunk_info);
211
212         return 0;
213 }
214
215 /*
216  * Helper to sort the struct btrfs_ioctl_space_info
217  */
218 static int cmp_btrfs_ioctl_space_info(const void *a, const void *b)
219 {
220         return cmp_chunk_block_group(
221                 ((struct btrfs_ioctl_space_info *)a)->flags,
222                 ((struct btrfs_ioctl_space_info *)b)->flags);
223 }
224
225 /*
226  * This function load all the information about the space usage
227  */
228 static struct btrfs_ioctl_space_args *load_space_info(int fd, char *path)
229 {
230         struct btrfs_ioctl_space_args *sargs = 0, *sargs_orig = 0;
231         int e, ret, count;
232
233         sargs_orig = sargs = calloc(1, sizeof(struct btrfs_ioctl_space_args));
234         if (!sargs) {
235                 fprintf(stderr, "ERROR: not enough memory\n");
236                 return NULL;
237         }
238
239         sargs->space_slots = 0;
240         sargs->total_spaces = 0;
241
242         ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
243         e = errno;
244         if (ret) {
245                 fprintf(stderr,
246                         "ERROR: couldn't get space info on '%s' - %s\n",
247                         path, strerror(e));
248                 free(sargs);
249                 return NULL;
250         }
251         if (!sargs->total_spaces) {
252                 free(sargs);
253                 printf("No chunks found\n");
254                 return NULL;
255         }
256
257         count = sargs->total_spaces;
258
259         sargs = realloc(sargs, sizeof(struct btrfs_ioctl_space_args) +
260                         (count * sizeof(struct btrfs_ioctl_space_info)));
261         if (!sargs) {
262                 free(sargs_orig);
263                 fprintf(stderr, "ERROR: not enough memory\n");
264                 return NULL;
265         }
266
267         sargs->space_slots = count;
268         sargs->total_spaces = 0;
269
270         ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
271         e = errno;
272
273         if (ret) {
274                 fprintf(stderr,
275                         "ERROR: couldn't get space info on '%s' - %s\n",
276                         path, strerror(e));
277                 free(sargs);
278                 return NULL;
279         }
280
281         qsort(&(sargs->spaces), count, sizeof(struct btrfs_ioctl_space_info),
282                 cmp_btrfs_ioctl_space_info);
283
284         return sargs;
285 }
286
287 /*
288  * This function computes the space occuped by a *single* RAID5/RAID6 chunk.
289  * The computation is performed on the basis of the number of stripes
290  * which compose the chunk, which could be different from the number of devices
291  * if a disk is added later.
292  */
293 static void get_raid56_used(int fd, struct chunk_info *chunks, int chunkcount,
294                 u64 *raid5_used, u64 *raid6_used)
295 {
296         struct chunk_info *info_ptr = chunks;
297         *raid5_used = 0;
298         *raid6_used = 0;
299
300         while (chunkcount-- > 0) {
301                 if (info_ptr->type & BTRFS_BLOCK_GROUP_RAID5)
302                         (*raid5_used) += info_ptr->size / (info_ptr->num_stripes - 1);
303                 if (info_ptr->type & BTRFS_BLOCK_GROUP_RAID6)
304                         (*raid6_used) += info_ptr->size / (info_ptr->num_stripes - 2);
305                 info_ptr++;
306         }
307 }
308
309 static int print_filesystem_usage_overall(int fd, struct chunk_info *chunkinfo,
310                 int chunkcount, struct device_info *devinfo, int devcount,
311                 char *path, int mode)
312 {
313         struct btrfs_ioctl_space_args *sargs = 0;
314         int i;
315         int ret = 0;
316         int e, width;
317         u64 total_disk;         /* filesystem size == sum of
318                                    device sizes */
319         u64 total_chunks;       /* sum of chunks sizes on disk(s) */
320         u64 total_used;         /* logical space used */
321         u64 total_free;         /* logical space un-used */
322         double K;
323         u64 raid5_used, raid6_used;
324         u64 global_reserve;
325         u64 global_reserve_used;
326
327         sargs = load_space_info(fd, path);
328         if (!sargs) {
329                 ret = 1;
330                 goto exit;
331         }
332
333         total_disk = disk_size(path);
334         e = errno;
335         if (total_disk == 0) {
336                 fprintf(stderr,
337                         "ERROR: couldn't get space info on '%s' - %s\n",
338                         path, strerror(e));
339
340                 ret = 1;
341                 goto exit;
342         }
343         get_raid56_used(fd, chunkinfo, chunkcount, &raid5_used, &raid6_used);
344
345         total_chunks = 0;
346         total_used = 0;
347         total_free = 0;
348         global_reserve = 0;
349         global_reserve_used = 0;
350
351         for (i = 0; i < sargs->total_spaces; i++) {
352                 float ratio = 1;
353                 u64 allocated;
354                 u64 flags = sargs->spaces[i].flags;
355
356                 /*
357                  * The raid5/raid6 ratio depends by the stripes number
358                  * used by every chunk. It is computed separately
359                  */
360                 if (flags & BTRFS_BLOCK_GROUP_RAID0)
361                         ratio = 1;
362                 else if (flags & BTRFS_BLOCK_GROUP_RAID1)
363                         ratio = 2;
364                 else if (flags & BTRFS_BLOCK_GROUP_RAID5)
365                         ratio = 0;
366                 else if (flags & BTRFS_BLOCK_GROUP_RAID6)
367                         ratio = 0;
368                 else if (flags & BTRFS_BLOCK_GROUP_DUP)
369                         ratio = 2;
370                 else if (flags & BTRFS_BLOCK_GROUP_RAID10)
371                         ratio = 2;
372                 else
373                         ratio = 1;
374
375                 if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV) {
376                         global_reserve = sargs->spaces[i].total_bytes;
377                         global_reserve_used = sargs->spaces[i].used_bytes;
378                 }
379
380                 allocated = sargs->spaces[i].total_bytes * ratio;
381
382                 total_chunks += allocated;
383                 total_used += sargs->spaces[i].used_bytes;
384                 total_free += (sargs->spaces[i].total_bytes -
385                                         sargs->spaces[i].used_bytes);
386
387         }
388
389         /* add the raid5/6 allocated space */
390         total_chunks += raid5_used + raid6_used;
391
392         K = ((double)total_used + (double)total_free) / (double)total_chunks;
393
394         if (mode == UNITS_HUMAN)
395                 width = 10;
396         else
397                 width = 18;
398
399         printf("Overall:\n");
400
401         printf("    Device size:\t\t%*s\n", width,
402                 pretty_size_mode(total_disk, mode));
403         printf("    Device allocated:\t\t%*s\n", width,
404                 pretty_size_mode(total_chunks, mode));
405         printf("    Device unallocated:\t\t%*s\n", width,
406                 pretty_size_mode(total_disk - total_chunks, mode));
407         printf("    Used:\t\t\t%*s\n", width,
408                 pretty_size_mode(total_used, mode));
409         printf("    Free (Estimated):\t\t%*s\t(",
410                 width,
411                 pretty_size_mode((u64)(K * total_disk - total_used), mode));
412         printf("Max: %s, ",
413                 pretty_size_mode(total_disk - total_chunks + total_free, mode));
414         printf("min: %s)\n",
415                 pretty_size_mode((total_disk-total_chunks) / 2 + total_free, mode));
416         printf("    Data to device ratio:\t%*.0f %%\n",
417                 width - 2, K * 100);
418         printf("    Global reserve:\t\t%*s\t(used: %s)\n", width,
419                 pretty_size_mode(global_reserve, mode),
420                 pretty_size_mode(global_reserve_used, mode));
421
422 exit:
423
424         if (sargs)
425                 free(sargs);
426
427         return ret;
428 }
429
430 /*
431  *  Helper to sort the device_info structure
432  */
433 static int cmp_device_info(const void *a, const void *b)
434 {
435         return strcmp(((struct device_info *)a)->path,
436                         ((struct device_info *)b)->path);
437 }
438
439 /*
440  *  This function loads the device_info structure and put them in an array
441  */
442 static int load_device_info(int fd, struct device_info **device_info_ptr,
443                            int *device_info_count)
444 {
445         int ret, i, ndevs;
446         struct btrfs_ioctl_fs_info_args fi_args;
447         struct btrfs_ioctl_dev_info_args dev_info;
448         struct device_info *info;
449
450         *device_info_count = 0;
451         *device_info_ptr = 0;
452
453         ret = ioctl(fd, BTRFS_IOC_FS_INFO, &fi_args);
454         if (ret == -EPERM)
455                 return ret;
456         if (ret < 0) {
457                 fprintf(stderr, "ERROR: cannot get filesystem info\n");
458                 return ret;
459         }
460
461         info = calloc(fi_args.num_devices, sizeof(struct device_info));
462         if (!info) {
463                 fprintf(stderr, "ERROR: not enough memory\n");
464                 return ret;
465         }
466
467         for (i = 0, ndevs = 0 ; i <= fi_args.max_id ; i++) {
468                 BUG_ON(ndevs >= fi_args.num_devices);
469                 memset(&dev_info, 0, sizeof(dev_info));
470                 ret = get_device_info(fd, i, &dev_info);
471
472                 if (ret == -ENODEV)
473                         continue;
474                 if (ret) {
475                         fprintf(stderr,
476                             "ERROR: cannot get info about device devid=%d\n",
477                             i);
478                         free(info);
479                         return ret;
480                 }
481
482                 info[ndevs].devid = dev_info.devid;
483                 strcpy(info[ndevs].path, (char *)dev_info.path);
484                 info[ndevs].device_size = get_partition_size((char *)dev_info.path);
485                 info[ndevs].size = dev_info.total_bytes;
486                 ++ndevs;
487         }
488
489         BUG_ON(ndevs != fi_args.num_devices);
490         qsort(info, fi_args.num_devices,
491                 sizeof(struct device_info), cmp_device_info);
492
493         *device_info_count = fi_args.num_devices;
494         *device_info_ptr = info;
495
496         return 0;
497 }
498
499 int load_chunk_and_device_info(int fd, struct chunk_info **chunkinfo,
500                 int *chunkcount, struct device_info **devinfo, int *devcount)
501 {
502         int ret;
503
504         ret = load_chunk_info(fd, chunkinfo, chunkcount);
505         if (ret == -EPERM) {
506                 fprintf(stderr,
507                         "WARNING: can't read detailed chunk info, RAID5/6 numbers will be incorrect, run as root\n");
508         } else if (ret) {
509                 return ret;
510         }
511
512         ret = load_device_info(fd, devinfo, devcount);
513         if (ret == -EPERM) {
514                 fprintf(stderr,
515                         "WARNING: can't get filesystem info from ioctl(FS_INFO), run as root\n");
516                 ret = 0;
517         }
518
519         return ret;
520 }
521
522 /*
523  *  This function computes the size of a chunk in a disk
524  */
525 static u64 calc_chunk_size(struct chunk_info *ci)
526 {
527         if (ci->type & BTRFS_BLOCK_GROUP_RAID0)
528                 return ci->size / ci->num_stripes;
529         else if (ci->type & BTRFS_BLOCK_GROUP_RAID1)
530                 return ci->size ;
531         else if (ci->type & BTRFS_BLOCK_GROUP_DUP)
532                 return ci->size ;
533         else if (ci->type & BTRFS_BLOCK_GROUP_RAID5)
534                 return ci->size / (ci->num_stripes -1);
535         else if (ci->type & BTRFS_BLOCK_GROUP_RAID6)
536                 return ci->size / (ci->num_stripes -2);
537         else if (ci->type & BTRFS_BLOCK_GROUP_RAID10)
538                 return ci->size / ci->num_stripes;
539         return ci->size;
540 }
541
542 /*
543  *  This function print the results of the command "btrfs fi usage"
544  *  in tabular format
545  */
546 static void _cmd_filesystem_usage_tabular(int mode,
547                                         struct btrfs_ioctl_space_args *sargs,
548                                         struct chunk_info *chunks_info_ptr,
549                                         int chunks_info_count,
550                                         struct device_info *device_info_ptr,
551                                         int device_info_count)
552 {
553         int i;
554         u64 total_unused = 0;
555         struct string_table *matrix = 0;
556         int  ncols, nrows;
557
558         ncols = sargs->total_spaces + 2;
559         nrows = 2 + 1 + device_info_count + 1 + 2;
560
561         matrix = table_create(ncols, nrows);
562         if (!matrix) {
563                 fprintf(stderr, "ERROR: not enough memory\n");
564                 return;
565         }
566
567         /* header */
568         for (i = 0; i < sargs->total_spaces; i++) {
569                 const char *description;
570                 u64 flags = sargs->spaces[i].flags;
571
572                 if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV)
573                         continue;
574
575                 description = btrfs_group_type_str(flags);
576
577                 table_printf(matrix, 1+i, 0, "<%s", description);
578         }
579
580         for (i = 0; i < sargs->total_spaces; i++) {
581                 const char *r_mode;
582
583                 u64 flags = sargs->spaces[i].flags;
584                 r_mode = btrfs_group_profile_str(flags);
585
586                 table_printf(matrix, 1+i, 1, "<%s", r_mode);
587         }
588
589         table_printf(matrix, 1+sargs->total_spaces, 1, "<Unallocated");
590
591         /* body */
592         for (i = 0; i < device_info_count; i++) {
593                 int k, col;
594                 char *p;
595
596                 u64  total_allocated = 0, unused;
597
598                 p = strrchr(device_info_ptr[i].path, '/');
599                 if (!p)
600                         p = device_info_ptr[i].path;
601                 else
602                         p++;
603
604                 table_printf(matrix, 0, i + 3, "<%s", device_info_ptr[i].path);
605
606                 for (col = 1, k = 0 ; k < sargs->total_spaces ; k++)  {
607                         u64     flags = sargs->spaces[k].flags;
608                         u64 devid = device_info_ptr[i].devid;
609                         int     j;
610                         u64 size = 0;
611
612                         for (j = 0 ; j < chunks_info_count ; j++) {
613                                 if (chunks_info_ptr[j].type != flags )
614                                                 continue;
615                                 if (chunks_info_ptr[j].devid != devid)
616                                                 continue;
617
618                                 size += calc_chunk_size(chunks_info_ptr+j);
619                         }
620
621                         if (size)
622                                 table_printf(matrix, col, i+3,
623                                         ">%s", pretty_size_mode(size, mode));
624                         else
625                                 table_printf(matrix, col, i+3, ">-");
626
627                         total_allocated += size;
628                         col++;
629                 }
630
631                 unused = get_partition_size(device_info_ptr[i].path)
632                                 - total_allocated;
633
634                 table_printf(matrix, sargs->total_spaces + 1, i + 3,
635                                ">%s", pretty_size_mode(unused, mode));
636                 total_unused += unused;
637
638         }
639
640         for (i = 0; i <= sargs->total_spaces; i++)
641                 table_printf(matrix, i + 1, device_info_count + 3, "=");
642
643         /* footer */
644         table_printf(matrix, 0, device_info_count + 4, "<Total");
645         for (i = 0; i < sargs->total_spaces; i++)
646                 table_printf(matrix, 1 + i, device_info_count + 4, ">%s",
647                         pretty_size_mode(sargs->spaces[i].total_bytes, mode));
648
649         table_printf(matrix, sargs->total_spaces + 1, device_info_count + 4,
650                         ">%s", pretty_size_mode(total_unused, mode));
651
652         table_printf(matrix, 0, device_info_count + 5, "<Used");
653         for (i = 0; i < sargs->total_spaces; i++)
654                 table_printf(matrix, 1 + i, device_info_count+5, ">%s",
655                         pretty_size_mode(sargs->spaces[i].used_bytes, mode));
656
657         table_dump(matrix);
658         table_free(matrix);
659 }
660
661 /*
662  *  This function prints the unused space per every disk
663  */
664 static void print_unused(struct chunk_info *info_ptr,
665                           int info_count,
666                           struct device_info *device_info_ptr,
667                           int device_info_count,
668                           int mode)
669 {
670         int i;
671         for (i = 0; i < device_info_count; i++) {
672                 int     j;
673                 u64     total = 0;
674
675                 for (j = 0; j < info_count; j++)
676                         if (info_ptr[j].devid == device_info_ptr[i].devid)
677                                 total += calc_chunk_size(info_ptr+j);
678
679                 printf("   %s\t%10s\n",
680                         device_info_ptr[i].path,
681                         pretty_size_mode(device_info_ptr[i].size - total, mode));
682         }
683 }
684
685 /*
686  *  This function prints the allocated chunk per every disk
687  */
688 static void print_chunk_device(u64 chunk_type,
689                                 struct chunk_info *chunks_info_ptr,
690                                 int chunks_info_count,
691                                 struct device_info *device_info_ptr,
692                                 int device_info_count,
693                                 int mode)
694 {
695         int i;
696
697         for (i = 0; i < device_info_count; i++) {
698                 int     j;
699                 u64     total = 0;
700
701                 for (j = 0; j < chunks_info_count; j++) {
702
703                         if (chunks_info_ptr[j].type != chunk_type)
704                                 continue;
705                         if (chunks_info_ptr[j].devid != device_info_ptr[i].devid)
706                                 continue;
707
708                         total += calc_chunk_size(&(chunks_info_ptr[j]));
709                         //total += chunks_info_ptr[j].size;
710                 }
711
712                 if (total > 0)
713                         printf("   %s\t%10s\n",
714                                 device_info_ptr[i].path,
715                                 pretty_size_mode(total, mode));
716         }
717 }
718
719 /*
720  *  This function print the results of the command "btrfs fi usage"
721  *  in linear format
722  */
723 static void _cmd_filesystem_usage_linear(int mode,
724                                         struct btrfs_ioctl_space_args *sargs,
725                                         struct chunk_info *info_ptr,
726                                         int info_count,
727                                         struct device_info *device_info_ptr,
728                                         int device_info_count)
729 {
730         int i;
731
732         for (i = 0; i < sargs->total_spaces; i++) {
733                 const char *description;
734                 const char *r_mode;
735                 u64 flags = sargs->spaces[i].flags;
736
737                 if (flags & BTRFS_SPACE_INFO_GLOBAL_RSV)
738                         continue;
739
740                 description = btrfs_group_type_str(flags);
741                 r_mode = btrfs_group_profile_str(flags);
742
743                 printf("%s,%s: Size:%s, ",
744                         description,
745                         r_mode,
746                         pretty_size_mode(sargs->spaces[i].total_bytes,
747                             mode));
748                 printf("Used:%s\n",
749                         pretty_size_mode(sargs->spaces[i].used_bytes, mode));
750                 print_chunk_device(flags, info_ptr, info_count,
751                                 device_info_ptr, device_info_count, mode);
752                 printf("\n");
753         }
754
755         printf("Unallocated:\n");
756         print_unused(info_ptr, info_count, device_info_ptr, device_info_count,
757                         mode);
758 }
759
760 static int print_filesystem_usage_by_chunk(int fd,
761                 struct chunk_info *chunkinfo, int chunkcount,
762                 struct device_info *devinfo, int devcount,
763                 char *path, int mode, int tabular)
764 {
765         struct btrfs_ioctl_space_args *sargs;
766         int ret = 0;
767
768         if (!chunkinfo)
769                 return 0;
770
771         sargs = load_space_info(fd, path);
772         if (!sargs) {
773                 ret = 1;
774                 goto out;
775         }
776
777         if (tabular)
778                 _cmd_filesystem_usage_tabular(mode, sargs, chunkinfo,
779                                 chunkcount, devinfo, devcount);
780         else
781                 _cmd_filesystem_usage_linear(mode, sargs, chunkinfo,
782                                 chunkcount, devinfo, devcount);
783
784         free(sargs);
785 out:
786         return ret;
787 }
788
789 const char * const cmd_filesystem_usage_usage[] = {
790         "btrfs filesystem usage [-b][-t] <path> [<path>..]",
791         "Show in which disk the chunks are allocated.",
792         "",
793         "-b\tSet byte as unit",
794         "-t\tShow data in tabular format",
795         NULL
796 };
797
798 int cmd_filesystem_usage(int argc, char **argv)
799 {
800         int mode = UNITS_HUMAN;
801         int ret = 0;
802         int     i, more_than_one = 0;
803         int     tabular = 0;
804
805         optind = 1;
806         while (1) {
807                 int c = getopt(argc, argv, "bt");
808
809                 if (c < 0)
810                         break;
811
812                 switch (c) {
813                 case 'b':
814                         mode = UNITS_RAW;
815                         break;
816                 case 't':
817                         tabular = 1;
818                         break;
819                 default:
820                         usage(cmd_filesystem_usage_usage);
821                 }
822         }
823
824         if (check_argc_min(argc - optind, 1))
825                 usage(cmd_filesystem_usage_usage);
826
827         for (i = optind; i < argc; i++) {
828                 int fd;
829                 DIR *dirstream = NULL;
830                 struct chunk_info *chunkinfo = NULL;
831                 struct device_info *devinfo = NULL;
832                 int chunkcount = 0;
833                 int devcount = 0;
834
835                 fd = open_file_or_dir(argv[i], &dirstream);
836                 if (fd < 0) {
837                         fprintf(stderr, "ERROR: can't access '%s'\n",
838                                 argv[i]);
839                         ret = 1;
840                         goto out;
841                 }
842                 if (more_than_one)
843                         printf("\n");
844
845                 ret = load_chunk_and_device_info(fd, &chunkinfo, &chunkcount,
846                                 &devinfo, &devcount);
847                 if (ret)
848                         goto cleanup;
849
850                 ret = print_filesystem_usage_overall(fd, chunkinfo, chunkcount,
851                                 devinfo, devcount, argv[i], mode);
852                 if (ret)
853                         goto cleanup;
854                 printf("\n");
855                 ret = print_filesystem_usage_by_chunk(fd, chunkinfo, chunkcount,
856                                 devinfo, devcount, argv[i], mode, tabular);
857 cleanup:
858                 close_file_or_dir(fd, dirstream);
859                 free(chunkinfo);
860                 free(devinfo);
861
862                 if (ret)
863                         goto out;
864                 more_than_one = 1;
865         }
866
867 out:
868         return !!ret;
869 }
870
871 void print_device_chunks(int fd, struct device_info *devinfo,
872                 struct chunk_info *chunks_info_ptr,
873                 int chunks_info_count, int mode)
874 {
875         int i;
876         u64 allocated = 0;
877
878         for (i = 0 ; i < chunks_info_count ; i++) {
879                 const char *description;
880                 const char *r_mode;
881                 u64 flags;
882                 u64 size;
883
884                 if (chunks_info_ptr[i].devid != devinfo->devid)
885                         continue;
886
887                 flags = chunks_info_ptr[i].type;
888
889                 description = btrfs_group_type_str(flags);
890                 r_mode = btrfs_group_profile_str(flags);
891                 size = calc_chunk_size(chunks_info_ptr+i);
892                 printf("   %s,%s:%*s%10s\n",
893                         description,
894                         r_mode,
895                         (int)(20 - strlen(description) - strlen(r_mode)), "",
896                         pretty_size_mode(size, mode));
897
898                 allocated += size;
899
900         }
901         printf("   Unallocated: %*s%10s\n",
902                 (int)(20 - strlen("Unallocated")), "",
903                 pretty_size_mode(devinfo->size - allocated, mode));
904 }
905
906 void print_device_sizes(int fd, struct device_info *devinfo, int mode)
907 {
908         printf("   Device size: %*s%10s\n",
909                 (int)(20 - strlen("Device size")), "",
910                 pretty_size_mode(devinfo->device_size, mode));
911 #if 0
912         /*
913          * The term has not seen an agreement and we don't want to change it
914          * once it's in non-development branches or even released.
915          */
916         printf("   FS occupied: %*s%10s\n",
917                 (int)(20 - strlen("FS occupied")), "",
918                 pretty_size_mode(devinfo->size, mode));
919 #endif
920 }