aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/rculist.h
diff options
context:
space:
mode:
authorPetko Manolov <petkan@mip-labs.com>2015-10-12 11:23:51 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2015-12-04 15:34:32 -0500
commit7d86dccf28a3ae2f790f399fc82d4c82521fd078 (patch)
tree4edd2478389ec0b6c31dcae73c62fdc875033004 /include/linux/rculist.h
parent1658d35ead5d8dd76f2b2d6ad0e32c08d123faa2 (diff)
list: Introduces generic list_splice_tail_init_rcu()
The list_splice_init_rcu() can be used as a stack onto which full lists are pushed, but queue-like behavior is now needed by some security policies. This requires a list_splice_tail_init_rcu(). This commit therefore supplies a list_splice_tail_init_rcu() by pulling code common it and to list_splice_init_rcu() into a new __list_splice_init_rcu() function. This new function is based on the existing list_splice_init_rcu() implementation. Signed-off-by: Petko Manolov <petkan@mip-labs.com> Cc: Mimi Zohar <zohar@linux.vnet.ibm.com> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'include/linux/rculist.h')
-rw-r--r--include/linux/rculist.h69
1 files changed, 49 insertions, 20 deletions
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index 5ed540986019..e99d834545b6 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -179,32 +179,31 @@ static inline void list_replace_rcu(struct list_head *old,
179} 179}
180 180
181/** 181/**
182 * list_splice_init_rcu - splice an RCU-protected list into an existing list. 182 * __list_splice_init_rcu - join an RCU-protected list into an existing list.
183 * @list: the RCU-protected list to splice 183 * @list: the RCU-protected list to splice
184 * @head: the place in the list to splice the first list into 184 * @prev: points to the last element of the existing list
185 * @next: points to the first element of the existing list
185 * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ... 186 * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ...
186 * 187 *
187 * @head can be RCU-read traversed concurrently with this function. 188 * The list pointed to by @prev and @next can be RCU-read traversed
189 * concurrently with this function.
188 * 190 *
189 * Note that this function blocks. 191 * Note that this function blocks.
190 * 192 *
191 * Important note: the caller must take whatever action is necessary to 193 * Important note: the caller must take whatever action is necessary to prevent
192 * prevent any other updates to @head. In principle, it is possible 194 * any other updates to the existing list. In principle, it is possible to
193 * to modify the list as soon as sync() begins execution. 195 * modify the list as soon as sync() begins execution. If this sort of thing
194 * If this sort of thing becomes necessary, an alternative version 196 * becomes necessary, an alternative version based on call_rcu() could be
195 * based on call_rcu() could be created. But only if -really- 197 * created. But only if -really- needed -- there is no shortage of RCU API
196 * needed -- there is no shortage of RCU API members. 198 * members.
197 */ 199 */
198static inline void list_splice_init_rcu(struct list_head *list, 200static inline void __list_splice_init_rcu(struct list_head *list,
199 struct list_head *head, 201 struct list_head *prev,
200 void (*sync)(void)) 202 struct list_head *next,
203 void (*sync)(void))
201{ 204{
202 struct list_head *first = list->next; 205 struct list_head *first = list->next;
203 struct list_head *last = list->prev; 206 struct list_head *last = list->prev;
204 struct list_head *at = head->next;
205
206 if (list_empty(list))
207 return;
208 207
209 /* 208 /*
210 * "first" and "last" tracking list, so initialize it. RCU readers 209 * "first" and "last" tracking list, so initialize it. RCU readers
@@ -231,10 +230,40 @@ static inline void list_splice_init_rcu(struct list_head *list,
231 * this function. 230 * this function.
232 */ 231 */
233 232
234 last->next = at; 233 last->next = next;
235 rcu_assign_pointer(list_next_rcu(head), first); 234 rcu_assign_pointer(list_next_rcu(prev), first);
236 first->prev = head; 235 first->prev = prev;
237 at->prev = last; 236 next->prev = last;
237}
238
239/**
240 * list_splice_init_rcu - splice an RCU-protected list into an existing list,
241 * designed for stacks.
242 * @list: the RCU-protected list to splice
243 * @head: the place in the existing list to splice the first list into
244 * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ...
245 */
246static inline void list_splice_init_rcu(struct list_head *list,
247 struct list_head *head,
248 void (*sync)(void))
249{
250 if (!list_empty(list))
251 __list_splice_init_rcu(list, head, head->next, sync);
252}
253
254/**
255 * list_splice_tail_init_rcu - splice an RCU-protected list into an existing
256 * list, designed for queues.
257 * @list: the RCU-protected list to splice
258 * @head: the place in the existing list to splice the first list into
259 * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ...
260 */
261static inline void list_splice_tail_init_rcu(struct list_head *list,
262 struct list_head *head,
263 void (*sync)(void))
264{
265 if (!list_empty(list))
266 __list_splice_init_rcu(list, head->prev, head, sync);
238} 267}
239 268
240/** 269/**