[RFC - PATCH] btrfs: do not write corrupted metadata blocks to disk

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



csum_dirty_buffer was issuing a warning in case the extent buffer
did not look alright, but was still returning success.
Let's return error in this case, and also add two additional sanity
checks on the extent buffer header.

We had btrfs metadata corruption, and after looking at the logs we saw
that WARN_ON(found_start != start) has been triggered. We are still investigating
which component trashed the cache page which belonged to btrfs. But btrfs
only issued a warning, and as a result, the corrupted metadata block went to disk.

I think we should return an error in such case that the extent buffer doesn't look alright. The caller up the chain may BUG_ON on this, for example flush_epd_write_bio will,
but it is better than to have a silent metadata corruption on disk.

Note: this patch has been properly tested on 3.18 kernel only.

Signed-off-by: Alex Lyakas <alex@xxxxxxxxxxxxxxxxx>
---
fs/btrfs/disk-io.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 4545e2e..701e706 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -508,22 +508,32 @@ static int csum_dirty_buffer(struct btrfs_fs_info *fs_info, struct page *page)
{
    u64 start = page_offset(page);
    u64 found_start;
    struct extent_buffer *eb;

    eb = (struct extent_buffer *)page->private;
    if (page != eb->pages[0])
        return 0;
    found_start = btrfs_header_bytenr(eb);
    if (WARN_ON(found_start != start || !PageUptodate(page)))
-        return 0;
-    csum_tree_block(fs_info, eb, 0);
+        return -EUCLEAN;
+#ifdef CONFIG_BTRFS_ASSERT
+    if (WARN_ON(memcmp_extent_buffer(eb, fs_info->fsid,
+                    (unsigned long)btrfs_header_fsid(), BTRFS_FSID_SIZE)))
+        return -EUCLEAN;
+    if (WARN_ON(memcmp_extent_buffer(eb, fs_info->fsid,
+                    (unsigned long)btrfs_header_chunk_tree_uuid(eb),
+                    BTRFS_FSID_SIZE)))
+        return -EUCLEAN;
+#endif
+    if (csum_tree_block(fs_info, eb, 0))
+        return -EUCLEAN;
    return 0;
}

static int check_tree_block_fsid(struct btrfs_fs_info *fs_info,
                 struct extent_buffer *eb)
{
    struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
    u8 fsid[BTRFS_UUID_SIZE];
    int ret = 1;

--
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux