)]}'
{
  "commit": "32385c7cf60a78375b63afc4f02001df84dfd1a0",
  "tree": "6419ac3c77cb38bac389e5efc59928e01780a2ae",
  "parents": [
    "3ec762ad8be364c2fadfe0d6b2cc6d4d3b5e1b54"
  ],
  "author": {
    "name": "Russell King",
    "email": "rmk+kernel@arm.linux.org.uk",
    "time": "Fri Jan 14 13:12:45 2011 +0000"
  },
  "committer": {
    "name": "Nick Piggin",
    "email": "npiggin@kernel.dk",
    "time": "Fri Jan 14 13:12:45 2011 +0000"
  },
  "message": "kernel: fix hlist_bl again\n\n__d_rehash is dereferencing an almost-NULL pointer on my ARM926.\nCONFIG_SMP\u003dn and CONFIG_DEBUG_SPINLOCK\u003dy.\n\nThe faulting instruction is:    strne   r3, [r2, #4]\nand as can be seen from the register dump below, r2 is 0x00000001, hence\nthe faulting 0x00000005 address.\n\n__d_rehash is essentially:\n\n       spin_lock_bucket(b);\n       entry-\u003ed_flags \u0026\u003d ~DCACHE_UNHASHED;\n       hlist_bl_add_head_rcu(\u0026entry-\u003ed_hash, \u0026b-\u003ehead);\n       spin_unlock_bucket(b);\n\nwhich is:\n\n       bit_spin_lock(0, (unsigned long *)\u0026b-\u003ehead.first);\n       entry-\u003ed_flags \u0026\u003d ~DCACHE_UNHASHED;\n       hlist_bl_add_head_rcu(\u0026entry-\u003ed_hash, \u0026b-\u003ehead);\n       __bit_spin_unlock(0, (unsigned long *)\u0026b-\u003ehead.first);\n\nbit_spin_lock(0, ptr) sets bit 0 of *ptr, in this case b-\u003ehead.first if\nCONFIG_SMP or CONFIG_DEBUG_SPINLOCK is set:\n\n#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)\n       while (unlikely(test_and_set_bit_lock(bitnum, addr))) {\n               while (test_bit(bitnum, addr)) {\n                       preempt_enable();\n                       cpu_relax();\n                       preempt_disable();\n               }\n       }\n#endif\n\nSo, b-\u003ehead.first starts off NULL, and becomes a non-NULL (address 1).\nhlist_bl_add_head_rcu() does this:\n\nstatic inline void hlist_bl_add_head_rcu(struct hlist_bl_node *n,\n                                       struct hlist_bl_head *h)\n{\n       first \u003d hlist_bl_first(h);\n       n-\u003enext \u003d first;\n       if (first)\n               first-\u003epprev \u003d \u0026n-\u003enext;\n\nIt is the store to first-\u003epprev which is faulting.\n\nhlist_bl_first():\n\nstatic inline struct hlist_bl_node *hlist_bl_first(struct hlist_bl_head *h)\n{\n       return (struct hlist_bl_node *)\n               ((unsigned long)h-\u003efirst \u0026 ~LIST_BL_LOCKMASK);\n}\n\nbut:\n#if defined(CONFIG_SMP)\n#define LIST_BL_LOCKMASK        1UL\n#else\n#define LIST_BL_LOCKMASK        0UL\n#endif\n\nSo, we have one piece of code which sets bit 0 of addresses, and another\nbit of code which doesn\u0027t clear it before dereferencing the pointer if\n!CONFIG_SMP \u0026\u0026 CONFIG_DEBUG_SPINLOCK.  With the patch below, I can again\nsucessfully boot the kernel on my Versatile PB/926 platform.\n\nSigned-off-by: Russell King \u003crmk+kernel@arm.linux.org.uk\u003e\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "b2adbb4b2f731f49d3b5f54918ef5b4a4508aa71",
      "old_mode": 33188,
      "old_path": "include/linux/list_bl.h",
      "new_id": "5bad17d1acdec6d386f6bf3d236c6900abb15ce8",
      "new_mode": 33188,
      "new_path": "include/linux/list_bl.h"
    }
  ]
}
