From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 819E01E2834 for ; Sat, 8 Aug 2026 15:48:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786204139; cv=none; b=WQjsxRKW1e3h2HEGDdxAC1YnqwTRW7r5zRv0scoAfHxmtkn9xu+MFcNEd1NFX3+qjkqE/iSY9vPxDBUJ8HRT9s8VhiA1+N0tor866iVRk3w4yrEGbU4ULHEGkgplwnvF5nyt8xP47MofO6yA5V7LNtqbtyOfm/Mtg9LHQBPLPbA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786204139; c=relaxed/simple; bh=r+FI3VHym/Ob9Apz5Lk5Drk30VsPRSTpVOd1vHzRcWI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RSnPqIPLb4VfXCSUrswEHszKnv20Yhb1NwfJrWuAq5G82e2jqHG6WBKEiuzA9KGZA9UB75ji/28EBomqCe4WCfDo8sJnjgm9Tw01aD0rlDiOZzYetGGys6/voxykL3hWRfPOb6KUvNtoZb0ukhD0/9AzQlhJBf9b6xxA8OCCUDU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=BhLAVMks; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="BhLAVMks" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0ADED1F00A3D; Sat, 8 Aug 2026 15:48:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786204138; bh=e6fKIbnnaHheu7/HezUVwA/my7q+Lirh24IatlbRHFY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=BhLAVMksvTCG8bxqhd4EiT2z1ggCI98nLa03otKLHIsrjbCFGVqN8AqaokINwHFkM 05EX61pMWtehf6n3Qad9hUNFajGBjn0hArzEYxUUtJUT8H0BhU129cZtsZcjNEjwyo UFBfhsw7Vbx78Nkm1Keghwweg5ABAgjv+HVfMDn1ZMidp4oH/AyXL1JW0m5dUky9uT GHVsHlyHg5Iccuggt641XVGEe34qQRCjYwCJQIjpnVNupajWvCarpOruNhmCGzBKRl WRhPgIceXiSl6a36/gIm86VNd0zCNHwJZNImnneZoXjYgkhcb+UahpcVk7PJOQJxBw +RmtI7vpV+YUg== From: Sasha Levin To: stable@vger.kernel.org Cc: Christian Brauner , Sasha Levin Subject: [PATCH 6.12.y 6/6] super: fix emergency thaw deadlock on frozen block devices Date: Sat, 8 Aug 2026 11:48:52 -0400 Message-ID: <20260808154852.370323-6-sashal@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260808154852.370323-1-sashal@kernel.org> References: <2026072927-mom-flyover-909f@gregkh> <20260808154852.370323-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Christian Brauner [ Upstream commit 749d7aa0377aae32af8c0a4ad43371e7bf830ab5 ] do_thaw_all_callback() calls bdev_thaw() while holding sb->s_umount exclusively. If the block device was frozen via bdev_freeze() dropping the last block layer freeze reference calls fs_bdev_thaw() which reacquires s_umount: do_thaw_all_callback(sb) super_lock_excl(sb) # holds sb->s_umount bdev_thaw(sb->s_bdev) mutex_lock(&bdev->bd_fsfreeze_mutex) # bd_fsfreeze_count drops 1 -> 0 bd_holder_ops->thaw == fs_bdev_thaw get_bdev_super(bdev) bdev_super_lock(bdev, true) super_lock(sb, true) down_write(&sb->s_umount) # same task: deadlock The emergency thaw worker deadlocks against itself holding both s_umount and bd_fsfreeze_mutex. That fscks any subsequent unmount, freeze, or thaw of that filesystem and block device. [ 81.878470] sysrq: Show Blocked State [ 81.880140] task:kworker/0:1 state:D stack:0 pid:11 tgid:11 ppid:2 task_flags:0x4208060 flags:0x00080000 [ 81.884876] Workqueue: events do_thaw_all [ 81.886656] Call Trace: [ 81.887759] [ 81.888763] __schedule+0x579/0x1420 [ 81.890372] schedule+0x3a/0x100 [ 81.891794] schedule_preempt_disabled+0x15/0x30 [ 81.893848] rwsem_down_write_slowpath+0x1ea/0x900 [ 81.895191] ? __pfx_do_thaw_all_callback+0x10/0x10 [ 81.896528] down_write+0xbd/0xc0 [ 81.897505] super_lock+0x91/0x180 [ 81.898457] ? __mutex_lock+0xa99/0x1140 [ 81.900748] ? __mutex_unlock_slowpath+0x1f/0x400 [ 81.902069] bdev_super_lock+0x5b/0x150 [ 81.903132] get_bdev_super+0x10/0x60 [ 81.904042] fs_bdev_thaw+0x23/0xf0 [ 81.904755] bdev_thaw+0x82/0x100 [ 81.905484] do_thaw_all_callback+0x2c/0x50 [ 81.906298] __iterate_supers+0x5d/0x130 [ 81.907067] do_thaw_all+0x20/0x40 [ 81.907739] process_one_work+0x206/0x5e0 [ 81.908545] worker_thread+0x1e2/0x3c0 [ 81.909339] ? __pfx_worker_thread+0x10/0x10 [ 81.910171] kthread+0xf4/0x130 [ 81.910799] ? __pfx_kthread+0x10/0x10 [ 81.911528] ret_from_fork+0x2e2/0x3b0 [ 81.912259] ? __pfx_kthread+0x10/0x10 [ 81.913010] ret_from_fork_asm+0x1a/0x30 [ 81.913806] bdev_super_lock() even documents the violated requirement with lockdep_assert_not_held(&sb->s_umount). Acquiring bd_fsfreeze_mutex under s_umount also inverts the bd_fsfreeze_mutex vs. s_umount ordering established by bdev_{freeze,thaw}() and can thus ABBA against a concurrent block-layer freeze even when the recursive path isn't hit. Fix this by not holding s_umount around the bdev_thaw() loop at all. Pin the superblock with an active reference instead as filesystems_freeze_callback() does. The active reference keeps the superblock from being shut down and so ->s_bdev stays valid without holding s_umount. The block-layer-held freeze is dropped by fs_bdev_thaw() with FREEZE_MAY_NEST | FREEZE_HOLDER_USERSPACE exactly as a regular unfreeze would and thaw_super_locked() handles filesystem-level freezes as before. The emergency thaw path has deadlocked like this in one form or another for a long long time but the current exclusively-held shape dates back to commit [1] where thaw_bdev() already ended in thaw_super() with s_umount held by do_thaw_all_callback(). Fixes: 08fdc8a0138a ("buffer.c: call thaw_super during emergency thaw") [1] Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260723-work-super-emergency_thaw-v1-1-7c315c600245@kernel.org Signed-off-by: Christian Brauner (Amutable) Signed-off-by: Sasha Levin --- fs/super.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/fs/super.c b/fs/super.c index fb047959526fd..2510de896ddad 100644 --- a/fs/super.c +++ b/fs/super.c @@ -1142,16 +1142,30 @@ void emergency_remount(void) } } +static inline bool get_active_super(struct super_block *sb) +{ + bool active = false; + + if (super_lock_excl(sb)) { + active = atomic_inc_not_zero(&sb->s_active); + super_unlock_excl(sb); + } + return active; +} + static void do_thaw_all_callback(struct super_block *sb, void *unused) { - if (!super_lock_excl(sb)) + if (!get_active_super(sb)) return; + /* fs_bdev_thaw() acquires s_umount so it must not be held here */ if (IS_ENABLED(CONFIG_BLOCK)) while (sb->s_bdev && !bdev_thaw(sb->s_bdev)) pr_warn("Emergency Thaw on %pg\n", sb->s_bdev); - thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE); + if (super_lock_excl(sb)) + thaw_super_locked(sb, FREEZE_HOLDER_USERSPACE); + deactivate_super(sb); } static void do_thaw_all(struct work_struct *work) -- 2.53.0