aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorFilipe David Borba Manana <fdmanana@gmail.com>2014-01-11 21:22:46 -0500
committerChris Mason <clm@fb.com>2014-01-28 16:20:31 -0500
commit14a958e678cd77cae475b60ca46c0797b1c006a1 (patch)
tree94bf5974065fc34d230e5c036b14f611389d621b /fs/btrfs
parentc57c2b3ed248b3f1712e4172eb85b361199582f2 (diff)
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>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/Kconfig3
-rw-r--r--fs/btrfs/Makefile2
-rw-r--r--fs/btrfs/extent-tree.c6
-rw-r--r--fs/btrfs/hash.c50
-rw-r--r--fs/btrfs/hash.h11
-rw-r--r--fs/btrfs/super.c10
6 files changed, 73 insertions, 9 deletions
diff --git a/fs/btrfs/Kconfig b/fs/btrfs/Kconfig
index aa976eced2d2..a66768ebc8d1 100644
--- a/fs/btrfs/Kconfig
+++ b/fs/btrfs/Kconfig
@@ -1,6 +1,7 @@
1config BTRFS_FS 1config BTRFS_FS
2 tristate "Btrfs filesystem support" 2 tristate "Btrfs filesystem support"
3 select LIBCRC32C 3 select CRYPTO
4 select CRYPTO_CRC32C
4 select ZLIB_INFLATE 5 select ZLIB_INFLATE
5 select ZLIB_DEFLATE 6 select ZLIB_DEFLATE
6 select LZO_COMPRESS 7 select LZO_COMPRESS
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index af7f000e905c..f341a98031d2 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -9,7 +9,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
9 export.o tree-log.o free-space-cache.o zlib.o lzo.o \ 9 export.o tree-log.o free-space-cache.o zlib.o lzo.o \
10 compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ 10 compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
11 reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \ 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
14btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o 14btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
15btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o 15btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index b5322596d60b..db1e32ffcfbb 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1074,11 +1074,11 @@ static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)
1074 __le64 lenum; 1074 __le64 lenum;
1075 1075
1076 lenum = cpu_to_le64(root_objectid); 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 lenum = cpu_to_le64(owner); 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 lenum = cpu_to_le64(offset); 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 return ((u64)high_crc << 31) ^ (u64)low_crc; 1083 return ((u64)high_crc << 31) ^ (u64)low_crc;
1084} 1084}
diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c
new file mode 100644
index 000000000000..85889aa82c62
--- /dev/null
+++ b/fs/btrfs/hash.c
@@ -0,0 +1,50 @@
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
18static struct crypto_shash *tfm;
19
20int __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
29void btrfs_hash_exit(void)
30{
31 crypto_free_shash(tfm);
32}
33
34u32 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}
diff --git a/fs/btrfs/hash.h b/fs/btrfs/hash.h
index 1d982812ab67..118a2316e5d3 100644
--- a/fs/btrfs/hash.h
+++ b/fs/btrfs/hash.h
@@ -19,10 +19,15 @@
19#ifndef __HASH__ 19#ifndef __HASH__
20#define __HASH__ 20#define __HASH__
21 21
22#include <linux/crc32c.h> 22int __init btrfs_hash_init(void);
23
24void btrfs_hash_exit(void);
25
26u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length);
27
23static inline u64 btrfs_name_hash(const char *name, int len) 28static 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/*
@@ -31,7 +36,7 @@ static inline u64 btrfs_name_hash(const char *name, int len)
31static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name, 36static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name,
32 int len) 37 int len)
33{ 38{
34 return (u64) crc32c(parent_objectid, name, len); 39 return (u64) btrfs_crc32c(parent_objectid, name, len);
35} 40}
36 41
37#endif 42#endif
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 461e41cb8ca7..f44cc6a0eb27 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -48,6 +48,7 @@
48#include "transaction.h" 48#include "transaction.h"
49#include "btrfs_inode.h" 49#include "btrfs_inode.h"
50#include "print-tree.h" 50#include "print-tree.h"
51#include "hash.h"
51#include "props.h" 52#include "props.h"
52#include "xattr.h" 53#include "xattr.h"
53#include "volumes.h" 54#include "volumes.h"
@@ -1866,11 +1867,15 @@ static int __init init_btrfs_fs(void)
1866{ 1867{
1867 int err; 1868 int err;
1868 1869
1870 err = btrfs_hash_init();
1871 if (err)
1872 return err;
1873
1869 btrfs_props_init(); 1874 btrfs_props_init();
1870 1875
1871 err = btrfs_init_sysfs(); 1876 err = btrfs_init_sysfs();
1872 if (err) 1877 if (err)
1873 return err; 1878 goto free_hash;
1874 1879
1875 btrfs_init_compress(); 1880 btrfs_init_compress();
1876 1881
@@ -1945,6 +1950,8 @@ free_cachep:
1945free_compress: 1950free_compress:
1946 btrfs_exit_compress(); 1951 btrfs_exit_compress();
1947 btrfs_exit_sysfs(); 1952 btrfs_exit_sysfs();
1953free_hash:
1954 btrfs_hash_exit();
1948 return err; 1955 return err;
1949} 1956}
1950 1957
@@ -1963,6 +1970,7 @@ static void __exit exit_btrfs_fs(void)
1963 btrfs_exit_sysfs(); 1970 btrfs_exit_sysfs();
1964 btrfs_cleanup_fs_uuids(); 1971 btrfs_cleanup_fs_uuids();
1965 btrfs_exit_compress(); 1972 btrfs_exit_compress();
1973 btrfs_hash_exit();
1966} 1974}
1967 1975
1968module_init(init_btrfs_fs) 1976module_init(init_btrfs_fs)