<feed xmlns='http://www.w3.org/2005/Atom'>
<title>linux-toradex.git/include/linux/list_bl.h, branch v2.6.38.8</title>
<subtitle>Linux kernel for Apalis and Colibri modules</subtitle>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/'/>
<entry>
<title>kernel: fix hlist_bl again</title>
<updated>2011-01-14T13:12:45+00:00</updated>
<author>
<name>Russell King</name>
<email>rmk+kernel@arm.linux.org.uk</email>
</author>
<published>2011-01-14T13:12:45+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=32385c7cf60a78375b63afc4f02001df84dfd1a0'/>
<id>32385c7cf60a78375b63afc4f02001df84dfd1a0</id>
<content type='text'>
__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-&gt;d_flags &amp;= ~DCACHE_UNHASHED;
       hlist_bl_add_head_rcu(&amp;entry-&gt;d_hash, &amp;b-&gt;head);
       spin_unlock_bucket(b);

which is:

       bit_spin_lock(0, (unsigned long *)&amp;b-&gt;head.first);
       entry-&gt;d_flags &amp;= ~DCACHE_UNHASHED;
       hlist_bl_add_head_rcu(&amp;entry-&gt;d_hash, &amp;b-&gt;head);
       __bit_spin_unlock(0, (unsigned long *)&amp;b-&gt;head.first);

bit_spin_lock(0, ptr) sets bit 0 of *ptr, in this case b-&gt;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-&gt;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-&gt;next = first;
       if (first)
               first-&gt;pprev = &amp;n-&gt;next;

It is the store to first-&gt;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-&gt;first &amp; ~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 &amp;&amp; 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 &lt;rmk+kernel@arm.linux.org.uk&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
__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-&gt;d_flags &amp;= ~DCACHE_UNHASHED;
       hlist_bl_add_head_rcu(&amp;entry-&gt;d_hash, &amp;b-&gt;head);
       spin_unlock_bucket(b);

which is:

       bit_spin_lock(0, (unsigned long *)&amp;b-&gt;head.first);
       entry-&gt;d_flags &amp;= ~DCACHE_UNHASHED;
       hlist_bl_add_head_rcu(&amp;entry-&gt;d_hash, &amp;b-&gt;head);
       __bit_spin_unlock(0, (unsigned long *)&amp;b-&gt;head.first);

bit_spin_lock(0, ptr) sets bit 0 of *ptr, in this case b-&gt;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-&gt;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-&gt;next = first;
       if (first)
               first-&gt;pprev = &amp;n-&gt;next;

It is the store to first-&gt;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-&gt;first &amp; ~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 &amp;&amp; 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 &lt;rmk+kernel@arm.linux.org.uk&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>fs: hlist UP debug fixup</title>
<updated>2011-01-14T02:36:43+00:00</updated>
<author>
<name>Nick Piggin</name>
<email>npiggin@kernel.dk</email>
</author>
<published>2011-01-14T02:36:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=2c6755988afc003a0332406a134fb6a1626f9b28'/>
<id>2c6755988afc003a0332406a134fb6a1626f9b28</id>
<content type='text'>
Po-Yu Chuang &lt;ratbert.chuang@gmail.com&gt; noticed that hlist_bl_set_first could
crash on a UP system when LIST_BL_LOCKMASK is 0, because

	LIST_BL_BUG_ON(!((unsigned long)h-&gt;first &amp; LIST_BL_LOCKMASK));

always evaulates to true.

Fix the expression, and also avoid a dependency between bit spinlock
implementation and list bl code (list code shouldn't know anything
except that bit 0 is set when adding and removing elements). Eventually
if a good use case comes up, we might use this list to store 1 or more
arbitrary bits of data, so it really shouldn't be tied to locking either,
but for now they are helpful for debugging.

Signed-off-by: Nick Piggin &lt;npiggin@kernel.dk&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Po-Yu Chuang &lt;ratbert.chuang@gmail.com&gt; noticed that hlist_bl_set_first could
crash on a UP system when LIST_BL_LOCKMASK is 0, because

	LIST_BL_BUG_ON(!((unsigned long)h-&gt;first &amp; LIST_BL_LOCKMASK));

always evaulates to true.

Fix the expression, and also avoid a dependency between bit spinlock
implementation and list bl code (list code shouldn't know anything
except that bit 0 is set when adding and removing elements). Eventually
if a good use case comes up, we might use this list to store 1 or more
arbitrary bits of data, so it really shouldn't be tied to locking either,
but for now they are helpful for debugging.

Signed-off-by: Nick Piggin &lt;npiggin@kernel.dk&gt;
</pre>
</div>
</content>
</entry>
<entry>
<title>kernel: add bl_list</title>
<updated>2011-01-07T06:50:31+00:00</updated>
<author>
<name>Nick Piggin</name>
<email>npiggin@kernel.dk</email>
</author>
<published>2011-01-07T06:50:03+00:00</published>
<link rel='alternate' type='text/html' href='https://git.toradex.cn/cgit/linux-toradex.git/commit/?id=4e35e6070b1ceed89c3bba2af4216c286fb1dafd'/>
<id>4e35e6070b1ceed89c3bba2af4216c286fb1dafd</id>
<content type='text'>
Introduce a type of hlist that can support the use of the lowest bit in the
hlist_head. This will be subsequently used to implement per-bucket bit spinlock
for inode and dentry hashes, and may be useful in other cases such as network
hashes.

Reviewed-by: Paul E. McKenney &lt;paulmck@linux.vnet.ibm.com&gt;
Signed-off-by: Nick Piggin &lt;npiggin@kernel.dk&gt;
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Introduce a type of hlist that can support the use of the lowest bit in the
hlist_head. This will be subsequently used to implement per-bucket bit spinlock
for inode and dentry hashes, and may be useful in other cases such as network
hashes.

Reviewed-by: Paul E. McKenney &lt;paulmck@linux.vnet.ibm.com&gt;
Signed-off-by: Nick Piggin &lt;npiggin@kernel.dk&gt;
</pre>
</div>
</content>
</entry>
</feed>
