From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756833Ab1ANK6Z (ORCPT ); Fri, 14 Jan 2011 05:58:25 -0500 Received: from caramon.arm.linux.org.uk ([78.32.30.218]:49530 "EHLO caramon.arm.linux.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751570Ab1ANK6T (ORCPT ); Fri, 14 Jan 2011 05:58:19 -0500 Date: Fri, 14 Jan 2011 10:58:08 +0000 From: Russell King To: linux-kernel@vger.kernel.org, Nick Piggin , Linus Torvalds Subject: BUG: __d_rehash explodes on boot Message-ID: <20110114105808.GA619@flint.arm.linux.org.uk> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.5.18 (2008-05-17) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org __d_rehash is dereferencing an almost-NULL pointer on my ARM926. CONFIG_SMP=n and CONFIG_DEBUG_SPINLOCK=y. The faulting instruction is: strne r3, [r2, #4] and as can be seen from the register dump below, r2 is 0x00000001, hence the faulting 0x00000005 address. __d_rehash is essentially: spin_lock_bucket(b); entry->d_flags &= ~DCACHE_UNHASHED; hlist_bl_add_head_rcu(&entry->d_hash, &b->head); spin_unlock_bucket(b); which is: bit_spin_lock(0, (unsigned long *)&b->head.first); entry->d_flags &= ~DCACHE_UNHASHED; hlist_bl_add_head_rcu(&entry->d_hash, &b->head); __bit_spin_unlock(0, (unsigned long *)&b->head.first); bit_spin_lock(0, ptr) sets bit 0 of *ptr, in this case b->head.first if CONFIG_SMP or CONFIG_DEBUG_SPINLOCK is set: #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) while (unlikely(test_and_set_bit_lock(bitnum, addr))) { while (test_bit(bitnum, addr)) { preempt_enable(); cpu_relax(); preempt_disable(); } } #endif So, b->head.first starts off NULL, and becomes a non-NULL (address 1). hlist_bl_add_head_rcu() does this: static inline void hlist_bl_add_head_rcu(struct hlist_bl_node *n, struct hlist_bl_head *h) { first = hlist_bl_first(h); n->next = first; if (first) first->pprev = &n->next; It is the store to first->pprev which is faulting. hlist_bl_first(): static inline struct hlist_bl_node *hlist_bl_first(struct hlist_bl_head *h) { return (struct hlist_bl_node *) ((unsigned long)h->first & ~LIST_BL_LOCKMASK); } but: #if defined(CONFIG_SMP) #define LIST_BL_LOCKMASK 1UL #else #define LIST_BL_LOCKMASK 0UL #endif So, we have one piece of code which sets bit 0 of addresses, and another bit of code which doesn't clear it before dereferencing the pointer if !CONFIG_SMP && CONFIG_DEBUG_SPINLOCK. With the patch below, I can again sucessfully boot the kernel on my Versatile PB/926 platform. Kernel messages: ... Calibrating delay loop... 104.24 BogoMIPS (lpj=521216) pid_max: default: 32768 minimum: 301 Mount-cache hash table entries: 512 CPU: Testing write buffer coherency: ok Unhandled fault: alignment exception (0x801) at 0x00000005 Internal error: : 801 [#1] last sysfs file: Modules linked in: CPU: 0 Not tainted (2.6.37+ #533) PC is at __d_rehash+0x74/0xb8 LR is at _d_rehash+0x4c/0x60 pc : [] lr : [] psr: 20000013 sp : c183fd18 ip : c09cb8c0 fp : c183fd24 r10: c183fdd8 r9 : c183fdec r8 : c183fde4 r7 : c1401940 r6 : c183fe7c r5 : c1401710 r4 : c14016c0 r3 : c14016c8 r2 : 00000001 r1 : 20000013 r0 : c14016c0 Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 0005317f Table: 00004000 DAC: 00000017 Process kworker/u:0 (pid: 9, stack limit = 0xc183e270) Stack: (0xc183fd18 to 0xc1840000) Backtrace: [] (__d_rehash+0x0/0xb8) from [] (_d_rehash+0x4c/0x60) [] (_d_rehash+0x0/0x60) from [] (d_rehash+0x24/0x30) [] (d_rehash+0x0/0x30) from [] (simple_lookup+0x44/0x50) [] (simple_lookup+0x0/0x50) from [] (d_alloc_and_lookup+0x50/0x6c) [] (d_alloc_and_lookup+0x0/0x6c) from [] (do_lookup+0x1b8/0x278) [] (do_lookup+0x0/0x278) from [] (link_path_walk+0x210/0xbec) [] (link_path_walk+0x0/0xbec) from [] (do_path_lookup+0x44/0xd0) [] (do_path_lookup+0x0/0xd0) from [] (do_filp_open+0xe4/0x5f8) [] (do_filp_open+0x0/0x5f8) from [] (open_exec+0x2c/0x90) [] (open_exec+0x0/0x90) from [] (do_execve+0x88/0x264) [] (do_execve+0x0/0x264) from [] (kernel_execve+0x40/0x88) [] (kernel_execve+0x0/0x88) from [] (____call_usermodehelper+0x88/0x98) [] (____call_usermodehelper+0x0/0x98) from [] (do_exit+0x0/0x5f8) Code: e59c2000 e3520000 12803008 e5802008 (15823004) ---[ end trace 1b75b31a2719ed1c ]--- Signed-off-by: Russell King --- include/linux/list_bl.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/include/linux/list_bl.h b/include/linux/list_bl.h index b2adbb4..5bad17d 100644 --- a/include/linux/list_bl.h +++ b/include/linux/list_bl.h @@ -16,7 +16,7 @@ * some fast and compact auxiliary data. */ -#if defined(CONFIG_SMP) +#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) #define LIST_BL_LOCKMASK 1UL #else #define LIST_BL_LOCKMASK 0UL -- Russell King Linux kernel 2.6 ARM Linux - http://www.arm.linux.org.uk/ maintainer of: