From: Christian Brauner Date: Thu, 25 Jun 2026 11:32:51 +0000 (+0200) Subject: Merge patch series "block,btrfs: fix frozen-superblock strand on device add/remove... X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=d152447614265750ead57816e2cc63c6116e35ec;p=thirdparty%2Flinux.git Merge patch series "block,btrfs: fix frozen-superblock strand on device add/remove/replace" Christian Brauner says: block,btrfs: fix frozen-superblock strand on device add/remove/replace This is another series of fixes that fell out of the device to superblock hashtable work. These are all pre-existing bugs. A block-device freeze that races a btrfs device membership change can leave the whole filesystem stuck frozen, recoverable only with a manual FITHAW. btrfs holds each of its devices open with the superblock as the block-device holder. bdev_freeze() - issued by "dmsetup suspend" or an LVM snapshot - resolves that holder to freeze the filesystem, and bdev_thaw() ("dmsetup resume") resolves it again to thaw. If a freeze lands while btrfs is adding, removing or replacing a device, it rides in on the device's holder link and freezes the filesystem; the membership change then drops that link, so the matching thaw can no longer find the superblock. The filesystem stays frozen with no way back short of FITHAW. To reproduce on the remove path: build a two-device btrfs with one member behind a dm-linear target, write enough data that removing that member relocates for a few seconds, start "btrfs device remove" on it, and "dmsetup suspend" the dm device while the removal is underway. The suspend's freeze blocks on the remove ioctl's write access and rides in as the ioctl drops it; the removal then clears the device's holder link, so the matching "dmsetup resume" can no longer reach the superblock. On an unpatched kernel the filesystem is left frozen and the next write hangs in D state until a manual FITHAW (fsfreeze -u). The fix lets a filesystem forbid freezing a device for the duration of a membership change, modelled on deny_write_access()/allow_write_access(). bd_fsfreeze_count becomes signed: > 0 counts active freezes, < 0 counts deny holders, and the two are mutually exclusive. bdev_deny_freeze() reserves the device (bdev_freeze() then returns -EBUSY) and bdev_allow_freeze() releases it; both are a single lockless atomic, so a filesystem can deny under s_umount without inverting against bdev_freeze()'s bd_fsfreeze_mutex. btrfs denies the device across each add, remove and replace, so a racing freeze is refused instead of riding in, while a normal freeze of a settled member still works. To re-allow freezing safely on release, bdev_yield_claim() is split out of bdev_fput(): the caller yields the holder while the device file is still open, re-allows freezing on the now-holderless device, and only then closes it. Re-allowing after the holder is gone avoids re-stranding on a racing freeze; doing it while the file is still open keeps the block device alive without referencing it after the final fput. With the fix the racing suspend is refused with -EBUSY mid-removal and the filesystem stays writable. * patches from https://patch.msgid.link/20260616-work-super-freeze_deny_upstream-v2-0-b3567c7f994b@kernel.org: btrfs: deny freezing devices undergoing a replace btrfs: deny freezing a device while it is being added btrfs: deny freezing a device while it is being removed block: split bdev_yield_claim() out of bdev_fput() block: allow making a block device unfreezable Link: https://patch.msgid.link/20260616-work-super-freeze_deny_upstream-v2-0-b3567c7f994b@kernel.org Signed-off-by: Christian Brauner (Amutable) --- d152447614265750ead57816e2cc63c6116e35ec