Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0 */ 2 : : #ifndef _LINUX_RCULIST_BL_H 3 : : #define _LINUX_RCULIST_BL_H 4 : : 5 : : /* 6 : : * RCU-protected bl list version. See include/linux/list_bl.h. 7 : : */ 8 : : #include <linux/list_bl.h> 9 : : #include <linux/rcupdate.h> 10 : : 11 : 1648331 : static inline void hlist_bl_set_first_rcu(struct hlist_bl_head *h, 12 : : struct hlist_bl_node *n) 13 : : { 14 : 1648331 : LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK); 15 : : LIST_BL_BUG_ON(((unsigned long)h->first & LIST_BL_LOCKMASK) != 16 : 1648331 : LIST_BL_LOCKMASK); 17 : 1648331 : rcu_assign_pointer(h->first, 18 : : (struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK)); 19 : : } 20 : : 21 : 7698786 : static inline struct hlist_bl_node *hlist_bl_first_rcu(struct hlist_bl_head *h) 22 : : { 23 : 7698786 : return (struct hlist_bl_node *) 24 : 7698786 : ((unsigned long)rcu_dereference_check(h->first, hlist_bl_is_locked(h)) & ~LIST_BL_LOCKMASK); 25 : : } 26 : : 27 : : /** 28 : : * hlist_bl_del_rcu - deletes entry from hash list without re-initialization 29 : : * @n: the element to delete from the hash list. 30 : : * 31 : : * Note: hlist_bl_unhashed() on entry does not return true after this, 32 : : * the entry is in an undefined state. It is useful for RCU based 33 : : * lockfree traversal. 34 : : * 35 : : * In particular, it means that we can not poison the forward 36 : : * pointers that may still be used for walking the hash list. 37 : : * 38 : : * The caller must take whatever precautions are necessary 39 : : * (such as holding appropriate locks) to avoid racing 40 : : * with another list-mutation primitive, such as hlist_bl_add_head_rcu() 41 : : * or hlist_bl_del_rcu(), running on this same list. 42 : : * However, it is perfectly legal to run concurrently with 43 : : * the _rcu list-traversal primitives, such as 44 : : * hlist_bl_for_each_entry(). 45 : : */ 46 : : static inline void hlist_bl_del_rcu(struct hlist_bl_node *n) 47 : : { 48 : : __hlist_bl_del(n); 49 : : n->pprev = LIST_POISON2; 50 : : } 51 : : 52 : : /** 53 : : * hlist_bl_add_head_rcu 54 : : * @n: the element to add to the hash list. 55 : : * @h: the list to add to. 56 : : * 57 : : * Description: 58 : : * Adds the specified element to the specified hlist_bl, 59 : : * while permitting racing traversals. 60 : : * 61 : : * The caller must take whatever precautions are necessary 62 : : * (such as holding appropriate locks) to avoid racing 63 : : * with another list-mutation primitive, such as hlist_bl_add_head_rcu() 64 : : * or hlist_bl_del_rcu(), running on this same list. 65 : : * However, it is perfectly legal to run concurrently with 66 : : * the _rcu list-traversal primitives, such as 67 : : * hlist_bl_for_each_entry_rcu(), used to prevent memory-consistency 68 : : * problems on Alpha CPUs. Regardless of the type of CPU, the 69 : : * list-traversal primitive must be guarded by rcu_read_lock(). 70 : : */ 71 : 1648331 : static inline void hlist_bl_add_head_rcu(struct hlist_bl_node *n, 72 : : struct hlist_bl_head *h) 73 : : { 74 : 1648331 : struct hlist_bl_node *first; 75 : : 76 : : /* don't need hlist_bl_first_rcu because we're under lock */ 77 [ + + + + ]: 1648331 : first = hlist_bl_first(h); 78 : : 79 : 1648331 : n->next = first; 80 [ + + + + ]: 1648331 : if (first) 81 : 63259 : first->pprev = &n->next; 82 : 1648331 : n->pprev = &h->first; 83 : : 84 : : /* need _rcu because we can have concurrent lock free readers */ 85 : 1648331 : hlist_bl_set_first_rcu(h, n); 86 : : } 87 : : /** 88 : : * hlist_bl_for_each_entry_rcu - iterate over rcu list of given type 89 : : * @tpos: the type * to use as a loop cursor. 90 : : * @pos: the &struct hlist_bl_node to use as a loop cursor. 91 : : * @head: the head for your list. 92 : : * @member: the name of the hlist_bl_node within the struct. 93 : : * 94 : : */ 95 : : #define hlist_bl_for_each_entry_rcu(tpos, pos, head, member) \ 96 : : for (pos = hlist_bl_first_rcu(head); \ 97 : : pos && \ 98 : : ({ tpos = hlist_bl_entry(pos, typeof(*tpos), member); 1; }); \ 99 : : pos = rcu_dereference_raw(pos->next)) 100 : : 101 : : #endif