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"
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 #define SEEN_FSID_HASH_SIZE 256
50 u8 fsid
[BTRFS_FSID_SIZE
];
51 struct seen_fsid
*next
;
54 static struct seen_fsid
*seen_fsid_hash
[SEEN_FSID_HASH_SIZE
] = {NULL
,};
56 static int is_seen_fsid(u8
*fsid
)
59 int slot
= hash
% SEEN_FSID_HASH_SIZE
;
60 struct seen_fsid
*seen
= seen_fsid_hash
[slot
];
63 if (memcmp(seen
->fsid
, fsid
, BTRFS_FSID_SIZE
) == 0)
72 static int add_seen_fsid(u8
*fsid
)
75 int slot
= hash
% SEEN_FSID_HASH_SIZE
;
76 struct seen_fsid
*seen
= seen_fsid_hash
[slot
];
77 struct seen_fsid
*alloc
;
83 if (memcmp(seen
->fsid
, fsid
, BTRFS_FSID_SIZE
) == 0)
94 alloc
= malloc(sizeof(*alloc
));
99 memcpy(alloc
->fsid
, fsid
, BTRFS_FSID_SIZE
);
104 seen_fsid_hash
[slot
] = alloc
;
109 static void free_seen_fsid(void)
112 struct seen_fsid
*seen
;
113 struct seen_fsid
*next
;
115 for (slot
= 0; slot
< SEEN_FSID_HASH_SIZE
; slot
++) {
116 seen
= seen_fsid_hash
[slot
];
122 seen_fsid_hash
[slot
] = NULL
;
126 static const char * const filesystem_cmd_group_usage
[] = {
127 "btrfs filesystem [<group>] <command> [<args>]",
131 static const char * const cmd_filesystem_df_usage
[] = {
132 "btrfs filesystem df [options] <path>",
133 "Show space usage information for a mount point",
134 HELPINFO_UNITS_SHORT_LONG
,
138 static int get_df(int fd
, struct btrfs_ioctl_space_args
**sargs_ret
)
142 struct btrfs_ioctl_space_args
*sargs
;
144 sargs
= malloc(sizeof(struct btrfs_ioctl_space_args
));
148 sargs
->space_slots
= 0;
149 sargs
->total_spaces
= 0;
151 ret
= ioctl(fd
, BTRFS_IOC_SPACE_INFO
, sargs
);
153 error("cannot get space info: %s", strerror(errno
));
157 /* This really should never happen */
158 if (!sargs
->total_spaces
) {
162 count
= sargs
->total_spaces
;
165 sargs
= malloc(sizeof(struct btrfs_ioctl_space_args
) +
166 (count
* sizeof(struct btrfs_ioctl_space_info
)));
170 sargs
->space_slots
= count
;
171 sargs
->total_spaces
= 0;
172 ret
= ioctl(fd
, BTRFS_IOC_SPACE_INFO
, sargs
);
174 error("cannot get space info with %llu slots: %s",
175 count
, strerror(errno
));
183 static void print_df(struct btrfs_ioctl_space_args
*sargs
, unsigned unit_mode
)
186 struct btrfs_ioctl_space_info
*sp
= sargs
->spaces
;
188 for (i
= 0; i
< sargs
->total_spaces
; i
++, sp
++) {
189 printf("%s, %s: total=%s, used=%s\n",
190 btrfs_group_type_str(sp
->flags
),
191 btrfs_group_profile_str(sp
->flags
),
192 pretty_size_mode(sp
->total_bytes
, unit_mode
),
193 pretty_size_mode(sp
->used_bytes
, unit_mode
));
197 static int cmd_filesystem_df(int argc
, char **argv
)
199 struct btrfs_ioctl_space_args
*sargs
= NULL
;
203 DIR *dirstream
= NULL
;
206 unit_mode
= get_unit_mode_from_arg(&argc
, argv
, 1);
208 clean_args_no_options(argc
, argv
, cmd_filesystem_df_usage
);
210 if (check_argc_exact(argc
- optind
, 1))
211 usage(cmd_filesystem_df_usage
);
215 fd
= btrfs_open_dir(path
, &dirstream
, 1);
219 ret
= get_df(fd
, &sargs
);
222 print_df(sargs
, unit_mode
);
225 error("get_df failed %s", strerror(-ret
));
228 close_file_or_dir(fd
, dirstream
);
232 static int match_search_item_kernel(__u8
*fsid
, char *mnt
, char *label
,
235 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
236 int search_len
= strlen(search
);
238 search_len
= min(search_len
, BTRFS_UUID_UNPARSED_SIZE
);
239 uuid_unparse(fsid
, uuidbuf
);
240 if (!strncmp(uuidbuf
, search
, search_len
))
243 if (*label
&& strcmp(label
, search
) == 0)
246 if (strcmp(mnt
, search
) == 0)
252 static int uuid_search(struct btrfs_fs_devices
*fs_devices
, const char *search
)
254 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
255 struct list_head
*cur
;
256 struct btrfs_device
*device
;
257 int search_len
= strlen(search
);
259 search_len
= min(search_len
, BTRFS_UUID_UNPARSED_SIZE
);
260 uuid_unparse(fs_devices
->fsid
, uuidbuf
);
261 if (!strncmp(uuidbuf
, search
, search_len
))
264 list_for_each(cur
, &fs_devices
->devices
) {
265 device
= list_entry(cur
, struct btrfs_device
, dev_list
);
266 if ((device
->label
&& strcmp(device
->label
, search
) == 0) ||
267 strcmp(device
->name
, search
) == 0)
274 * Sort devices by devid, ascending
276 static int cmp_device_id(void *priv
, struct list_head
*a
,
279 const struct btrfs_device
*da
= list_entry(a
, struct btrfs_device
,
281 const struct btrfs_device
*db
= list_entry(b
, struct btrfs_device
,
284 return da
->devid
< db
->devid
? -1 :
285 da
->devid
> db
->devid
? 1 : 0;
288 static void splice_device_list(struct list_head
*seed_devices
,
289 struct list_head
*all_devices
)
291 struct btrfs_device
*in_all
, *next_all
;
292 struct btrfs_device
*in_seed
, *next_seed
;
294 list_for_each_entry_safe(in_all
, next_all
, all_devices
, dev_list
) {
295 list_for_each_entry_safe(in_seed
, next_seed
, seed_devices
,
297 if (in_all
->devid
== in_seed
->devid
) {
299 * When do dev replace in a sprout fs
300 * to a dev in its seed fs, the replacing
301 * dev will reside in the sprout fs and
302 * the replaced dev will still exist
304 * So pick the latest one when showing
307 if (in_all
->generation
308 < in_seed
->generation
) {
309 list_del(&in_all
->dev_list
);
311 } else if (in_all
->generation
312 > in_seed
->generation
) {
313 list_del(&in_seed
->dev_list
);
321 list_splice(seed_devices
, all_devices
);
324 static void print_devices(struct btrfs_fs_devices
*fs_devices
,
325 u64
*devs_found
, unsigned unit_mode
)
327 struct btrfs_device
*device
;
328 struct btrfs_fs_devices
*cur_fs
;
329 struct list_head
*all_devices
;
331 all_devices
= &fs_devices
->devices
;
332 cur_fs
= fs_devices
->seed
;
333 /* add all devices of seed fs to the fs to be printed */
335 splice_device_list(&cur_fs
->devices
, all_devices
);
336 cur_fs
= cur_fs
->seed
;
339 list_sort(NULL
, all_devices
, cmp_device_id
);
340 list_for_each_entry(device
, all_devices
, dev_list
) {
341 printf("\tdevid %4llu size %s used %s path %s\n",
342 (unsigned long long)device
->devid
,
343 pretty_size_mode(device
->total_bytes
, unit_mode
),
344 pretty_size_mode(device
->bytes_used
, unit_mode
),
351 static void print_one_uuid(struct btrfs_fs_devices
*fs_devices
,
354 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
355 struct btrfs_device
*device
;
359 if (add_seen_fsid(fs_devices
->fsid
))
362 uuid_unparse(fs_devices
->fsid
, uuidbuf
);
363 device
= list_entry(fs_devices
->devices
.next
, struct btrfs_device
,
365 if (device
->label
&& device
->label
[0])
366 printf("Label: '%s' ", device
->label
);
368 printf("Label: none ");
370 total
= device
->total_devs
;
371 printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf
,
372 (unsigned long long)total
,
373 pretty_size_mode(device
->super_bytes_used
, unit_mode
));
375 print_devices(fs_devices
, &devs_found
, unit_mode
);
377 if (devs_found
< total
) {
378 printf("\t*** Some devices missing\n");
383 /* adds up all the used spaces as reported by the space info ioctl
385 static u64
calc_used_bytes(struct btrfs_ioctl_space_args
*si
)
389 for (i
= 0; i
< si
->total_spaces
; i
++)
390 ret
+= si
->spaces
[i
].used_bytes
;
394 static int print_one_fs(struct btrfs_ioctl_fs_info_args
*fs_info
,
395 struct btrfs_ioctl_dev_info_args
*dev_info
,
396 struct btrfs_ioctl_space_args
*space_info
,
397 char *label
, unsigned unit_mode
)
402 char uuidbuf
[BTRFS_UUID_UNPARSED_SIZE
];
403 struct btrfs_ioctl_dev_info_args
*tmp_dev_info
;
406 ret
= add_seen_fsid(fs_info
->fsid
);
412 uuid_unparse(fs_info
->fsid
, uuidbuf
);
414 printf("Label: '%s' ", label
);
416 printf("Label: none ");
418 printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf
,
419 fs_info
->num_devices
,
420 pretty_size_mode(calc_used_bytes(space_info
),
423 for (i
= 0; i
< fs_info
->num_devices
; i
++) {
424 char *canonical_path
;
426 tmp_dev_info
= (struct btrfs_ioctl_dev_info_args
*)&dev_info
[i
];
428 /* Add check for missing devices even mounted */
429 fd
= open((char *)tmp_dev_info
->path
, O_RDONLY
);
435 canonical_path
= canonicalize_path((char *)tmp_dev_info
->path
);
436 printf("\tdevid %4llu size %s used %s path %s\n",
438 pretty_size_mode(tmp_dev_info
->total_bytes
, unit_mode
),
439 pretty_size_mode(tmp_dev_info
->bytes_used
, unit_mode
),
442 free(canonical_path
);
446 printf("\t*** Some devices missing\n");
451 static int btrfs_scan_kernel(void *search
, unsigned unit_mode
)
457 struct btrfs_ioctl_fs_info_args fs_info_arg
;
458 struct btrfs_ioctl_dev_info_args
*dev_info_arg
= NULL
;
459 struct btrfs_ioctl_space_args
*space_info_arg
= NULL
;
460 char label
[BTRFS_LABEL_SIZE
];
462 f
= setmntent("/proc/self/mounts", "r");
466 memset(label
, 0, sizeof(label
));
467 while ((mnt
= getmntent(f
)) != NULL
) {
470 if (strcmp(mnt
->mnt_type
, "btrfs"))
472 ret
= get_fs_info(mnt
->mnt_dir
, &fs_info_arg
,
477 /* skip all fs already shown as mounted fs */
478 if (is_seen_fsid(fs_info_arg
.fsid
))
481 ret
= get_label_mounted(mnt
->mnt_dir
, label
);
482 /* provide backward kernel compatibility */
484 ret
= get_label_unmounted(
485 (const char *)dev_info_arg
->path
, label
);
490 if (search
&& !match_search_item_kernel(fs_info_arg
.fsid
,
491 mnt
->mnt_dir
, label
, search
)) {
495 fd
= open(mnt
->mnt_dir
, O_RDONLY
);
496 if ((fd
!= -1) && !get_df(fd
, &space_info_arg
)) {
497 print_one_fs(&fs_info_arg
, dev_info_arg
,
498 space_info_arg
, label
, unit_mode
);
499 free(space_info_arg
);
500 memset(label
, 0, sizeof(label
));
513 static int dev_to_fsid(const char *dev
, __u8
*fsid
)
515 struct btrfs_super_block
*disk_super
;
516 char buf
[BTRFS_SUPER_INFO_SIZE
];
520 fd
= open(dev
, O_RDONLY
);
526 disk_super
= (struct btrfs_super_block
*)buf
;
527 ret
= btrfs_read_dev_super(fd
, disk_super
,
528 BTRFS_SUPER_INFO_OFFSET
, SBREAD_DEFAULT
);
532 memcpy(fsid
, disk_super
->fsid
, BTRFS_FSID_SIZE
);
540 static void free_fs_devices(struct btrfs_fs_devices
*fs_devices
)
542 struct btrfs_fs_devices
*cur_seed
, *next_seed
;
543 struct btrfs_device
*device
;
545 while (!list_empty(&fs_devices
->devices
)) {
546 device
= list_entry(fs_devices
->devices
.next
,
547 struct btrfs_device
, dev_list
);
548 list_del(&device
->dev_list
);
555 /* free seed fs chain */
556 cur_seed
= fs_devices
->seed
;
557 fs_devices
->seed
= NULL
;
559 next_seed
= cur_seed
->seed
;
562 cur_seed
= next_seed
;
565 list_del(&fs_devices
->list
);
569 static int copy_device(struct btrfs_device
*dst
,
570 struct btrfs_device
*src
)
572 dst
->devid
= src
->devid
;
573 memcpy(dst
->uuid
, src
->uuid
, BTRFS_UUID_SIZE
);
574 if (src
->name
== NULL
)
577 dst
->name
= strdup(src
->name
);
581 if (src
->label
== NULL
)
584 dst
->label
= strdup(src
->label
);
590 dst
->total_devs
= src
->total_devs
;
591 dst
->super_bytes_used
= src
->super_bytes_used
;
592 dst
->total_bytes
= src
->total_bytes
;
593 dst
->bytes_used
= src
->bytes_used
;
594 dst
->generation
= src
->generation
;
599 static int copy_fs_devices(struct btrfs_fs_devices
*dst
,
600 struct btrfs_fs_devices
*src
)
602 struct btrfs_device
*cur_dev
, *dev_copy
;
605 memcpy(dst
->fsid
, src
->fsid
, BTRFS_FSID_SIZE
);
606 INIT_LIST_HEAD(&dst
->devices
);
609 list_for_each_entry(cur_dev
, &src
->devices
, dev_list
) {
610 dev_copy
= malloc(sizeof(*dev_copy
));
616 ret
= copy_device(dev_copy
, cur_dev
);
622 list_add(&dev_copy
->dev_list
, &dst
->devices
);
623 dev_copy
->fs_devices
= dst
;
629 static int find_and_copy_seed(struct btrfs_fs_devices
*seed
,
630 struct btrfs_fs_devices
*copy
,
631 struct list_head
*fs_uuids
) {
632 struct btrfs_fs_devices
*cur_fs
;
634 list_for_each_entry(cur_fs
, fs_uuids
, list
)
635 if (!memcmp(seed
->fsid
, cur_fs
->fsid
, BTRFS_FSID_SIZE
))
636 return copy_fs_devices(copy
, cur_fs
);
641 static int has_seed_devices(struct btrfs_fs_devices
*fs_devices
)
643 struct btrfs_device
*device
;
644 int dev_cnt_total
, dev_cnt
= 0;
646 device
= list_first_entry(&fs_devices
->devices
, struct btrfs_device
,
649 dev_cnt_total
= device
->total_devs
;
651 list_for_each_entry(device
, &fs_devices
->devices
, dev_list
)
654 return dev_cnt_total
!= dev_cnt
;
657 static int search_umounted_fs_uuids(struct list_head
*all_uuids
,
658 char *search
, int *found
)
660 struct btrfs_fs_devices
*cur_fs
, *fs_copy
;
661 struct list_head
*fs_uuids
;
664 fs_uuids
= btrfs_scanned_uuids();
667 * The fs_uuids list is global, and open_ctree_* will
668 * modify it, make a private copy here
670 list_for_each_entry(cur_fs
, fs_uuids
, list
) {
671 /* don't bother handle all fs, if search target specified */
673 if (uuid_search(cur_fs
, search
) == 0)
679 /* skip all fs already shown as mounted fs */
680 if (is_seen_fsid(cur_fs
->fsid
))
683 fs_copy
= calloc(1, sizeof(*fs_copy
));
689 ret
= copy_fs_devices(fs_copy
, cur_fs
);
695 list_add(&fs_copy
->list
, all_uuids
);
702 static int map_seed_devices(struct list_head
*all_uuids
)
704 struct btrfs_fs_devices
*cur_fs
, *cur_seed
;
705 struct btrfs_fs_devices
*seed_copy
;
706 struct btrfs_fs_devices
*opened_fs
;
707 struct btrfs_device
*device
;
708 struct btrfs_fs_info
*fs_info
;
709 struct list_head
*fs_uuids
;
712 fs_uuids
= btrfs_scanned_uuids();
714 list_for_each_entry(cur_fs
, all_uuids
, list
) {
715 device
= list_first_entry(&cur_fs
->devices
,
716 struct btrfs_device
, dev_list
);
720 /* skip fs without seeds */
721 if (!has_seed_devices(cur_fs
))
725 * open_ctree_* detects seed/sprout mapping
727 fs_info
= open_ctree_fs_info(device
->name
, 0, 0, 0,
733 * copy the seed chain under the opened fs
735 opened_fs
= fs_info
->fs_devices
;
737 while (opened_fs
->seed
) {
738 seed_copy
= malloc(sizeof(*seed_copy
));
743 ret
= find_and_copy_seed(opened_fs
->seed
, seed_copy
,
750 cur_seed
->seed
= seed_copy
;
752 opened_fs
= opened_fs
->seed
;
753 cur_seed
= cur_seed
->seed
;
756 close_ctree(fs_info
->chunk_root
);
762 close_ctree(fs_info
->chunk_root
);
766 static const char * const cmd_filesystem_show_usage
[] = {
767 "btrfs filesystem show [options] [<path>|<uuid>|<device>|label]",
768 "Show the structure of a filesystem",
769 "-d|--all-devices show only disks under /dev containing btrfs filesystem",
770 "-m|--mounted show only mounted btrfs",
772 "If no argument is given, structure of all present filesystems is shown.",
776 static int cmd_filesystem_show(int argc
, char **argv
)
778 LIST_HEAD(all_uuids
);
779 struct btrfs_fs_devices
*fs_devices
;
782 /* default, search both kernel and udev */
787 __u8 fsid
[BTRFS_FSID_SIZE
];
788 char uuid_buf
[BTRFS_UUID_UNPARSED_SIZE
];
792 unit_mode
= get_unit_mode_from_arg(&argc
, argv
, 0);
796 static const struct option long_options
[] = {
797 { "all-devices", no_argument
, NULL
, 'd'},
798 { "mounted", no_argument
, NULL
, 'm'},
802 c
= getopt_long(argc
, argv
, "dm", long_options
, NULL
);
807 where
= BTRFS_SCAN_LBLKID
;
810 where
= BTRFS_SCAN_MOUNTED
;
813 usage(cmd_filesystem_show_usage
);
817 if (check_argc_max(argc
, optind
+ 1))
818 usage(cmd_filesystem_show_usage
);
821 search
= argv
[optind
];
823 usage(cmd_filesystem_show_usage
);
824 type
= check_arg_type(search
);
827 * For search is a device:
828 * realpath do /dev/mapper/XX => /dev/dm-X
829 * which is required by BTRFS_SCAN_DEV
830 * For search is a mountpoint:
831 * realpath do /mnt/btrfs/ => /mnt/btrfs
832 * which shall be recognized by btrfs_scan_kernel()
834 if (realpath(search
, path
))
838 * Needs special handling if input arg is block dev And if
839 * input arg is mount-point just print it right away
841 if (type
== BTRFS_ARG_BLKDEV
&& where
!= BTRFS_SCAN_LBLKID
) {
842 ret
= get_btrfs_mount(search
, mp
, sizeof(mp
));
844 /* given block dev is mounted */
846 type
= BTRFS_ARG_MNTPOINT
;
848 ret
= dev_to_fsid(search
, fsid
);
850 error("no btrfs on %s", search
);
853 uuid_unparse(fsid
, uuid_buf
);
855 type
= BTRFS_ARG_UUID
;
861 if (where
== BTRFS_SCAN_LBLKID
)
864 /* show mounted btrfs */
865 ret
= btrfs_scan_kernel(search
, unit_mode
);
866 if (search
&& !ret
) {
867 /* since search is found we are done */
871 /* shows mounted only */
872 if (where
== BTRFS_SCAN_MOUNTED
)
876 ret
= btrfs_scan_devices();
879 error("blkid device scan returned %d", ret
);
883 ret
= search_umounted_fs_uuids(&all_uuids
, search
, &found
);
885 error("searching target device returned error %d", ret
);
890 * The seed/sprout mapping are not detected yet,
891 * do mapping build for all umounted fs
893 ret
= map_seed_devices(&all_uuids
);
895 error("mapping seed devices returned error %d", ret
);
899 list_for_each_entry(fs_devices
, &all_uuids
, list
)
900 print_one_uuid(fs_devices
, unit_mode
);
902 if (search
&& !found
) {
903 error("not a valid btrfs filesystem: %s", search
);
906 while (!list_empty(&all_uuids
)) {
907 fs_devices
= list_entry(all_uuids
.next
,
908 struct btrfs_fs_devices
, list
);
909 free_fs_devices(fs_devices
);
916 static const char * const cmd_filesystem_sync_usage
[] = {
917 "btrfs filesystem sync <path>",
918 "Force a sync on a filesystem",
922 static int cmd_filesystem_sync(int argc
, char **argv
)
926 DIR *dirstream
= NULL
;
928 clean_args_no_options(argc
, argv
, cmd_filesystem_sync_usage
);
930 if (check_argc_exact(argc
- optind
, 1))
931 usage(cmd_filesystem_sync_usage
);
935 fd
= btrfs_open_dir(path
, &dirstream
, 1);
939 res
= ioctl(fd
, BTRFS_IOC_SYNC
);
941 close_file_or_dir(fd
, dirstream
);
943 error("sync ioctl failed on '%s': %s", path
, strerror(e
));
950 static int parse_compress_type(char *s
)
952 if (strcmp(optarg
, "zlib") == 0)
953 return BTRFS_COMPRESS_ZLIB
;
954 else if (strcmp(optarg
, "lzo") == 0)
955 return BTRFS_COMPRESS_LZO
;
957 error("unknown compression type %s", s
);
962 static const char * const cmd_filesystem_defrag_usage
[] = {
963 "btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
964 "Defragment a file or a directory",
967 "-r defragment files recursively",
968 "-c[zlib,lzo] compress the file while defragmenting",
969 "-f flush data to disk immediately after defragmenting",
970 "-s start defragment only from byte onward",
971 "-l len defragment only up to len bytes",
972 "-t size target extent size hint (default: 32M)",
976 static struct btrfs_ioctl_defrag_range_args defrag_global_range
;
977 static int defrag_global_verbose
;
978 static int defrag_global_errors
;
979 static int defrag_callback(const char *fpath
, const struct stat
*sb
,
980 int typeflag
, struct FTW
*ftwbuf
)
986 if ((typeflag
== FTW_F
) && S_ISREG(sb
->st_mode
)) {
987 if (defrag_global_verbose
)
988 printf("%s\n", fpath
);
989 fd
= open(fpath
, O_RDWR
);
994 ret
= ioctl(fd
, BTRFS_IOC_DEFRAG_RANGE
, &defrag_global_range
);
996 if (ret
&& errno
== ENOTTY
) {
998 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
999 defrag_global_errors
++;
1010 error("defrag failed on %s: %s", fpath
, strerror(err
));
1011 defrag_global_errors
++;
1015 static int cmd_filesystem_defrag(int argc
, char **argv
)
1025 int compress_type
= BTRFS_COMPRESS_NONE
;
1029 * Kernel has a different default (256K) that is supposed to be safe,
1030 * but it does not defragment very well. The 32M will likely lead to
1031 * better results and is independent of the kernel default. We have to
1032 * use the v2 defrag ioctl.
1036 defrag_global_errors
= 0;
1037 defrag_global_verbose
= 0;
1038 defrag_global_errors
= 0;
1040 int c
= getopt(argc
, argv
, "vrc::fs:l:t:");
1046 compress_type
= BTRFS_COMPRESS_ZLIB
;
1048 compress_type
= parse_compress_type(optarg
);
1054 defrag_global_verbose
= 1;
1057 start
= parse_size(optarg
);
1060 len
= parse_size(optarg
);
1063 thresh
= parse_size(optarg
);
1064 if (thresh
> (u32
)-1) {
1066 "target extent size %llu too big, trimmed to %u",
1075 usage(cmd_filesystem_defrag_usage
);
1079 if (check_argc_min(argc
- optind
, 1))
1080 usage(cmd_filesystem_defrag_usage
);
1082 memset(&defrag_global_range
, 0, sizeof(defrag_global_range
));
1083 defrag_global_range
.start
= start
;
1084 defrag_global_range
.len
= len
;
1085 defrag_global_range
.extent_thresh
= (u32
)thresh
;
1086 if (compress_type
) {
1087 defrag_global_range
.flags
|= BTRFS_DEFRAG_RANGE_COMPRESS
;
1088 defrag_global_range
.compress_type
= compress_type
;
1091 defrag_global_range
.flags
|= BTRFS_DEFRAG_RANGE_START_IO
;
1094 * Look for directory arguments and warn if the recursive mode is not
1095 * requested, as this is not implemented as recursive defragmentation
1096 * in kernel. The stat errors are silent here as we check them below.
1101 for (i
= optind
; i
< argc
; i
++) {
1104 if (stat(argv
[i
], &st
))
1107 if (S_ISDIR(st
.st_mode
)) {
1109 "directory specified but recursive mode not requested: %s",
1116 "a directory passed to the defrag ioctl will not process the files\n"
1117 "recursively but will defragment the subvolume tree and the extent tree.\n"
1118 "If this is not intended, please use option -r .");
1122 for (i
= optind
; i
< argc
; i
++) {
1127 fd
= open_file_or_dir(argv
[i
], &dirstream
);
1129 error("cannot open %s: %s", argv
[i
],
1131 defrag_global_errors
++;
1132 close_file_or_dir(fd
, dirstream
);
1135 if (fstat(fd
, &st
)) {
1136 error("failed to stat %s: %s",
1137 argv
[i
], strerror(errno
));
1138 defrag_global_errors
++;
1139 close_file_or_dir(fd
, dirstream
);
1142 if (!(S_ISDIR(st
.st_mode
) || S_ISREG(st
.st_mode
))) {
1143 error("%s is not a directory or a regular file",
1145 defrag_global_errors
++;
1146 close_file_or_dir(fd
, dirstream
);
1149 if (recursive
&& S_ISDIR(st
.st_mode
)) {
1150 ret
= nftw(argv
[i
], defrag_callback
, 10,
1151 FTW_MOUNT
| FTW_PHYS
);
1154 /* errors are handled in the callback */
1157 if (defrag_global_verbose
)
1158 printf("%s\n", argv
[i
]);
1159 ret
= ioctl(fd
, BTRFS_IOC_DEFRAG_RANGE
,
1160 &defrag_global_range
);
1163 close_file_or_dir(fd
, dirstream
);
1164 if (ret
&& defrag_err
== ENOTTY
) {
1166 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
1167 defrag_global_errors
++;
1171 error("defrag failed on %s: %s", argv
[i
],
1172 strerror(defrag_err
));
1173 defrag_global_errors
++;
1176 if (defrag_global_errors
)
1177 fprintf(stderr
, "total %d failures\n", defrag_global_errors
);
1179 return !!defrag_global_errors
;
1182 static const char * const cmd_filesystem_resize_usage
[] = {
1183 "btrfs filesystem resize [devid:][+/-]<newsize>[kKmMgGtTpPeE]|[devid:]max <path>",
1184 "Resize a filesystem",
1185 "If 'max' is passed, the filesystem will occupy all available space",
1186 "on the device 'devid'.",
1187 "[kK] means KiB, which denotes 1KiB = 1024B, 1MiB = 1024KiB, etc.",
1191 static int cmd_filesystem_resize(int argc
, char **argv
)
1193 struct btrfs_ioctl_vol_args args
;
1194 int fd
, res
, len
, e
;
1195 char *amount
, *path
;
1196 DIR *dirstream
= NULL
;
1199 clean_args_no_options_relaxed(argc
, argv
, cmd_filesystem_resize_usage
);
1201 if (check_argc_exact(argc
- optind
, 2))
1202 usage(cmd_filesystem_resize_usage
);
1204 amount
= argv
[optind
];
1205 path
= argv
[optind
+ 1];
1207 len
= strlen(amount
);
1208 if (len
== 0 || len
>= BTRFS_VOL_NAME_MAX
) {
1209 error("resize value too long (%s)", amount
);
1213 res
= stat(path
, &st
);
1215 error("resize: cannot stat %s: %s", path
, strerror(errno
));
1218 if (!S_ISDIR(st
.st_mode
)) {
1219 error("resize works on mounted filesystems and accepts only\n"
1220 "directories as argument. Passing file containing a btrfs image\n"
1221 "would resize the underlying filesystem instead of the image.\n");
1225 fd
= btrfs_open_dir(path
, &dirstream
, 1);
1229 printf("Resize '%s' of '%s'\n", path
, amount
);
1230 memset(&args
, 0, sizeof(args
));
1231 strncpy_null(args
.name
, amount
);
1232 res
= ioctl(fd
, BTRFS_IOC_RESIZE
, &args
);
1234 close_file_or_dir(fd
, dirstream
);
1238 error("unable to resize '%s': no enough free space",
1242 error("unable to resize '%s': %s", path
, strerror(e
));
1246 } else if (res
> 0) {
1247 const char *err_str
= btrfs_err_str(res
);
1250 error("resizing of '%s' failed: %s", path
, err_str
);
1252 error("resizing of '%s' failed: unknown error %d",
1260 static const char * const cmd_filesystem_label_usage
[] = {
1261 "btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
1262 "Get or change the label of a filesystem",
1263 "With one argument, get the label of filesystem on <device>.",
1264 "If <newlabel> is passed, set the filesystem label to <newlabel>.",
1268 static int cmd_filesystem_label(int argc
, char **argv
)
1270 clean_args_no_options(argc
, argv
, cmd_filesystem_label_usage
);
1272 if (check_argc_min(argc
- optind
, 1) ||
1273 check_argc_max(argc
- optind
, 2))
1274 usage(cmd_filesystem_label_usage
);
1276 if (argc
- optind
> 1) {
1277 return set_label(argv
[optind
], argv
[optind
+ 1]);
1279 char label
[BTRFS_LABEL_SIZE
];
1282 ret
= get_label(argv
[optind
], label
);
1284 fprintf(stdout
, "%s\n", label
);
1290 static const char filesystem_cmd_group_info
[] =
1291 "overall filesystem tasks and information";
1293 const struct cmd_group filesystem_cmd_group
= {
1294 filesystem_cmd_group_usage
, filesystem_cmd_group_info
, {
1295 { "df", cmd_filesystem_df
, cmd_filesystem_df_usage
, NULL
, 0 },
1296 { "du", cmd_filesystem_du
, cmd_filesystem_du_usage
, NULL
, 0 },
1297 { "show", cmd_filesystem_show
, cmd_filesystem_show_usage
, NULL
,
1299 { "sync", cmd_filesystem_sync
, cmd_filesystem_sync_usage
, NULL
,
1301 { "defragment", cmd_filesystem_defrag
,
1302 cmd_filesystem_defrag_usage
, NULL
, 0 },
1303 { "balance", cmd_balance
, NULL
, &balance_cmd_group
,
1305 { "resize", cmd_filesystem_resize
, cmd_filesystem_resize_usage
,
1307 { "label", cmd_filesystem_label
, cmd_filesystem_label_usage
,
1309 { "usage", cmd_filesystem_usage
,
1310 cmd_filesystem_usage_usage
, NULL
, 0 },
1316 int cmd_filesystem(int argc
, char **argv
)
1318 return handle_command_group(&filesystem_cmd_group
, argc
, argv
);