From d4aa2bc07e8d0ed3fb5b87c67ae2f2228178de82 Mon Sep 17 00:00:00 2001 From: David Sterba Date: Mon, 31 Oct 2016 13:56:28 +0100 Subject: [PATCH] btrfs-progs: subvol show: print more details about toplevel subvolume The toplevel subvolume is special and the other listing code leaves it out so we have to add several special cases to handle it. There's no backreference so the path is built artificially. New helper btrfs_get_toplevel_subvol is a reduced version of btrfs_get_subvol. There's some information usually missing for the toplevel subvolume, eg. the uuid or creation info. This has to be fixed on the mkfs side, the other subvolumes are created by kernel. Example: /mnt Name: UUID: - Parent UUID: - Received UUID: - Creation time: - Subvolume ID: 5 Generation: 233 Gen at creation: 0 Parent ID: 0 Top level ID: 0 Flags: - Snapshot(s): subv1 Signed-off-by: David Sterba --- btrfs-list.c | 37 +++++++++++++++++++++++++++++++++++-- btrfs-list.h | 1 + cmds-subvolume.c | 9 --------- utils.c | 13 ++++--------- 4 files changed, 40 insertions(+), 20 deletions(-) diff --git a/btrfs-list.c b/btrfs-list.c index 8f207b6f..8eec05ea 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -983,7 +983,7 @@ static int list_subvol_search(int fd, struct root_lookup *root_lookup) /* Search both live and deleted subvolumes */ sk->min_type = BTRFS_ROOT_ITEM_KEY; sk->max_type = BTRFS_ROOT_BACKREF_KEY; - sk->min_objectid = BTRFS_FIRST_FREE_OBJECTID; + sk->min_objectid = BTRFS_FS_TREE_OBJECTID; sk->max_objectid = BTRFS_LAST_FREE_OBJECTID; sk->max_offset = (u64)-1; sk->max_transid = (u64)-1; @@ -1014,7 +1014,9 @@ static int list_subvol_search(int fd, struct root_lookup *root_lookup) add_root_backref(root_lookup, sh.objectid, sh.offset, dir_id, name, name_len); - } else if (sh.type == BTRFS_ROOT_ITEM_KEY) { + } else if (sh.type == BTRFS_ROOT_ITEM_KEY && + (sh.objectid >= BTRFS_FIRST_FREE_OBJECTID || + sh.objectid == BTRFS_FS_TREE_OBJECTID)) { time_t otime; u8 uuid[BTRFS_UUID_SIZE]; u8 puuid[BTRFS_UUID_SIZE]; @@ -1524,6 +1526,37 @@ static char *strdup_or_null(const char *s) return strdup(s); } +int btrfs_get_toplevel_subvol(int fd, struct root_info *the_ri) +{ + int ret; + struct root_lookup rl; + struct rb_node *rbn; + struct root_info *ri; + u64 root_id; + + ret = btrfs_list_get_path_rootid(fd, &root_id); + if (ret) + return ret; + + ret = btrfs_list_subvols(fd, &rl); + if (ret) + return ret; + + rbn = rb_first(&rl.root); + ri = rb_entry(rbn, struct root_info, rb_node); + + if (ri->root_id != BTRFS_FS_TREE_OBJECTID) + return -ENOENT; + + memcpy(the_ri, ri, offsetof(struct root_info, path)); + the_ri->path = strdup_or_null("/"); + the_ri->name = strdup_or_null(""); + the_ri->full_path = strdup_or_null("/"); + rb_free_nodes(&rl.root, free_root_info); + + return ret; +} + int btrfs_get_subvol(int fd, struct root_info *the_ri) { int ret, rr; diff --git a/btrfs-list.h b/btrfs-list.h index 528d5a98..6e5fc778 100644 --- a/btrfs-list.h +++ b/btrfs-list.h @@ -175,5 +175,6 @@ int btrfs_list_get_default_subvolume(int fd, u64 *default_id); char *btrfs_list_path_for_root(int fd, u64 root); int btrfs_list_get_path_rootid(int fd, u64 *treeid); int btrfs_get_subvol(int fd, struct root_info *the_ri); +int btrfs_get_toplevel_subvol(int fd, struct root_info *the_ri); #endif diff --git a/cmds-subvolume.c b/cmds-subvolume.c index 9f220851..4cd2e0ec 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -921,15 +921,6 @@ static int cmd_subvol_show(int argc, char **argv) } ret = get_subvol_info(fullpath, &get_ri); - if (ret == 2) { - /* - * Since the top level btrfs was given don't - * take that as error - */ - printf("%s is toplevel subvolume\n", fullpath); - ret = 0; - goto out; - } if (ret) { if (ret < 0) { error("Failed to get subvol info %s: %s\n", diff --git a/utils.c b/utils.c index e10d199f..9c2e4eb7 100644 --- a/utils.c +++ b/utils.c @@ -4168,18 +4168,13 @@ int get_subvol_info(const char *fullpath, struct root_info *get_ri) if (mntfd < 0) goto out; - if (sv_id == BTRFS_FS_TREE_OBJECTID) { - ret = 2; - /* - * So that caller may decide if thats an error or just fine. - */ - goto out; - } - memset(get_ri, 0, sizeof(*get_ri)); get_ri->root_id = sv_id; - ret = btrfs_get_subvol(mntfd, get_ri); + if (sv_id == BTRFS_FS_TREE_OBJECTID) + ret = btrfs_get_toplevel_subvol(mntfd, get_ri); + else + ret = btrfs_get_subvol(mntfd, get_ri); if (ret) error("can't find '%s': %d", svpath, ret);