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.
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