Commit 1cc52327 authored by stephen hemminger's avatar stephen hemminger Committed by David S. Miller

seq_file: add RCU versions of new hlist/list iterators (v3)

Many usages of seq_file use RCU protected lists, so non RCU
iterators will not work safely.
Signed-off-by: default avatarStephen Hemminger <shemminger@vyatta.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 35e2da46
...@@ -750,3 +750,74 @@ struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head, ...@@ -750,3 +750,74 @@ struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head,
return node->next; return node->next;
} }
EXPORT_SYMBOL(seq_hlist_next); EXPORT_SYMBOL(seq_hlist_next);
/**
* seq_hlist_start_rcu - start an iteration of a hlist protected by RCU
* @head: the head of the hlist
* @pos: the start position of the sequence
*
* Called at seq_file->op->start().
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as hlist_add_head_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
struct hlist_node *seq_hlist_start_rcu(struct hlist_head *head,
loff_t pos)
{
struct hlist_node *node;
__hlist_for_each_rcu(node, head)
if (pos-- == 0)
return node;
return NULL;
}
EXPORT_SYMBOL(seq_hlist_start_rcu);
/**
* seq_hlist_start_head_rcu - start an iteration of a hlist protected by RCU
* @head: the head of the hlist
* @pos: the start position of the sequence
*
* Called at seq_file->op->start(). Call this function if you want to
* print a header at the top of the output.
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as hlist_add_head_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head,
loff_t pos)
{
if (!pos)
return SEQ_START_TOKEN;
return seq_hlist_start_rcu(head, pos - 1);
}
EXPORT_SYMBOL(seq_hlist_start_head_rcu);
/**
* seq_hlist_next_rcu - move to the next position of the hlist protected by RCU
* @v: the current iterator
* @head: the head of the hlist
* @pos: the current posision
*
* Called at seq_file->op->next().
*
* This list-traversal primitive may safely run concurrently with
* the _rcu list-mutation primitives such as hlist_add_head_rcu()
* as long as the traversal is guarded by rcu_read_lock().
*/
struct hlist_node *seq_hlist_next_rcu(void *v,
struct hlist_head *head,
loff_t *ppos)
{
struct hlist_node *node = v;
++*ppos;
if (v == SEQ_START_TOKEN)
return rcu_dereference(head->first);
else
return rcu_dereference(node->next);
}
EXPORT_SYMBOL(seq_hlist_next_rcu);
...@@ -406,6 +406,11 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev, ...@@ -406,6 +406,11 @@ static inline void hlist_add_after_rcu(struct hlist_node *prev,
n->next->pprev = &n->next; n->next->pprev = &n->next;
} }
#define __hlist_for_each_rcu(pos, head) \
for (pos = rcu_dereference((head)->first); \
pos && ({ prefetch(pos->next); 1; }); \
pos = rcu_dereference(pos->next))
/** /**
* hlist_for_each_entry_rcu - iterate over rcu list of given type * hlist_for_each_entry_rcu - iterate over rcu list of given type
* @tpos: the type * to use as a loop cursor. * @tpos: the type * to use as a loop cursor.
......
...@@ -140,10 +140,17 @@ extern struct list_head *seq_list_next(void *v, struct list_head *head, ...@@ -140,10 +140,17 @@ extern struct list_head *seq_list_next(void *v, struct list_head *head,
*/ */
extern struct hlist_node *seq_hlist_start(struct hlist_head *head, extern struct hlist_node *seq_hlist_start(struct hlist_head *head,
loff_t pos); loff_t pos);
extern struct hlist_node *seq_hlist_start_head(struct hlist_head *head, extern struct hlist_node *seq_hlist_start_head(struct hlist_head *head,
loff_t pos); loff_t pos);
extern struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head, extern struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head,
loff_t *ppos); loff_t *ppos);
extern struct hlist_node *seq_hlist_start_rcu(struct hlist_head *head,
loff_t pos);
extern struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head,
loff_t pos);
extern struct hlist_node *seq_hlist_next_rcu(void *v,
struct hlist_head *head,
loff_t *ppos);
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment