]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
ext4: clear buffer verified flag if read meta block from disk
authorzhangyi (F) <yi.zhang@huawei.com>
Thu, 24 Sep 2020 07:33:31 +0000 (15:33 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 5 Nov 2020 10:51:52 +0000 (11:51 +0100)
commit d9befedaafcf3a111428baa7c45b02923eab2d87 upstream.

The metadata buffer is no longer trusted after we read it from disk
again because it is not uptodate for some reasons (e.g. failed to write
back). Otherwise we may get below memory corruption problem in
ext4_ext_split()->memset() if we read stale data from the newly
allocated extent block on disk which has been failed to async write
out but miss verify again since the verified bit has already been set
on the buffer.

[   29.774674] BUG: unable to handle kernel paging request at ffff88841949d000
...
[   29.783317] Oops: 0002 [#2] SMP
[   29.784219] R10: 00000000000f4240 R11: 0000000000002e28 R12: ffff88842fa1c800
[   29.784627] CPU: 1 PID: 126 Comm: kworker/u4:3 Tainted: G      D W
[   29.785546] R13: ffffffff9cddcc20 R14: ffffffff9cddd420 R15: ffff88842fa1c2f8
[   29.786679] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996),BIOS ?-20190727_0738364
[   29.787588] FS:  0000000000000000(0000) GS:ffff88842fa00000(0000) knlGS:0000000000000000
[   29.789288] Workqueue: writeback wb_workfn
[   29.790319] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[   29.790321]  (flush-8:0)
[   29.790844] CR2: 0000000000000008 CR3: 00000004234f2000 CR4: 00000000000006f0
[   29.791924] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[   29.792839] RIP: 0010:__memset+0x24/0x30
[   29.793739] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[   29.794256] Code: 90 90 90 90 90 90 0f 1f 44 00 00 49 89 f9 48 89 d1 83 e2 07 48 c1 e9 033
[   29.795161] Kernel panic - not syncing: Fatal exception in interrupt
...
[   29.808149] Call Trace:
[   29.808475]  ext4_ext_insert_extent+0x102e/0x1be0
[   29.809085]  ext4_ext_map_blocks+0xa89/0x1bb0
[   29.809652]  ext4_map_blocks+0x290/0x8a0
[   29.809085]  ext4_ext_map_blocks+0xa89/0x1bb0
[   29.809652]  ext4_map_blocks+0x290/0x8a0
[   29.810161]  ext4_writepages+0xc85/0x17c0
...

Fix this by clearing buffer's verified bit if we read meta block from
disk again.

Signed-off-by: zhangyi (F) <yi.zhang@huawei.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20200924073337.861472-2-yi.zhang@huawei.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
fs/ext4/balloc.c
fs/ext4/extents.c
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/super.c

index 48c3df47748dbefc74669fb666356d57a6b61278..8e7e9715cde9c9f408057eaf7f67ada5b42f23bf 100644 (file)
@@ -494,6 +494,7 @@ ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group,
         * submit the buffer_head for reading
         */
        set_buffer_new(bh);
+       clear_buffer_verified(bh);
        trace_ext4_read_block_bitmap_load(sb, block_group, ignore_locked);
        bh->b_end_io = ext4_end_bitmap_read;
        get_bh(bh);
index a0481582187a35c42997caf4aa7ad9a4380fa8f6..0a5205edc00a8f2b14bb22ac74c38f7556d63596 100644 (file)
@@ -501,6 +501,7 @@ __read_extent_tree_block(const char *function, unsigned int line,
 
        if (!bh_uptodate_or_lock(bh)) {
                trace_ext4_ext_load_extent(inode, pblk, _RET_IP_);
+               clear_buffer_verified(bh);
                err = bh_submit_read(bh);
                if (err < 0)
                        goto errout;
index df25d38d65393ed1e88254a73104031886777dae..20cda952c62198bb20ea46d3182fb725d1f6664f 100644 (file)
@@ -188,6 +188,7 @@ ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group)
        /*
         * submit the buffer_head for reading
         */
+       clear_buffer_verified(bh);
        trace_ext4_load_inode_bitmap(sb, block_group);
        bh->b_end_io = ext4_end_bitmap_read;
        get_bh(bh);
index bbe95498f8f2dc2d6cfd309c2ed9bd97befe34f3..288704e9064b355a5c4f57eae08cfe724602ed18 100644 (file)
@@ -884,6 +884,7 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode,
                return bh;
        if (!bh || ext4_buffer_uptodate(bh))
                return bh;
+       clear_buffer_verified(bh);
        ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, &bh);
        wait_on_buffer(bh);
        if (buffer_uptodate(bh))
@@ -909,9 +910,11 @@ int ext4_bread_batch(struct inode *inode, ext4_lblk_t block, int bh_count,
 
        for (i = 0; i < bh_count; i++)
                /* Note that NULL bhs[i] is valid because of holes. */
-               if (bhs[i] && !ext4_buffer_uptodate(bhs[i]))
+               if (bhs[i] && !ext4_buffer_uptodate(bhs[i])) {
+                       clear_buffer_verified(bhs[i]);
                        ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1,
                                    &bhs[i]);
+               }
 
        if (!wait)
                return 0;
index 76291cd879a3737c1121dc16c854074da49602b8..265c75256989e21fd39b98421a3182c208bec8c0 100644 (file)
@@ -156,6 +156,7 @@ ext4_sb_bread(struct super_block *sb, sector_t block, int op_flags)
                return ERR_PTR(-ENOMEM);
        if (ext4_buffer_uptodate(bh))
                return bh;
+       clear_buffer_verified(bh);
        ll_rw_block(REQ_OP_READ, REQ_META | op_flags, 1, &bh);
        wait_on_buffer(bh);
        if (buffer_uptodate(bh))