summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/delayed-ref.c28
-rw-r--r--fs/btrfs/transaction.c8
2 files changed, 36 insertions, 0 deletions
diff --git a/fs/btrfs/delayed-ref.c b/fs/btrfs/delayed-ref.c
index 3766ff29fbbb..605858c2d9a9 100644
--- a/fs/btrfs/delayed-ref.c
+++ b/fs/btrfs/delayed-ref.c
@@ -207,6 +207,30 @@ void btrfs_dec_delayed_refs_rsv_bg_updates(struct btrfs_fs_info *fs_info)
* This will refill the delayed block_rsv up to 1 items size worth of space and
* will return -ENOSPC if we can't make the reservation.
*/
+static int btrfs_zoned_cap_metadata_reservation(struct btrfs_space_info *space_info)
+{
+ struct btrfs_fs_info *fs_info = space_info->fs_info;
+ struct btrfs_block_rsv *block_rsv = &fs_info->delayed_refs_rsv;
+ u64 usable;
+ u64 cap;
+ int ret = 0;
+
+ if (!btrfs_is_zoned(fs_info))
+ return 0;
+
+ spin_lock(&space_info->lock);
+ usable = space_info->total_bytes - space_info->bytes_zone_unusable;
+ spin_unlock(&space_info->lock);
+ cap = usable >> 1;
+
+ spin_lock(&block_rsv->lock);
+ if (block_rsv->size > cap)
+ ret = -EAGAIN;
+ spin_unlock(&block_rsv->lock);
+
+ return ret;
+}
+
int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
enum btrfs_reserve_flush_enum flush)
{
@@ -228,6 +252,10 @@ int btrfs_delayed_refs_rsv_refill(struct btrfs_fs_info *fs_info,
if (!num_bytes)
return 0;
+ ret = btrfs_zoned_cap_metadata_reservation(space_info);
+ if (ret)
+ return ret;
+
ret = btrfs_reserve_metadata_bytes(space_info, num_bytes, flush);
if (ret)
return ret;
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 4c1fcf9a71a2..77249dcbd7b4 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -678,6 +678,14 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
* here.
*/
ret = btrfs_delayed_refs_rsv_refill(fs_info, flush);
+ if (ret == -EAGAIN) {
+ ASSERT(btrfs_is_zoned(fs_info));
+ ret = btrfs_commit_current_transaction(root);
+ if (ret)
+ goto reserve_fail;
+ ret = btrfs_delayed_refs_rsv_refill(fs_info, flush);
+ }
+
if (ret)
goto reserve_fail;
}