summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Leroy <christophe.leroy@c-s.fr>2019-08-21 11:05:55 -0400
committerDavid Sterba <dsterba@suse.com>2019-09-09 08:59:14 -0400
commit3acd48507dc43eeeb0a1fe965b8bad91cab904a7 (patch)
tree5dd3e0e79f99ed6e28f36dc267ae7c22dbcba542
parent62fdaa52a3d00a875da771719b6dc537ca79fce1 (diff)
btrfs: fix allocation of free space cache v1 bitmap pages
Various notifications of type "BUG kmalloc-4096 () : Redzone overwritten" have been observed recently in various parts of the kernel. After some time, it has been made a relation with the use of BTRFS filesystem and with SLUB_DEBUG turned on. [ 22.809700] BUG kmalloc-4096 (Tainted: G W ): Redzone overwritten [ 22.810286] INFO: 0xbe1a5921-0xfbfc06cd. First byte 0x0 instead of 0xcc [ 22.810866] INFO: Allocated in __load_free_space_cache+0x588/0x780 [btrfs] age=22 cpu=0 pid=224 [ 22.811193] __slab_alloc.constprop.26+0x44/0x70 [ 22.811345] kmem_cache_alloc_trace+0xf0/0x2ec [ 22.811588] __load_free_space_cache+0x588/0x780 [btrfs] [ 22.811848] load_free_space_cache+0xf4/0x1b0 [btrfs] [ 22.812090] cache_block_group+0x1d0/0x3d0 [btrfs] [ 22.812321] find_free_extent+0x680/0x12a4 [btrfs] [ 22.812549] btrfs_reserve_extent+0xec/0x220 [btrfs] [ 22.812785] btrfs_alloc_tree_block+0x178/0x5f4 [btrfs] [ 22.813032] __btrfs_cow_block+0x150/0x5d4 [btrfs] [ 22.813262] btrfs_cow_block+0x194/0x298 [btrfs] [ 22.813484] commit_cowonly_roots+0x44/0x294 [btrfs] [ 22.813718] btrfs_commit_transaction+0x63c/0xc0c [btrfs] [ 22.813973] close_ctree+0xf8/0x2a4 [btrfs] [ 22.814107] generic_shutdown_super+0x80/0x110 [ 22.814250] kill_anon_super+0x18/0x30 [ 22.814437] btrfs_kill_super+0x18/0x90 [btrfs] [ 22.814590] INFO: Freed in proc_cgroup_show+0xc0/0x248 age=41 cpu=0 pid=83 [ 22.814841] proc_cgroup_show+0xc0/0x248 [ 22.814967] proc_single_show+0x54/0x98 [ 22.815086] seq_read+0x278/0x45c [ 22.815190] __vfs_read+0x28/0x17c [ 22.815289] vfs_read+0xa8/0x14c [ 22.815381] ksys_read+0x50/0x94 [ 22.815475] ret_from_syscall+0x0/0x38 Commit 69d2480456d1 ("btrfs: use copy_page for copying pages instead of memcpy") changed the way bitmap blocks are copied. But allthough bitmaps have the size of a page, they were allocated with kzalloc(). Most of the time, kzalloc() allocates aligned blocks of memory, so copy_page() can be used. But when some debug options like SLAB_DEBUG are activated, kzalloc() may return unaligned pointer. On powerpc, memcpy(), copy_page() and other copying functions use 'dcbz' instruction which provides an entire zeroed cacheline to avoid memory read when the intention is to overwrite a full line. Functions like memcpy() are writen to care about partial cachelines at the start and end of the destination, but copy_page() assumes it gets pages. As pages are naturally cache aligned, copy_page() doesn't care about partial lines. This means that when copy_page() is called with a misaligned pointer, a few leading bytes are zeroed. To fix it, allocate bitmaps through kmem_cache instead of using kzalloc() The cache pool is created with PAGE_SIZE alignment constraint. Reported-by: Erhard F. <erhard_f@mailbox.org> Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=204371 Fixes: 69d2480456d1 ("btrfs: use copy_page for copying pages instead of memcpy") Cc: stable@vger.kernel.org # 4.19+ Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr> Reviewed-by: David Sterba <dsterba@suse.com> [ rename to btrfs_free_space_bitmap ] Signed-off-by: David Sterba <dsterba@suse.com>
-rw-r--r--fs/btrfs/ctree.h1
-rw-r--r--fs/btrfs/free-space-cache.c20
-rw-r--r--fs/btrfs/inode.c8
3 files changed, 22 insertions, 7 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index d27b39858339..ef40fffb5e46 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -43,6 +43,7 @@ extern struct kmem_cache *btrfs_trans_handle_cachep;
43extern struct kmem_cache *btrfs_bit_radix_cachep; 43extern struct kmem_cache *btrfs_bit_radix_cachep;
44extern struct kmem_cache *btrfs_path_cachep; 44extern struct kmem_cache *btrfs_path_cachep;
45extern struct kmem_cache *btrfs_free_space_cachep; 45extern struct kmem_cache *btrfs_free_space_cachep;
46extern struct kmem_cache *btrfs_free_space_bitmap_cachep;
46struct btrfs_ordered_sum; 47struct btrfs_ordered_sum;
47struct btrfs_ref; 48struct btrfs_ref;
48 49
diff --git a/fs/btrfs/free-space-cache.c b/fs/btrfs/free-space-cache.c
index 265dc75f7a7a..ab806d82fe12 100644
--- a/fs/btrfs/free-space-cache.c
+++ b/fs/btrfs/free-space-cache.c
@@ -765,7 +765,8 @@ static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode,
765 } else { 765 } else {
766 ASSERT(num_bitmaps); 766 ASSERT(num_bitmaps);
767 num_bitmaps--; 767 num_bitmaps--;
768 e->bitmap = kzalloc(PAGE_SIZE, GFP_NOFS); 768 e->bitmap = kmem_cache_zalloc(
769 btrfs_free_space_bitmap_cachep, GFP_NOFS);
769 if (!e->bitmap) { 770 if (!e->bitmap) {
770 kmem_cache_free( 771 kmem_cache_free(
771 btrfs_free_space_cachep, e); 772 btrfs_free_space_cachep, e);
@@ -1882,7 +1883,7 @@ static void free_bitmap(struct btrfs_free_space_ctl *ctl,
1882 struct btrfs_free_space *bitmap_info) 1883 struct btrfs_free_space *bitmap_info)
1883{ 1884{
1884 unlink_free_space(ctl, bitmap_info); 1885 unlink_free_space(ctl, bitmap_info);
1885 kfree(bitmap_info->bitmap); 1886 kmem_cache_free(btrfs_free_space_bitmap_cachep, bitmap_info->bitmap);
1886 kmem_cache_free(btrfs_free_space_cachep, bitmap_info); 1887 kmem_cache_free(btrfs_free_space_cachep, bitmap_info);
1887 ctl->total_bitmaps--; 1888 ctl->total_bitmaps--;
1888 ctl->op->recalc_thresholds(ctl); 1889 ctl->op->recalc_thresholds(ctl);
@@ -2136,7 +2137,8 @@ new_bitmap:
2136 } 2137 }
2137 2138
2138 /* allocate the bitmap */ 2139 /* allocate the bitmap */
2139 info->bitmap = kzalloc(PAGE_SIZE, GFP_NOFS); 2140 info->bitmap = kmem_cache_zalloc(btrfs_free_space_bitmap_cachep,
2141 GFP_NOFS);
2140 spin_lock(&ctl->tree_lock); 2142 spin_lock(&ctl->tree_lock);
2141 if (!info->bitmap) { 2143 if (!info->bitmap) {
2142 ret = -ENOMEM; 2144 ret = -ENOMEM;
@@ -2147,7 +2149,9 @@ new_bitmap:
2147 2149
2148out: 2150out:
2149 if (info) { 2151 if (info) {
2150 kfree(info->bitmap); 2152 if (info->bitmap)
2153 kmem_cache_free(btrfs_free_space_bitmap_cachep,
2154 info->bitmap);
2151 kmem_cache_free(btrfs_free_space_cachep, info); 2155 kmem_cache_free(btrfs_free_space_cachep, info);
2152 } 2156 }
2153 2157
@@ -2811,7 +2815,8 @@ out:
2811 if (entry->bytes == 0) { 2815 if (entry->bytes == 0) {
2812 ctl->free_extents--; 2816 ctl->free_extents--;
2813 if (entry->bitmap) { 2817 if (entry->bitmap) {
2814 kfree(entry->bitmap); 2818 kmem_cache_free(btrfs_free_space_bitmap_cachep,
2819 entry->bitmap);
2815 ctl->total_bitmaps--; 2820 ctl->total_bitmaps--;
2816 ctl->op->recalc_thresholds(ctl); 2821 ctl->op->recalc_thresholds(ctl);
2817 } 2822 }
@@ -3615,7 +3620,7 @@ again:
3615 } 3620 }
3616 3621
3617 if (!map) { 3622 if (!map) {
3618 map = kzalloc(PAGE_SIZE, GFP_NOFS); 3623 map = kmem_cache_zalloc(btrfs_free_space_bitmap_cachep, GFP_NOFS);
3619 if (!map) { 3624 if (!map) {
3620 kmem_cache_free(btrfs_free_space_cachep, info); 3625 kmem_cache_free(btrfs_free_space_cachep, info);
3621 return -ENOMEM; 3626 return -ENOMEM;
@@ -3644,7 +3649,8 @@ again:
3644 3649
3645 if (info) 3650 if (info)
3646 kmem_cache_free(btrfs_free_space_cachep, info); 3651 kmem_cache_free(btrfs_free_space_cachep, info);
3647 kfree(map); 3652 if (map)
3653 kmem_cache_free(btrfs_free_space_bitmap_cachep, map);
3648 return 0; 3654 return 0;
3649} 3655}
3650 3656
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index b52282df8c4d..d79ad5abd06e 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -74,6 +74,7 @@ static struct kmem_cache *btrfs_inode_cachep;
74struct kmem_cache *btrfs_trans_handle_cachep; 74struct kmem_cache *btrfs_trans_handle_cachep;
75struct kmem_cache *btrfs_path_cachep; 75struct kmem_cache *btrfs_path_cachep;
76struct kmem_cache *btrfs_free_space_cachep; 76struct kmem_cache *btrfs_free_space_cachep;
77struct kmem_cache *btrfs_free_space_bitmap_cachep;
77 78
78static int btrfs_setsize(struct inode *inode, struct iattr *attr); 79static int btrfs_setsize(struct inode *inode, struct iattr *attr);
79static int btrfs_truncate(struct inode *inode, bool skip_writeback); 80static int btrfs_truncate(struct inode *inode, bool skip_writeback);
@@ -9409,6 +9410,7 @@ void __cold btrfs_destroy_cachep(void)
9409 kmem_cache_destroy(btrfs_trans_handle_cachep); 9410 kmem_cache_destroy(btrfs_trans_handle_cachep);
9410 kmem_cache_destroy(btrfs_path_cachep); 9411 kmem_cache_destroy(btrfs_path_cachep);
9411 kmem_cache_destroy(btrfs_free_space_cachep); 9412 kmem_cache_destroy(btrfs_free_space_cachep);
9413 kmem_cache_destroy(btrfs_free_space_bitmap_cachep);
9412} 9414}
9413 9415
9414int __init btrfs_init_cachep(void) 9416int __init btrfs_init_cachep(void)
@@ -9438,6 +9440,12 @@ int __init btrfs_init_cachep(void)
9438 if (!btrfs_free_space_cachep) 9440 if (!btrfs_free_space_cachep)
9439 goto fail; 9441 goto fail;
9440 9442
9443 btrfs_free_space_bitmap_cachep = kmem_cache_create("btrfs_free_space_bitmap",
9444 PAGE_SIZE, PAGE_SIZE,
9445 SLAB_RED_ZONE, NULL);
9446 if (!btrfs_free_space_bitmap_cachep)
9447 goto fail;
9448
9441 return 0; 9449 return 0;
9442fail: 9450fail:
9443 btrfs_destroy_cachep(); 9451 btrfs_destroy_cachep();