diff options
author | Petko Manolov <petkan@mip-labs.com> | 2015-10-12 11:23:51 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2015-12-04 15:34:32 -0500 |
commit | 7d86dccf28a3ae2f790f399fc82d4c82521fd078 (patch) | |
tree | 4edd2478389ec0b6c31dcae73c62fdc875033004 /include/linux/rculist.h | |
parent | 1658d35ead5d8dd76f2b2d6ad0e32c08d123faa2 (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.h | 69 |
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 | */ |
198 | static inline void list_splice_init_rcu(struct list_head *list, | 200 | static 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 | */ | ||
246 | static 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 | */ | ||
261 | static 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 | /** |