Files
kernel-tenderloin-3.0/include/linux
Russell King 32385c7cf6 kernel: fix hlist_bl again
__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.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
2011-01-14 13:12:45 +00:00
..
2010-11-15 20:44:26 -05:00
2010-10-30 08:31:35 -07:00
2010-10-15 21:18:59 +02:00
2010-12-11 01:28:58 -05:00
2010-10-30 08:45:43 -04:00
2010-11-10 14:54:09 +01:00
2010-11-10 14:54:09 +01:00
2010-12-13 16:11:13 -08:00
2010-10-25 21:18:20 -04:00
2010-10-25 08:02:40 -07:00
2011-01-07 17:50:32 +11:00
2010-10-22 15:55:22 +02:00
2010-10-21 14:47:59 +02:00
2010-09-23 14:33:39 -07:00
2010-11-17 14:55:45 +09:00
2011-01-07 17:50:27 +11:00
2011-01-07 17:50:31 +11:00
2011-01-07 17:50:23 +11:00
2010-10-25 14:11:37 -07:00
2010-10-23 22:49:32 +02:00
2010-10-12 16:53:37 +02:00
2010-11-15 22:40:38 +01:00
2010-11-15 22:40:38 +01:00
2010-09-21 18:04:47 -07:00
2010-09-30 21:16:05 -07:00
2010-10-26 16:52:08 -07:00
2010-10-07 14:08:55 +01:00
2010-10-28 17:22:13 -04:00
2010-10-22 15:34:12 -05:00
2010-12-22 10:27:53 +01:00
2010-11-12 07:55:32 -08:00
2010-11-16 13:33:23 -08:00
2011-01-14 13:12:45 +00:00
2010-10-25 21:24:15 -04:00
2010-10-28 09:08:47 -05:00
2010-10-26 16:52:05 -07:00
2011-01-07 17:50:33 +11:00
2010-10-12 16:53:34 +02:00
2011-01-07 17:50:27 +11:00
2010-10-04 21:10:52 +02:00
2011-01-07 17:50:19 +11:00
2010-10-07 18:48:49 -04:00
2010-10-15 12:45:44 +02:00
2011-01-07 17:50:33 +11:00
2010-10-17 20:03:03 -07:00
2010-10-17 20:03:06 -07:00
2010-10-24 15:07:11 -07:00
2010-11-12 07:55:32 -08:00
2010-10-29 04:16:31 -04:00
2011-01-14 02:36:43 +00:00
2010-10-27 18:03:16 -07:00
2011-01-07 17:50:27 +11:00
2010-10-30 12:12:50 +02:00
2011-01-07 17:50:27 +11:00
2010-10-20 03:02:23 -07:00
2010-10-27 17:28:36 +01:00
2010-10-07 14:08:55 +01:00
2010-09-24 21:27:41 -07:00
2010-10-21 04:11:07 -07:00
2010-10-22 10:20:04 -07:00
2010-10-26 16:52:03 -07:00
2010-10-26 16:52:14 -07:00