block_rsv->full = (block_rsv->reserved == block_rsv->size);
- if (block_rsv->size >= sinfo->total_bytes)
+ /*
+ * The global reserve must be backed by space a tree block can
+ * actually land in. Under stripe_meta that excludes the bytes
+ * trapped in partially used stripes, so compare against the usable
+ * capacity, not the raw total, and force a chunk allocation as soon
+ * as the reserve would not fit in it.
+ */
+ if (block_rsv->size >= sinfo->total_bytes - sinfo->bytes_stripe_unusable)
sinfo->force_alloc = CHUNK_ALLOC_FORCE;
spin_unlock(&block_rsv->lock);
spin_unlock(&sinfo->lock);
btrfs_warn_rl(fs_info,
"stripe_alloc: data writeback allocation of %llu bytes returned ENOSPC despite reservation margin; buffered data in this range will be dropped",
num_bytes);
+ /*
+ * Metadata twin. A tree block reservation was admitted
+ * against the whole-stripe supply (trapped and open-run bytes
+ * count as used in the space_info), so a raid56 stripe_meta
+ * tree block should always find a whole stripe or an open
+ * run. If it does not, the transaction aborts: report the
+ * counters so the accounting hole can be identified.
+ */
+ if (!is_data && btrfs_test_opt(fs_info, STRIPE_ALLOC) &&
+ (flags & BTRFS_BLOCK_GROUP_RAID56_MASK)) {
+ struct btrfs_space_info *sinfo;
+
+ sinfo = btrfs_find_space_info(fs_info, flags);
+ if (sinfo)
+ btrfs_warn_rl(fs_info,
+ "stripe_meta: tree block allocation of %llu bytes returned ENOSPC: claimable %llu open %llu trapped %llu may_use %llu reserved %llu total %llu",
+ num_bytes,
+ sinfo->bytes_stripe_claimable,
+ sinfo->bytes_stripe_open,
+ sinfo->bytes_stripe_unusable,
+ sinfo->bytes_may_use,
+ sinfo->bytes_reserved,
+ sinfo->total_bytes);
+ }
}
return ret;