Branch data Line data Source code
1 : : #ifndef _LINUX_RCULIST_NULLS_H
2 : : #define _LINUX_RCULIST_NULLS_H
3 : :
4 : : #ifdef __KERNEL__
5 : :
6 : : /*
7 : : * RCU-protected list version
8 : : */
9 : : #include <linux/list_nulls.h>
10 : : #include <linux/rcupdate.h>
11 : :
12 : : /**
13 : : * hlist_nulls_del_init_rcu - deletes entry from hash list with re-initialization
14 : : * @n: the element to delete from the hash list.
15 : : *
16 : : * Note: hlist_nulls_unhashed() on the node return true after this. It is
17 : : * useful for RCU based read lockfree traversal if the writer side
18 : : * must know if the list entry is still hashed or already unhashed.
19 : : *
20 : : * In particular, it means that we can not poison the forward pointers
21 : : * that may still be used for walking the hash list and we can only
22 : : * zero the pprev pointer so list_unhashed() will return true after
23 : : * this.
24 : : *
25 : : * The caller must take whatever precautions are necessary (such as
26 : : * holding appropriate locks) to avoid racing with another
27 : : * list-mutation primitive, such as hlist_nulls_add_head_rcu() or
28 : : * hlist_nulls_del_rcu(), running on this same list. However, it is
29 : : * perfectly legal to run concurrently with the _rcu list-traversal
30 : : * primitives, such as hlist_nulls_for_each_entry_rcu().
31 : : */
32 : 102 : static inline void hlist_nulls_del_init_rcu(struct hlist_nulls_node *n)
33 : : {
34 [ + - ][ + - ]: 229 : if (!hlist_nulls_unhashed(n)) {
[ + - + - ]
35 : : __hlist_nulls_del(n);
36 : 229 : n->pprev = NULL;
37 : : }
38 : : }
39 : :
40 : : #define hlist_nulls_first_rcu(head) \
41 : : (*((struct hlist_nulls_node __rcu __force **)&(head)->first))
42 : :
43 : : #define hlist_nulls_next_rcu(node) \
44 : : (*((struct hlist_nulls_node __rcu __force **)&(node)->next))
45 : :
46 : : /**
47 : : * hlist_nulls_del_rcu - deletes entry from hash list without re-initialization
48 : : * @n: the element to delete from the hash list.
49 : : *
50 : : * Note: hlist_nulls_unhashed() on entry does not return true after this,
51 : : * the entry is in an undefined state. It is useful for RCU based
52 : : * lockfree traversal.
53 : : *
54 : : * In particular, it means that we can not poison the forward
55 : : * pointers that may still be used for walking the hash list.
56 : : *
57 : : * The caller must take whatever precautions are necessary
58 : : * (such as holding appropriate locks) to avoid racing
59 : : * with another list-mutation primitive, such as hlist_nulls_add_head_rcu()
60 : : * or hlist_nulls_del_rcu(), running on this same list.
61 : : * However, it is perfectly legal to run concurrently with
62 : : * the _rcu list-traversal primitives, such as
63 : : * hlist_nulls_for_each_entry().
64 : : */
65 : : static inline void hlist_nulls_del_rcu(struct hlist_nulls_node *n)
66 : : {
67 : : __hlist_nulls_del(n);
68 : 16 : n->pprev = LIST_POISON2;
69 : : }
70 : :
71 : : /**
72 : : * hlist_nulls_add_head_rcu
73 : : * @n: the element to add to the hash list.
74 : : * @h: the list to add to.
75 : : *
76 : : * Description:
77 : : * Adds the specified element to the specified hlist_nulls,
78 : : * while permitting racing traversals.
79 : : *
80 : : * The caller must take whatever precautions are necessary
81 : : * (such as holding appropriate locks) to avoid racing
82 : : * with another list-mutation primitive, such as hlist_nulls_add_head_rcu()
83 : : * or hlist_nulls_del_rcu(), running on this same list.
84 : : * However, it is perfectly legal to run concurrently with
85 : : * the _rcu list-traversal primitives, such as
86 : : * hlist_nulls_for_each_entry_rcu(), used to prevent memory-consistency
87 : : * problems on Alpha CPUs. Regardless of the type of CPU, the
88 : : * list-traversal primitive must be guarded by rcu_read_lock().
89 : : */
90 : : static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n,
91 : : struct hlist_nulls_head *h)
92 : : {
93 : 245 : struct hlist_nulls_node *first = h->first;
94 : :
95 : 245 : n->next = first;
96 : 245 : n->pprev = &h->first;
97 : 245 : rcu_assign_pointer(hlist_nulls_first_rcu(h), n);
98 [ + + + + : 245 : if (!is_a_nulls(first))
+ + ]
99 : 18 : first->pprev = &n->next;
100 : : }
101 : : /**
102 : : * hlist_nulls_for_each_entry_rcu - iterate over rcu list of given type
103 : : * @tpos: the type * to use as a loop cursor.
104 : : * @pos: the &struct hlist_nulls_node to use as a loop cursor.
105 : : * @head: the head for your list.
106 : : * @member: the name of the hlist_nulls_node within the struct.
107 : : *
108 : : * The barrier() is needed to make sure compiler doesn't cache first element [1],
109 : : * as this loop can be restarted [2]
110 : : * [1] Documentation/atomic_ops.txt around line 114
111 : : * [2] Documentation/RCU/rculist_nulls.txt around line 146
112 : : */
113 : : #define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \
114 : : for (({barrier();}), \
115 : : pos = rcu_dereference_raw(hlist_nulls_first_rcu(head)); \
116 : : (!is_a_nulls(pos)) && \
117 : : ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1; }); \
118 : : pos = rcu_dereference_raw(hlist_nulls_next_rcu(pos)))
119 : :
120 : : #endif
121 : : #endif
|