In the Linux kernel, the following vulnerability has been resolved:
btrfs: zoned: fix deadlock between metadata writeback and transaction commit
When writing out metadata extent buffers in a zoned filesystem, btreewritepages() holds fsinfo->zonedmetaiolock across the whole writeback loop, including the call to btrfscheckmetawritepointer() -> checkbgisactive().
For the tree-log block group, checkbgisactive() may fail to activate the zone and fall back to btrfszonefinishonebg() to free an active zone. That path waits for the running transaction to commit while still holding zonedmetaiolock, but the committer needs that same lock to write out the tree extents, so the two tasks deadlock:
Task A (kworker, metadata writeback) Task B (fsstress, transaction commit) ------------------------------------ ------------------------------------- wbworkfn() btrfscommittransaction(T) btreewritepages() btrfswriteandwaittransaction() btrfszonedmetaiolock() btrfswritemarkedextents() btrfscheckmetawritepointer() btreewritepages() checkbgisactive() [treelogbg] btrfszonedmetaiolock() btrfszonefinishonebg() <blocks on zonedmetaiolock, btrfszonefinish() held by Task A> dozonefinish() btrfsincblockgroupro() btrfswaitforcommit() <blocks waiting for commit of transaction T, done by Task B>
The sibling branch in checkbgisactive() already drops zonedmetaiolock around dozonefinish() for this exact reason. Do the same in the tree-log branch: release the lock around btrfszonefinishonebg() and re-acquire it afterwards. The lock only protects fsinfo->active{meta,system}bg, which this branch does not touch, and ctx->zonedbg keeps a reference to the block group across the unlock, so nothing is lost while the lock is dropped.
This hang occasionally reproduces with fstests generic/475 on a zoned btrfs filesystem.