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"
36 #include "cmds-fi-usage.h"
37 #include "list_sort.h"
42 * for btrfs fi show, we maintain a hash of fsids we've already printed.
43 * This way we don't print dups if a given FS is mounted more than once.
45 static struct seen_fsid *seen_fsid_hash[SEEN_FSID_HASH_SIZE] = {NULL,};
47 static const char * const filesystem_cmd_group_usage[] = {
48 "btrfs filesystem [<group>] <command> [<args>]",
52 static const char * const cmd_filesystem_df_usage[] = {
53 "btrfs filesystem df [options] <path>",
54 "Show space usage information for a mount point",
55 HELPINFO_UNITS_SHORT_LONG,
59 static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret)
63 struct btrfs_ioctl_space_args *sargs;
65 sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
69 sargs->space_slots = 0;
70 sargs->total_spaces = 0;
72 ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
74 error("cannot get space info: %s", strerror(errno));
78 /* This really should never happen */
79 if (!sargs->total_spaces) {
83 count = sargs->total_spaces;
86 sargs = malloc(sizeof(struct btrfs_ioctl_space_args) +
87 (count * sizeof(struct btrfs_ioctl_space_info)));
91 sargs->space_slots = count;
92 sargs->total_spaces = 0;
93 ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
95 error("cannot get space info with %llu slots: %s",
96 count, strerror(errno));
104 static void print_df(struct btrfs_ioctl_space_args *sargs, unsigned unit_mode)
107 struct btrfs_ioctl_space_info *sp = sargs->spaces;
109 for (i = 0; i < sargs->total_spaces; i++, sp++) {
110 printf("%s, %s: total=%s, used=%s\n",
111 btrfs_group_type_str(sp->flags),
112 btrfs_group_profile_str(sp->flags),
113 pretty_size_mode(sp->total_bytes, unit_mode),
114 pretty_size_mode(sp->used_bytes, unit_mode));
118 static int cmd_filesystem_df(int argc, char **argv)
120 struct btrfs_ioctl_space_args *sargs = NULL;
124 DIR *dirstream = NULL;
127 unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
129 clean_args_no_options(argc, argv, cmd_filesystem_df_usage);
131 if (check_argc_exact(argc - optind, 1))
132 usage(cmd_filesystem_df_usage);
136 fd = btrfs_open_dir(path, &dirstream, 1);
140 ret = get_df(fd, &sargs);
143 print_df(sargs, unit_mode);
146 error("get_df failed %s", strerror(-ret));
149 close_file_or_dir(fd, dirstream);
153 static int match_search_item_kernel(__u8 *fsid, char *mnt, char *label,
156 char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
157 int search_len = strlen(search);
159 search_len = min(search_len, BTRFS_UUID_UNPARSED_SIZE);
160 uuid_unparse(fsid, uuidbuf);
161 if (!strncmp(uuidbuf, search, search_len))
164 if (*label && strcmp(label, search) == 0)
167 if (strcmp(mnt, search) == 0)
173 static int uuid_search(struct btrfs_fs_devices *fs_devices, const char *search)
175 char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
176 struct list_head *cur;
177 struct btrfs_device *device;
178 int search_len = strlen(search);
180 search_len = min(search_len, BTRFS_UUID_UNPARSED_SIZE);
181 uuid_unparse(fs_devices->fsid, uuidbuf);
182 if (!strncmp(uuidbuf, search, search_len))
185 list_for_each(cur, &fs_devices->devices) {
186 device = list_entry(cur, struct btrfs_device, 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))
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);
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 int dev_to_fsid(const char *dev, __u8 *fsid)
436 struct btrfs_super_block *disk_super;
437 char buf[BTRFS_SUPER_INFO_SIZE];
441 fd = open(dev, O_RDONLY);
447 disk_super = (struct btrfs_super_block *)buf;
448 ret = btrfs_read_dev_super(fd, disk_super,
449 BTRFS_SUPER_INFO_OFFSET, SBREAD_DEFAULT);
453 memcpy(fsid, disk_super->fsid, BTRFS_FSID_SIZE);
461 static void free_fs_devices(struct btrfs_fs_devices *fs_devices)
463 struct btrfs_fs_devices *cur_seed, *next_seed;
464 struct btrfs_device *device;
466 while (!list_empty(&fs_devices->devices)) {
467 device = list_entry(fs_devices->devices.next,
468 struct btrfs_device, dev_list);
469 list_del(&device->dev_list);
476 /* free seed fs chain */
477 cur_seed = fs_devices->seed;
478 fs_devices->seed = NULL;
480 next_seed = cur_seed->seed;
483 cur_seed = next_seed;
486 list_del(&fs_devices->list);
490 static int copy_device(struct btrfs_device *dst,
491 struct btrfs_device *src)
493 dst->devid = src->devid;
494 memcpy(dst->uuid, src->uuid, BTRFS_UUID_SIZE);
495 if (src->name == NULL)
498 dst->name = strdup(src->name);
502 if (src->label == NULL)
505 dst->label = strdup(src->label);
511 dst->total_devs = src->total_devs;
512 dst->super_bytes_used = src->super_bytes_used;
513 dst->total_bytes = src->total_bytes;
514 dst->bytes_used = src->bytes_used;
515 dst->generation = src->generation;
520 static int copy_fs_devices(struct btrfs_fs_devices *dst,
521 struct btrfs_fs_devices *src)
523 struct btrfs_device *cur_dev, *dev_copy;
526 memcpy(dst->fsid, src->fsid, BTRFS_FSID_SIZE);
527 INIT_LIST_HEAD(&dst->devices);
530 list_for_each_entry(cur_dev, &src->devices, dev_list) {
531 dev_copy = malloc(sizeof(*dev_copy));
537 ret = copy_device(dev_copy, cur_dev);
543 list_add(&dev_copy->dev_list, &dst->devices);
544 dev_copy->fs_devices = dst;
550 static int find_and_copy_seed(struct btrfs_fs_devices *seed,
551 struct btrfs_fs_devices *copy,
552 struct list_head *fs_uuids) {
553 struct btrfs_fs_devices *cur_fs;
555 list_for_each_entry(cur_fs, fs_uuids, list)
556 if (!memcmp(seed->fsid, cur_fs->fsid, BTRFS_FSID_SIZE))
557 return copy_fs_devices(copy, cur_fs);
562 static int has_seed_devices(struct btrfs_fs_devices *fs_devices)
564 struct btrfs_device *device;
565 int dev_cnt_total, dev_cnt = 0;
567 device = list_first_entry(&fs_devices->devices, struct btrfs_device,
570 dev_cnt_total = device->total_devs;
572 list_for_each_entry(device, &fs_devices->devices, dev_list)
575 return dev_cnt_total != dev_cnt;
578 static int search_umounted_fs_uuids(struct list_head *all_uuids,
579 char *search, int *found)
581 struct btrfs_fs_devices *cur_fs, *fs_copy;
582 struct list_head *fs_uuids;
585 fs_uuids = btrfs_scanned_uuids();
588 * The fs_uuids list is global, and open_ctree_* will
589 * modify it, make a private copy here
591 list_for_each_entry(cur_fs, fs_uuids, list) {
592 /* don't bother handle all fs, if search target specified */
594 if (uuid_search(cur_fs, search) == 0)
600 /* skip all fs already shown as mounted fs */
601 if (is_seen_fsid(cur_fs->fsid, seen_fsid_hash))
604 fs_copy = calloc(1, sizeof(*fs_copy));
610 ret = copy_fs_devices(fs_copy, cur_fs);
616 list_add(&fs_copy->list, all_uuids);
623 static int map_seed_devices(struct list_head *all_uuids)
625 struct btrfs_fs_devices *cur_fs, *cur_seed;
626 struct btrfs_fs_devices *seed_copy;
627 struct btrfs_fs_devices *opened_fs;
628 struct btrfs_device *device;
629 struct btrfs_fs_info *fs_info;
630 struct list_head *fs_uuids;
633 fs_uuids = btrfs_scanned_uuids();
635 list_for_each_entry(cur_fs, all_uuids, list) {
636 device = list_first_entry(&cur_fs->devices,
637 struct btrfs_device, dev_list);
641 /* skip fs without seeds */
642 if (!has_seed_devices(cur_fs))
646 * open_ctree_* detects seed/sprout mapping
648 fs_info = open_ctree_fs_info(device->name, 0, 0, 0,
654 * copy the seed chain under the opened fs
656 opened_fs = fs_info->fs_devices;
658 while (opened_fs->seed) {
659 seed_copy = malloc(sizeof(*seed_copy));
664 ret = find_and_copy_seed(opened_fs->seed, seed_copy,
671 cur_seed->seed = seed_copy;
673 opened_fs = opened_fs->seed;
674 cur_seed = cur_seed->seed;
677 close_ctree(fs_info->chunk_root);
683 close_ctree(fs_info->chunk_root);
687 static const char * const cmd_filesystem_show_usage[] = {
688 "btrfs filesystem show [options] [<path>|<uuid>|<device>|label]",
689 "Show the structure of a filesystem",
690 "-d|--all-devices show only disks under /dev containing btrfs filesystem",
691 "-m|--mounted show only mounted btrfs",
693 "If no argument is given, structure of all present filesystems is shown.",
697 static int cmd_filesystem_show(int argc, char **argv)
699 LIST_HEAD(all_uuids);
700 struct btrfs_fs_devices *fs_devices;
703 /* default, search both kernel and udev */
708 __u8 fsid[BTRFS_FSID_SIZE];
709 char uuid_buf[BTRFS_UUID_UNPARSED_SIZE];
713 unit_mode = get_unit_mode_from_arg(&argc, argv, 0);
717 static const struct option long_options[] = {
718 { "all-devices", no_argument, NULL, 'd'},
719 { "mounted", no_argument, NULL, 'm'},
723 c = getopt_long(argc, argv, "dm", long_options, NULL);
728 where = BTRFS_SCAN_LBLKID;
731 where = BTRFS_SCAN_MOUNTED;
734 usage(cmd_filesystem_show_usage);
738 if (check_argc_max(argc, optind + 1))
739 usage(cmd_filesystem_show_usage);
742 search = argv[optind];
744 usage(cmd_filesystem_show_usage);
745 type = check_arg_type(search);
748 * For search is a device:
749 * realpath do /dev/mapper/XX => /dev/dm-X
750 * which is required by BTRFS_SCAN_DEV
751 * For search is a mountpoint:
752 * realpath do /mnt/btrfs/ => /mnt/btrfs
753 * which shall be recognized by btrfs_scan_kernel()
755 if (realpath(search, path))
759 * Needs special handling if input arg is block dev And if
760 * input arg is mount-point just print it right away
762 if (type == BTRFS_ARG_BLKDEV && where != BTRFS_SCAN_LBLKID) {
763 ret = get_btrfs_mount(search, mp, sizeof(mp));
765 /* given block dev is mounted */
767 type = BTRFS_ARG_MNTPOINT;
769 ret = dev_to_fsid(search, fsid);
771 error("no btrfs on %s", search);
774 uuid_unparse(fsid, uuid_buf);
776 type = BTRFS_ARG_UUID;
782 if (where == BTRFS_SCAN_LBLKID)
785 /* show mounted btrfs */
786 ret = btrfs_scan_kernel(search, unit_mode);
787 if (search && !ret) {
788 /* since search is found we are done */
792 /* shows mounted only */
793 if (where == BTRFS_SCAN_MOUNTED)
797 ret = btrfs_scan_devices();
800 error("blkid device scan returned %d", ret);
804 ret = search_umounted_fs_uuids(&all_uuids, search, &found);
806 error("searching target device returned error %d", ret);
811 * The seed/sprout mapping are not detected yet,
812 * do mapping build for all umounted fs
814 ret = map_seed_devices(&all_uuids);
816 error("mapping seed devices returned error %d", ret);
820 list_for_each_entry(fs_devices, &all_uuids, list)
821 print_one_uuid(fs_devices, unit_mode);
823 if (search && !found) {
824 error("not a valid btrfs filesystem: %s", search);
827 while (!list_empty(&all_uuids)) {
828 fs_devices = list_entry(all_uuids.next,
829 struct btrfs_fs_devices, list);
830 free_fs_devices(fs_devices);
833 free_seen_fsid(seen_fsid_hash);
837 static const char * const cmd_filesystem_sync_usage[] = {
838 "btrfs filesystem sync <path>",
839 "Force a sync on a filesystem",
843 static int cmd_filesystem_sync(int argc, char **argv)
847 DIR *dirstream = NULL;
849 clean_args_no_options(argc, argv, cmd_filesystem_sync_usage);
851 if (check_argc_exact(argc - optind, 1))
852 usage(cmd_filesystem_sync_usage);
856 fd = btrfs_open_dir(path, &dirstream, 1);
860 res = ioctl(fd, BTRFS_IOC_SYNC);
862 close_file_or_dir(fd, dirstream);
864 error("sync ioctl failed on '%s': %s", path, strerror(e));
871 static int parse_compress_type(char *s)
873 if (strcmp(optarg, "zlib") == 0)
874 return BTRFS_COMPRESS_ZLIB;
875 else if (strcmp(optarg, "lzo") == 0)
876 return BTRFS_COMPRESS_LZO;
877 else if (strcmp(optarg, "zstd") == 0)
878 return BTRFS_COMPRESS_ZSTD;
880 error("unknown compression type %s", s);
885 static const char * const cmd_filesystem_defrag_usage[] = {
886 "btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
887 "Defragment a file or a directory",
890 "-r defragment files recursively",
891 "-c[zlib,lzo,zstd] compress the file while defragmenting",
892 "-f flush data to disk immediately after defragmenting",
893 "-s start defragment only from byte onward",
894 "-l len defragment only up to len bytes",
895 "-t size target extent size hint (default: 32M)",
899 static struct btrfs_ioctl_defrag_range_args defrag_global_range;
900 static int defrag_global_verbose;
901 static int defrag_global_errors;
902 static int defrag_callback(const char *fpath, const struct stat *sb,
903 int typeflag, struct FTW *ftwbuf)
909 if ((typeflag == FTW_F) && S_ISREG(sb->st_mode)) {
910 if (defrag_global_verbose)
911 printf("%s\n", fpath);
912 fd = open(fpath, O_RDWR);
917 ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &defrag_global_range);
919 if (ret && errno == ENOTTY) {
921 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
922 defrag_global_errors++;
933 error("defrag failed on %s: %s", fpath, strerror(err));
934 defrag_global_errors++;
938 static int cmd_filesystem_defrag(int argc, char **argv)
948 int compress_type = BTRFS_COMPRESS_NONE;
952 * Kernel has a different default (256K) that is supposed to be safe,
953 * but it does not defragment very well. The 32M will likely lead to
954 * better results and is independent of the kernel default. We have to
955 * use the v2 defrag ioctl.
959 defrag_global_errors = 0;
960 defrag_global_verbose = 0;
961 defrag_global_errors = 0;
963 int c = getopt(argc, argv, "vrc::fs:l:t:");
969 compress_type = BTRFS_COMPRESS_ZLIB;
971 compress_type = parse_compress_type(optarg);
977 defrag_global_verbose = 1;
980 start = parse_size(optarg);
983 len = parse_size(optarg);
986 thresh = parse_size(optarg);
987 if (thresh > (u32)-1) {
989 "target extent size %llu too big, trimmed to %u",
998 usage(cmd_filesystem_defrag_usage);
1002 if (check_argc_min(argc - optind, 1))
1003 usage(cmd_filesystem_defrag_usage);
1005 memset(&defrag_global_range, 0, sizeof(defrag_global_range));
1006 defrag_global_range.start = start;
1007 defrag_global_range.len = len;
1008 defrag_global_range.extent_thresh = (u32)thresh;
1009 if (compress_type) {
1010 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
1011 defrag_global_range.compress_type = compress_type;
1014 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
1017 * Look for directory arguments and warn if the recursive mode is not
1018 * requested, as this is not implemented as recursive defragmentation
1019 * in kernel. The stat errors are silent here as we check them below.
1024 for (i = optind; i < argc; i++) {
1027 if (stat(argv[i], &st))
1030 if (S_ISDIR(st.st_mode)) {
1032 "directory specified but recursive mode not requested: %s",
1039 "a directory passed to the defrag ioctl will not process the files\n"
1040 "recursively but will defragment the subvolume tree and the extent tree.\n"
1041 "If this is not intended, please use option -r .");
1045 for (i = optind; i < argc; i++) {
1050 fd = open_file_or_dir(argv[i], &dirstream);
1052 error("cannot open %s: %s", argv[i],
1054 defrag_global_errors++;
1055 close_file_or_dir(fd, dirstream);
1058 if (fstat(fd, &st)) {
1059 error("failed to stat %s: %s",
1060 argv[i], strerror(errno));
1061 defrag_global_errors++;
1062 close_file_or_dir(fd, dirstream);
1065 if (!(S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))) {
1066 error("%s is not a directory or a regular file",
1068 defrag_global_errors++;
1069 close_file_or_dir(fd, dirstream);
1072 if (recursive && S_ISDIR(st.st_mode)) {
1073 ret = nftw(argv[i], defrag_callback, 10,
1074 FTW_MOUNT | FTW_PHYS);
1077 /* errors are handled in the callback */
1080 if (defrag_global_verbose)
1081 printf("%s\n", argv[i]);
1082 ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE,
1083 &defrag_global_range);
1086 close_file_or_dir(fd, dirstream);
1087 if (ret && defrag_err == ENOTTY) {
1089 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
1090 defrag_global_errors++;
1094 error("defrag failed on %s: %s", argv[i],
1095 strerror(defrag_err));
1096 defrag_global_errors++;
1099 if (defrag_global_errors)
1100 fprintf(stderr, "total %d failures\n", defrag_global_errors);
1102 return !!defrag_global_errors;
1105 static const char * const cmd_filesystem_resize_usage[] = {
1106 "btrfs filesystem resize [devid:][+/-]<newsize>[kKmMgGtTpPeE]|[devid:]max <path>",
1107 "Resize a filesystem",
1108 "If 'max' is passed, the filesystem will occupy all available space",
1109 "on the device 'devid'.",
1110 "[kK] means KiB, which denotes 1KiB = 1024B, 1MiB = 1024KiB, etc.",
1114 static int cmd_filesystem_resize(int argc, char **argv)
1116 struct btrfs_ioctl_vol_args args;
1117 int fd, res, len, e;
1118 char *amount, *path;
1119 DIR *dirstream = NULL;
1122 clean_args_no_options_relaxed(argc, argv, cmd_filesystem_resize_usage);
1124 if (check_argc_exact(argc - optind, 2))
1125 usage(cmd_filesystem_resize_usage);
1127 amount = argv[optind];
1128 path = argv[optind + 1];
1130 len = strlen(amount);
1131 if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
1132 error("resize value too long (%s)", amount);
1136 res = stat(path, &st);
1138 error("resize: cannot stat %s: %s", path, strerror(errno));
1141 if (!S_ISDIR(st.st_mode)) {
1142 error("resize works on mounted filesystems and accepts only\n"
1143 "directories as argument. Passing file containing a btrfs image\n"
1144 "would resize the underlying filesystem instead of the image.\n");
1148 fd = btrfs_open_dir(path, &dirstream, 1);
1152 printf("Resize '%s' of '%s'\n", path, amount);
1153 memset(&args, 0, sizeof(args));
1154 strncpy_null(args.name, amount);
1155 res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
1157 close_file_or_dir(fd, dirstream);
1161 error("unable to resize '%s': no enough free space",
1165 error("unable to resize '%s': %s", path, strerror(e));
1169 } else if (res > 0) {
1170 const char *err_str = btrfs_err_str(res);
1173 error("resizing of '%s' failed: %s", path, err_str);
1175 error("resizing of '%s' failed: unknown error %d",
1183 static const char * const cmd_filesystem_label_usage[] = {
1184 "btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
1185 "Get or change the label of a filesystem",
1186 "With one argument, get the label of filesystem on <device>.",
1187 "If <newlabel> is passed, set the filesystem label to <newlabel>.",
1191 static int cmd_filesystem_label(int argc, char **argv)
1193 clean_args_no_options(argc, argv, cmd_filesystem_label_usage);
1195 if (check_argc_min(argc - optind, 1) ||
1196 check_argc_max(argc - optind, 2))
1197 usage(cmd_filesystem_label_usage);
1199 if (argc - optind > 1) {
1200 return set_label(argv[optind], argv[optind + 1]);
1202 char label[BTRFS_LABEL_SIZE];
1205 ret = get_label(argv[optind], label);
1207 fprintf(stdout, "%s\n", label);
1213 static const char filesystem_cmd_group_info[] =
1214 "overall filesystem tasks and information";
1216 const struct cmd_group filesystem_cmd_group = {
1217 filesystem_cmd_group_usage, filesystem_cmd_group_info, {
1218 { "df", cmd_filesystem_df, cmd_filesystem_df_usage, NULL, 0 },
1219 { "du", cmd_filesystem_du, cmd_filesystem_du_usage, NULL, 0 },
1220 { "show", cmd_filesystem_show, cmd_filesystem_show_usage, NULL,
1222 { "sync", cmd_filesystem_sync, cmd_filesystem_sync_usage, NULL,
1224 { "defragment", cmd_filesystem_defrag,
1225 cmd_filesystem_defrag_usage, NULL, 0 },
1226 { "balance", cmd_balance, NULL, &balance_cmd_group,
1228 { "resize", cmd_filesystem_resize, cmd_filesystem_resize_usage,
1230 { "label", cmd_filesystem_label, cmd_filesystem_label_usage,
1232 { "usage", cmd_filesystem_usage,
1233 cmd_filesystem_usage_usage, NULL, 0 },
1239 int cmd_filesystem(int argc, char **argv)
1241 return handle_command_group(&filesystem_cmd_group, argc, argv);