Anand jain
2012-Dec-15 11:52 UTC
[PATCH 0/5] add tree format display for btrfs subvol list subcommand
From: Anand Jain <anand.jain@oracle.com> This will add new option -x to the btrfs subvol list sub-command to display subvol-snapshot relation in tree format with appropriate indentation. Anand Jain (5): Btrfs-progs: add parent uuid for snapshots Btrfs-progs: maintain similar case in heading prefix Btrfs-progs: Move printing outside of btrfs_list_subvols Btrfs-progs: make provision to print subvol list tree format Btrfs-progs: Add -x option to btrfs subvol list to display snapshots in tree format btrfs-list.c | 227 +++++++++++++++++++++++++++++++++++++++++++++++------ btrfs-list.h | 3 +- cmds-subvolume.c | 20 ++++-- man/btrfs.8.in | 4 +- 4 files changed, 220 insertions(+), 34 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
From: Anand Jain <anand.jain@oracle.com> Signed-off-by: Anand Jain <anand.jain@oracle.com> --- btrfs-list.c | 32 +++++++++++++++++++++++++++----- btrfs-list.h | 1 + cmds-subvolume.c | 6 +++++- 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/btrfs-list.c b/btrfs-list.c index e5f0f96..5314ced 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -80,6 +80,7 @@ struct root_info { time_t otime; u8 uuid[BTRFS_UUID_SIZE]; + u8 puuid[BTRFS_UUID_SIZE]; /* path from the subvol we live in to this root, including the * root''s name. This is null until we do the extra lookup ioctl. @@ -128,6 +129,11 @@ struct { .need_print = 0, }, { + .name = "parent UUID", + .column_name = "Parent UUID", + .need_print = 0, + }, + { .name = "uuid", .column_name = "UUID", .need_print = 0, @@ -435,7 +441,7 @@ static struct root_info *root_tree_search(struct root_lookup *root_tree, static int update_root(struct root_lookup *root_lookup, u64 root_id, u64 ref_tree, u64 root_offset, u64 flags, u64 dir_id, char *name, int name_len, u64 ogen, u64 gen, - time_t ot, void *uuid) + time_t ot, void *uuid, void *puuid) { struct root_info *ri; @@ -472,6 +478,8 @@ static int update_root(struct root_lookup *root_lookup, ri->otime = ot; if (uuid) memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE); + if (puuid) + memcpy(&ri->puuid, puuid, BTRFS_UUID_SIZE); return 0; } @@ -489,17 +497,18 @@ static int update_root(struct root_lookup *root_lookup, * gen: the current generation of the root * ot: the original time(create time) of the root * uuid: uuid of the root + * puuid: uuid of the root parent if any */ static int add_root(struct root_lookup *root_lookup, u64 root_id, u64 ref_tree, u64 root_offset, u64 flags, u64 dir_id, char *name, int name_len, u64 ogen, u64 gen, - time_t ot, void *uuid) + time_t ot, void *uuid, void *puuid) { struct root_info *ri; int ret; ret = update_root(root_lookup, root_id, ref_tree, root_offset, flags, - dir_id, name, name_len, ogen, gen, ot, uuid); + dir_id, name, name_len, ogen, gen, ot, uuid, puuid); if (!ret) return 0; @@ -540,6 +549,9 @@ static int add_root(struct root_lookup *root_lookup, if (uuid) memcpy(&ri->uuid, uuid, BTRFS_UUID_SIZE); + if (puuid) + memcpy(&ri->puuid, puuid, BTRFS_UUID_SIZE); + ret = root_tree_insert(root_lookup, ri); if (ret) { printf("failed to insert tree %llu\n", (unsigned long long)root_id); @@ -1022,6 +1034,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup) int i; time_t t; u8 uuid[BTRFS_UUID_SIZE]; + u8 puuid[BTRFS_UUID_SIZE]; root_lookup_init(root_lookup); memset(&args, 0, sizeof(args)); @@ -1075,7 +1088,7 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup) add_root(root_lookup, sh->objectid, sh->offset, 0, 0, dir_id, name, name_len, 0, 0, 0, - NULL); + NULL, NULL); } else if (sh->type == BTRFS_ROOT_ITEM_KEY) { ri = (struct btrfs_root_item *)(args.buf + off); gen = btrfs_root_generation(ri); @@ -1085,15 +1098,17 @@ static int __list_subvol_search(int fd, struct root_lookup *root_lookup) t = ri->otime.sec; ogen = btrfs_root_otransid(ri); memcpy(uuid, ri->uuid, BTRFS_UUID_SIZE); + memcpy(puuid, ri->parent_uuid, BTRFS_UUID_SIZE); } else { t = 0; ogen = 0; memset(uuid, 0, BTRFS_UUID_SIZE); + memset(puuid, 0, BTRFS_UUID_SIZE); } add_root(root_lookup, sh->objectid, 0, sh->offset, flags, 0, NULL, 0, ogen, - gen, t, uuid); + gen, t, uuid, puuid); } off += sh->len; @@ -1347,6 +1362,13 @@ static void print_subvolume_column(struct root_info *subv, uuid_unparse(subv->uuid, uuidparse); printf("%s", uuidparse); break; + case BTRFS_LIST_PUUID: + if (uuid_is_null(subv->puuid)) + strcpy(uuidparse, "-"); + else + uuid_unparse(subv->puuid, uuidparse); + printf("%s", uuidparse); + break; case BTRFS_LIST_PATH: BUG_ON(!subv->full_path); printf("%s", subv->full_path); diff --git a/btrfs-list.h b/btrfs-list.h index cde4b3c..a32545f 100644 --- a/btrfs-list.h +++ b/btrfs-list.h @@ -53,6 +53,7 @@ enum btrfs_list_column_enum { BTRFS_LIST_PARENT, BTRFS_LIST_TOP_LEVEL, BTRFS_LIST_OTIME, + BTRFS_LIST_PUUID, BTRFS_LIST_UUID, BTRFS_LIST_PATH, BTRFS_LIST_ALL, diff --git a/cmds-subvolume.c b/cmds-subvolume.c index ac39f7b..427263a 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -279,6 +279,7 @@ static const char * const cmd_subvol_list_usage[] = { "-p print parent ID", "-a print all the subvolumes in the filesystem.", "-u print the uuid of subvolumes (and snapshots)", + "-q print the parent uuid of snapshots", "-t print the result as a table", "-s list snapshots only in the filesystem", "-r list readonly subvolumes (including snapshots)", @@ -318,7 +319,7 @@ static int cmd_subvol_list(int argc, char **argv) optind = 1; while(1) { c = getopt_long(argc, argv, - "apsurg:c:t", long_options, NULL); + "apsuqrg:c:t", long_options, NULL); if (c < 0) break; @@ -342,6 +343,9 @@ static int cmd_subvol_list(int argc, char **argv) case ''u'': btrfs_list_setup_print_column(BTRFS_LIST_UUID); break; + case ''q'': + btrfs_list_setup_print_column(BTRFS_LIST_PUUID); + break; case ''r'': flags |= BTRFS_ROOT_SUBVOL_RDONLY; break; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand jain
2012-Dec-15 11:52 UTC
[PATCH 2/5] Btrfs-progs: maintain similar case in heading prefix
From: Anand Jain <anand.jain@oracle.com> A trivial fix before this patch btrfs su list -qu /btrfs ID 256 gen 35 top level 5 parent UUID - uuid 60e54c4a-8136-3c43-a107-ea42052c6240 path sv1 ID 257 gen 35 top level 5 parent UUID 60e54c4a-8136-3c43-a107-ea42052c6240 uuid fdefa4a9-5b67-4f4c-8a11-c43acec51d43 path ss1 after this path btrfs su list -qu /btrfs ID 256 gen 35 top level 5 parent_uuid - uuid 60e54c4a-8136-3c43-a107-ea42052c6240 path sv1 ID 257 gen 35 top level 5 parent_uuid 60e54c4a-8136-3c43-a107-ea42052c6240 uuid fdefa4a9-5b67-4f4c-8a11-c43acec51d43 path ss1 Signed-off-by: Anand Jain <anand.jain@oracle.com> --- btrfs-list.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/btrfs-list.c b/btrfs-list.c index 5314ced..3db5f14 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -129,7 +129,7 @@ struct { .need_print = 0, }, { - .name = "parent UUID", + .name = "parent_uuid", .column_name = "Parent UUID", .need_print = 0, }, -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand jain
2012-Dec-15 11:52 UTC
[PATCH 3/5] Btrfs-progs: Move printing outside of btrfs_list_subvols
From: Anand Jain <anand.jain@oracle.com> its better to have btrfs_list_subvols just return witout printing so that btrfs_list_subvols can be reused. Signed-off-by: Anand Jain <anand.jain@oracle.com> --- btrfs-list.c | 28 ++++++++++++++++++---------- btrfs-list.h | 2 +- cmds-subvolume.c | 4 ++-- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/btrfs-list.c b/btrfs-list.c index 3db5f14..45d8d05 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -1463,15 +1463,11 @@ static void print_all_volume_info(struct root_lookup *sorted_tree, } } -int btrfs_list_subvols(int fd, struct btrfs_list_filter_set *filter_set, - struct btrfs_list_comparer_set *comp_set, - int is_tab_result) +int btrfs_list_subvols(int fd, struct root_lookup *root_lookup) { - struct root_lookup root_lookup; - struct root_lookup root_sort; int ret; - ret = __list_subvol_search(fd, &root_lookup); + ret = __list_subvol_search(fd, root_lookup); if (ret) { fprintf(stderr, "ERROR: can''t perform the search - %s\n", strerror(errno)); @@ -1482,16 +1478,28 @@ int btrfs_list_subvols(int fd, struct btrfs_list_filter_set *filter_set, * now we have an rbtree full of root_info objects, but we need to fill * in their path names within the subvol that is referencing each one. */ - ret = __list_subvol_fill_paths(fd, &root_lookup); - if (ret < 0) - return ret; + ret = __list_subvol_fill_paths(fd, root_lookup); + return ret; +} +int btrfs_list_subvols_print(int fd, struct btrfs_list_filter_set *filter_set, + struct btrfs_list_comparer_set *comp_set, + int is_tab_result) +{ + struct root_lookup root_lookup; + struct root_lookup root_sort; + int ret; + + ret = btrfs_list_subvols(fd, &root_lookup); + if (ret) + return ret; __filter_and_sort_subvol(&root_lookup, &root_sort, filter_set, comp_set, fd); print_all_volume_info(&root_sort, is_tab_result); __free_all_subvolumn(&root_lookup); - return ret; + + return 0; } static int print_one_extent(int fd, struct btrfs_ioctl_search_header *sh, diff --git a/btrfs-list.h b/btrfs-list.h index a32545f..855e73d 100644 --- a/btrfs-list.h +++ b/btrfs-list.h @@ -99,7 +99,7 @@ int btrfs_list_setup_comparer(struct btrfs_list_comparer_set **comp_set, enum btrfs_list_comp_enum comparer, int is_descending); -int btrfs_list_subvols(int fd, struct btrfs_list_filter_set *filter_set, +int btrfs_list_subvols_print(int fd, struct btrfs_list_filter_set *filter_set, struct btrfs_list_comparer_set *comp_set, int is_tab_result); int btrfs_list_find_updated_files(int fd, u64 root_id, u64 oldest_gen); diff --git a/cmds-subvolume.c b/cmds-subvolume.c index 427263a..b481a3b 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -409,7 +409,7 @@ static int cmd_subvol_list(int argc, char **argv) BTRFS_LIST_FILTER_TOPID_EQUAL, top_id); - ret = btrfs_list_subvols(fd, filter_set, comparer_set, + ret = btrfs_list_subvols_print(fd, filter_set, comparer_set, is_tab_result); if (ret) return 19; @@ -616,7 +616,7 @@ static int cmd_subvol_get_default(int argc, char **argv) btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_ROOTID, default_id); - ret = btrfs_list_subvols(fd, filter_set, NULL, 0); + ret = btrfs_list_subvols_print(fd, filter_set, NULL, 0); if (ret) return 19; return 0; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand jain
2012-Dec-15 11:52 UTC
[PATCH 4/5] Btrfs-progs: make provision to print subvol list tree format
From: Anand Jain <anand.jain@oracle.com> Currently we have default (name <value>) and table format to list the subvol. This patch will help to accommodate the enhancement to provide the tree display for the subvol-snapshot list. Signed-off-by: Anand Jain <anand.jain@oracle.com> --- btrfs-list.c | 34 ++++++++++++++++++++++------------ cmds-subvolume.c | 6 +++--- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/btrfs-list.c b/btrfs-list.c index 45d8d05..571efd0 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -1444,22 +1444,32 @@ static void print_all_volume_info_tab_head() } static void print_all_volume_info(struct root_lookup *sorted_tree, - int is_tab_result) + int layout) { struct rb_node *n; struct root_info *entry; - if (is_tab_result) + switch (layout) { + case 0: // default: name <value> + n = rb_first(&sorted_tree->root); + while (n) { + entry = rb_entry(n, struct root_info, sort_node); + print_single_volume_info_default(entry); + n = rb_next(n); + } + break; + case 1: // table print_all_volume_info_tab_head(); - - n = rb_first(&sorted_tree->root); - while (n) { - entry = rb_entry(n, struct root_info, sort_node); - if (is_tab_result) + n = rb_first(&sorted_tree->root); + while (n) { + entry = rb_entry(n, struct root_info, sort_node); print_single_volume_info_table(entry); - else - print_single_volume_info_default(entry); - n = rb_next(n); + n = rb_next(n); + } + break; + default: + printf("ERROR: default switch print_all_volume_info\n"); + return; } } @@ -1484,7 +1494,7 @@ int btrfs_list_subvols(int fd, struct root_lookup *root_lookup) int btrfs_list_subvols_print(int fd, struct btrfs_list_filter_set *filter_set, struct btrfs_list_comparer_set *comp_set, - int is_tab_result) + int layout) { struct root_lookup root_lookup; struct root_lookup root_sort; @@ -1496,7 +1506,7 @@ int btrfs_list_subvols_print(int fd, struct btrfs_list_filter_set *filter_set, __filter_and_sort_subvol(&root_lookup, &root_sort, filter_set, comp_set, fd); - print_all_volume_info(&root_sort, is_tab_result); + print_all_volume_info(&root_sort, layout); __free_all_subvolumn(&root_lookup); return 0; diff --git a/cmds-subvolume.c b/cmds-subvolume.c index b481a3b..411a5de 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -306,7 +306,7 @@ static int cmd_subvol_list(int argc, char **argv) int ret; int c; char *subvol; - int is_tab_result = 0; + int layout = 0; int is_list_all = 0; struct option long_options[] = { {"sort", 1, NULL, ''S''}, @@ -331,7 +331,7 @@ static int cmd_subvol_list(int argc, char **argv) is_list_all = 1; break; case ''t'': - is_tab_result = 1; + layout = 1; break; case ''s'': btrfs_list_setup_filter(&filter_set, @@ -410,7 +410,7 @@ static int cmd_subvol_list(int argc, char **argv) top_id); ret = btrfs_list_subvols_print(fd, filter_set, comparer_set, - is_tab_result); + layout); if (ret) return 19; return 0; -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Anand jain
2012-Dec-15 11:52 UTC
[PATCH 5/5] Btrfs-progs: Add -x option to btrfs subvol list to display snapshots in tree format
From: Anand Jain <anand.jain@oracle.com> This will add new option -x to the btrfs subvol list sub-command to display the snapshots under its parent subvol with appropriate indentation. Signed-off-by: Anand Jain <anand.jain@oracle.com> --- btrfs-list.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ cmds-subvolume.c | 6 ++- man/btrfs.8.in | 4 +- 3 files changed, 143 insertions(+), 2 deletions(-) diff --git a/btrfs-list.c b/btrfs-list.c index 571efd0..43c279c 100644 --- a/btrfs-list.c +++ b/btrfs-list.c @@ -150,6 +150,11 @@ struct { }, }; +struct str_print { + char path[BTRFS_PATH_NAME_MAX]; + char otime[256]; +}; + static btrfs_list_filter_func all_filter_funcs[]; static btrfs_list_comp_func all_comp_funcs[]; @@ -1414,6 +1419,133 @@ static void print_single_volume_info_default(struct root_info *subv) printf("\n"); } +static void print_single_volume_info_tree(struct root_info *subv, + struct str_print *sp) +{ + char tstr[256]; + + sprintf(sp->path, "%s", subv->full_path); + if (subv->otime) + strftime(tstr, 256, "%X %d-%m-%Y", localtime(&subv->otime)); + else + strcpy(tstr, "-"); + sprintf(sp->otime, "%s", tstr); +} + +int snapshot_is_orphan(struct root_lookup *root_tree, void *uuid) +{ + struct rb_node *n; + struct root_info *entry; + + n = rb_first(&root_tree->root); + while (n) { + entry = rb_entry(n, struct root_info, sort_node); + if ( ! uuid_compare(entry->uuid, uuid)) { + return 0; + } + n = rb_next(n); + } + return 1; +} + +void * print_snapshots_of(struct root_lookup *root_tree, void *uuid, + int indent, struct str_print *sp) +{ + struct rb_node *n; + struct root_info *entry; + int i = indent; + char ispace[BTRFS_PATH_NAME_MAX + 256]; + char *ispacep = ispace; + + n = rb_first(&root_tree->root); + while (n) { + entry = rb_entry(n, struct root_info, sort_node); + if ( ! uuid_compare(entry->puuid, uuid)) { + while(i--) { + sprintf(ispacep,"%s"," "); + ispacep++; + } + print_single_volume_info_tree(entry, sp); + strcat(ispace, sp->path); + strcpy(sp->path, ispace); + sp++; + sp = (struct str_print *) print_snapshots_of(root_tree, + entry->uuid, indent+1, sp); + } + i = indent; + n = rb_next(n); + } + return sp; +} + +void print_subvol_tree(struct root_lookup *root_tree) +{ + struct rb_node *n; + struct root_info *entry; + int listlen = 0; + int max_slen = 0; + int pad; + int stmp; + int i; + struct str_print *head; + struct str_print *cur; + + n = rb_first(&root_tree->root); + while (n) { + listlen++; + n = rb_next(n); + } + head = (struct str_print *) malloc(sizeof(struct str_print)*listlen); + memset(head, 0, sizeof(struct str_print)*listlen); + + cur = head; + n = rb_first(&root_tree->root); + while (n) { + entry = rb_entry(n, struct root_info, sort_node); + if ( uuid_is_null(entry->puuid)) { + print_single_volume_info_tree(entry, cur); + cur++; + cur = (struct str_print *) print_snapshots_of(root_tree, + entry->uuid, 1, cur); + } + n = rb_next(n); + } + n = rb_first(&root_tree->root); + while (n) { + entry = rb_entry(n, struct root_info, sort_node); + if ( !uuid_is_null(entry->puuid) + && snapshot_is_orphan(root_tree, entry->puuid)) { + print_single_volume_info_tree(entry, cur); + cur++; + cur = (struct str_print *) print_snapshots_of(root_tree, + entry->uuid, 1, cur); + } + n = rb_next(n); + } + //BUG_ON(cur != (head + (sizeof(struct str_print) * listlen))); + + cur = head; + for (i=0; i < listlen; i++) { + stmp = strlen(cur->path); + if (stmp > max_slen) + max_slen = stmp; + cur++; + } + + cur = head; + for (i=0; i < listlen; i++) { + printf("%s", cur->path); + pad = max_slen - strlen(cur->path) + 1; + while(pad--) + printf("%s"," "); + printf("%s"," "); + printf("%s", cur->otime); + printf("\n"); + cur++; + } + free(head); +} + static void print_all_volume_info_tab_head() { int i; @@ -1467,6 +1599,9 @@ static void print_all_volume_info(struct root_lookup *sorted_tree, n = rb_next(n); } break; + case 2: // tree format + print_subvol_tree(sorted_tree); + break; default: printf("ERROR: default switch print_all_volume_info\n"); return; diff --git a/cmds-subvolume.c b/cmds-subvolume.c index 411a5de..4f2704f 100644 --- a/cmds-subvolume.c +++ b/cmds-subvolume.c @@ -281,6 +281,7 @@ static const char * const cmd_subvol_list_usage[] = { "-u print the uuid of subvolumes (and snapshots)", "-q print the parent uuid of snapshots", "-t print the result as a table", + "-x print the result as a tree", "-s list snapshots only in the filesystem", "-r list readonly subvolumes (including snapshots)", "-g [+|-]value", @@ -319,7 +320,7 @@ static int cmd_subvol_list(int argc, char **argv) optind = 1; while(1) { c = getopt_long(argc, argv, - "apsuqrg:c:t", long_options, NULL); + "apsuqrg:c:tx", long_options, NULL); if (c < 0) break; @@ -333,6 +334,9 @@ static int cmd_subvol_list(int argc, char **argv) case ''t'': layout = 1; break; + case ''x'': + layout = 2; + break; case ''s'': btrfs_list_setup_filter(&filter_set, BTRFS_LIST_FILTER_SNAPSHOT_ONLY, diff --git a/man/btrfs.8.in b/man/btrfs.8.in index 9222580..1bb0415 100644 --- a/man/btrfs.8.in +++ b/man/btrfs.8.in @@ -11,7 +11,7 @@ btrfs \- control a btrfs filesystem .PP \fBbtrfs\fP \fBsubvolume create\fP\fI [<dest>/]<name>\fP .PP -\fBbtrfs\fP \fBsubvolume list\fP\fI [-aprts] [-g [+|-]value] [-c [+|-]value] [--rootid=rootid,gen,ogen,path] <path>\fP +\fBbtrfs\fP \fBsubvolume list\fP\fI [-aprtxs] [-g [+|-]value] [-c [+|-]value] [--rootid=rootid,gen,ogen,path] <path>\fP .PP \fBbtrfs\fP \fBsubvolume set-default\fP\fI <id> <path>\fP .PP @@ -124,6 +124,8 @@ and top level. The parent''s ID may be used at mount time via the \fB-t\fP print the result as a table. +\fB-x\fP print the result as a tree. + \fB-a\fP print all the subvolumes in the filesystem. \fB-r\fP only readonly subvolumes in the filesystem wille be listed. -- 1.7.1 -- To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html