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:                   <FS_TREE>
        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 <dsterba@suse.com>
This commit is contained in:
David Sterba 2016-10-31 13:56:28 +01:00
parent eb28e2fcae
commit d4aa2bc07e
4 changed files with 40 additions and 20 deletions

View file

@ -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("<FS_TREE>");
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;

View file

@ -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

View file

@ -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",

13
utils.c
View file

@ -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);