summaryrefslogtreecommitdiff
path: root/include/xen
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-03-09 19:38:41 +0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2013-03-15 00:18:30 +0400
commitf65846a1800ef8c48d1ae1973c30dae4c356a800 (patch)
tree87bd07485309f57d4002a5cd634636e9a2ce3025 /include/xen
parentf6161aa153581da4a3867a2d1a7caf4be19b6ec9 (diff)
downloadlinux-f65846a1800ef8c48d1ae1973c30dae4c356a800.tar.xz
list: Fix double fetch of pointer in hlist_entry_safe()
The current version of hlist_entry_safe() fetches the pointer twice, once to test for NULL and the other to compute the offset back to the enclosing structure. This is OK for normal lock-based use because in that case, the pointer cannot change. However, when the pointer is protected by RCU (as in "rcu_dereference(p)"), then the pointer can change at any time. This use case can result in the following sequence of events: 1. CPU 0 invokes hlist_entry_safe(), fetches the RCU-protected pointer as sees that it is non-NULL. 2. CPU 1 invokes hlist_del_rcu(), deleting the entry that CPU 0 just fetched a pointer to. Because this is the last entry in the list, the pointer fetched by CPU 0 is now NULL. 3. CPU 0 refetches the pointer, obtains NULL, and then gets a NULL-pointer crash. This commit therefore applies gcc's "({ })" statement expression to create a temporary variable so that the specified pointer is fetched only once, avoiding the above sequence of events. Please note that it is the caller's responsibility to use rcu_dereference() as needed. This allows RCU-protected uses to work correctly without imposing any additional overhead on the non-RCU case. Many thanks to Eric Dumazet for spotting root cause! Reported-by: CAI Qian <caiqian@redhat.com> Reported-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Tested-by: Li Zefan <lizefan@huawei.com>
Diffstat (limited to 'include/xen')
0 files changed, 0 insertions, 0 deletions