]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
fs: Handle multiply claimed blocks more gracefully with mmb
authorJan Kara <jack@suse.cz>
Thu, 23 Apr 2026 09:03:12 +0000 (11:03 +0200)
committerChristian Brauner <brauner@kernel.org>
Thu, 23 Apr 2026 22:34:59 +0000 (00:34 +0200)
When a metadata block is referenced by multiple inodes and tracked by
metadata bh infrastructure (which is forbidden and generally indicates
filesystem corruption), it can happen that mmb_mark_buffer_dirty() is
called for two different mmb structures in parallel. This can lead to a
corruption of mmb linked list. Handle that situation gracefully (at
least from mmb POV) by serializing on setting bh->b_mmb.

Reported-by: Ruikai Peng <ruikai@pwno.io>
Signed-off-by: Jan Kara <jack@suse.cz>
Link: https://patch.msgid.link/20260423090311.10955-2-jack@suse.cz
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/buffer.c

index e6980dab1a7f76a49782eccf4d3de6fbafa211a2..770a5d89277c03d8e822c4cfa4dc69be68d32d6c 100644 (file)
@@ -719,8 +719,15 @@ void mmb_mark_buffer_dirty(struct buffer_head *bh,
        mark_buffer_dirty(bh);
        if (!bh->b_mmb) {
                spin_lock(&mmb->lock);
+               /*
+                * For a corrupted filesystem with multiply claimed blocks this
+                * can fail. Avoid corrupting the linked list in that case.
+                */
+               if (cmpxchg(&bh->b_mmb, NULL, mmb) != NULL) {
+                       spin_unlock(&mmb->lock);
+                       return;
+               }
                list_move_tail(&bh->b_assoc_buffers, &mmb->list);
-               bh->b_mmb = mmb;
                spin_unlock(&mmb->lock);
        }
 }