mirror of
https://github.com/torvalds/linux.git
synced 2026-05-28 17:13:52 +02:00
btrfs: relax squota parent qgroup deletion rule
Currently, with squotas, we do not allow removing a parent qgroup with no members if it still has usage accounted to it. This makes it really difficult to recover from accounting bugs, as we have no good way of getting back to 0 usage. Instead, allow deletion (it's safe at 0 members..) while still warning about the inconsistency by adding a squota parent check. Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Boris Burkov <boris@bur.io> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
9c46bcda5f
commit
adb0af40fe
|
|
@ -1718,6 +1718,36 @@ int btrfs_create_qgroup(struct btrfs_trans_handle *trans, u64 qgroupid)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool can_delete_parent_qgroup(struct btrfs_qgroup *qgroup)
|
||||
|
||||
{
|
||||
ASSERT(btrfs_qgroup_level(qgroup->qgroupid));
|
||||
return list_empty(&qgroup->members);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if we can delete the squota qgroup and false otherwise.
|
||||
*
|
||||
* Rules for whether we can delete:
|
||||
*
|
||||
* A subvolume qgroup can be removed iff the subvolume is fully deleted, which
|
||||
* is iff there is 0 usage in the qgroup.
|
||||
*
|
||||
* A higher level qgroup can be removed iff it has no members.
|
||||
* Note: We audit its usage to warn on inconsitencies without blocking deletion.
|
||||
*/
|
||||
static bool can_delete_squota_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup *qgroup)
|
||||
{
|
||||
ASSERT(btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE);
|
||||
|
||||
if (btrfs_qgroup_level(qgroup->qgroupid) > 0) {
|
||||
squota_check_parent_usage(fs_info, qgroup);
|
||||
return can_delete_parent_qgroup(qgroup);
|
||||
}
|
||||
|
||||
return !(qgroup->rfer || qgroup->excl || qgroup->rfer_cmpr || qgroup->excl_cmpr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return 0 if we can not delete the qgroup (not empty or has children etc).
|
||||
* Return >0 if we can delete the qgroup.
|
||||
|
|
@ -1728,23 +1758,13 @@ static int can_delete_qgroup(struct btrfs_fs_info *fs_info, struct btrfs_qgroup
|
|||
struct btrfs_key key;
|
||||
BTRFS_PATH_AUTO_FREE(path);
|
||||
|
||||
/*
|
||||
* Squota would never be inconsistent, but there can still be case
|
||||
* where a dropped subvolume still has qgroup numbers, and squota
|
||||
* relies on such qgroup for future accounting.
|
||||
*
|
||||
* So for squota, do not allow dropping any non-zero qgroup.
|
||||
*/
|
||||
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE &&
|
||||
(qgroup->rfer || qgroup->excl || qgroup->excl_cmpr || qgroup->rfer_cmpr))
|
||||
return 0;
|
||||
/* Since squotas cannot be inconsistent, they have special rules for deletion. */
|
||||
if (btrfs_qgroup_mode(fs_info) == BTRFS_QGROUP_MODE_SIMPLE)
|
||||
return can_delete_squota_qgroup(fs_info, qgroup);
|
||||
|
||||
/* For higher level qgroup, we can only delete it if it has no child. */
|
||||
if (btrfs_qgroup_level(qgroup->qgroupid)) {
|
||||
if (!list_empty(&qgroup->members))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
if (btrfs_qgroup_level(qgroup->qgroupid))
|
||||
return can_delete_parent_qgroup(qgroup);
|
||||
|
||||
/*
|
||||
* For level-0 qgroups, we can only delete it if it has no subvolume
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user