Home Home > GIT Browse
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2014-08-21 17:46:35 +0200
committerTakashi Iwai <tiwai@suse.de>2014-08-21 17:46:35 +0200
commit8fc81d38d8b63789858468f74d67d86ddb96d14e (patch)
tree0926a7b89aefa63d7bce0654fb789d4188b1496a
parent9040052da41fc60a266cc730712a3da3d0d438eb (diff)
parentb1e2a41334dd869dafec719326c2664b8c152129 (diff)
Merge remote-tracking branch 'origin/master' into stable
-rw-r--r--patches.fixes/Btrfs-Fix-memory-corruption-by-ulist_add_merge-on-32114
-rwxr-xr-xrpm/compress-vmlinux.sh5
-rw-r--r--rpm/kernel-binary.spec.in2
-rw-r--r--series.conf1
4 files changed, 121 insertions, 1 deletions
diff --git a/patches.fixes/Btrfs-Fix-memory-corruption-by-ulist_add_merge-on-32 b/patches.fixes/Btrfs-Fix-memory-corruption-by-ulist_add_merge-on-32
new file mode 100644
index 0000000000..ae163986e3
--- /dev/null
+++ b/patches.fixes/Btrfs-Fix-memory-corruption-by-ulist_add_merge-on-32
@@ -0,0 +1,114 @@
+From 4eb1f66dce6c4dc28dd90a7ffbe6b2b1cb08aa4e Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 28 Jul 2014 10:57:04 +0200
+Subject: [PATCH] Btrfs: Fix memory corruption by ulist_add_merge() on 32bit arch
+Git-commit: 4eb1f66dce6c4dc28dd90a7ffbe6b2b1cb08aa4e
+Patch-mainline: 3.17-rc1
+References: bnc#887046
+
+We've got bug reports that btrfs crashes when quota is enabled on
+32bit kernel, typically with the Oops like below:
+ BUG: unable to handle kernel NULL pointer dereference at 00000004
+ IP: [<f9234590>] find_parent_nodes+0x360/0x1380 [btrfs]
+ *pde = 00000000
+ Oops: 0000 [#1] SMP
+ CPU: 0 PID: 151 Comm: kworker/u8:2 Tainted: G S W 3.15.2-1.gd43d97e-default #1
+ Workqueue: btrfs-qgroup-rescan normal_work_helper [btrfs]
+ task: f1478130 ti: f147c000 task.ti: f147c000
+ EIP: 0060:[<f9234590>] EFLAGS: 00010213 CPU: 0
+ EIP is at find_parent_nodes+0x360/0x1380 [btrfs]
+ EAX: f147dda8 EBX: f147ddb0 ECX: 00000011 EDX: 00000000
+ ESI: 00000000 EDI: f147dda4 EBP: f147ddf8 ESP: f147dd38
+ DS: 007b ES: 007b FS: 00d8 GS: 00e0 SS: 0068
+ CR0: 8005003b CR2: 00000004 CR3: 00bf3000 CR4: 00000690
+ Stack:
+ 00000000 00000000 f147dda4 00000050 00000001 00000000 00000001 00000050
+ 00000001 00000000 d3059000 00000001 00000022 000000a8 00000000 00000000
+ 00000000 000000a1 00000000 00000000 00000001 00000000 00000000 11800000
+ Call Trace:
+ [<f923564d>] __btrfs_find_all_roots+0x9d/0xf0 [btrfs]
+ [<f9237bb1>] btrfs_qgroup_rescan_worker+0x401/0x760 [btrfs]
+ [<f9206148>] normal_work_helper+0xc8/0x270 [btrfs]
+ [<c025e38b>] process_one_work+0x11b/0x390
+ [<c025eea1>] worker_thread+0x101/0x340
+ [<c026432b>] kthread+0x9b/0xb0
+ [<c0712a71>] ret_from_kernel_thread+0x21/0x30
+ [<c0264290>] kthread_create_on_node+0x110/0x110
+
+This indicates a NULL corruption in prefs_delayed list. The further
+investigation and bisection pointed that the call of ulist_add_merge()
+results in the corruption.
+
+ulist_add_merge() takes u64 as aux and writes a 64bit value into
+old_aux. The callers of this function in backref.c, however, pass a
+pointer of a pointer to old_aux. That is, the function overwrites
+64bit value on 32bit pointer. This caused a NULL in the adjacent
+variable, in this case, prefs_delayed.
+
+Here is a quick attempt to band-aid over this: a new function,
+ulist_add_merge_ptr() is introduced to pass/store properly a pointer
+value instead of u64. There are still ugly void ** cast remaining
+in the callers because void ** cannot be taken implicitly. But, it's
+safer than explicit cast to u64, anyway.
+
+Bugzilla: https://bugzilla.novell.com/show_bug.cgi?id=887046
+Cc: <stable@vger.kernel.org> [v3.11+]
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Chris Mason <clm@fb.com>
+
+---
+ fs/btrfs/backref.c | 11 +++++------
+ fs/btrfs/ulist.h | 15 +++++++++++++++
+ 2 files changed, 20 insertions(+), 6 deletions(-)
+
+--- a/fs/btrfs/backref.c
++++ b/fs/btrfs/backref.c
+@@ -276,9 +276,8 @@ static int add_all_parents(struct btrfs_
+ }
+ if (ret > 0)
+ goto next;
+- ret = ulist_add_merge(parents, eb->start,
+- (uintptr_t)eie,
+- (u64 *)&old, GFP_NOFS);
++ ret = ulist_add_merge_ptr(parents, eb->start,
++ eie, (void **)&old, GFP_NOFS);
+ if (ret < 0)
+ break;
+ if (!ret && extent_item_pos) {
+@@ -1008,9 +1007,9 @@ again:
+ goto out;
+ ref->inode_list = eie;
+ }
+- ret = ulist_add_merge(refs, ref->parent,
+- (uintptr_t)ref->inode_list,
+- (u64 *)&eie, GFP_NOFS);
++ ret = ulist_add_merge_ptr(refs, ref->parent,
++ ref->inode_list,
++ (void **)&eie, GFP_NOFS);
+ if (ret < 0)
+ goto out;
+ if (!ret && extent_item_pos) {
+--- a/fs/btrfs/ulist.h
++++ b/fs/btrfs/ulist.h
+@@ -57,6 +57,21 @@ void ulist_free(struct ulist *ulist);
+ int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask);
+ int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
+ u64 *old_aux, gfp_t gfp_mask);
++
++/* just like ulist_add_merge() but take a pointer for the aux data */
++static inline int ulist_add_merge_ptr(struct ulist *ulist, u64 val, void *aux,
++ void **old_aux, gfp_t gfp_mask)
++{
++#if BITS_PER_LONG == 32
++ u64 old64 = (uintptr_t)*old_aux;
++ int ret = ulist_add_merge(ulist, val, (uintptr_t)aux, &old64, gfp_mask);
++ *old_aux = (void *)((uintptr_t)old64);
++ return ret;
++#else
++ return ulist_add_merge(ulist, val, (u64)aux, (u64 *)old_aux, gfp_mask);
++#endif
++}
++
+ struct ulist_node *ulist_next(struct ulist *ulist,
+ struct ulist_iterator *uiter);
+
diff --git a/rpm/compress-vmlinux.sh b/rpm/compress-vmlinux.sh
index 840ae6ee7f..f5afa33d50 100755
--- a/rpm/compress-vmlinux.sh
+++ b/rpm/compress-vmlinux.sh
@@ -2,6 +2,11 @@
set -x
+# Once the brp script is reasonably widespread, we will remove the specfile
+# hack and this script
+if test -x /usr/lib/rpm/brp-suse.d/brp-99-compress-vmlinux; then
+ exit 0
+fi
vmlinux=$1
if test -e "$vmlinux" -a -e "$vmlinux.gz"; then
# Deliberately not using gzip -n; the vmlinux image has a predictable
diff --git a/rpm/kernel-binary.spec.in b/rpm/kernel-binary.spec.in
index 5dd74f927d..f928045d91 100644
--- a/rpm/kernel-binary.spec.in
+++ b/rpm/kernel-binary.spec.in
@@ -688,7 +688,7 @@ if [ %CONFIG_MODULES = y ]; then
# Recreate the generated Makefile with correct path
sh ../scripts/mkmakefile ../../../linux-%kernelrelease%variant \
%rpm_install_dir/%cpu_arch_flavor \
- $(echo %srcversion | sed -r 's/^([0-9]+)\.([0-9]+)[\.-].*/\1 \2/')
+ $(echo %srcversion | sed -r 's/^([0-9]+)\.([0-9]+).*/\1 \2/')
fi
add_dirs_to_filelist() {
diff --git a/series.conf b/series.conf
index daa382d30e..405c863c5f 100644
--- a/series.conf
+++ b/series.conf
@@ -251,6 +251,7 @@
########################################################
patches.suse/btrfs-use-correct-device-for-maps.patch
patches.suse/btrfs-check-index-in-extent_buffer_page
+ patches.fixes/Btrfs-Fix-memory-corruption-by-ulist_add_merge-on-32
########################################################
# Reiserfs Patches