Blame view

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