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.
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.
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.
21 #include <sys/ioctl.h>
23 #include <uuid/uuid.h>
28 #include <linux/limits.h>
31 #include <btrfsutil.h>
33 #include "kerncompat.h"
38 #include "cmds-fi-usage.h"
39 #include "list_sort.h"
44 * for btrfs fi show, we maintain a hash of fsids we've already printed.
45 * This way we don't print dups if a given FS is mounted more than once.
47 static struct seen_fsid
*seen_fsid_hash
[SEEN_FSID_HASH_SIZE
] = {NULL
,};
49 static const char * const filesystem_cmd_group_usage
[] = {
50 "btrfs filesystem [<group>] <command> [<args>]",
54 static const char * const cmd_filesystem_df_usage
[] = {
55 "btrfs filesystem df [options] <path>",
56 "Show space usage information for a mount point",
57 HELPINFO_UNITS_SHORT_LONG
,
61 static int get_df(int fd
, struct btrfs_ioctl_space_args
**sargs_ret
)
65 struct btrfs_ioctl_space_args
*sargs
;
67 sargs
= malloc(sizeof(struct btrfs_ioctl_space_args
));
71 sargs
->space_slots
= 0;
72 sargs
->total_spaces
= 0;
74 ret
= ioctl(fd
, BTRFS_IOC_SPACE_INFO
, sargs
);
76 error("cannot get space info: %m");
80 /* This really should never happen */
81 if (!sargs
->total_spaces
) {
85 count
= sargs
->total_spaces
;
88 sargs
= malloc(sizeof(struct btrfs_ioctl_space_args
) +
89 (count
* sizeof(struct btrfs_ioctl_space_info
)));
93 sargs
->space_slots
= count
;
94 sargs
->total_spaces
= 0;
95 ret
= ioctl(fd
, BTRFS_IOC_SPACE_INFO
, sargs
);
97 error("cannot get space info with %llu slots: %m",
106 static void print_df(struct btrfs_ioctl_space_args
*sargs
, unsigned unit_mode
)
109 struct btrfs_ioctl_space_info
*sp
= sargs
->spaces
;
111 for (i
= 0; i
< sargs
->total_spaces
; i
++, sp
++) {
112 printf("%s, %s: total=%s, used=%s\n",
113 btrfs_group_type_str(sp
->flags
),
114 btrfs_group_profile_str(sp
->flags
),
115 pretty_size_mode(sp
->total_bytes
, unit_mode
),
116 pretty_size_mode(sp
->used_bytes
, unit_mode
));
120 static int cmd_filesystem_df(int argc
, char **argv
)
122 struct btrfs_ioctl_space_args
*sargs
= NULL
;
126 DIR *dirstream
= NULL
;
129 unit_mode
= get_unit_mode_from_arg(&argc
, argv
, 1);
131 clean_args_no_options(argc
, argv
, cmd_filesystem_df_usage
);
133 if (check_argc_exact(argc
- optind
, 1))
134 usage(cmd_filesystem_df_usage
);
138 fd
= btrfs_open_dir(path
, &dirstream
, 1);
142 ret
= get_df(fd
, &sargs
);
145 print_df(sargs
, unit_mode
);
148 error("get_df failed %s", strerror(-ret
));
151 close_file_or_dir(fd
, dirstream
);
155 static int match_search_item_kernel(u8
*fsid
, char *mnt
, char *label
,
158 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
159 int search_len
= strlen(search
);
161 search_len
= min(search_len
, BTRFS_UUID_UNPARSED_SIZE
);
162 uuid_unparse(fsid
, uuidbuf
);
163 if (!strncmp(uuidbuf
, search
, search_len
))
166 if (*label
&& strcmp(label
, search
) == 0)
169 if (strcmp(mnt
, search
) == 0)
175 static int uuid_search(struct btrfs_fs_devices
*fs_devices
, const char *search
)
177 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
178 struct btrfs_device
*device
;
179 int search_len
= strlen(search
);
181 search_len
= min(search_len
, BTRFS_UUID_UNPARSED_SIZE
);
182 uuid_unparse(fs_devices
->fsid
, uuidbuf
);
183 if (!strncmp(uuidbuf
, search
, search_len
))
186 list_for_each_entry(device
, &fs_devices
->devices
, dev_list
) {
187 if ((device
->label
&& strcmp(device
->label
, search
) == 0) ||
188 strcmp(device
->name
, search
) == 0)
195 * Sort devices by devid, ascending
197 static int cmp_device_id(void *priv
, struct list_head
*a
,
200 const struct btrfs_device
*da
= list_entry(a
, struct btrfs_device
,
202 const struct btrfs_device
*db
= list_entry(b
, struct btrfs_device
,
205 return da
->devid
< db
->devid
? -1 :
206 da
->devid
> db
->devid
? 1 : 0;
209 static void splice_device_list(struct list_head
*seed_devices
,
210 struct list_head
*all_devices
)
212 struct btrfs_device
*in_all
, *next_all
;
213 struct btrfs_device
*in_seed
, *next_seed
;
215 list_for_each_entry_safe(in_all
, next_all
, all_devices
, dev_list
) {
216 list_for_each_entry_safe(in_seed
, next_seed
, seed_devices
,
218 if (in_all
->devid
== in_seed
->devid
) {
220 * When do dev replace in a sprout fs
221 * to a dev in its seed fs, the replacing
222 * dev will reside in the sprout fs and
223 * the replaced dev will still exist
225 * So pick the latest one when showing
228 if (in_all
->generation
229 < in_seed
->generation
) {
230 list_del(&in_all
->dev_list
);
232 } else if (in_all
->generation
233 > in_seed
->generation
) {
234 list_del(&in_seed
->dev_list
);
242 list_splice(seed_devices
, all_devices
);
245 static void print_devices(struct btrfs_fs_devices
*fs_devices
,
246 u64
*devs_found
, unsigned unit_mode
)
248 struct btrfs_device
*device
;
249 struct btrfs_fs_devices
*cur_fs
;
250 struct list_head
*all_devices
;
252 all_devices
= &fs_devices
->devices
;
253 cur_fs
= fs_devices
->seed
;
254 /* add all devices of seed fs to the fs to be printed */
256 splice_device_list(&cur_fs
->devices
, all_devices
);
257 cur_fs
= cur_fs
->seed
;
260 list_sort(NULL
, all_devices
, cmp_device_id
);
261 list_for_each_entry(device
, all_devices
, dev_list
) {
262 printf("\tdevid %4llu size %s used %s path %s\n",
263 (unsigned long long)device
->devid
,
264 pretty_size_mode(device
->total_bytes
, unit_mode
),
265 pretty_size_mode(device
->bytes_used
, unit_mode
),
272 static void print_one_uuid(struct btrfs_fs_devices
*fs_devices
,
275 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
276 struct btrfs_device
*device
;
280 if (add_seen_fsid(fs_devices
->fsid
, seen_fsid_hash
, -1, NULL
))
283 uuid_unparse(fs_devices
->fsid
, uuidbuf
);
284 device
= list_entry(fs_devices
->devices
.next
, struct btrfs_device
,
286 if (device
->label
&& device
->label
[0])
287 printf("Label: '%s' ", device
->label
);
289 printf("Label: none ");
291 total
= device
->total_devs
;
292 printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf
,
293 (unsigned long long)total
,
294 pretty_size_mode(device
->super_bytes_used
, unit_mode
));
296 print_devices(fs_devices
, &devs_found
, unit_mode
);
298 if (devs_found
< total
) {
299 printf("\t*** Some devices missing\n");
304 /* adds up all the used spaces as reported by the space info ioctl
306 static u64
calc_used_bytes(struct btrfs_ioctl_space_args
*si
)
310 for (i
= 0; i
< si
->total_spaces
; i
++)
311 ret
+= si
->spaces
[i
].used_bytes
;
315 static int print_one_fs(struct btrfs_ioctl_fs_info_args
*fs_info
,
316 struct btrfs_ioctl_dev_info_args
*dev_info
,
317 struct btrfs_ioctl_space_args
*space_info
,
318 char *label
, unsigned unit_mode
)
323 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
324 struct btrfs_ioctl_dev_info_args
*tmp_dev_info
;
327 ret
= add_seen_fsid(fs_info
->fsid
, seen_fsid_hash
, -1, NULL
);
333 uuid_unparse(fs_info
->fsid
, uuidbuf
);
335 printf("Label: '%s' ", label
);
337 printf("Label: none ");
339 printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf
,
340 fs_info
->num_devices
,
341 pretty_size_mode(calc_used_bytes(space_info
),
344 for (i
= 0; i
< fs_info
->num_devices
; i
++) {
345 char *canonical_path
;
347 tmp_dev_info
= (struct btrfs_ioctl_dev_info_args
*)&dev_info
[i
];
349 /* Add check for missing devices even mounted */
350 fd
= open((char *)tmp_dev_info
->path
, O_RDONLY
);
356 canonical_path
= canonicalize_path((char *)tmp_dev_info
->path
);
357 printf("\tdevid %4llu size %s used %s path %s\n",
359 pretty_size_mode(tmp_dev_info
->total_bytes
, unit_mode
),
360 pretty_size_mode(tmp_dev_info
->bytes_used
, unit_mode
),
363 free(canonical_path
);
367 printf("\t*** Some devices missing\n");
372 static int btrfs_scan_kernel(void *search
, unsigned unit_mode
)
378 struct btrfs_ioctl_fs_info_args fs_info_arg
;
379 struct btrfs_ioctl_dev_info_args
*dev_info_arg
= NULL
;
380 struct btrfs_ioctl_space_args
*space_info_arg
= NULL
;
381 char label
[BTRFS_LABEL_SIZE
];
383 f
= setmntent("/proc/self/mounts", "r");
387 memset(label
, 0, sizeof(label
));
388 while ((mnt
= getmntent(f
)) != NULL
) {
391 if (strcmp(mnt
->mnt_type
, "btrfs"))
393 ret
= get_fs_info(mnt
->mnt_dir
, &fs_info_arg
,
398 /* skip all fs already shown as mounted fs */
399 if (is_seen_fsid(fs_info_arg
.fsid
, seen_fsid_hash
))
402 ret
= get_label_mounted(mnt
->mnt_dir
, label
);
403 /* provide backward kernel compatibility */
405 ret
= get_label_unmounted(
406 (const char *)dev_info_arg
->path
, label
);
411 if (search
&& !match_search_item_kernel(fs_info_arg
.fsid
,
412 mnt
->mnt_dir
, label
, search
)) {
416 fd
= open(mnt
->mnt_dir
, O_RDONLY
);
417 if ((fd
!= -1) && !get_df(fd
, &space_info_arg
)) {
418 print_one_fs(&fs_info_arg
, dev_info_arg
,
419 space_info_arg
, label
, unit_mode
);
420 free(space_info_arg
);
421 memset(label
, 0, sizeof(label
));
434 static void free_fs_devices(struct btrfs_fs_devices
*fs_devices
)
436 struct btrfs_fs_devices
*cur_seed
, *next_seed
;
437 struct btrfs_device
*device
;
439 while (!list_empty(&fs_devices
->devices
)) {
440 device
= list_entry(fs_devices
->devices
.next
,
441 struct btrfs_device
, dev_list
);
442 list_del(&device
->dev_list
);
449 /* free seed fs chain */
450 cur_seed
= fs_devices
->seed
;
451 fs_devices
->seed
= NULL
;
453 next_seed
= cur_seed
->seed
;
456 cur_seed
= next_seed
;
459 list_del(&fs_devices
->list
);
463 static int copy_device(struct btrfs_device
*dst
,
464 struct btrfs_device
*src
)
466 dst
->devid
= src
->devid
;
467 memcpy(dst
->uuid
, src
->uuid
, BTRFS_UUID_SIZE
);
468 if (src
->name
== NULL
)
471 dst
->name
= strdup(src
->name
);
475 if (src
->label
== NULL
)
478 dst
->label
= strdup(src
->label
);
484 dst
->total_devs
= src
->total_devs
;
485 dst
->super_bytes_used
= src
->super_bytes_used
;
486 dst
->total_bytes
= src
->total_bytes
;
487 dst
->bytes_used
= src
->bytes_used
;
488 dst
->generation
= src
->generation
;
493 static int copy_fs_devices(struct btrfs_fs_devices
*dst
,
494 struct btrfs_fs_devices
*src
)
496 struct btrfs_device
*cur_dev
, *dev_copy
;
499 memcpy(dst
->fsid
, src
->fsid
, BTRFS_FSID_SIZE
);
500 INIT_LIST_HEAD(&dst
->devices
);
503 list_for_each_entry(cur_dev
, &src
->devices
, dev_list
) {
504 dev_copy
= malloc(sizeof(*dev_copy
));
510 ret
= copy_device(dev_copy
, cur_dev
);
516 list_add(&dev_copy
->dev_list
, &dst
->devices
);
517 dev_copy
->fs_devices
= dst
;
523 static int find_and_copy_seed(struct btrfs_fs_devices
*seed
,
524 struct btrfs_fs_devices
*copy
,
525 struct list_head
*fs_uuids
) {
526 struct btrfs_fs_devices
*cur_fs
;
528 list_for_each_entry(cur_fs
, fs_uuids
, list
)
529 if (!memcmp(seed
->fsid
, cur_fs
->fsid
, BTRFS_FSID_SIZE
))
530 return copy_fs_devices(copy
, cur_fs
);
535 static int has_seed_devices(struct btrfs_fs_devices
*fs_devices
)
537 struct btrfs_device
*device
;
538 int dev_cnt_total
, dev_cnt
= 0;
540 device
= list_first_entry(&fs_devices
->devices
, struct btrfs_device
,
543 dev_cnt_total
= device
->total_devs
;
545 list_for_each_entry(device
, &fs_devices
->devices
, dev_list
)
548 return dev_cnt_total
!= dev_cnt
;
551 static int search_umounted_fs_uuids(struct list_head
*all_uuids
,
552 char *search
, int *found
)
554 struct btrfs_fs_devices
*cur_fs
, *fs_copy
;
555 struct list_head
*fs_uuids
;
558 fs_uuids
= btrfs_scanned_uuids();
561 * The fs_uuids list is global, and open_ctree_* will
562 * modify it, make a private copy here
564 list_for_each_entry(cur_fs
, fs_uuids
, list
) {
565 /* don't bother handle all fs, if search target specified */
567 if (uuid_search(cur_fs
, search
) == 0)
573 /* skip all fs already shown as mounted fs */
574 if (is_seen_fsid(cur_fs
->fsid
, seen_fsid_hash
))
577 fs_copy
= calloc(1, sizeof(*fs_copy
));
583 ret
= copy_fs_devices(fs_copy
, cur_fs
);
589 list_add(&fs_copy
->list
, all_uuids
);
596 static int map_seed_devices(struct list_head
*all_uuids
)
598 struct btrfs_fs_devices
*cur_fs
, *cur_seed
;
599 struct btrfs_fs_devices
*seed_copy
;
600 struct btrfs_fs_devices
*opened_fs
;
601 struct btrfs_device
*device
;
602 struct btrfs_fs_info
*fs_info
;
603 struct list_head
*fs_uuids
;
606 fs_uuids
= btrfs_scanned_uuids();
608 list_for_each_entry(cur_fs
, all_uuids
, list
) {
609 device
= list_first_entry(&cur_fs
->devices
,
610 struct btrfs_device
, dev_list
);
614 /* skip fs without seeds */
615 if (!has_seed_devices(cur_fs
))
619 * open_ctree_* detects seed/sprout mapping
621 fs_info
= open_ctree_fs_info(device
->name
, 0, 0, 0,
627 * copy the seed chain under the opened fs
629 opened_fs
= fs_info
->fs_devices
;
631 while (opened_fs
->seed
) {
632 seed_copy
= malloc(sizeof(*seed_copy
));
637 ret
= find_and_copy_seed(opened_fs
->seed
, seed_copy
,
644 cur_seed
->seed
= seed_copy
;
646 opened_fs
= opened_fs
->seed
;
647 cur_seed
= cur_seed
->seed
;
650 close_ctree(fs_info
->chunk_root
);
656 close_ctree(fs_info
->chunk_root
);
660 static const char * const cmd_filesystem_show_usage
[] = {
661 "btrfs filesystem show [options] [<path>|<uuid>|<device>|label]",
662 "Show the structure of a filesystem",
663 "-d|--all-devices show only disks under /dev containing btrfs filesystem",
664 "-m|--mounted show only mounted btrfs",
666 "If no argument is given, structure of all present filesystems is shown.",
670 static int cmd_filesystem_show(int argc
, char **argv
)
672 LIST_HEAD(all_uuids
);
673 struct btrfs_fs_devices
*fs_devices
;
676 /* default, search both kernel and udev */
681 u8 fsid
[BTRFS_FSID_SIZE
];
682 char uuid_buf
[BTRFS_UUID_UNPARSED_SIZE
];
686 unit_mode
= get_unit_mode_from_arg(&argc
, argv
, 0);
690 static const struct option long_options
[] = {
691 { "all-devices", no_argument
, NULL
, 'd'},
692 { "mounted", no_argument
, NULL
, 'm'},
696 c
= getopt_long(argc
, argv
, "dm", long_options
, NULL
);
701 where
= BTRFS_SCAN_LBLKID
;
704 where
= BTRFS_SCAN_MOUNTED
;
707 usage(cmd_filesystem_show_usage
);
711 if (check_argc_max(argc
, optind
+ 1))
712 usage(cmd_filesystem_show_usage
);
715 search
= argv
[optind
];
717 usage(cmd_filesystem_show_usage
);
718 type
= check_arg_type(search
);
721 * For search is a device:
722 * realpath do /dev/mapper/XX => /dev/dm-X
723 * which is required by BTRFS_SCAN_DEV
724 * For search is a mountpoint:
725 * realpath do /mnt/btrfs/ => /mnt/btrfs
726 * which shall be recognized by btrfs_scan_kernel()
728 if (realpath(search
, path
))
732 * Needs special handling if input arg is block dev And if
733 * input arg is mount-point just print it right away
735 if (type
== BTRFS_ARG_BLKDEV
&& where
!= BTRFS_SCAN_LBLKID
) {
736 ret
= get_btrfs_mount(search
, mp
, sizeof(mp
));
738 /* given block dev is mounted */
740 type
= BTRFS_ARG_MNTPOINT
;
742 ret
= dev_to_fsid(search
, fsid
);
744 error("no btrfs on %s", search
);
747 uuid_unparse(fsid
, uuid_buf
);
749 type
= BTRFS_ARG_UUID
;
755 if (where
== BTRFS_SCAN_LBLKID
)
758 /* show mounted btrfs */
759 ret
= btrfs_scan_kernel(search
, unit_mode
);
760 if (search
&& !ret
) {
761 /* since search is found we are done */
765 /* shows mounted only */
766 if (where
== BTRFS_SCAN_MOUNTED
)
770 ret
= btrfs_scan_devices();
773 error("blkid device scan returned %d", ret
);
777 ret
= search_umounted_fs_uuids(&all_uuids
, search
, &found
);
779 error("searching target device returned error %d", ret
);
784 * The seed/sprout mapping are not detected yet,
785 * do mapping build for all umounted fs
787 ret
= map_seed_devices(&all_uuids
);
789 error("mapping seed devices returned error %d", ret
);
793 list_for_each_entry(fs_devices
, &all_uuids
, list
)
794 print_one_uuid(fs_devices
, unit_mode
);
796 if (search
&& !found
) {
797 error("not a valid btrfs filesystem: %s", search
);
800 while (!list_empty(&all_uuids
)) {
801 fs_devices
= list_entry(all_uuids
.next
,
802 struct btrfs_fs_devices
, list
);
803 free_fs_devices(fs_devices
);
806 free_seen_fsid(seen_fsid_hash
);
810 static const char * const cmd_filesystem_sync_usage
[] = {
811 "btrfs filesystem sync <path>",
812 "Force a sync on a filesystem",
816 static int cmd_filesystem_sync(int argc
, char **argv
)
818 enum btrfs_util_error err
;
820 clean_args_no_options(argc
, argv
, cmd_filesystem_sync_usage
);
822 if (check_argc_exact(argc
- optind
, 1))
823 usage(cmd_filesystem_sync_usage
);
825 err
= btrfs_util_sync(argv
[optind
]);
827 error_btrfs_util(err
);
834 static int parse_compress_type(char *s
)
836 if (strcmp(optarg
, "zlib") == 0)
837 return BTRFS_COMPRESS_ZLIB
;
838 else if (strcmp(optarg
, "lzo") == 0)
839 return BTRFS_COMPRESS_LZO
;
840 else if (strcmp(optarg
, "zstd") == 0)
841 return BTRFS_COMPRESS_ZSTD
;
843 error("unknown compression type %s", s
);
848 static const char * const cmd_filesystem_defrag_usage
[] = {
849 "btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
850 "Defragment a file or a directory",
853 "-r defragment files recursively",
854 "-c[zlib,lzo,zstd] compress the file while defragmenting",
855 "-f flush data to disk immediately after defragmenting",
856 "-s start defragment only from byte onward",
857 "-l len defragment only up to len bytes",
858 "-t size target extent size hint (default: 32M)",
860 "Warning: most Linux kernels will break up the ref-links of COW data",
861 "(e.g., files copied with 'cp --reflink', snapshots) which may cause",
862 "considerable increase of space usage. See btrfs-filesystem(8) for",
867 static struct btrfs_ioctl_defrag_range_args defrag_global_range
;
868 static int defrag_global_verbose
;
869 static int defrag_global_errors
;
870 static int defrag_callback(const char *fpath
, const struct stat
*sb
,
871 int typeflag
, struct FTW
*ftwbuf
)
876 if ((typeflag
== FTW_F
) && S_ISREG(sb
->st_mode
)) {
877 if (defrag_global_verbose
)
878 printf("%s\n", fpath
);
879 fd
= open(fpath
, O_RDWR
);
883 ret
= ioctl(fd
, BTRFS_IOC_DEFRAG_RANGE
, &defrag_global_range
);
885 if (ret
&& errno
== ENOTTY
) {
887 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
888 defrag_global_errors
++;
898 error("defrag failed on %s: %m", fpath
);
899 defrag_global_errors
++;
903 static int cmd_filesystem_defrag(int argc
, char **argv
)
913 int compress_type
= BTRFS_COMPRESS_NONE
;
917 * Kernel has a different default (256K) that is supposed to be safe,
918 * but it does not defragment very well. The 32M will likely lead to
919 * better results and is independent of the kernel default. We have to
920 * use the v2 defrag ioctl.
924 defrag_global_errors
= 0;
925 defrag_global_verbose
= 0;
926 defrag_global_errors
= 0;
928 int c
= getopt(argc
, argv
, "vrc::fs:l:t:");
934 compress_type
= BTRFS_COMPRESS_ZLIB
;
936 compress_type
= parse_compress_type(optarg
);
942 defrag_global_verbose
= 1;
945 start
= parse_size(optarg
);
948 len
= parse_size(optarg
);
951 thresh
= parse_size(optarg
);
952 if (thresh
> (u32
)-1) {
954 "target extent size %llu too big, trimmed to %u",
963 usage(cmd_filesystem_defrag_usage
);
967 if (check_argc_min(argc
- optind
, 1))
968 usage(cmd_filesystem_defrag_usage
);
970 memset(&defrag_global_range
, 0, sizeof(defrag_global_range
));
971 defrag_global_range
.start
= start
;
972 defrag_global_range
.len
= len
;
973 defrag_global_range
.extent_thresh
= (u32
)thresh
;
975 defrag_global_range
.flags
|= BTRFS_DEFRAG_RANGE_COMPRESS
;
976 defrag_global_range
.compress_type
= compress_type
;
979 defrag_global_range
.flags
|= BTRFS_DEFRAG_RANGE_START_IO
;
982 * Look for directory arguments and warn if the recursive mode is not
983 * requested, as this is not implemented as recursive defragmentation
984 * in kernel. The stat errors are silent here as we check them below.
989 for (i
= optind
; i
< argc
; i
++) {
992 if (stat(argv
[i
], &st
))
995 if (S_ISDIR(st
.st_mode
)) {
997 "directory specified but recursive mode not requested: %s",
1004 "a directory passed to the defrag ioctl will not process the files\n"
1005 "recursively but will defragment the subvolume tree and the extent tree.\n"
1006 "If this is not intended, please use option -r .");
1010 for (i
= optind
; i
< argc
; i
++) {
1015 fd
= open_file_or_dir(argv
[i
], &dirstream
);
1017 error("cannot open %s: %m", argv
[i
]);
1022 ret
= fstat(fd
, &st
);
1024 error("failed to stat %s: %m", argv
[i
]);
1028 if (!(S_ISDIR(st
.st_mode
) || S_ISREG(st
.st_mode
))) {
1029 error("%s is not a directory or a regular file",
1034 if (recursive
&& S_ISDIR(st
.st_mode
)) {
1035 ret
= nftw(argv
[i
], defrag_callback
, 10,
1036 FTW_MOUNT
| FTW_PHYS
);
1039 /* errors are handled in the callback */
1042 if (defrag_global_verbose
)
1043 printf("%s\n", argv
[i
]);
1044 ret
= ioctl(fd
, BTRFS_IOC_DEFRAG_RANGE
,
1045 &defrag_global_range
);
1047 if (ret
&& defrag_err
== ENOTTY
) {
1049 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
1050 defrag_global_errors
++;
1051 close_file_or_dir(fd
, dirstream
);
1055 error("defrag failed on %s: %s", argv
[i
],
1056 strerror(defrag_err
));
1062 defrag_global_errors
++;
1063 close_file_or_dir(fd
, dirstream
);
1066 if (defrag_global_errors
)
1067 fprintf(stderr
, "total %d failures\n", defrag_global_errors
);
1069 return !!defrag_global_errors
;
1072 static const char * const cmd_filesystem_resize_usage
[] = {
1073 "btrfs filesystem resize [devid:][+/-]<newsize>[kKmMgGtTpPeE]|[devid:]max <path>",
1074 "Resize a filesystem",
1075 "If 'max' is passed, the filesystem will occupy all available space",
1076 "on the device 'devid'.",
1077 "[kK] means KiB, which denotes 1KiB = 1024B, 1MiB = 1024KiB, etc.",
1081 static int cmd_filesystem_resize(int argc
, char **argv
)
1083 struct btrfs_ioctl_vol_args args
;
1084 int fd
, res
, len
, e
;
1085 char *amount
, *path
;
1086 DIR *dirstream
= NULL
;
1089 clean_args_no_options_relaxed(argc
, argv
);
1091 if (check_argc_exact(argc
- optind
, 2))
1092 usage(cmd_filesystem_resize_usage
);
1094 amount
= argv
[optind
];
1095 path
= argv
[optind
+ 1];
1097 len
= strlen(amount
);
1098 if (len
== 0 || len
>= BTRFS_VOL_NAME_MAX
) {
1099 error("resize value too long (%s)", amount
);
1103 res
= stat(path
, &st
);
1105 error("resize: cannot stat %s: %m", path
);
1108 if (!S_ISDIR(st
.st_mode
)) {
1109 error("resize works on mounted filesystems and accepts only\n"
1110 "directories as argument. Passing file containing a btrfs image\n"
1111 "would resize the underlying filesystem instead of the image.\n");
1115 fd
= btrfs_open_dir(path
, &dirstream
, 1);
1119 printf("Resize '%s' of '%s'\n", path
, amount
);
1120 memset(&args
, 0, sizeof(args
));
1121 strncpy_null(args
.name
, amount
);
1122 res
= ioctl(fd
, BTRFS_IOC_RESIZE
, &args
);
1124 close_file_or_dir(fd
, dirstream
);
1128 error("unable to resize '%s': no enough free space",
1132 error("unable to resize '%s': %m", path
);
1136 } else if (res
> 0) {
1137 const char *err_str
= btrfs_err_str(res
);
1140 error("resizing of '%s' failed: %s", path
, err_str
);
1142 error("resizing of '%s' failed: unknown error %d",
1150 static const char * const cmd_filesystem_label_usage
[] = {
1151 "btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
1152 "Get or change the label of a filesystem",
1153 "With one argument, get the label of filesystem on <device>.",
1154 "If <newlabel> is passed, set the filesystem label to <newlabel>.",
1158 static int cmd_filesystem_label(int argc
, char **argv
)
1160 clean_args_no_options(argc
, argv
, cmd_filesystem_label_usage
);
1162 if (check_argc_min(argc
- optind
, 1) ||
1163 check_argc_max(argc
- optind
, 2))
1164 usage(cmd_filesystem_label_usage
);
1166 if (argc
- optind
> 1) {
1167 return set_label(argv
[optind
], argv
[optind
+ 1]);
1169 char label
[BTRFS_LABEL_SIZE
];
1172 ret
= get_label(argv
[optind
], label
);
1174 fprintf(stdout
, "%s\n", label
);
1180 static const char filesystem_cmd_group_info
[] =
1181 "overall filesystem tasks and information";
1183 const struct cmd_group filesystem_cmd_group
= {
1184 filesystem_cmd_group_usage
, filesystem_cmd_group_info
, {
1185 { "df", cmd_filesystem_df
, cmd_filesystem_df_usage
, NULL
, 0 },
1186 { "du", cmd_filesystem_du
, cmd_filesystem_du_usage
, NULL
, 0 },
1187 { "show", cmd_filesystem_show
, cmd_filesystem_show_usage
, NULL
,
1189 { "sync", cmd_filesystem_sync
, cmd_filesystem_sync_usage
, NULL
,
1191 { "defragment", cmd_filesystem_defrag
,
1192 cmd_filesystem_defrag_usage
, NULL
, 0 },
1193 { "balance", cmd_balance
, NULL
, &balance_cmd_group
,
1195 { "resize", cmd_filesystem_resize
, cmd_filesystem_resize_usage
,
1197 { "label", cmd_filesystem_label
, cmd_filesystem_label_usage
,
1199 { "usage", cmd_filesystem_usage
,
1200 cmd_filesystem_usage_usage
, NULL
, 0 },
1206 int cmd_filesystem(int argc
, char **argv
)
1208 return handle_command_group(&filesystem_cmd_group
, argc
, argv
);