btrfs-progs: qgroup: add more special statuses for qgroups

Currently `btrfs qgroup show` command shows any 0 level qgroup without a
root backref as `<stale>`, which is not correct.

There are several more cases:

- Under deletion
  The subvolume is not yet full dropped, but unlinked.
  In that case we would not have a root backref item, but the qgroup is
  not stale.

- Squota space holder
  This is for squota mode, that a fully dropped subvolume still have
  extents accounting on the already-gone subvolume.
  In this case it's not stale either, and future accounting relies on
  it.

This patch would add above special cases, and add an extra `SPECIAL
PATHS` section to explain all the cases, including `<stale>`.

Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
Qu Wenruo 2024-05-09 18:42:33 +09:30 committed by David Sterba
parent 82f7d6c1d7
commit 7f3ab46400
2 changed files with 50 additions and 6 deletions

View File

@ -153,6 +153,30 @@ show [options] <path>
To retrieve information after updating the state of qgroups,
force sync of the filesystem identified by *path* before getting information.
SPECIAL PATHS
-------------
For `btrfs qgroup show` subcommand, the ``path`` column may has some special
strings:
`<toplevel>`
The toplevel subvolume
`<under deletion>`
The subvolume is unlinked, but not yet fully deleted.
`<squota space holder>`
For simple quota mode only.
By its design, a fully deleted subvolume may still have accounting on
it, so even the subvolume is gone, the numbers are still here for future
accounting.
`<stale>`
The qgroup has no corresponding subvolume anymore, and the qgroup
can be cleaned up under most cases.
The only exception is that, if the qgroup numbers are inconsistent and
the qgroup numbers are not all zeros, some older kernels may refuse to
delete such qgroups until a full rescan.
QUOTA RESCAN
------------

View File

@ -71,6 +71,8 @@ struct qgroup_lookup {
};
struct btrfs_qgroup {
struct qgroup_lookup *lookup;
struct rb_node rb_node;
struct rb_node sort_node;
/*
@ -321,6 +323,26 @@ static void print_qgroup_column_add_blank(enum btrfs_qgroup_column_enum column,
printf(" ");
}
static const char *get_qgroup_path(struct btrfs_qgroup *qgroup)
{
if (qgroup->path)
return qgroup->path;
/* No path but not stale either, the qgroup is being deleted. */
if (!qgroup->stale)
return "<under deletion>";
/*
* Squota mode stale qgroup, but not empty.
* This is fully deleted but still necessary.
*/
if (qgroup->stale &&
(qgroup->lookup->flags & BTRFS_QGROUP_STATUS_FLAG_SIMPLE_MODE) &&
!is_qgroup_empty(qgroup))
return "<squota space holder>";
return "<stale>";
}
static void print_path_column(struct btrfs_qgroup *qgroup)
{
struct btrfs_qgroup_list *list = NULL;
@ -338,11 +360,8 @@ static void print_path_column(struct btrfs_qgroup *qgroup)
if (count)
pr_verbose(LOG_DEFAULT, " ");
if (level == 0) {
const char *path = member->path;
if (!path)
path = "<stale>";
pr_verbose(LOG_DEFAULT, "%s", path);
pr_verbose(LOG_DEFAULT, "%s",
get_qgroup_path(qgroup));
} else {
pr_verbose(LOG_DEFAULT, "%llu/%llu", level, sid);
}
@ -353,7 +372,7 @@ static void print_path_column(struct btrfs_qgroup *qgroup)
} else if (qgroup->path) {
pr_verbose(LOG_DEFAULT, "%s%s", (*qgroup->path ? "" : "<toplevel>"), qgroup->path);
} else {
pr_verbose(LOG_DEFAULT, "<stale>");
pr_verbose(LOG_DEFAULT, "%s", get_qgroup_path(qgroup));
}
}
@ -805,6 +824,7 @@ static struct btrfs_qgroup *get_or_add_qgroup(int fd,
return ERR_PTR(-ENOMEM);
}
bq->lookup = qgroup_lookup;
bq->qgroupid = qgroupid;
INIT_LIST_HEAD(&bq->qgroups);
INIT_LIST_HEAD(&bq->members);