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 "kerncompat.h"
37 #include "cmds-fi-usage.h"
38 #include "list_sort.h"
40 #include "cmds-fi-du.h"
43 * for btrfs fi show, we maintain a hash of fsids we've already printed.
44 * This way we don't print dups if a given FS is mounted more than once.
46 #define SEEN_FSID_HASH_SIZE 256
49 u8 fsid
[BTRFS_FSID_SIZE
];
50 struct seen_fsid
*next
;
53 static struct seen_fsid
*seen_fsid_hash
[SEEN_FSID_HASH_SIZE
] = {NULL
,};
55 static int is_seen_fsid(u8
*fsid
)
58 int slot
= hash
% SEEN_FSID_HASH_SIZE
;
59 struct seen_fsid
*seen
= seen_fsid_hash
[slot
];
64 static int add_seen_fsid(u8
*fsid
)
67 int slot
= hash
% SEEN_FSID_HASH_SIZE
;
68 struct seen_fsid
*seen
= seen_fsid_hash
[slot
];
69 struct seen_fsid
*alloc
;
75 if (memcmp(seen
->fsid
, fsid
, BTRFS_FSID_SIZE
) == 0)
86 alloc
= malloc(sizeof(*alloc
));
91 memcpy(alloc
->fsid
, fsid
, BTRFS_FSID_SIZE
);
96 seen_fsid_hash
[slot
] = alloc
;
101 static void free_seen_fsid(void)
104 struct seen_fsid
*seen
;
105 struct seen_fsid
*next
;
107 for (slot
= 0; slot
< SEEN_FSID_HASH_SIZE
; slot
++) {
108 seen
= seen_fsid_hash
[slot
];
114 seen_fsid_hash
[slot
] = NULL
;
118 static const char * const filesystem_cmd_group_usage
[] = {
119 "btrfs filesystem [<group>] <command> [<args>]",
123 static const char * const cmd_filesystem_df_usage
[] = {
124 "btrfs filesystem df [options] <path>",
125 "Show space usage information for a mount point",
126 HELPINFO_UNITS_SHORT_LONG
,
130 static int get_df(int fd
, struct btrfs_ioctl_space_args
**sargs_ret
)
134 struct btrfs_ioctl_space_args
*sargs
;
136 sargs
= malloc(sizeof(struct btrfs_ioctl_space_args
));
140 sargs
->space_slots
= 0;
141 sargs
->total_spaces
= 0;
143 ret
= ioctl(fd
, BTRFS_IOC_SPACE_INFO
, sargs
);
145 error("cannot get space info: %s\n", strerror(errno
));
149 /* This really should never happen */
150 if (!sargs
->total_spaces
) {
154 count
= sargs
->total_spaces
;
157 sargs
= malloc(sizeof(struct btrfs_ioctl_space_args
) +
158 (count
* sizeof(struct btrfs_ioctl_space_info
)));
162 sargs
->space_slots
= count
;
163 sargs
->total_spaces
= 0;
164 ret
= ioctl(fd
, BTRFS_IOC_SPACE_INFO
, sargs
);
166 error("cannot get space info with %llu slots: %s",
167 count
, strerror(errno
));
175 static void print_df(struct btrfs_ioctl_space_args
*sargs
, unsigned unit_mode
)
178 struct btrfs_ioctl_space_info
*sp
= sargs
->spaces
;
180 for (i
= 0; i
< sargs
->total_spaces
; i
++, sp
++) {
181 printf("%s, %s: total=%s, used=%s\n",
182 btrfs_group_type_str(sp
->flags
),
183 btrfs_group_profile_str(sp
->flags
),
184 pretty_size_mode(sp
->total_bytes
, unit_mode
),
185 pretty_size_mode(sp
->used_bytes
, unit_mode
));
189 static int cmd_filesystem_df(int argc
, char **argv
)
191 struct btrfs_ioctl_space_args
*sargs
= NULL
;
195 DIR *dirstream
= NULL
;
198 unit_mode
= get_unit_mode_from_arg(&argc
, argv
, 1);
200 clean_args_no_options(argc
, argv
, cmd_filesystem_df_usage
);
202 if (check_argc_exact(argc
- optind
, 1))
203 usage(cmd_filesystem_df_usage
);
207 fd
= btrfs_open_dir(path
, &dirstream
, 1);
211 ret
= get_df(fd
, &sargs
);
214 print_df(sargs
, unit_mode
);
217 error("get_df failed %s", strerror(-ret
));
220 close_file_or_dir(fd
, dirstream
);
224 static int match_search_item_kernel(__u8
*fsid
, char *mnt
, char *label
,
227 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
228 int search_len
= strlen(search
);
230 search_len
= min(search_len
, BTRFS_UUID_UNPARSED_SIZE
);
231 uuid_unparse(fsid
, uuidbuf
);
232 if (!strncmp(uuidbuf
, search
, search_len
))
235 if (*label
&& strcmp(label
, search
) == 0)
238 if (strcmp(mnt
, search
) == 0)
244 static int uuid_search(struct btrfs_fs_devices
*fs_devices
, char *search
)
246 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
247 struct list_head
*cur
;
248 struct btrfs_device
*device
;
249 int search_len
= strlen(search
);
251 search_len
= min(search_len
, BTRFS_UUID_UNPARSED_SIZE
);
252 uuid_unparse(fs_devices
->fsid
, uuidbuf
);
253 if (!strncmp(uuidbuf
, search
, search_len
))
256 list_for_each(cur
, &fs_devices
->devices
) {
257 device
= list_entry(cur
, struct btrfs_device
, dev_list
);
258 if ((device
->label
&& strcmp(device
->label
, search
) == 0) ||
259 strcmp(device
->name
, search
) == 0)
266 * Sort devices by devid, ascending
268 static int cmp_device_id(void *priv
, struct list_head
*a
,
271 const struct btrfs_device
*da
= list_entry(a
, struct btrfs_device
,
273 const struct btrfs_device
*db
= list_entry(b
, struct btrfs_device
,
276 return da
->devid
< db
->devid
? -1 :
277 da
->devid
> db
->devid
? 1 : 0;
280 static void splice_device_list(struct list_head
*seed_devices
,
281 struct list_head
*all_devices
)
283 struct btrfs_device
*in_all
, *next_all
;
284 struct btrfs_device
*in_seed
, *next_seed
;
286 list_for_each_entry_safe(in_all
, next_all
, all_devices
, dev_list
) {
287 list_for_each_entry_safe(in_seed
, next_seed
, seed_devices
,
289 if (in_all
->devid
== in_seed
->devid
) {
291 * When do dev replace in a sprout fs
292 * to a dev in its seed fs, the replacing
293 * dev will reside in the sprout fs and
294 * the replaced dev will still exist
296 * So pick the latest one when showing
299 if (in_all
->generation
300 < in_seed
->generation
) {
301 list_del(&in_all
->dev_list
);
303 } else if (in_all
->generation
304 > in_seed
->generation
) {
305 list_del(&in_seed
->dev_list
);
313 list_splice(seed_devices
, all_devices
);
316 static void print_devices(struct btrfs_fs_devices
*fs_devices
,
317 u64
*devs_found
, unsigned unit_mode
)
319 struct btrfs_device
*device
;
320 struct btrfs_fs_devices
*cur_fs
;
321 struct list_head
*all_devices
;
323 all_devices
= &fs_devices
->devices
;
324 cur_fs
= fs_devices
->seed
;
325 /* add all devices of seed fs to the fs to be printed */
327 splice_device_list(&cur_fs
->devices
, all_devices
);
328 cur_fs
= cur_fs
->seed
;
331 list_sort(NULL
, all_devices
, cmp_device_id
);
332 list_for_each_entry(device
, all_devices
, dev_list
) {
333 printf("\tdevid %4llu size %s used %s path %s\n",
334 (unsigned long long)device
->devid
,
335 pretty_size_mode(device
->total_bytes
, unit_mode
),
336 pretty_size_mode(device
->bytes_used
, unit_mode
),
343 static void print_one_uuid(struct btrfs_fs_devices
*fs_devices
,
346 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
347 struct btrfs_device
*device
;
351 if (add_seen_fsid(fs_devices
->fsid
))
354 uuid_unparse(fs_devices
->fsid
, uuidbuf
);
355 device
= list_entry(fs_devices
->devices
.next
, struct btrfs_device
,
357 if (device
->label
&& device
->label
[0])
358 printf("Label: '%s' ", device
->label
);
360 printf("Label: none ");
362 total
= device
->total_devs
;
363 printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf
,
364 (unsigned long long)total
,
365 pretty_size_mode(device
->super_bytes_used
, unit_mode
));
367 print_devices(fs_devices
, &devs_found
, unit_mode
);
369 if (devs_found
< total
) {
370 printf("\t*** Some devices missing\n");
375 /* adds up all the used spaces as reported by the space info ioctl
377 static u64
calc_used_bytes(struct btrfs_ioctl_space_args
*si
)
381 for (i
= 0; i
< si
->total_spaces
; i
++)
382 ret
+= si
->spaces
[i
].used_bytes
;
386 static int print_one_fs(struct btrfs_ioctl_fs_info_args
*fs_info
,
387 struct btrfs_ioctl_dev_info_args
*dev_info
,
388 struct btrfs_ioctl_space_args
*space_info
,
389 char *label
, unsigned unit_mode
)
394 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
395 struct btrfs_ioctl_dev_info_args
*tmp_dev_info
;
398 ret
= add_seen_fsid(fs_info
->fsid
);
404 uuid_unparse(fs_info
->fsid
, uuidbuf
);
406 printf("Label: '%s' ", label
);
408 printf("Label: none ");
410 printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf
,
411 fs_info
->num_devices
,
412 pretty_size_mode(calc_used_bytes(space_info
),
415 for (i
= 0; i
< fs_info
->num_devices
; i
++) {
416 char *canonical_path
;
418 tmp_dev_info
= (struct btrfs_ioctl_dev_info_args
*)&dev_info
[i
];
420 /* Add check for missing devices even mounted */
421 fd
= open((char *)tmp_dev_info
->path
, O_RDONLY
);
427 canonical_path
= canonicalize_path((char *)tmp_dev_info
->path
);
428 printf("\tdevid %4llu size %s used %s path %s\n",
430 pretty_size_mode(tmp_dev_info
->total_bytes
, unit_mode
),
431 pretty_size_mode(tmp_dev_info
->bytes_used
, unit_mode
),
434 free(canonical_path
);
438 printf("\t*** Some devices missing\n");
443 static int btrfs_scan_kernel(void *search
, unsigned unit_mode
)
449 struct btrfs_ioctl_fs_info_args fs_info_arg
;
450 struct btrfs_ioctl_dev_info_args
*dev_info_arg
= NULL
;
451 struct btrfs_ioctl_space_args
*space_info_arg
= NULL
;
452 char label
[BTRFS_LABEL_SIZE
];
454 f
= setmntent("/proc/self/mounts", "r");
458 memset(label
, 0, sizeof(label
));
459 while ((mnt
= getmntent(f
)) != NULL
) {
460 if (strcmp(mnt
->mnt_type
, "btrfs"))
462 ret
= get_fs_info(mnt
->mnt_dir
, &fs_info_arg
,
469 /* skip all fs already shown as mounted fs */
470 if (is_seen_fsid(fs_info_arg
.fsid
))
473 ret
= get_label_mounted(mnt
->mnt_dir
, label
);
474 /* provide backward kernel compatibility */
476 ret
= get_label_unmounted(
477 (const char *)dev_info_arg
->path
, label
);
483 if (search
&& !match_search_item_kernel(fs_info_arg
.fsid
,
484 mnt
->mnt_dir
, label
, search
)) {
490 fd
= open(mnt
->mnt_dir
, O_RDONLY
);
491 if ((fd
!= -1) && !get_df(fd
, &space_info_arg
)) {
492 print_one_fs(&fs_info_arg
, dev_info_arg
,
493 space_info_arg
, label
, unit_mode
);
494 kfree(space_info_arg
);
495 memset(label
, 0, sizeof(label
));
509 static int dev_to_fsid(char *dev
, __u8
*fsid
)
511 struct btrfs_super_block
*disk_super
;
512 char buf
[BTRFS_SUPER_INFO_SIZE
];
516 fd
= open(dev
, O_RDONLY
);
522 disk_super
= (struct btrfs_super_block
*)buf
;
523 ret
= btrfs_read_dev_super(fd
, disk_super
,
524 BTRFS_SUPER_INFO_OFFSET
, 0);
528 memcpy(fsid
, disk_super
->fsid
, BTRFS_FSID_SIZE
);
536 static void free_fs_devices(struct btrfs_fs_devices
*fs_devices
)
538 struct btrfs_fs_devices
*cur_seed
, *next_seed
;
539 struct btrfs_device
*device
;
541 while (!list_empty(&fs_devices
->devices
)) {
542 device
= list_entry(fs_devices
->devices
.next
,
543 struct btrfs_device
, dev_list
);
544 list_del(&device
->dev_list
);
551 /* free seed fs chain */
552 cur_seed
= fs_devices
->seed
;
553 fs_devices
->seed
= NULL
;
555 next_seed
= cur_seed
->seed
;
558 cur_seed
= next_seed
;
561 list_del(&fs_devices
->list
);
565 static int copy_device(struct btrfs_device
*dst
,
566 struct btrfs_device
*src
)
568 dst
->devid
= src
->devid
;
569 memcpy(dst
->uuid
, src
->uuid
, BTRFS_UUID_SIZE
);
570 if (src
->name
== NULL
)
573 dst
->name
= strdup(src
->name
);
577 if (src
->label
== NULL
)
580 dst
->label
= strdup(src
->label
);
586 dst
->total_devs
= src
->total_devs
;
587 dst
->super_bytes_used
= src
->super_bytes_used
;
588 dst
->total_bytes
= src
->total_bytes
;
589 dst
->bytes_used
= src
->bytes_used
;
590 dst
->generation
= src
->generation
;
595 static int copy_fs_devices(struct btrfs_fs_devices
*dst
,
596 struct btrfs_fs_devices
*src
)
598 struct btrfs_device
*cur_dev
, *dev_copy
;
601 memcpy(dst
->fsid
, src
->fsid
, BTRFS_FSID_SIZE
);
602 INIT_LIST_HEAD(&dst
->devices
);
605 list_for_each_entry(cur_dev
, &src
->devices
, dev_list
) {
606 dev_copy
= malloc(sizeof(*dev_copy
));
612 ret
= copy_device(dev_copy
, cur_dev
);
618 list_add(&dev_copy
->dev_list
, &dst
->devices
);
619 dev_copy
->fs_devices
= dst
;
625 static int find_and_copy_seed(struct btrfs_fs_devices
*seed
,
626 struct btrfs_fs_devices
*copy
,
627 struct list_head
*fs_uuids
) {
628 struct btrfs_fs_devices
*cur_fs
;
630 list_for_each_entry(cur_fs
, fs_uuids
, list
)
631 if (!memcmp(seed
->fsid
, cur_fs
->fsid
, BTRFS_FSID_SIZE
))
632 return copy_fs_devices(copy
, cur_fs
);
637 static int has_seed_devices(struct btrfs_fs_devices
*fs_devices
)
639 struct btrfs_device
*device
;
640 int dev_cnt_total
, dev_cnt
= 0;
642 device
= list_first_entry(&fs_devices
->devices
, struct btrfs_device
,
645 dev_cnt_total
= device
->total_devs
;
647 list_for_each_entry(device
, &fs_devices
->devices
, dev_list
)
650 return dev_cnt_total
!= dev_cnt
;
653 static int search_umounted_fs_uuids(struct list_head
*all_uuids
,
654 char *search
, int *found
)
656 struct btrfs_fs_devices
*cur_fs
, *fs_copy
;
657 struct list_head
*fs_uuids
;
660 fs_uuids
= btrfs_scanned_uuids();
663 * The fs_uuids list is global, and open_ctree_* will
664 * modify it, make a private copy here
666 list_for_each_entry(cur_fs
, fs_uuids
, list
) {
667 /* don't bother handle all fs, if search target specified */
669 if (uuid_search(cur_fs
, search
) == 0)
675 /* skip all fs already shown as mounted fs */
676 if (is_seen_fsid(cur_fs
->fsid
))
679 fs_copy
= calloc(1, sizeof(*fs_copy
));
685 ret
= copy_fs_devices(fs_copy
, cur_fs
);
691 list_add(&fs_copy
->list
, all_uuids
);
698 static int map_seed_devices(struct list_head
*all_uuids
)
700 struct btrfs_fs_devices
*cur_fs
, *cur_seed
;
701 struct btrfs_fs_devices
*seed_copy
;
702 struct btrfs_fs_devices
*opened_fs
;
703 struct btrfs_device
*device
;
704 struct btrfs_fs_info
*fs_info
;
705 struct list_head
*fs_uuids
;
708 fs_uuids
= btrfs_scanned_uuids();
710 list_for_each_entry(cur_fs
, all_uuids
, list
) {
711 device
= list_first_entry(&cur_fs
->devices
,
712 struct btrfs_device
, dev_list
);
716 /* skip fs without seeds */
717 if (!has_seed_devices(cur_fs
))
721 * open_ctree_* detects seed/sprout mapping
723 fs_info
= open_ctree_fs_info(device
->name
, 0, 0, 0,
729 * copy the seed chain under the opened fs
731 opened_fs
= fs_info
->fs_devices
;
733 while (opened_fs
->seed
) {
734 seed_copy
= malloc(sizeof(*seed_copy
));
739 ret
= find_and_copy_seed(opened_fs
->seed
, seed_copy
,
746 cur_seed
->seed
= seed_copy
;
748 opened_fs
= opened_fs
->seed
;
749 cur_seed
= cur_seed
->seed
;
752 close_ctree(fs_info
->chunk_root
);
758 close_ctree(fs_info
->chunk_root
);
762 static const char * const cmd_filesystem_show_usage
[] = {
763 "btrfs filesystem show [options] [<path>|<uuid>|<device>|label]",
764 "Show the structure of a filesystem",
765 "-d|--all-devices show only disks under /dev containing btrfs filesystem",
766 "-m|--mounted show only mounted btrfs",
768 "If no argument is given, structure of all present filesystems is shown.",
772 static int cmd_filesystem_show(int argc
, char **argv
)
774 LIST_HEAD(all_uuids
);
775 struct btrfs_fs_devices
*fs_devices
;
778 /* default, search both kernel and udev */
783 __u8 fsid
[BTRFS_FSID_SIZE
];
784 char uuid_buf
[BTRFS_UUID_UNPARSED_SIZE
];
788 unit_mode
= get_unit_mode_from_arg(&argc
, argv
, 0);
792 static const struct option long_options
[] = {
793 { "all-devices", no_argument
, NULL
, 'd'},
794 { "mounted", no_argument
, NULL
, 'm'},
798 c
= getopt_long(argc
, argv
, "dm", long_options
, NULL
);
803 where
= BTRFS_SCAN_LBLKID
;
806 where
= BTRFS_SCAN_MOUNTED
;
809 usage(cmd_filesystem_show_usage
);
813 if (check_argc_max(argc
, optind
+ 1))
814 usage(cmd_filesystem_show_usage
);
817 search
= argv
[optind
];
819 usage(cmd_filesystem_show_usage
);
820 type
= check_arg_type(search
);
823 * For search is a device:
824 * realpath do /dev/mapper/XX => /dev/dm-X
825 * which is required by BTRFS_SCAN_DEV
826 * For search is a mountpoint:
827 * realpath do /mnt/btrfs/ => /mnt/btrfs
828 * which shall be recognized by btrfs_scan_kernel()
830 if (realpath(search
, path
))
834 * Needs special handling if input arg is block dev And if
835 * input arg is mount-point just print it right away
837 if (type
== BTRFS_ARG_BLKDEV
&& where
!= BTRFS_SCAN_LBLKID
) {
838 ret
= get_btrfs_mount(search
, mp
, sizeof(mp
));
840 /* given block dev is mounted */
842 type
= BTRFS_ARG_MNTPOINT
;
844 ret
= dev_to_fsid(search
, fsid
);
846 error("no btrfs on %s", search
);
849 uuid_unparse(fsid
, uuid_buf
);
851 type
= BTRFS_ARG_UUID
;
857 if (where
== BTRFS_SCAN_LBLKID
)
860 /* show mounted btrfs */
861 ret
= btrfs_scan_kernel(search
, unit_mode
);
862 if (search
&& !ret
) {
863 /* since search is found we are done */
867 /* shows mounted only */
868 if (where
== BTRFS_SCAN_MOUNTED
)
872 ret
= btrfs_scan_lblkid();
875 error("blkid device scan returned %d\n", ret
);
879 ret
= search_umounted_fs_uuids(&all_uuids
, search
, &found
);
881 error("searching target device returned error %d", ret
);
886 * The seed/sprout mapping are not detected yet,
887 * do mapping build for all umounted fs
889 ret
= map_seed_devices(&all_uuids
);
891 error("mapping seed devices returned error %d", ret
);
895 list_for_each_entry(fs_devices
, &all_uuids
, list
)
896 print_one_uuid(fs_devices
, unit_mode
);
898 if (search
&& !found
)
901 while (!list_empty(&all_uuids
)) {
902 fs_devices
= list_entry(all_uuids
.next
,
903 struct btrfs_fs_devices
, list
);
904 free_fs_devices(fs_devices
);
911 static const char * const cmd_filesystem_sync_usage
[] = {
912 "btrfs filesystem sync <path>",
913 "Force a sync on a filesystem",
917 static int cmd_filesystem_sync(int argc
, char **argv
)
921 DIR *dirstream
= NULL
;
923 clean_args_no_options(argc
, argv
, cmd_filesystem_sync_usage
);
925 if (check_argc_exact(argc
- optind
, 1))
926 usage(cmd_filesystem_sync_usage
);
930 fd
= btrfs_open_dir(path
, &dirstream
, 1);
934 printf("FSSync '%s'\n", path
);
935 res
= ioctl(fd
, BTRFS_IOC_SYNC
);
937 close_file_or_dir(fd
, dirstream
);
939 error("sync ioctl failed on '%s': %s", path
, strerror(e
));
946 static int parse_compress_type(char *s
)
948 if (strcmp(optarg
, "zlib") == 0)
949 return BTRFS_COMPRESS_ZLIB
;
950 else if (strcmp(optarg
, "lzo") == 0)
951 return BTRFS_COMPRESS_LZO
;
953 error("unknown compression type %s", s
);
958 static const char * const cmd_filesystem_defrag_usage
[] = {
959 "btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
960 "Defragment a file or a directory",
963 "-r defragment files recursively",
964 "-c[zlib,lzo] compress the file while defragmenting",
965 "-f flush data to disk immediately after defragmenting",
966 "-s start defragment only from byte onward",
967 "-l len defragment only up to len bytes",
968 "-t size target extent size hint",
972 static int do_defrag(int fd
, int fancy_ioctl
,
973 struct btrfs_ioctl_defrag_range_args
*range
)
978 ret
= ioctl(fd
, BTRFS_IOC_DEFRAG
, NULL
);
980 ret
= ioctl(fd
, BTRFS_IOC_DEFRAG_RANGE
, range
);
985 static int defrag_global_fancy_ioctl
;
986 static struct btrfs_ioctl_defrag_range_args defrag_global_range
;
987 static int defrag_global_verbose
;
988 static int defrag_global_errors
;
989 static int defrag_callback(const char *fpath
, const struct stat
*sb
,
990 int typeflag
, struct FTW
*ftwbuf
)
996 if ((typeflag
== FTW_F
) && S_ISREG(sb
->st_mode
)) {
997 if (defrag_global_verbose
)
998 printf("%s\n", fpath
);
999 fd
= open(fpath
, O_RDWR
);
1002 ret
= do_defrag(fd
, defrag_global_fancy_ioctl
, &defrag_global_range
);
1005 if (ret
&& e
== ENOTTY
&& defrag_global_fancy_ioctl
) {
1006 error("defrag range ioctl not "
1007 "supported in this kernel, please try "
1008 "without any options.");
1009 defrag_global_errors
++;
1018 error("defrag failed on %s: %s", fpath
, strerror(e
));
1019 defrag_global_errors
++;
1023 static int cmd_filesystem_defrag(int argc
, char **argv
)
1034 int compress_type
= BTRFS_COMPRESS_NONE
;
1037 defrag_global_errors
= 0;
1038 defrag_global_verbose
= 0;
1039 defrag_global_errors
= 0;
1040 defrag_global_fancy_ioctl
= 0;
1043 int c
= getopt(argc
, argv
, "vrc::fs:l:t:");
1049 compress_type
= BTRFS_COMPRESS_ZLIB
;
1051 compress_type
= parse_compress_type(optarg
);
1052 defrag_global_fancy_ioctl
= 1;
1056 defrag_global_fancy_ioctl
= 1;
1059 defrag_global_verbose
= 1;
1062 start
= parse_size(optarg
);
1063 defrag_global_fancy_ioctl
= 1;
1066 len
= parse_size(optarg
);
1067 defrag_global_fancy_ioctl
= 1;
1070 thresh
= parse_size(optarg
);
1071 if (thresh
> (u32
)-1) {
1073 "target extent size %llu too big, trimmed to %u",
1077 defrag_global_fancy_ioctl
= 1;
1083 usage(cmd_filesystem_defrag_usage
);
1087 if (check_argc_min(argc
- optind
, 1))
1088 usage(cmd_filesystem_defrag_usage
);
1090 memset(&defrag_global_range
, 0, sizeof(defrag_global_range
));
1091 defrag_global_range
.start
= start
;
1092 defrag_global_range
.len
= len
;
1093 defrag_global_range
.extent_thresh
= (u32
)thresh
;
1094 if (compress_type
) {
1095 defrag_global_range
.flags
|= BTRFS_DEFRAG_RANGE_COMPRESS
;
1096 defrag_global_range
.compress_type
= compress_type
;
1099 defrag_global_range
.flags
|= BTRFS_DEFRAG_RANGE_START_IO
;
1101 for (i
= optind
; i
< argc
; i
++) {
1105 fd
= open_file_or_dir(argv
[i
], &dirstream
);
1107 error("cannot open %s: %s\n", argv
[i
],
1109 defrag_global_errors
++;
1110 close_file_or_dir(fd
, dirstream
);
1113 if (fstat(fd
, &st
)) {
1114 error("failed to stat %s: %s",
1115 argv
[i
], strerror(errno
));
1116 defrag_global_errors
++;
1117 close_file_or_dir(fd
, dirstream
);
1120 if (!(S_ISDIR(st
.st_mode
) || S_ISREG(st
.st_mode
))) {
1121 error("%s is not a directory or a regular file\n",
1123 defrag_global_errors
++;
1124 close_file_or_dir(fd
, dirstream
);
1128 if (S_ISDIR(st
.st_mode
)) {
1129 ret
= nftw(argv
[i
], defrag_callback
, 10,
1130 FTW_MOUNT
| FTW_PHYS
);
1133 /* errors are handled in the callback */
1136 if (defrag_global_verbose
)
1137 printf("%s\n", argv
[i
]);
1138 ret
= do_defrag(fd
, defrag_global_fancy_ioctl
,
1139 &defrag_global_range
);
1143 if (defrag_global_verbose
)
1144 printf("%s\n", argv
[i
]);
1145 ret
= do_defrag(fd
, defrag_global_fancy_ioctl
,
1146 &defrag_global_range
);
1149 close_file_or_dir(fd
, dirstream
);
1150 if (ret
&& e
== ENOTTY
&& defrag_global_fancy_ioctl
) {
1151 error("defrag range ioctl not "
1152 "supported in this kernel, please try "
1153 "without any options.");
1154 defrag_global_errors
++;
1158 error("defrag failed on %s: %s", argv
[i
], strerror(e
));
1159 defrag_global_errors
++;
1162 if (defrag_global_errors
)
1163 fprintf(stderr
, "total %d failures\n", defrag_global_errors
);
1165 return !!defrag_global_errors
;
1168 static const char * const cmd_filesystem_resize_usage
[] = {
1169 "btrfs filesystem resize [devid:][+/-]<newsize>[kKmMgGtTpPeE]|[devid:]max <path>",
1170 "Resize a filesystem",
1171 "If 'max' is passed, the filesystem will occupy all available space",
1172 "on the device 'devid'.",
1173 "[kK] means KiB, which denotes 1KiB = 1024B, 1MiB = 1024KiB, etc.",
1177 static int cmd_filesystem_resize(int argc
, char **argv
)
1179 struct btrfs_ioctl_vol_args args
;
1180 int fd
, res
, len
, e
;
1181 char *amount
, *path
;
1182 DIR *dirstream
= NULL
;
1185 clean_args_no_options(argc
, argv
, cmd_filesystem_resize_usage
);
1187 if (check_argc_exact(argc
- optind
, 2))
1188 usage(cmd_filesystem_resize_usage
);
1190 amount
= argv
[optind
];
1191 path
= argv
[optind
+ 1];
1193 len
= strlen(amount
);
1194 if (len
== 0 || len
>= BTRFS_VOL_NAME_MAX
) {
1195 error("resize value too long (%s)", amount
);
1199 res
= stat(path
, &st
);
1201 error("resize: cannot stat %s: %s", path
, strerror(errno
));
1204 if (!S_ISDIR(st
.st_mode
)) {
1205 error("resize works on mounted filesystems and accepts only\n"
1206 "directories as argument. Passing file containing a btrfs image\n"
1207 "would resize the underlying filesystem instead of the image.\n");
1211 fd
= btrfs_open_dir(path
, &dirstream
, 1);
1215 printf("Resize '%s' of '%s'\n", path
, amount
);
1216 memset(&args
, 0, sizeof(args
));
1217 strncpy_null(args
.name
, amount
);
1218 res
= ioctl(fd
, BTRFS_IOC_RESIZE
, &args
);
1220 close_file_or_dir(fd
, dirstream
);
1224 error("unable to resize '%s': no enough free space",
1228 error("unable to resize '%s': %s", path
, strerror(e
));
1232 } else if (res
> 0) {
1233 const char *err_str
= btrfs_err_str(res
);
1236 error("resizing of '%s' failed: %s", path
, err_str
);
1238 error("resizing of '%s' failed: unknown error %d",
1246 static const char * const cmd_filesystem_label_usage
[] = {
1247 "btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
1248 "Get or change the label of a filesystem",
1249 "With one argument, get the label of filesystem on <device>.",
1250 "If <newlabel> is passed, set the filesystem label to <newlabel>.",
1254 static int cmd_filesystem_label(int argc
, char **argv
)
1256 clean_args_no_options(argc
, argv
, cmd_filesystem_label_usage
);
1258 if (check_argc_min(argc
- optind
, 1) ||
1259 check_argc_max(argc
- optind
, 2))
1260 usage(cmd_filesystem_label_usage
);
1262 if (argc
- optind
> 1) {
1263 return set_label(argv
[optind
], argv
[optind
+ 1]);
1265 char label
[BTRFS_LABEL_SIZE
];
1268 ret
= get_label(argv
[optind
], label
);
1270 fprintf(stdout
, "%s\n", label
);
1276 static const char filesystem_cmd_group_info
[] =
1277 "overall filesystem tasks and information";
1279 const struct cmd_group filesystem_cmd_group
= {
1280 filesystem_cmd_group_usage
, filesystem_cmd_group_info
, {
1281 { "df", cmd_filesystem_df
, cmd_filesystem_df_usage
, NULL
, 0 },
1282 { "du", cmd_filesystem_du
, cmd_filesystem_du_usage
, NULL
, 0 },
1283 { "show", cmd_filesystem_show
, cmd_filesystem_show_usage
, NULL
,
1285 { "sync", cmd_filesystem_sync
, cmd_filesystem_sync_usage
, NULL
,
1287 { "defragment", cmd_filesystem_defrag
,
1288 cmd_filesystem_defrag_usage
, NULL
, 0 },
1289 { "balance", cmd_balance
, NULL
, &balance_cmd_group
,
1291 { "resize", cmd_filesystem_resize
, cmd_filesystem_resize_usage
,
1293 { "label", cmd_filesystem_label
, cmd_filesystem_label_usage
,
1295 { "usage", cmd_filesystem_usage
,
1296 cmd_filesystem_usage_usage
, NULL
, 0 },
1302 int cmd_filesystem(int argc
, char **argv
)
1304 return handle_command_group(&filesystem_cmd_group
, argc
, argv
);