+ ret = lookup_ino_path(fd, entry);
+ if (ret && ret != -ENOENT)
+ return ret;
+ n = rb_next(n);
+ }
+
+ return 0;
+}
+
+static void print_subvolume_column(struct root_info *subv,
+ enum btrfs_list_column_enum column)
+{
+ char tstr[256];
+ char uuidparse[BTRFS_UUID_UNPARSED_SIZE];
+
+ ASSERT(0 <= column && column < BTRFS_LIST_ALL);
+
+ switch (column) {
+ case BTRFS_LIST_OBJECTID:
+ printf("%llu", subv->root_id);
+ break;
+ case BTRFS_LIST_GENERATION:
+ printf("%llu", subv->gen);
+ break;
+ case BTRFS_LIST_OGENERATION:
+ printf("%llu", subv->ogen);
+ break;
+ case BTRFS_LIST_PARENT:
+ printf("%llu", subv->ref_tree);
+ break;
+ case BTRFS_LIST_TOP_LEVEL:
+ printf("%llu", subv->top_id);
+ break;
+ case BTRFS_LIST_OTIME:
+ if (subv->otime) {
+ struct tm tm;
+
+ localtime_r(&subv->otime, &tm);
+ strftime(tstr, 256, "%Y-%m-%d %X", &tm);
+ } else
+ strcpy(tstr, "-");
+ printf("%s", tstr);
+ break;
+ case BTRFS_LIST_UUID:
+ if (uuid_is_null(subv->uuid))
+ strcpy(uuidparse, "-");
+ else
+ uuid_unparse(subv->uuid, uuidparse);
+ printf("%-36s", uuidparse);
+ break;
+ case BTRFS_LIST_PUUID:
+ if (uuid_is_null(subv->puuid))
+ strcpy(uuidparse, "-");
+ else
+ uuid_unparse(subv->puuid, uuidparse);
+ printf("%-36s", uuidparse);
+ break;
+ case BTRFS_LIST_RUUID:
+ if (uuid_is_null(subv->ruuid))
+ strcpy(uuidparse, "-");
+ else
+ uuid_unparse(subv->ruuid, uuidparse);
+ printf("%-36s", uuidparse);
+ break;
+ case BTRFS_LIST_PATH:
+ BUG_ON(!subv->full_path);
+ printf("%s", subv->full_path);
+ break;
+ default:
+ break;
+ }
+}
+
+static void print_one_subvol_info_raw(struct root_info *subv,
+ const char *raw_prefix)
+{
+ int i;
+
+ for (i = 0; i < BTRFS_LIST_ALL; i++) {
+ if (!btrfs_list_columns[i].need_print)
+ continue;
+
+ if (raw_prefix)
+ printf("%s",raw_prefix);
+
+ print_subvolume_column(subv, i);
+ }
+ printf("\n");
+}
+
+static void print_one_subvol_info_table(struct root_info *subv)
+{
+ int i;
+
+ for (i = 0; i < BTRFS_LIST_ALL; i++) {
+ if (!btrfs_list_columns[i].need_print)
+ continue;
+
+ print_subvolume_column(subv, i);
+
+ if (i != BTRFS_LIST_PATH)
+ printf("\t");
+
+ if (i == BTRFS_LIST_TOP_LEVEL)
+ printf("\t");
+ }
+ printf("\n");
+}
+
+static void print_one_subvol_info_default(struct root_info *subv)
+{
+ int i;
+
+ for (i = 0; i < BTRFS_LIST_ALL; i++) {
+ if (!btrfs_list_columns[i].need_print)
+ continue;
+
+ printf("%s ", btrfs_list_columns[i].name);
+ print_subvolume_column(subv, i);
+
+ if (i != BTRFS_LIST_PATH)
+ printf(" ");
+ }
+ printf("\n");
+}
+
+static void print_all_subvol_info_tab_head(void)
+{
+ int i;
+ int len;
+ char barrier[20];
+
+ for (i = 0; i < BTRFS_LIST_ALL; i++) {
+ if (btrfs_list_columns[i].need_print)
+ printf("%s\t", btrfs_list_columns[i].name);
+
+ if (i == BTRFS_LIST_ALL-1)
+ printf("\n");
+ }
+
+ for (i = 0; i < BTRFS_LIST_ALL; i++) {
+ memset(barrier, 0, sizeof(barrier));
+
+ if (btrfs_list_columns[i].need_print) {
+ len = strlen(btrfs_list_columns[i].name);
+ while (len--)
+ strcat(barrier, "-");
+
+ printf("%s\t", barrier);
+ }
+ if (i == BTRFS_LIST_ALL-1)
+ printf("\n");
+ }
+}
+
+static void print_all_subvol_info(struct root_lookup *sorted_tree,
+ enum btrfs_list_layout layout, const char *raw_prefix)
+{
+ struct rb_node *n;
+ struct root_info *entry;
+
+ if (layout == BTRFS_LIST_LAYOUT_TABLE)
+ print_all_subvol_info_tab_head();
+
+ n = rb_first(&sorted_tree->root);
+ while (n) {
+ entry = rb_entry(n, struct root_info, sort_node);
+
+ /* The toplevel subvolume is not listed by default */
+ if (entry->root_id == BTRFS_FS_TREE_OBJECTID)
+ goto next;
+
+ switch (layout) {
+ case BTRFS_LIST_LAYOUT_DEFAULT:
+ print_one_subvol_info_default(entry);