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];
62 if (memcmp(seen->fsid, fsid, BTRFS_FSID_SIZE) == 0)
71 static int add_seen_fsid(u8 *fsid)
74 int slot = hash % SEEN_FSID_HASH_SIZE;
75 struct seen_fsid *seen = seen_fsid_hash[slot];
76 struct seen_fsid *alloc;
82 if (memcmp(seen->fsid, fsid, BTRFS_FSID_SIZE) == 0)
93 alloc = malloc(sizeof(*alloc));
98 memcpy(alloc->fsid, fsid, BTRFS_FSID_SIZE);
103 seen_fsid_hash[slot] = alloc;
108 static void free_seen_fsid(void)
111 struct seen_fsid *seen;
112 struct seen_fsid *next;
114 for (slot = 0; slot < SEEN_FSID_HASH_SIZE; slot++) {
115 seen = seen_fsid_hash[slot];
121 seen_fsid_hash[slot] = NULL;
125 static const char * const filesystem_cmd_group_usage[] = {
126 "btrfs filesystem [<group>] <command> [<args>]",
130 static const char * const cmd_filesystem_df_usage[] = {
131 "btrfs filesystem df [options] <path>",
132 "Show space usage information for a mount point",
133 HELPINFO_UNITS_SHORT_LONG,
137 static int get_df(int fd, struct btrfs_ioctl_space_args **sargs_ret)
141 struct btrfs_ioctl_space_args *sargs;
143 sargs = malloc(sizeof(struct btrfs_ioctl_space_args));
147 sargs->space_slots = 0;
148 sargs->total_spaces = 0;
150 ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
152 error("cannot get space info: %s", strerror(errno));
156 /* This really should never happen */
157 if (!sargs->total_spaces) {
161 count = sargs->total_spaces;
164 sargs = malloc(sizeof(struct btrfs_ioctl_space_args) +
165 (count * sizeof(struct btrfs_ioctl_space_info)));
169 sargs->space_slots = count;
170 sargs->total_spaces = 0;
171 ret = ioctl(fd, BTRFS_IOC_SPACE_INFO, sargs);
173 error("cannot get space info with %llu slots: %s",
174 count, strerror(errno));
182 static void print_df(struct btrfs_ioctl_space_args *sargs, unsigned unit_mode)
185 struct btrfs_ioctl_space_info *sp = sargs->spaces;
187 for (i = 0; i < sargs->total_spaces; i++, sp++) {
188 printf("%s, %s: total=%s, used=%s\n",
189 btrfs_group_type_str(sp->flags),
190 btrfs_group_profile_str(sp->flags),
191 pretty_size_mode(sp->total_bytes, unit_mode),
192 pretty_size_mode(sp->used_bytes, unit_mode));
196 static int cmd_filesystem_df(int argc, char **argv)
198 struct btrfs_ioctl_space_args *sargs = NULL;
202 DIR *dirstream = NULL;
205 unit_mode = get_unit_mode_from_arg(&argc, argv, 1);
207 clean_args_no_options(argc, argv, cmd_filesystem_df_usage);
209 if (check_argc_exact(argc - optind, 1))
210 usage(cmd_filesystem_df_usage);
214 fd = btrfs_open_dir(path, &dirstream, 1);
218 ret = get_df(fd, &sargs);
221 print_df(sargs, unit_mode);
224 error("get_df failed %s", strerror(-ret));
227 close_file_or_dir(fd, dirstream);
231 static int match_search_item_kernel(__u8 *fsid, char *mnt, char *label,
234 char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
235 int search_len = strlen(search);
237 search_len = min(search_len, BTRFS_UUID_UNPARSED_SIZE);
238 uuid_unparse(fsid, uuidbuf);
239 if (!strncmp(uuidbuf, search, search_len))
242 if (*label && strcmp(label, search) == 0)
245 if (strcmp(mnt, search) == 0)
251 static int uuid_search(struct btrfs_fs_devices *fs_devices, const char *search)
253 char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
254 struct list_head *cur;
255 struct btrfs_device *device;
256 int search_len = strlen(search);
258 search_len = min(search_len, BTRFS_UUID_UNPARSED_SIZE);
259 uuid_unparse(fs_devices->fsid, uuidbuf);
260 if (!strncmp(uuidbuf, search, search_len))
263 list_for_each(cur, &fs_devices->devices) {
264 device = list_entry(cur, struct btrfs_device, dev_list);
265 if ((device->label && strcmp(device->label, search) == 0) ||
266 strcmp(device->name, search) == 0)
273 * Sort devices by devid, ascending
275 static int cmp_device_id(void *priv, struct list_head *a,
278 const struct btrfs_device *da = list_entry(a, struct btrfs_device,
280 const struct btrfs_device *db = list_entry(b, struct btrfs_device,
283 return da->devid < db->devid ? -1 :
284 da->devid > db->devid ? 1 : 0;
287 static void splice_device_list(struct list_head *seed_devices,
288 struct list_head *all_devices)
290 struct btrfs_device *in_all, *next_all;
291 struct btrfs_device *in_seed, *next_seed;
293 list_for_each_entry_safe(in_all, next_all, all_devices, dev_list) {
294 list_for_each_entry_safe(in_seed, next_seed, seed_devices,
296 if (in_all->devid == in_seed->devid) {
298 * When do dev replace in a sprout fs
299 * to a dev in its seed fs, the replacing
300 * dev will reside in the sprout fs and
301 * the replaced dev will still exist
303 * So pick the latest one when showing
306 if (in_all->generation
307 < in_seed->generation) {
308 list_del(&in_all->dev_list);
310 } else if (in_all->generation
311 > in_seed->generation) {
312 list_del(&in_seed->dev_list);
320 list_splice(seed_devices, all_devices);
323 static void print_devices(struct btrfs_fs_devices *fs_devices,
324 u64 *devs_found, unsigned unit_mode)
326 struct btrfs_device *device;
327 struct btrfs_fs_devices *cur_fs;
328 struct list_head *all_devices;
330 all_devices = &fs_devices->devices;
331 cur_fs = fs_devices->seed;
332 /* add all devices of seed fs to the fs to be printed */
334 splice_device_list(&cur_fs->devices, all_devices);
335 cur_fs = cur_fs->seed;
338 list_sort(NULL, all_devices, cmp_device_id);
339 list_for_each_entry(device, all_devices, dev_list) {
340 printf("\tdevid %4llu size %s used %s path %s\n",
341 (unsigned long long)device->devid,
342 pretty_size_mode(device->total_bytes, unit_mode),
343 pretty_size_mode(device->bytes_used, unit_mode),
350 static void print_one_uuid(struct btrfs_fs_devices *fs_devices,
353 char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
354 struct btrfs_device *device;
358 if (add_seen_fsid(fs_devices->fsid))
361 uuid_unparse(fs_devices->fsid, uuidbuf);
362 device = list_entry(fs_devices->devices.next, struct btrfs_device,
364 if (device->label && device->label[0])
365 printf("Label: '%s' ", device->label);
367 printf("Label: none ");
369 total = device->total_devs;
370 printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf,
371 (unsigned long long)total,
372 pretty_size_mode(device->super_bytes_used, unit_mode));
374 print_devices(fs_devices, &devs_found, unit_mode);
376 if (devs_found < total) {
377 printf("\t*** Some devices missing\n");
382 /* adds up all the used spaces as reported by the space info ioctl
384 static u64 calc_used_bytes(struct btrfs_ioctl_space_args *si)
388 for (i = 0; i < si->total_spaces; i++)
389 ret += si->spaces[i].used_bytes;
393 static int print_one_fs(struct btrfs_ioctl_fs_info_args *fs_info,
394 struct btrfs_ioctl_dev_info_args *dev_info,
395 struct btrfs_ioctl_space_args *space_info,
396 char *label, unsigned unit_mode)
401 char uuidbuf[BTRFS_UUID_UNPARSED_SIZE];
402 struct btrfs_ioctl_dev_info_args *tmp_dev_info;
405 ret = add_seen_fsid(fs_info->fsid);
411 uuid_unparse(fs_info->fsid, uuidbuf);
413 printf("Label: '%s' ", label);
415 printf("Label: none ");
417 printf(" uuid: %s\n\tTotal devices %llu FS bytes used %s\n", uuidbuf,
418 fs_info->num_devices,
419 pretty_size_mode(calc_used_bytes(space_info),
422 for (i = 0; i < fs_info->num_devices; i++) {
423 char *canonical_path;
425 tmp_dev_info = (struct btrfs_ioctl_dev_info_args *)&dev_info[i];
427 /* Add check for missing devices even mounted */
428 fd = open((char *)tmp_dev_info->path, O_RDONLY);
434 canonical_path = canonicalize_path((char *)tmp_dev_info->path);
435 printf("\tdevid %4llu size %s used %s path %s\n",
437 pretty_size_mode(tmp_dev_info->total_bytes, unit_mode),
438 pretty_size_mode(tmp_dev_info->bytes_used, unit_mode),
441 free(canonical_path);
445 printf("\t*** Some devices missing\n");
450 static int btrfs_scan_kernel(void *search, unsigned unit_mode)
456 struct btrfs_ioctl_fs_info_args fs_info_arg;
457 struct btrfs_ioctl_dev_info_args *dev_info_arg = NULL;
458 struct btrfs_ioctl_space_args *space_info_arg = NULL;
459 char label[BTRFS_LABEL_SIZE];
461 f = setmntent("/proc/self/mounts", "r");
465 memset(label, 0, sizeof(label));
466 while ((mnt = getmntent(f)) != NULL) {
469 if (strcmp(mnt->mnt_type, "btrfs"))
471 ret = get_fs_info(mnt->mnt_dir, &fs_info_arg,
476 /* skip all fs already shown as mounted fs */
477 if (is_seen_fsid(fs_info_arg.fsid))
480 ret = get_label_mounted(mnt->mnt_dir, label);
481 /* provide backward kernel compatibility */
483 ret = get_label_unmounted(
484 (const char *)dev_info_arg->path, label);
489 if (search && !match_search_item_kernel(fs_info_arg.fsid,
490 mnt->mnt_dir, label, search)) {
494 fd = open(mnt->mnt_dir, O_RDONLY);
495 if ((fd != -1) && !get_df(fd, &space_info_arg)) {
496 print_one_fs(&fs_info_arg, dev_info_arg,
497 space_info_arg, label, unit_mode);
498 free(space_info_arg);
499 memset(label, 0, sizeof(label));
512 static int dev_to_fsid(const char *dev, __u8 *fsid)
514 struct btrfs_super_block *disk_super;
515 char buf[BTRFS_SUPER_INFO_SIZE];
519 fd = open(dev, O_RDONLY);
525 disk_super = (struct btrfs_super_block *)buf;
526 ret = btrfs_read_dev_super(fd, disk_super,
527 BTRFS_SUPER_INFO_OFFSET, SBREAD_DEFAULT);
531 memcpy(fsid, disk_super->fsid, BTRFS_FSID_SIZE);
539 static void free_fs_devices(struct btrfs_fs_devices *fs_devices)
541 struct btrfs_fs_devices *cur_seed, *next_seed;
542 struct btrfs_device *device;
544 while (!list_empty(&fs_devices->devices)) {
545 device = list_entry(fs_devices->devices.next,
546 struct btrfs_device, dev_list);
547 list_del(&device->dev_list);
554 /* free seed fs chain */
555 cur_seed = fs_devices->seed;
556 fs_devices->seed = NULL;
558 next_seed = cur_seed->seed;
561 cur_seed = next_seed;
564 list_del(&fs_devices->list);
568 static int copy_device(struct btrfs_device *dst,
569 struct btrfs_device *src)
571 dst->devid = src->devid;
572 memcpy(dst->uuid, src->uuid, BTRFS_UUID_SIZE);
573 if (src->name == NULL)
576 dst->name = strdup(src->name);
580 if (src->label == NULL)
583 dst->label = strdup(src->label);
589 dst->total_devs = src->total_devs;
590 dst->super_bytes_used = src->super_bytes_used;
591 dst->total_bytes = src->total_bytes;
592 dst->bytes_used = src->bytes_used;
593 dst->generation = src->generation;
598 static int copy_fs_devices(struct btrfs_fs_devices *dst,
599 struct btrfs_fs_devices *src)
601 struct btrfs_device *cur_dev, *dev_copy;
604 memcpy(dst->fsid, src->fsid, BTRFS_FSID_SIZE);
605 INIT_LIST_HEAD(&dst->devices);
608 list_for_each_entry(cur_dev, &src->devices, dev_list) {
609 dev_copy = malloc(sizeof(*dev_copy));
615 ret = copy_device(dev_copy, cur_dev);
621 list_add(&dev_copy->dev_list, &dst->devices);
622 dev_copy->fs_devices = dst;
628 static int find_and_copy_seed(struct btrfs_fs_devices *seed,
629 struct btrfs_fs_devices *copy,
630 struct list_head *fs_uuids) {
631 struct btrfs_fs_devices *cur_fs;
633 list_for_each_entry(cur_fs, fs_uuids, list)
634 if (!memcmp(seed->fsid, cur_fs->fsid, BTRFS_FSID_SIZE))
635 return copy_fs_devices(copy, cur_fs);
640 static int has_seed_devices(struct btrfs_fs_devices *fs_devices)
642 struct btrfs_device *device;
643 int dev_cnt_total, dev_cnt = 0;
645 device = list_first_entry(&fs_devices->devices, struct btrfs_device,
648 dev_cnt_total = device->total_devs;
650 list_for_each_entry(device, &fs_devices->devices, dev_list)
653 return dev_cnt_total != dev_cnt;
656 static int search_umounted_fs_uuids(struct list_head *all_uuids,
657 char *search, int *found)
659 struct btrfs_fs_devices *cur_fs, *fs_copy;
660 struct list_head *fs_uuids;
663 fs_uuids = btrfs_scanned_uuids();
666 * The fs_uuids list is global, and open_ctree_* will
667 * modify it, make a private copy here
669 list_for_each_entry(cur_fs, fs_uuids, list) {
670 /* don't bother handle all fs, if search target specified */
672 if (uuid_search(cur_fs, search) == 0)
678 /* skip all fs already shown as mounted fs */
679 if (is_seen_fsid(cur_fs->fsid))
682 fs_copy = calloc(1, sizeof(*fs_copy));
688 ret = copy_fs_devices(fs_copy, cur_fs);
694 list_add(&fs_copy->list, all_uuids);
701 static int map_seed_devices(struct list_head *all_uuids)
703 struct btrfs_fs_devices *cur_fs, *cur_seed;
704 struct btrfs_fs_devices *seed_copy;
705 struct btrfs_fs_devices *opened_fs;
706 struct btrfs_device *device;
707 struct btrfs_fs_info *fs_info;
708 struct list_head *fs_uuids;
711 fs_uuids = btrfs_scanned_uuids();
713 list_for_each_entry(cur_fs, all_uuids, list) {
714 device = list_first_entry(&cur_fs->devices,
715 struct btrfs_device, dev_list);
719 /* skip fs without seeds */
720 if (!has_seed_devices(cur_fs))
724 * open_ctree_* detects seed/sprout mapping
726 fs_info = open_ctree_fs_info(device->name, 0, 0, 0,
732 * copy the seed chain under the opened fs
734 opened_fs = fs_info->fs_devices;
736 while (opened_fs->seed) {
737 seed_copy = malloc(sizeof(*seed_copy));
742 ret = find_and_copy_seed(opened_fs->seed, seed_copy,
749 cur_seed->seed = seed_copy;
751 opened_fs = opened_fs->seed;
752 cur_seed = cur_seed->seed;
755 close_ctree(fs_info->chunk_root);
761 close_ctree(fs_info->chunk_root);
765 static const char * const cmd_filesystem_show_usage[] = {
766 "btrfs filesystem show [options] [<path>|<uuid>|<device>|label]",
767 "Show the structure of a filesystem",
768 "-d|--all-devices show only disks under /dev containing btrfs filesystem",
769 "-m|--mounted show only mounted btrfs",
771 "If no argument is given, structure of all present filesystems is shown.",
775 static int cmd_filesystem_show(int argc, char **argv)
777 LIST_HEAD(all_uuids);
778 struct btrfs_fs_devices *fs_devices;
781 /* default, search both kernel and udev */
786 __u8 fsid[BTRFS_FSID_SIZE];
787 char uuid_buf[BTRFS_UUID_UNPARSED_SIZE];
791 unit_mode = get_unit_mode_from_arg(&argc, argv, 0);
795 static const struct option long_options[] = {
796 { "all-devices", no_argument, NULL, 'd'},
797 { "mounted", no_argument, NULL, 'm'},
801 c = getopt_long(argc, argv, "dm", long_options, NULL);
806 where = BTRFS_SCAN_LBLKID;
809 where = BTRFS_SCAN_MOUNTED;
812 usage(cmd_filesystem_show_usage);
816 if (check_argc_max(argc, optind + 1))
817 usage(cmd_filesystem_show_usage);
820 search = argv[optind];
822 usage(cmd_filesystem_show_usage);
823 type = check_arg_type(search);
826 * For search is a device:
827 * realpath do /dev/mapper/XX => /dev/dm-X
828 * which is required by BTRFS_SCAN_DEV
829 * For search is a mountpoint:
830 * realpath do /mnt/btrfs/ => /mnt/btrfs
831 * which shall be recognized by btrfs_scan_kernel()
833 if (realpath(search, path))
837 * Needs special handling if input arg is block dev And if
838 * input arg is mount-point just print it right away
840 if (type == BTRFS_ARG_BLKDEV && where != BTRFS_SCAN_LBLKID) {
841 ret = get_btrfs_mount(search, mp, sizeof(mp));
843 /* given block dev is mounted */
845 type = BTRFS_ARG_MNTPOINT;
847 ret = dev_to_fsid(search, fsid);
849 error("no btrfs on %s", search);
852 uuid_unparse(fsid, uuid_buf);
854 type = BTRFS_ARG_UUID;
860 if (where == BTRFS_SCAN_LBLKID)
863 /* show mounted btrfs */
864 ret = btrfs_scan_kernel(search, unit_mode);
865 if (search && !ret) {
866 /* since search is found we are done */
870 /* shows mounted only */
871 if (where == BTRFS_SCAN_MOUNTED)
875 ret = btrfs_scan_devices();
878 error("blkid device scan returned %d", ret);
882 ret = search_umounted_fs_uuids(&all_uuids, search, &found);
884 error("searching target device returned error %d", ret);
889 * The seed/sprout mapping are not detected yet,
890 * do mapping build for all umounted fs
892 ret = map_seed_devices(&all_uuids);
894 error("mapping seed devices returned error %d", ret);
898 list_for_each_entry(fs_devices, &all_uuids, list)
899 print_one_uuid(fs_devices, unit_mode);
901 if (search && !found) {
902 error("not a valid btrfs filesystem: %s", search);
905 while (!list_empty(&all_uuids)) {
906 fs_devices = list_entry(all_uuids.next,
907 struct btrfs_fs_devices, list);
908 free_fs_devices(fs_devices);
915 static const char * const cmd_filesystem_sync_usage[] = {
916 "btrfs filesystem sync <path>",
917 "Force a sync on a filesystem",
921 static int cmd_filesystem_sync(int argc, char **argv)
925 DIR *dirstream = NULL;
927 clean_args_no_options(argc, argv, cmd_filesystem_sync_usage);
929 if (check_argc_exact(argc - optind, 1))
930 usage(cmd_filesystem_sync_usage);
934 fd = btrfs_open_dir(path, &dirstream, 1);
938 res = ioctl(fd, BTRFS_IOC_SYNC);
940 close_file_or_dir(fd, dirstream);
942 error("sync ioctl failed on '%s': %s", path, strerror(e));
949 static int parse_compress_type(char *s)
951 if (strcmp(optarg, "zlib") == 0)
952 return BTRFS_COMPRESS_ZLIB;
953 else if (strcmp(optarg, "lzo") == 0)
954 return BTRFS_COMPRESS_LZO;
956 error("unknown compression type %s", s);
961 static const char * const cmd_filesystem_defrag_usage[] = {
962 "btrfs filesystem defragment [options] <file>|<dir> [<file>|<dir>...]",
963 "Defragment a file or a directory",
966 "-r defragment files recursively",
967 "-c[zlib,lzo] compress the file while defragmenting",
968 "-f flush data to disk immediately after defragmenting",
969 "-s start defragment only from byte onward",
970 "-l len defragment only up to len bytes",
971 "-t size target extent size hint (default: 32M)",
975 static struct btrfs_ioctl_defrag_range_args defrag_global_range;
976 static int defrag_global_verbose;
977 static int defrag_global_errors;
978 static int defrag_callback(const char *fpath, const struct stat *sb,
979 int typeflag, struct FTW *ftwbuf)
985 if ((typeflag == FTW_F) && S_ISREG(sb->st_mode)) {
986 if (defrag_global_verbose)
987 printf("%s\n", fpath);
988 fd = open(fpath, O_RDWR);
993 ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE, &defrag_global_range);
995 if (ret && errno == ENOTTY) {
997 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
998 defrag_global_errors++;
1009 error("defrag failed on %s: %s", fpath, strerror(err));
1010 defrag_global_errors++;
1014 static int cmd_filesystem_defrag(int argc, char **argv)
1024 int compress_type = BTRFS_COMPRESS_NONE;
1028 * Kernel has a different default (256K) that is supposed to be safe,
1029 * but it does not defragment very well. The 32M will likely lead to
1030 * better results and is independent of the kernel default. We have to
1031 * use the v2 defrag ioctl.
1033 thresh = 32 * 1024 * 1024;
1035 defrag_global_errors = 0;
1036 defrag_global_verbose = 0;
1037 defrag_global_errors = 0;
1039 int c = getopt(argc, argv, "vrc::fs:l:t:");
1045 compress_type = BTRFS_COMPRESS_ZLIB;
1047 compress_type = parse_compress_type(optarg);
1053 defrag_global_verbose = 1;
1056 start = parse_size(optarg);
1059 len = parse_size(optarg);
1062 thresh = parse_size(optarg);
1063 if (thresh > (u32)-1) {
1065 "target extent size %llu too big, trimmed to %u",
1074 usage(cmd_filesystem_defrag_usage);
1078 if (check_argc_min(argc - optind, 1))
1079 usage(cmd_filesystem_defrag_usage);
1081 memset(&defrag_global_range, 0, sizeof(defrag_global_range));
1082 defrag_global_range.start = start;
1083 defrag_global_range.len = len;
1084 defrag_global_range.extent_thresh = (u32)thresh;
1085 if (compress_type) {
1086 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_COMPRESS;
1087 defrag_global_range.compress_type = compress_type;
1090 defrag_global_range.flags |= BTRFS_DEFRAG_RANGE_START_IO;
1093 * Look for directory arguments and warn if the recursive mode is not
1094 * requested, as this is not implemented as recursive defragmentation
1095 * in kernel. The stat errors are silent here as we check them below.
1100 for (i = optind; i < argc; i++) {
1103 if (stat(argv[i], &st))
1106 if (S_ISDIR(st.st_mode)) {
1108 "directory specified but recursive mode not requested: %s",
1115 "a directory passed to the defrag ioctl will not process the files\n"
1116 "recursively but will defragment the subvolume tree and the extent tree.\n"
1117 "If this is not intended, please use option -r .");
1121 for (i = optind; i < argc; i++) {
1126 fd = open_file_or_dir(argv[i], &dirstream);
1128 error("cannot open %s: %s", argv[i],
1130 defrag_global_errors++;
1131 close_file_or_dir(fd, dirstream);
1134 if (fstat(fd, &st)) {
1135 error("failed to stat %s: %s",
1136 argv[i], strerror(errno));
1137 defrag_global_errors++;
1138 close_file_or_dir(fd, dirstream);
1141 if (!(S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))) {
1142 error("%s is not a directory or a regular file",
1144 defrag_global_errors++;
1145 close_file_or_dir(fd, dirstream);
1148 if (recursive && S_ISDIR(st.st_mode)) {
1149 ret = nftw(argv[i], defrag_callback, 10,
1150 FTW_MOUNT | FTW_PHYS);
1153 /* errors are handled in the callback */
1156 if (defrag_global_verbose)
1157 printf("%s\n", argv[i]);
1158 ret = ioctl(fd, BTRFS_IOC_DEFRAG_RANGE,
1159 &defrag_global_range);
1162 close_file_or_dir(fd, dirstream);
1163 if (ret && defrag_err == ENOTTY) {
1165 "defrag range ioctl not supported in this kernel version, 2.6.33 and newer is required");
1166 defrag_global_errors++;
1170 error("defrag failed on %s: %s", argv[i],
1171 strerror(defrag_err));
1172 defrag_global_errors++;
1175 if (defrag_global_errors)
1176 fprintf(stderr, "total %d failures\n", defrag_global_errors);
1178 return !!defrag_global_errors;
1181 static const char * const cmd_filesystem_resize_usage[] = {
1182 "btrfs filesystem resize [devid:][+/-]<newsize>[kKmMgGtTpPeE]|[devid:]max <path>",
1183 "Resize a filesystem",
1184 "If 'max' is passed, the filesystem will occupy all available space",
1185 "on the device 'devid'.",
1186 "[kK] means KiB, which denotes 1KiB = 1024B, 1MiB = 1024KiB, etc.",
1190 static int cmd_filesystem_resize(int argc, char **argv)
1192 struct btrfs_ioctl_vol_args args;
1193 int fd, res, len, e;
1194 char *amount, *path;
1195 DIR *dirstream = NULL;
1198 clean_args_no_options_relaxed(argc, argv, cmd_filesystem_resize_usage);
1200 if (check_argc_exact(argc - optind, 2))
1201 usage(cmd_filesystem_resize_usage);
1203 amount = argv[optind];
1204 path = argv[optind + 1];
1206 len = strlen(amount);
1207 if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
1208 error("resize value too long (%s)", amount);
1212 res = stat(path, &st);
1214 error("resize: cannot stat %s: %s", path, strerror(errno));
1217 if (!S_ISDIR(st.st_mode)) {
1218 error("resize works on mounted filesystems and accepts only\n"
1219 "directories as argument. Passing file containing a btrfs image\n"
1220 "would resize the underlying filesystem instead of the image.\n");
1224 fd = btrfs_open_dir(path, &dirstream, 1);
1228 printf("Resize '%s' of '%s'\n", path, amount);
1229 memset(&args, 0, sizeof(args));
1230 strncpy_null(args.name, amount);
1231 res = ioctl(fd, BTRFS_IOC_RESIZE, &args);
1233 close_file_or_dir(fd, dirstream);
1237 error("unable to resize '%s': no enough free space",
1241 error("unable to resize '%s': %s", path, strerror(e));
1245 } else if (res > 0) {
1246 const char *err_str = btrfs_err_str(res);
1249 error("resizing of '%s' failed: %s", path, err_str);
1251 error("resizing of '%s' failed: unknown error %d",
1259 static const char * const cmd_filesystem_label_usage[] = {
1260 "btrfs filesystem label [<device>|<mount_point>] [<newlabel>]",
1261 "Get or change the label of a filesystem",
1262 "With one argument, get the label of filesystem on <device>.",
1263 "If <newlabel> is passed, set the filesystem label to <newlabel>.",
1267 static int cmd_filesystem_label(int argc, char **argv)
1269 clean_args_no_options(argc, argv, cmd_filesystem_label_usage);
1271 if (check_argc_min(argc - optind, 1) ||
1272 check_argc_max(argc - optind, 2))
1273 usage(cmd_filesystem_label_usage);
1275 if (argc - optind > 1) {
1276 return set_label(argv[optind], argv[optind + 1]);
1278 char label[BTRFS_LABEL_SIZE];
1281 ret = get_label(argv[optind], label);
1283 fprintf(stdout, "%s\n", label);
1289 static const char filesystem_cmd_group_info[] =
1290 "overall filesystem tasks and information";
1292 const struct cmd_group filesystem_cmd_group = {
1293 filesystem_cmd_group_usage, filesystem_cmd_group_info, {
1294 { "df", cmd_filesystem_df, cmd_filesystem_df_usage, NULL, 0 },
1295 { "du", cmd_filesystem_du, cmd_filesystem_du_usage, NULL, 0 },
1296 { "show", cmd_filesystem_show, cmd_filesystem_show_usage, NULL,
1298 { "sync", cmd_filesystem_sync, cmd_filesystem_sync_usage, NULL,
1300 { "defragment", cmd_filesystem_defrag,
1301 cmd_filesystem_defrag_usage, NULL, 0 },
1302 { "balance", cmd_balance, NULL, &balance_cmd_group,
1304 { "resize", cmd_filesystem_resize, cmd_filesystem_resize_usage,
1306 { "label", cmd_filesystem_label, cmd_filesystem_label_usage,
1308 { "usage", cmd_filesystem_usage,
1309 cmd_filesystem_usage_usage, NULL, 0 },
1315 int cmd_filesystem(int argc, char **argv)
1317 return handle_command_group(&filesystem_cmd_group, argc, argv);