diff --git a/btrfs-list.c b/btrfs-list.c index d605871c..f079d998 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -584,7 +584,8 @@ void __free_all_subvolumn(struct root_lookup *root_tree) * This can't be called until all the root_info->path fields are filled * in by lookup_ino_path */ -static int resolve_root(struct root_lookup *rl, struct root_info *ri) +static int resolve_root(struct root_lookup *rl, struct root_info *ri, + u64 top_id) { char *full_path = NULL; int len = 0; @@ -621,6 +622,11 @@ static int resolve_root(struct root_lookup *rl, struct root_info *ri) next = found->ref_tree; + if (next == top_id) { + ri->top_id = top_id; + break; + } + /* if the ref_tree refers to ourselves, we're at the top */ if (next == found->root_id) { ri->top_id = next; @@ -1157,6 +1163,11 @@ static int filter_cgen_equal(struct root_info *ri, u64 data) return ri->ogen == data; } +static int filter_topid_equal(struct root_info *ri, u64 data) +{ + return ri->top_id == data; +} + static btrfs_list_filter_func all_filter_funcs[] = { [BTRFS_LIST_FILTER_ROOTID] = filter_by_rootid, [BTRFS_LIST_FILTER_SNAPSHOT_ONLY] = filter_snapshot, @@ -1167,6 +1178,7 @@ static btrfs_list_filter_func all_filter_funcs[] = { [BTRFS_LIST_FILTER_CGEN_MORE] = filter_cgen_more, [BTRFS_LIST_FILTER_CGEN_LESS] = filter_cgen_less, [BTRFS_LIST_FILTER_CGEN_EQUAL] = filter_cgen_equal, + [BTRFS_LIST_FILTER_TOPID_EQUAL] = filter_topid_equal, }; struct btrfs_list_filter_set *btrfs_list_alloc_filter_set(void) @@ -1248,11 +1260,13 @@ static int filter_root(struct root_info *ri, static void __filter_and_sort_subvol(struct root_lookup *all_subvols, struct root_lookup *sort_tree, struct btrfs_list_filter_set *filter_set, - struct btrfs_list_comparer_set *comp_set) + struct btrfs_list_comparer_set *comp_set, + int fd) { struct rb_node *n; struct root_info *entry; int ret; + u64 top_id = btrfs_list_get_path_rootid(fd); root_lookup_init(sort_tree); @@ -1260,7 +1274,7 @@ static void __filter_and_sort_subvol(struct root_lookup *all_subvols, while (n) { entry = rb_entry(n, struct root_info, rb_node); - resolve_root(all_subvols, entry); + resolve_root(all_subvols, entry, top_id); ret = filter_root(entry, filter_set); if (ret) sort_tree_insert(sort_tree, entry, comp_set); @@ -1443,7 +1457,7 @@ int btrfs_list_subvols(int fd, struct btrfs_list_filter_set *filter_set, return ret; __filter_and_sort_subvol(&root_lookup, &root_sort, filter_set, - comp_set); + comp_set, fd); print_all_volume_info(&root_sort, is_tab_result); __free_all_subvolumn(&root_lookup); @@ -1636,6 +1650,7 @@ char *btrfs_list_path_for_root(int fd, u64 root) struct rb_node *n; char *ret_path = NULL; int ret; + u64 top_id = btrfs_list_get_path_rootid(fd); ret = __list_subvol_search(fd, &root_lookup); if (ret < 0) @@ -1650,7 +1665,7 @@ char *btrfs_list_path_for_root(int fd, u64 root) struct root_info *entry; entry = rb_entry(n, struct root_info, rb_node); - resolve_root(&root_lookup, entry); + resolve_root(&root_lookup, entry, top_id); if (entry->root_id == root) { ret_path = entry->full_path; entry->full_path = NULL; @@ -1758,3 +1773,20 @@ int btrfs_list_parse_filter_string(char *optarg, return 0; } +u64 btrfs_list_get_path_rootid(int fd) +{ + int ret; + struct btrfs_ioctl_ino_lookup_args args; + + memset(&args, 0, sizeof(args)); + args.objectid = BTRFS_FIRST_FREE_OBJECTID; + + ret = ioctl(fd, BTRFS_IOC_INO_LOOKUP, &args); + if (ret < 0) { + fprintf(stderr, + "ERROR: can't perform the search -%s\n", + strerror(errno)); + return ret; + } + return args.treeid; +} diff --git a/btrfs-list.h b/btrfs-list.h index 9d3687ea..cde4b3cc 100644 --- a/btrfs-list.h +++ b/btrfs-list.h @@ -70,6 +70,7 @@ enum btrfs_list_filter_enum { BTRFS_LIST_FILTER_CGEN_EQUAL = BTRFS_LIST_FILTER_CGEN, BTRFS_LIST_FILTER_CGEN_LESS, BTRFS_LIST_FILTER_CGEN_MORE, + BTRFS_LIST_FILTER_TOPID_EQUAL, BTRFS_LIST_FILTER_MAX, }; @@ -103,3 +104,4 @@ int btrfs_list_subvols(int fd, struct btrfs_list_filter_set *filter_set, int btrfs_list_find_updated_files(int fd, u64 root_id, u64 oldest_gen); int btrfs_list_get_default_subvolume(int fd, u64 *default_id); char *btrfs_list_path_for_root(int fd, u64 root); +u64 btrfs_list_get_path_rootid(int fd); diff --git a/cmds-subvolume.c b/cmds-subvolume.c index 8399e72e..b96af3eb 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -289,6 +289,7 @@ static int cmd_subvol_list(int argc, char **argv) struct btrfs_list_comparer_set *comparer_set; u64 flags = 0; int fd; + u64 top_id; int ret; int order; int c; @@ -387,6 +388,11 @@ static int cmd_subvol_list(int argc, char **argv) return 12; } + top_id = btrfs_list_get_path_rootid(fd); + btrfs_list_setup_filter(&filter_set, + BTRFS_LIST_FILTER_TOPID_EQUAL, + top_id); + ret = btrfs_list_subvols(fd, filter_set, comparer_set, is_tab_result); if (ret)