btrfs-progs: add filter for deleted but uncleanded subvolumes

New option to subvolume list that acts as a global filter and applies
the other filters to either live subvolumes or the uncleaned ones.

The path to the deleted subvolumes is lost at the deletion time, sample
output looks like:

ID 259 gen 7 top level 0 path <FS_TREE>/DELETED

Signed-off-by: David Sterba <dsterba@suse.cz>
Signed-off-by: Chris Mason <chris.mason@fusionio.com>
This commit is contained in:
David Sterba 2013-10-23 19:00:09 +02:00 committed by Chris Mason
parent b91d84abc0
commit 4fc17596aa
3 changed files with 32 additions and 4 deletions

View File

@ -1173,6 +1173,11 @@ static int filter_by_parent(struct root_info *ri, u64 data)
return !uuid_compare(ri->puuid, (u8 *)(unsigned long)data);
}
static int filter_deleted(struct root_info *ri, u64 data)
{
return ri->deleted;
}
static btrfs_list_filter_func all_filter_funcs[] = {
[BTRFS_LIST_FILTER_ROOTID] = filter_by_rootid,
[BTRFS_LIST_FILTER_SNAPSHOT_ONLY] = filter_snapshot,
@ -1186,6 +1191,7 @@ static btrfs_list_filter_func all_filter_funcs[] = {
[BTRFS_LIST_FILTER_TOPID_EQUAL] = filter_topid_equal,
[BTRFS_LIST_FILTER_FULL_PATH] = filter_full_path,
[BTRFS_LIST_FILTER_BY_PARENT] = filter_by_parent,
[BTRFS_LIST_FILTER_DELETED] = filter_deleted,
};
struct btrfs_list_filter_set *btrfs_list_alloc_filter_set(void)
@ -1222,6 +1228,11 @@ int btrfs_list_setup_filter(struct btrfs_list_filter_set **filter_set,
BUG_ON(filter >= BTRFS_LIST_FILTER_MAX);
BUG_ON(set->nfilters > set->total);
if (filter == BTRFS_LIST_FILTER_DELETED) {
set->only_deleted = 1;
return 0;
}
if (set->nfilters == set->total) {
size = set->total + BTRFS_LIST_NFILTERS_INCREASE;
size = sizeof(*set) + size * sizeof(struct btrfs_list_filter);
@ -1254,6 +1265,12 @@ static int filter_root(struct root_info *ri,
if (!set || !set->nfilters)
return 1;
if (set->only_deleted && !ri->deleted)
return 0;
if (!set->only_deleted && ri->deleted)
return 0;
for (i = 0; i < set->nfilters; i++) {
if (!set->filters[i].filter_func)
break;
@ -1281,12 +1298,13 @@ static void __filter_and_sort_subvol(struct root_lookup *all_subvols,
entry = rb_entry(n, struct root_info, rb_node);
ret = resolve_root(all_subvols, entry, top_id);
if (ret == -ENOENT)
goto skip;
if (ret == -ENOENT) {
entry->full_path = strdup("DELETED");
entry->deleted = 1;
}
ret = filter_root(entry, filter_set);
if (ret)
sort_tree_insert(sort_tree, entry, comp_set);
skip:
n = rb_prev(n);
}
}

View File

@ -71,6 +71,8 @@ struct root_info {
char *name;
char *full_path;
int deleted;
};
typedef int (*btrfs_list_filter_func)(struct root_info *, u64);
@ -90,6 +92,7 @@ struct btrfs_list_comparer {
struct btrfs_list_filter_set {
int total;
int nfilters;
int only_deleted;
struct btrfs_list_filter filters[0];
};
@ -127,6 +130,7 @@ enum btrfs_list_filter_enum {
BTRFS_LIST_FILTER_TOPID_EQUAL,
BTRFS_LIST_FILTER_FULL_PATH,
BTRFS_LIST_FILTER_BY_PARENT,
BTRFS_LIST_FILTER_DELETED,
BTRFS_LIST_FILTER_MAX,
};

View File

@ -317,6 +317,7 @@ static const char * const cmd_subvol_list_usage[] = {
"-t print the result as a table",
"-s list snapshots only in the filesystem",
"-r list readonly subvolumes (including snapshots)",
"-d list deleted subvolumes that are not yet cleaned",
"-G [+|-]value",
" filter the subvolumes by generation",
" (+value: >= value; -value: <= value; value: = value)",
@ -355,7 +356,7 @@ static int cmd_subvol_list(int argc, char **argv)
optind = 1;
while(1) {
c = getopt_long(argc, argv,
"acgopqsurG:C:t", long_options, NULL);
"acdgopqsurG:C:t", long_options, NULL);
if (c < 0)
break;
@ -369,6 +370,11 @@ static int cmd_subvol_list(int argc, char **argv)
case 'c':
btrfs_list_setup_print_column(BTRFS_LIST_OGENERATION);
break;
case 'd':
btrfs_list_setup_filter(&filter_set,
BTRFS_LIST_FILTER_DELETED,
0);
break;
case 'g':
btrfs_list_setup_print_column(BTRFS_LIST_GENERATION);
break;