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>
28 #include <uuid/uuid.h>
29 #include <linux/magic.h>
31 #include "kerncompat.h"
38 #include "btrfs-list.h"
42 static int is_subvolume_cleaned(int fd, u64 subvolid)
45 struct btrfs_ioctl_search_args args;
46 struct btrfs_ioctl_search_key *sk = &args.key;
48 sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
49 sk->min_objectid = subvolid;
50 sk->max_objectid = subvolid;
51 sk->min_type = BTRFS_ROOT_ITEM_KEY;
52 sk->max_type = BTRFS_ROOT_ITEM_KEY;
54 sk->max_offset = (u64)-1;
56 sk->max_transid = (u64)-1;
59 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
63 if (sk->nr_items == 0)
69 static int wait_for_subvolume_cleaning(int fd, int count, u64 *ids,
78 for (i = 0; i < count; i++) {
81 ret = is_subvolume_cleaned(fd, ids[i]);
84 "cannot read status of dead subvolume %llu: %s",
85 (unsigned long long)ids[i], strerror(-ret));
89 printf("Subvolume id %llu is gone\n", ids[i]);
97 sleep(sleep_interval);
103 static const char * const subvolume_cmd_group_usage[] = {
104 "btrfs subvolume <command> <args>",
108 static const char * const cmd_subvol_create_usage[] = {
109 "btrfs subvolume create [-i <qgroupid>] [<dest>/]<name>",
110 "Create a subvolume",
111 "Create a subvolume <name> in <dest>. If <dest> is not given",
112 "subvolume <name> will be created in the current directory.",
114 "-i <qgroupid> add the newly created subvolume to a qgroup. This",
115 " option can be given multiple times.",
119 static int cmd_subvol_create(int argc, char **argv)
121 int retval, res, len;
123 char *dupname = NULL;
128 struct btrfs_qgroup_inherit *inherit = NULL;
129 DIR *dirstream = NULL;
132 int c = getopt(argc, argv, "c:i:");
138 res = qgroup_inherit_add_copy(&inherit, optarg, 0);
145 res = qgroup_inherit_add_group(&inherit, optarg);
152 usage(cmd_subvol_create_usage);
156 if (check_argc_exact(argc - optind, 1))
157 usage(cmd_subvol_create_usage);
161 retval = 1; /* failure */
162 res = test_isdir(dst);
163 if (res < 0 && res != -ENOENT) {
164 error("cannot access %s: %s", dst, strerror(-res));
168 error("target path already exists: %s", dst);
172 dupname = strdup(dst);
173 newname = basename(dupname);
174 dupdir = strdup(dst);
175 dstdir = dirname(dupdir);
177 if (!test_issubvolname(newname)) {
178 error("invalid subvolume name: %s", newname);
182 len = strlen(newname);
183 if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
184 error("subvolume name too long: %s", newname);
188 fddst = btrfs_open_dir(dstdir, &dirstream, 1);
192 printf("Create subvolume '%s/%s'\n", dstdir, newname);
194 struct btrfs_ioctl_vol_args_v2 args;
196 memset(&args, 0, sizeof(args));
197 strncpy_null(args.name, newname);
198 args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
199 args.size = qgroup_inherit_size(inherit);
200 args.qgroup_inherit = inherit;
202 res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE_V2, &args);
204 struct btrfs_ioctl_vol_args args;
206 memset(&args, 0, sizeof(args));
207 strncpy_null(args.name, newname);
209 res = ioctl(fddst, BTRFS_IOC_SUBVOL_CREATE, &args);
213 error("cannot create subvolume: %s", strerror(errno));
217 retval = 0; /* success */
219 close_file_or_dir(fddst, dirstream);
227 static int wait_for_commit(int fd)
231 ret = ioctl(fd, BTRFS_IOC_START_SYNC, NULL);
234 return ioctl(fd, BTRFS_IOC_WAIT_SYNC, NULL);
237 static const char * const cmd_subvol_delete_usage[] = {
238 "btrfs subvolume delete [options] <subvolume> [<subvolume>...]",
239 "Delete subvolume(s)",
240 "Delete subvolumes from the filesystem. The corresponding directory",
241 "is removed instantly but the data blocks are removed later.",
242 "The deletion does not involve full commit by default due to",
243 "performance reasons (as a consequence, the subvolume may appear again",
244 "after a crash). Use one of the --commit options to wait until the",
245 "operation is safely stored on the media.",
247 "-c|--commit-after wait for transaction commit at the end of the operation",
248 "-C|--commit-each wait for transaction commit after deleting each subvolume",
249 "-v|--verbose verbose output of operations",
253 static int cmd_subvol_delete(int argc, char **argv)
258 struct btrfs_ioctl_vol_args args;
259 char *dname, *vname, *cpath;
260 char *dupdname = NULL;
261 char *dupvname = NULL;
263 DIR *dirstream = NULL;
269 static const struct option long_options[] = {
270 {"commit-after", no_argument, NULL, 'c'}, /* commit mode 1 */
271 {"commit-each", no_argument, NULL, 'C'}, /* commit mode 2 */
272 {"verbose", no_argument, NULL, 'v'},
276 c = getopt_long(argc, argv, "cCv", long_options, NULL);
291 usage(cmd_subvol_delete_usage);
295 if (check_argc_min(argc - optind, 1))
296 usage(cmd_subvol_delete_usage);
299 printf("Transaction commit: %s\n",
300 !commit_mode ? "none (default)" :
301 commit_mode == 1 ? "at the end" : "after each");
309 res = test_issubvolume(path);
311 error("cannot access subvolume %s: %s", path, strerror(-res));
316 error("not a subvolume: %s", path);
321 cpath = realpath(path, NULL);
324 error("cannot find real path for '%s': %s",
325 path, strerror(errno));
328 dupdname = strdup(cpath);
329 dname = dirname(dupdname);
330 dupvname = strdup(cpath);
331 vname = basename(dupvname);
334 fd = btrfs_open_dir(dname, &dirstream, 1);
340 printf("Delete subvolume (%s): '%s/%s'\n",
341 commit_mode == 2 || (commit_mode == 1 && cnt + 1 == argc)
342 ? "commit" : "no-commit", dname, vname);
343 memset(&args, 0, sizeof(args));
344 strncpy_null(args.name, vname);
345 res = ioctl(fd, BTRFS_IOC_SNAP_DESTROY, &args);
347 error("cannot delete '%s/%s': %s", dname, vname,
353 if (commit_mode == 1) {
354 res = wait_for_commit(fd);
356 error("unable to wait for commit after '%s': %s",
357 path, strerror(errno));
369 close_file_or_dir(fd, dirstream);
370 /* avoid double free */
376 if (commit_mode == 2 && fd != -1) {
377 res = wait_for_commit(fd);
379 error("unable to do final sync after deletion: %s",
384 close_file_or_dir(fd, dirstream);
391 * - uppercase for filters and sort options
392 * - lowercase for enabling specific items in the output
394 static const char * const cmd_subvol_list_usage[] = {
395 "btrfs subvolume list [options] [-G [+|-]value] [-C [+|-]value] "
396 "[--sort=gen,ogen,rootid,path] <path>",
397 "List subvolumes (and snapshots)",
399 "-p print parent ID",
400 "-a print all the subvolumes in the filesystem and",
401 " distinguish absolute and relative path with respect",
402 " to the given <path>",
403 "-c print the ogeneration of the subvolume",
404 "-g print the generation of the subvolume",
405 "-o print only subvolumes below specified path",
406 "-u print the uuid of subvolumes (and snapshots)",
407 "-q print the parent uuid of the snapshots",
408 "-R print the uuid of the received snapshots",
409 "-t print the result as a table",
410 "-s list snapshots only in the filesystem",
411 "-r list readonly subvolumes (including snapshots)",
412 "-d list deleted subvolumes that are not yet cleaned",
414 " filter the subvolumes by generation",
415 " (+value: >= value; -value: <= value; value: = value)",
417 " filter the subvolumes by ogeneration",
418 " (+value: >= value; -value: <= value; value: = value)",
419 "--sort=gen,ogen,rootid,path",
420 " list the subvolume in order of gen, ogen, rootid or path",
421 " you also can add '+' or '-' in front of each items.",
422 " (+:ascending, -:descending, ascending default)",
426 static int cmd_subvol_list(int argc, char **argv)
428 struct btrfs_list_filter_set *filter_set;
429 struct btrfs_list_comparer_set *comparer_set;
433 int ret = -1, uerr = 0;
436 int is_only_in_path = 0;
437 DIR *dirstream = NULL;
438 enum btrfs_list_layout layout = BTRFS_LIST_LAYOUT_DEFAULT;
440 filter_set = btrfs_list_alloc_filter_set();
441 comparer_set = btrfs_list_alloc_comparer_set();
445 static const struct option long_options[] = {
446 {"sort", required_argument, NULL, 'S'},
450 c = getopt_long(argc, argv,
451 "acdgopqsurRG:C:t", long_options, NULL);
457 btrfs_list_setup_print_column(BTRFS_LIST_PARENT);
463 btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
466 btrfs_list_setup_filter(&filter_set,
467 BTRFS_LIST_FILTER_DELETED,
471 btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
477 layout = BTRFS_LIST_LAYOUT_TABLE;
480 btrfs_list_setup_filter(&filter_set,
481 BTRFS_LIST_FILTER_SNAPSHOT_ONLY,
483 btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
484 btrfs_list_setup_print_column(BTRFS_LIST_OTIME);
487 btrfs_list_setup_print_column(BTRFS_LIST_UUID);
490 btrfs_list_setup_print_column(BTRFS_LIST_PUUID);
493 btrfs_list_setup_print_column(BTRFS_LIST_RUUID);
496 flags |= BTRFS_ROOT_SUBVOL_RDONLY;
499 btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
500 ret = btrfs_list_parse_filter_string(optarg,
502 BTRFS_LIST_FILTER_GEN);
510 btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
511 ret = btrfs_list_parse_filter_string(optarg,
513 BTRFS_LIST_FILTER_CGEN);
520 ret = btrfs_list_parse_sort_string(optarg,
534 if (check_argc_exact(argc - optind, 1)) {
539 subvol = argv[optind];
540 fd = btrfs_open_dir(subvol, &dirstream, 1);
543 error("can't access '%s'", subvol);
548 btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_FLAGS,
551 ret = btrfs_list_get_path_rootid(fd, &top_id);
556 btrfs_list_setup_filter(&filter_set,
557 BTRFS_LIST_FILTER_FULL_PATH,
559 else if (is_only_in_path)
560 btrfs_list_setup_filter(&filter_set,
561 BTRFS_LIST_FILTER_TOPID_EQUAL,
564 /* by default we shall print the following columns*/
565 btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
566 btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
567 btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
568 btrfs_list_setup_print_column(BTRFS_LIST_PATH);
570 ret = btrfs_list_subvols_print(fd, filter_set, comparer_set,
571 layout, !is_list_all && !is_only_in_path, NULL);
574 close_file_or_dir(fd, dirstream);
580 usage(cmd_subvol_list_usage);
584 static const char * const cmd_subvol_snapshot_usage[] = {
585 "btrfs subvolume snapshot [-r] [-i <qgroupid>] <source> <dest>|[<dest>/]<name>",
586 "Create a snapshot of the subvolume",
587 "Create a writable/readonly snapshot of the subvolume <source> with",
588 "the name <name> in the <dest> directory. If only <dest> is given,",
589 "the subvolume will be named the basename of <source>.",
591 "-r create a readonly snapshot",
592 "-i <qgroupid> add the newly created snapshot to a qgroup. This",
593 " option can be given multiple times.",
597 static int cmd_subvol_snapshot(int argc, char **argv)
601 int fd = -1, fddst = -1;
602 int len, readonly = 0;
603 char *dupname = NULL;
607 struct btrfs_ioctl_vol_args_v2 args;
608 struct btrfs_qgroup_inherit *inherit = NULL;
609 DIR *dirstream1 = NULL, *dirstream2 = NULL;
611 memset(&args, 0, sizeof(args));
613 int c = getopt(argc, argv, "c:i:r");
619 res = qgroup_inherit_add_copy(&inherit, optarg, 0);
626 res = qgroup_inherit_add_group(&inherit, optarg);
636 res = qgroup_inherit_add_copy(&inherit, optarg, 1);
643 usage(cmd_subvol_snapshot_usage);
647 if (check_argc_exact(argc - optind, 2))
648 usage(cmd_subvol_snapshot_usage);
650 subvol = argv[optind];
651 dst = argv[optind + 1];
653 retval = 1; /* failure */
654 res = test_issubvolume(subvol);
656 error("cannot access subvolume %s: %s", subvol, strerror(-res));
660 error("not a subvolume: %s", subvol);
664 res = test_isdir(dst);
665 if (res < 0 && res != -ENOENT) {
666 error("cannot access %s: %s", dst, strerror(-res));
670 error("'%s' exists and it is not a directory", dst);
675 dupname = strdup(subvol);
676 newname = basename(dupname);
679 dupname = strdup(dst);
680 newname = basename(dupname);
681 dupdir = strdup(dst);
682 dstdir = dirname(dupdir);
685 if (!test_issubvolname(newname)) {
686 error("invalid snapshot name '%s'", newname);
690 len = strlen(newname);
691 if (len == 0 || len >= BTRFS_VOL_NAME_MAX) {
692 error("snapshot name too long '%s'", newname);
696 fddst = btrfs_open_dir(dstdir, &dirstream1, 1);
700 fd = btrfs_open_dir(subvol, &dirstream2, 1);
705 args.flags |= BTRFS_SUBVOL_RDONLY;
706 printf("Create a readonly snapshot of '%s' in '%s/%s'\n",
707 subvol, dstdir, newname);
709 printf("Create a snapshot of '%s' in '%s/%s'\n",
710 subvol, dstdir, newname);
715 args.flags |= BTRFS_SUBVOL_QGROUP_INHERIT;
716 args.size = qgroup_inherit_size(inherit);
717 args.qgroup_inherit = inherit;
719 strncpy_null(args.name, newname);
721 res = ioctl(fddst, BTRFS_IOC_SNAP_CREATE_V2, &args);
724 error("cannot snapshot '%s': %s", subvol, strerror(errno));
728 retval = 0; /* success */
731 close_file_or_dir(fddst, dirstream1);
732 close_file_or_dir(fd, dirstream2);
740 static const char * const cmd_subvol_get_default_usage[] = {
741 "btrfs subvolume get-default <path>",
742 "Get the default subvolume of a filesystem",
746 static int cmd_subvol_get_default(int argc, char **argv)
751 struct btrfs_list_filter_set *filter_set;
753 DIR *dirstream = NULL;
755 clean_args_no_options(argc, argv, cmd_subvol_get_default_usage);
757 if (check_argc_exact(argc - optind, 1))
758 usage(cmd_subvol_get_default_usage);
761 fd = btrfs_open_dir(subvol, &dirstream, 1);
765 ret = btrfs_list_get_default_subvolume(fd, &default_id);
767 error("failed to look up default subvolume: %s",
773 if (default_id == 0) {
774 error("'default' dir item not found");
778 /* no need to resolve roots if FS_TREE is default */
779 if (default_id == BTRFS_FS_TREE_OBJECTID) {
780 printf("ID 5 (FS_TREE)\n");
785 filter_set = btrfs_list_alloc_filter_set();
786 btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_ROOTID,
789 /* by default we shall print the following columns*/
790 btrfs_list_setup_print_column(BTRFS_LIST_OBJECTID);
791 btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
792 btrfs_list_setup_print_column(BTRFS_LIST_TOP_LEVEL);
793 btrfs_list_setup_print_column(BTRFS_LIST_PATH);
795 ret = btrfs_list_subvols_print(fd, filter_set, NULL,
796 BTRFS_LIST_LAYOUT_DEFAULT, 1, NULL);
801 close_file_or_dir(fd, dirstream);
805 static const char * const cmd_subvol_set_default_usage[] = {
806 "btrfs subvolume set-default <subvolid> <path>",
807 "Set the default subvolume of a filesystem",
811 static int cmd_subvol_set_default(int argc, char **argv)
817 DIR *dirstream = NULL;
819 clean_args_no_options(argc, argv, cmd_subvol_set_default_usage);
821 if (check_argc_exact(argc - optind, 2))
822 usage(cmd_subvol_set_default_usage);
824 subvolid = argv[optind];
825 path = argv[optind + 1];
827 objectid = arg_strtou64(subvolid);
829 fd = btrfs_open_dir(path, &dirstream, 1);
833 ret = ioctl(fd, BTRFS_IOC_DEFAULT_SUBVOL, &objectid);
835 close_file_or_dir(fd, dirstream);
837 error("unable to set a new default subvolume: %s",
844 static const char * const cmd_subvol_find_new_usage[] = {
845 "btrfs subvolume find-new <path> <lastgen>",
846 "List the recently modified files in a filesystem",
850 static int cmd_subvol_find_new(int argc, char **argv)
856 DIR *dirstream = NULL;
858 clean_args_no_options(argc, argv, cmd_subvol_find_new_usage);
860 if (check_argc_exact(argc - optind, 2))
861 usage(cmd_subvol_find_new_usage);
863 subvol = argv[optind];
864 last_gen = arg_strtou64(argv[optind + 1]);
866 ret = test_issubvolume(subvol);
868 error("cannot access subvolume %s: %s", subvol, strerror(-ret));
872 error("not a subvolume: %s", subvol);
876 fd = btrfs_open_dir(subvol, &dirstream, 1);
880 ret = ioctl(fd, BTRFS_IOC_SYNC);
882 error("sync ioctl failed on '%s': %s",
883 subvol, strerror(errno));
884 close_file_or_dir(fd, dirstream);
888 ret = btrfs_list_find_updated_files(fd, 0, last_gen);
889 close_file_or_dir(fd, dirstream);
893 static const char * const cmd_subvol_show_usage[] = {
894 "btrfs subvolume show <subvol-path>",
895 "Show more information of the subvolume",
899 static int cmd_subvol_show(int argc, char **argv)
901 struct root_info get_ri;
902 struct btrfs_list_filter_set *filter_set = NULL;
904 char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
905 char *fullpath = NULL;
906 char raw_prefix[] = "\t\t\t\t";
909 DIR *dirstream1 = NULL;
911 clean_args_no_options(argc, argv, cmd_subvol_show_usage);
913 if (check_argc_exact(argc - optind, 1))
914 usage(cmd_subvol_show_usage);
916 memset(&get_ri, 0, sizeof(get_ri));
917 fullpath = realpath(argv[optind], NULL);
919 error("cannot find real path for '%s': %s",
920 argv[optind], strerror(errno));
924 ret = get_subvol_info(fullpath, &get_ri);
927 error("Failed to get subvol info %s: %s",
928 fullpath, strerror(-ret));
930 error("Failed to get subvol info %s: %d",
937 printf("%s\n", fullpath);
938 printf("\tName: \t\t\t%s\n", get_ri.name);
940 if (uuid_is_null(get_ri.uuid))
941 strcpy(uuidparse, "-");
943 uuid_unparse(get_ri.uuid, uuidparse);
944 printf("\tUUID: \t\t\t%s\n", uuidparse);
946 if (uuid_is_null(get_ri.puuid))
947 strcpy(uuidparse, "-");
949 uuid_unparse(get_ri.puuid, uuidparse);
950 printf("\tParent UUID: \t\t%s\n", uuidparse);
952 if (uuid_is_null(get_ri.ruuid))
953 strcpy(uuidparse, "-");
955 uuid_unparse(get_ri.ruuid, uuidparse);
956 printf("\tReceived UUID: \t\t%s\n", uuidparse);
961 localtime_r(&get_ri.otime, &tm);
962 strftime(tstr, 256, "%Y-%m-%d %X %z", &tm);
965 printf("\tCreation time: \t\t%s\n", tstr);
967 printf("\tSubvolume ID: \t\t%llu\n", get_ri.root_id);
968 printf("\tGeneration: \t\t%llu\n", get_ri.gen);
969 printf("\tGen at creation: \t%llu\n", get_ri.ogen);
970 printf("\tParent ID: \t\t%llu\n", get_ri.ref_tree);
971 printf("\tTop level ID: \t\t%llu\n", get_ri.top_id);
973 if (get_ri.flags & BTRFS_ROOT_SUBVOL_RDONLY)
974 printf("\tFlags: \t\t\treadonly\n");
976 printf("\tFlags: \t\t\t-\n");
978 /* print the snapshots of the given subvol if any*/
979 printf("\tSnapshot(s):\n");
980 filter_set = btrfs_list_alloc_filter_set();
981 btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_BY_PARENT,
982 (u64)(unsigned long)get_ri.uuid);
983 btrfs_list_setup_print_column(BTRFS_LIST_PATH);
985 fd = open_file_or_dir(fullpath, &dirstream1);
987 fprintf(stderr, "ERROR: can't access '%s'\n", fullpath);
990 btrfs_list_subvols_print(fd, filter_set, NULL, BTRFS_LIST_LAYOUT_RAW,
997 free(get_ri.full_path);
1000 close_file_or_dir(fd, dirstream1);
1005 static const char * const cmd_subvol_sync_usage[] = {
1006 "btrfs subvolume sync <path> [<subvol-id>...]",
1007 "Wait until given subvolume(s) are completely removed from the filesystem.",
1008 "Wait until given subvolume(s) are completely removed from the filesystem",
1010 "If no subvolume id is given, wait until all current deletion requests",
1011 "are completed, but do not wait for subvolumes deleted meanwhile.",
1012 "The status of subvolume ids is checked periodically.",
1014 "-s <N> sleep N seconds between checks (default: 1)",
1020 * If we're looking for any dead subvolume, take a shortcut and look
1021 * for any ORPHAN_ITEMs in the tree root
1023 static int fs_has_dead_subvolumes(int fd)
1026 struct btrfs_ioctl_search_args args;
1027 struct btrfs_ioctl_search_key *sk = &args.key;
1028 struct btrfs_ioctl_search_header sh;
1029 u64 min_subvolid = 0;
1032 sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1033 sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1034 sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1035 sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1036 sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1037 sk->min_offset = min_subvolid;
1038 sk->max_offset = (u64)-1;
1039 sk->min_transid = 0;
1040 sk->max_transid = (u64)-1;
1043 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1050 memcpy(&sh, args.buf, sizeof(sh));
1051 min_subvolid = sh.offset;
1054 * Verify that the root item is really there and we haven't hit
1057 sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1058 sk->min_objectid = min_subvolid;
1059 sk->max_objectid = min_subvolid;
1060 sk->min_type = BTRFS_ROOT_ITEM_KEY;
1061 sk->max_type = BTRFS_ROOT_ITEM_KEY;
1063 sk->max_offset = (u64)-1;
1064 sk->min_transid = 0;
1065 sk->max_transid = (u64)-1;
1068 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1073 * Stale orphan, try the next one
1075 if (!sk->nr_items) {
1084 #define SUBVOL_ID_BATCH 1024
1087 * Enumerate all dead subvolumes that exist in the filesystem.
1088 * Fill @ids and reallocate to bigger size if needed.
1090 static int enumerate_dead_subvols(int fd, u64 **ids)
1093 struct btrfs_ioctl_search_args args;
1094 struct btrfs_ioctl_search_key *sk = &args.key;
1098 memset(&args, 0, sizeof(args));
1100 sk->tree_id = BTRFS_ROOT_TREE_OBJECTID;
1101 sk->min_objectid = BTRFS_ORPHAN_OBJECTID;
1102 sk->max_objectid = BTRFS_ORPHAN_OBJECTID;
1103 sk->min_type = BTRFS_ORPHAN_ITEM_KEY;
1104 sk->max_type = BTRFS_ORPHAN_ITEM_KEY;
1106 sk->max_offset = (u64)-1;
1107 sk->min_transid = 0;
1108 sk->max_transid = (u64)-1;
1109 sk->nr_items = 4096;
1113 struct btrfs_ioctl_search_header *sh;
1117 ret = ioctl(fd, BTRFS_IOC_TREE_SEARCH, &args);
1125 for (i = 0; i < sk->nr_items; i++) {
1126 sh = (struct btrfs_ioctl_search_header*)(args.buf + off);
1129 if (btrfs_search_header_type(sh)
1130 == BTRFS_ORPHAN_ITEM_KEY) {
1134 count += SUBVOL_ID_BATCH;
1135 newids = (u64*)realloc(*ids,
1136 count * sizeof(u64));
1141 (*ids)[idx] = btrfs_search_header_offset(sh);
1144 off += btrfs_search_header_len(sh);
1146 sk->min_objectid = btrfs_search_header_objectid(sh);
1147 sk->min_type = btrfs_search_header_type(sh);
1148 sk->min_offset = btrfs_search_header_offset(sh);
1150 if (sk->min_offset < (u64)-1)
1154 if (sk->min_type != BTRFS_ORPHAN_ITEM_KEY)
1156 if (sk->min_objectid != BTRFS_ORPHAN_OBJECTID)
1163 static int cmd_subvol_sync(int argc, char **argv)
1168 DIR *dirstream = NULL;
1171 int sleep_interval = 1;
1174 int c = getopt(argc, argv, "s:");
1181 sleep_interval = atoi(optarg);
1182 if (sleep_interval < 1) {
1183 error("invalid sleep interval %s", optarg);
1189 usage(cmd_subvol_sync_usage);
1193 if (check_argc_min(argc - optind, 1))
1194 usage(cmd_subvol_sync_usage);
1196 fd = btrfs_open_dir(argv[optind], &dirstream, 1);
1203 id_count = argc - optind;
1205 id_count = enumerate_dead_subvols(fd, &ids);
1207 error("can't enumerate dead subvolumes: %s",
1208 strerror(-id_count));
1212 if (id_count == 0) {
1217 ids = (u64*)malloc(id_count * sizeof(u64));
1219 error("not enough memory");
1224 for (i = 0; i < id_count; i++) {
1228 arg = argv[optind + i];
1230 id = strtoull(arg, NULL, 10);
1232 error("unrecognized subvolume id %s", arg);
1236 if (id < BTRFS_FIRST_FREE_OBJECTID
1237 || id > BTRFS_LAST_FREE_OBJECTID) {
1238 error("subvolume id %s out of range", arg);
1246 ret = wait_for_subvolume_cleaning(fd, id_count, ids, sleep_interval);
1250 close_file_or_dir(fd, dirstream);
1255 static const char subvolume_cmd_group_info[] =
1256 "manage subvolumes: create, delete, list, etc";
1258 const struct cmd_group subvolume_cmd_group = {
1259 subvolume_cmd_group_usage, subvolume_cmd_group_info, {
1260 { "create", cmd_subvol_create, cmd_subvol_create_usage, NULL, 0 },
1261 { "delete", cmd_subvol_delete, cmd_subvol_delete_usage, NULL, 0 },
1262 { "list", cmd_subvol_list, cmd_subvol_list_usage, NULL, 0 },
1263 { "snapshot", cmd_subvol_snapshot, cmd_subvol_snapshot_usage,
1265 { "get-default", cmd_subvol_get_default,
1266 cmd_subvol_get_default_usage, NULL, 0 },
1267 { "set-default", cmd_subvol_set_default,
1268 cmd_subvol_set_default_usage, NULL, 0 },
1269 { "find-new", cmd_subvol_find_new, cmd_subvol_find_new_usage,
1271 { "show", cmd_subvol_show, cmd_subvol_show_usage, NULL, 0 },
1272 { "sync", cmd_subvol_sync, cmd_subvol_sync_usage, NULL, 0 },
1277 int cmd_subvolume(int argc, char **argv)
1279 return handle_command_group(&subvolume_cmd_group, argc, argv);