Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Btrfs: fix btrfs boot when compiled as built-in

After the change titled "Btrfs: add support for inode properties", if
btrfs was built-in the kernel (i.e. not as a module), it would cause a
kernel panic, as reported recently by Fengguang:

[ 2.024722] BUG: unable to handle kernel NULL pointer dereference at (null)
[ 2.027814] IP: [<ffffffff81501594>] crc32c+0xc/0x6b
[ 2.028684] PGD 0
[ 2.028684] Oops: 0000 [#1] SMP
[ 2.028684] Modules linked in:
[ 2.028684] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 3.13.0-rc7-04795-ga7b57c2 #1
[ 2.028684] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011
[ 2.028684] task: ffff88000edba100 ti: ffff88000edd6000 task.ti: ffff88000edd6000
[ 2.028684] RIP: 0010:[<ffffffff81501594>] [<ffffffff81501594>] crc32c+0xc/0x6b
[ 2.028684] RSP: 0000:ffff88000edd7e58 EFLAGS: 00010246
[ 2.028684] RAX: 0000000000000000 RBX: ffffffff82295550 RCX: 0000000000000000
[ 2.028684] RDX: 0000000000000011 RSI: ffffffff81efe393 RDI: 00000000fffffffe
[ 2.028684] RBP: ffff88000edd7e60 R08: 0000000000000003 R09: 0000000000015d20
[ 2.028684] R10: ffffffff81ef225e R11: ffffffff811b0222 R12: ffffffffffffffff
[ 2.028684] R13: 0000000000000239 R14: 0000000000000000 R15: 0000000000000000
[ 2.028684] FS: 0000000000000000(0000) GS:ffff88000fa00000(0000) knlGS:0000000000000000
[ 2.028684] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[ 2.028684] CR2: 0000000000000000 CR3: 000000000220c000 CR4: 00000000000006f0
[ 2.028684] Stack:
[ 2.028684] ffffffff82295550 ffff88000edd7e80 ffffffff8238af62 ffffffff8238ac05
[ 2.028684] 0000000000000000 ffff88000edd7e98 ffffffff8238ac0f ffffffff8238ac05
[ 2.028684] ffff88000edd7f08 ffffffff810002ba ffff88000edd7f00 ffffffff810e2404
[ 2.028684] Call Trace:
[ 2.028684] [<ffffffff8238af62>] btrfs_props_init+0x4f/0x96
[ 2.028684] [<ffffffff8238ac05>] ? ftrace_define_fields_btrfs_space_reservation+0x145/0x145
[ 2.028684] [<ffffffff8238ac0f>] init_btrfs_fs+0xa/0xf0
[ 2.028684] [<ffffffff8238ac05>] ? ftrace_define_fields_btrfs_space_reservation+0x145/0x145
[ 2.028684] [<ffffffff810002ba>] do_one_initcall+0xa4/0x13a
[ 2.028684] [<ffffffff810e2404>] ? parse_args+0x25f/0x33d
[ 2.028684] [<ffffffff8234cf75>] kernel_init_freeable+0x1aa/0x230
[ 2.028684] [<ffffffff8234c785>] ? do_early_param+0x88/0x88
[ 2.028684] [<ffffffff819f61b5>] ? rest_init+0x89/0x89
[ 2.028684] [<ffffffff819f61c3>] kernel_init+0xe/0x109

The issue here is that the initialization function of btrfs (super.c:init_btrfs_fs)
started using crc32c (from lib/libcrc32c.c). But when it needs to call crc32c (as
part of the properties initialization routine), the libcrc32c is not yet initialized,
so crc32c derreferenced a NULL pointer (lib/libcrc32c.c:tfm), causing the kernel
panic on boot.

The approach to fix this is to use crypto component directly to use its crc32c (which
is basically what lib/libcrc32c.c is, a wrapper around crypto). This is what ext4 is
doing as well, it uses crypto directly to get crc32c functionality.

Verified this works both when btrfs is built-in and when it's loadable kernel module.

Signed-off-by: Filipe David Borba Manana <fdmanana@gmail.com>
Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: Chris Mason <clm@fb.com>

authored by

Filipe David Borba Manana and committed by
Chris Mason
14a958e6 c57c2b3e

+73 -9
+2 -1
fs/btrfs/Kconfig
··· 1 1 config BTRFS_FS 2 2 tristate "Btrfs filesystem support" 3 - select LIBCRC32C 3 + select CRYPTO 4 + select CRYPTO_CRC32C 4 5 select ZLIB_INFLATE 5 6 select ZLIB_DEFLATE 6 7 select LZO_COMPRESS
+1 -1
fs/btrfs/Makefile
··· 9 9 export.o tree-log.o free-space-cache.o zlib.o lzo.o \ 10 10 compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ 11 11 reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \ 12 - uuid-tree.o props.o 12 + uuid-tree.o props.o hash.o 13 13 14 14 btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o 15 15 btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
+3 -3
fs/btrfs/extent-tree.c
··· 1074 1074 __le64 lenum; 1075 1075 1076 1076 lenum = cpu_to_le64(root_objectid); 1077 - high_crc = crc32c(high_crc, &lenum, sizeof(lenum)); 1077 + high_crc = btrfs_crc32c(high_crc, &lenum, sizeof(lenum)); 1078 1078 lenum = cpu_to_le64(owner); 1079 - low_crc = crc32c(low_crc, &lenum, sizeof(lenum)); 1079 + low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum)); 1080 1080 lenum = cpu_to_le64(offset); 1081 - low_crc = crc32c(low_crc, &lenum, sizeof(lenum)); 1081 + low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum)); 1082 1082 1083 1083 return ((u64)high_crc << 31) ^ (u64)low_crc; 1084 1084 }
+50
fs/btrfs/hash.c
··· 1 + /* 2 + * Copyright (C) 2014 Filipe David Borba Manana <fdmanana@gmail.com> 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public 6 + * License v2 as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 + * General Public License for more details. 12 + */ 13 + 14 + #include <crypto/hash.h> 15 + #include <linux/err.h> 16 + #include "hash.h" 17 + 18 + static struct crypto_shash *tfm; 19 + 20 + int __init btrfs_hash_init(void) 21 + { 22 + tfm = crypto_alloc_shash("crc32c", 0, 0); 23 + if (IS_ERR(tfm)) 24 + return PTR_ERR(tfm); 25 + 26 + return 0; 27 + } 28 + 29 + void btrfs_hash_exit(void) 30 + { 31 + crypto_free_shash(tfm); 32 + } 33 + 34 + u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length) 35 + { 36 + struct { 37 + struct shash_desc shash; 38 + char ctx[crypto_shash_descsize(tfm)]; 39 + } desc; 40 + int err; 41 + 42 + desc.shash.tfm = tfm; 43 + desc.shash.flags = 0; 44 + *(u32 *)desc.ctx = crc; 45 + 46 + err = crypto_shash_update(&desc.shash, address, length); 47 + BUG_ON(err); 48 + 49 + return *(u32 *)desc.ctx; 50 + }
+8 -3
fs/btrfs/hash.h
··· 19 19 #ifndef __HASH__ 20 20 #define __HASH__ 21 21 22 - #include <linux/crc32c.h> 22 + int __init btrfs_hash_init(void); 23 + 24 + void btrfs_hash_exit(void); 25 + 26 + u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length); 27 + 23 28 static inline u64 btrfs_name_hash(const char *name, int len) 24 29 { 25 - return crc32c((u32)~1, name, len); 30 + return btrfs_crc32c((u32)~1, name, len); 26 31 } 27 32 28 33 /* ··· 36 31 static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name, 37 32 int len) 38 33 { 39 - return (u64) crc32c(parent_objectid, name, len); 34 + return (u64) btrfs_crc32c(parent_objectid, name, len); 40 35 } 41 36 42 37 #endif
+9 -1
fs/btrfs/super.c
··· 48 48 #include "transaction.h" 49 49 #include "btrfs_inode.h" 50 50 #include "print-tree.h" 51 + #include "hash.h" 51 52 #include "props.h" 52 53 #include "xattr.h" 53 54 #include "volumes.h" ··· 1867 1866 { 1868 1867 int err; 1869 1868 1869 + err = btrfs_hash_init(); 1870 + if (err) 1871 + return err; 1872 + 1870 1873 btrfs_props_init(); 1871 1874 1872 1875 err = btrfs_init_sysfs(); 1873 1876 if (err) 1874 - return err; 1877 + goto free_hash; 1875 1878 1876 1879 btrfs_init_compress(); 1877 1880 ··· 1950 1945 free_compress: 1951 1946 btrfs_exit_compress(); 1952 1947 btrfs_exit_sysfs(); 1948 + free_hash: 1949 + btrfs_hash_exit(); 1953 1950 return err; 1954 1951 } 1955 1952 ··· 1970 1963 btrfs_exit_sysfs(); 1971 1964 btrfs_cleanup_fs_uuids(); 1972 1965 btrfs_exit_compress(); 1966 + btrfs_hash_exit(); 1973 1967 } 1974 1968 1975 1969 module_init(init_btrfs_fs)