summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Linjama <daniel@dev.linjama.com>2026-09-16 09:15:56 +0300
committerDavid Sterba <dsterba@suse.com>2026-09-16 15:32:26 +0200
commit4804b60c97bb94a6b8f954f1656c9907097bbf32 (patch)
tree79e9112fadc54b0871fe2f493e3c410c0cccbf67
parentfa1951b6a67fe23865bcea47915a8da6c408ddb4 (diff)
downloadlinux-next-4804b60c97bb94a6b8f954f1656c9907097bbf32.tar.gz
linux-next-4804b60c97bb94a6b8f954f1656c9907097bbf32.zip
btrfs: handle lack of space when cleaning up verity items
When enable_verity() hits the qgroup limit, rollback_verity() needs its own metadata reservation. When the qgroup limit or lack of space refuses the rollback, the whole filesystem is forced read-only even though the qgroup limit was for one subvolume only. Also orphan cleanup at the next mount fails the same way, so the leftover items are never removed: with -EDQUOT the subvolume stays unreachable, and with -ENOSPC on a full filesystem the next read-write mount fails. Start transactions with btrfs_start_transaction_fallback_global_rsv() in btrfs_orphan_cleanup(), drop_verity_items() and rollback_verity(). Those calls only delete items and free the space in the end, so they may use the global reserve and skip the qgroup limit, which avoids -ENOSPC and -EDQUOT. Fixes: 146054090b08 ("btrfs: initial fsverity support") Reviewed-by: Qu Wenruo <wqu@suse.com> Signed-off-by: Daniel Linjama <daniel@dev.linjama.com> Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/inode.c3
-rw-r--r--fs/btrfs/verity.c18
2 files changed, 18 insertions, 3 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 766dbdbf6e7d..53f4532593b3 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3857,7 +3857,8 @@ int btrfs_orphan_cleanup(struct btrfs_root *root)
if (ret)
goto out;
}
- trans = btrfs_start_transaction(root, 1);
+ /* Only deletes the orphan. */
+ trans = btrfs_start_transaction_fallback_global_rsv(root, 1);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
goto out;
diff --git a/fs/btrfs/verity.c b/fs/btrfs/verity.c
index d432fec21c15..83dc7dee14cf 100644
--- a/fs/btrfs/verity.c
+++ b/fs/btrfs/verity.c
@@ -94,6 +94,20 @@ static loff_t merkle_file_pos(const struct inode *inode)
}
/*
+ * Start a transaction for removing verity items or the verity orphan.
+ *
+ * Like unlink, this only deletes items and frees space in the end, so the
+ * reservation may come from the global reserve when the filesystem is full
+ * (-ENOSPC) and is not subject to the qgroup limit (-EDQUOT). Otherwise a
+ * failed enable could never be cleaned up in either situation.
+ */
+static struct btrfs_trans_handle *start_verity_cleanup_trans(struct btrfs_root *root,
+ unsigned int num_items)
+{
+ return btrfs_start_transaction_fallback_global_rsv(root, num_items);
+}
+
+/*
* Drop all the items for this inode with this key_type.
*
* @inode: inode to drop items for
@@ -120,7 +134,7 @@ static int drop_verity_items(struct btrfs_inode *inode, u8 key_type)
while (1) {
/* 1 for the item being dropped */
- trans = btrfs_start_transaction(root, 1);
+ trans = start_verity_cleanup_trans(root, 1);
if (IS_ERR(trans))
return PTR_ERR(trans);
@@ -460,7 +474,7 @@ static int rollback_verity(struct btrfs_inode *inode)
* 1 for updating the inode flag
* 1 for deleting the orphan
*/
- trans = btrfs_start_transaction(root, 2);
+ trans = start_verity_cleanup_trans(root, 2);
if (IS_ERR(trans)) {
ret = PTR_ERR(trans);
trans = NULL;