Commit 1cc523271ef0b6305c565a143e3d48f6fff826dd

Authored by stephen hemminger
Committed by David S. Miller
1 parent 35e2da46d2

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: Stephen Hemminger <shemminger@vyatta.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 3 changed files with 87 additions and 4 deletions Side-by-side Diff

... ... @@ -750,4 +750,75 @@
750 750 return node->next;
751 751 }
752 752 EXPORT_SYMBOL(seq_hlist_next);
  753 +
  754 +/**
  755 + * seq_hlist_start_rcu - start an iteration of a hlist protected by RCU
  756 + * @head: the head of the hlist
  757 + * @pos: the start position of the sequence
  758 + *
  759 + * Called at seq_file->op->start().
  760 + *
  761 + * This list-traversal primitive may safely run concurrently with
  762 + * the _rcu list-mutation primitives such as hlist_add_head_rcu()
  763 + * as long as the traversal is guarded by rcu_read_lock().
  764 + */
  765 +struct hlist_node *seq_hlist_start_rcu(struct hlist_head *head,
  766 + loff_t pos)
  767 +{
  768 + struct hlist_node *node;
  769 +
  770 + __hlist_for_each_rcu(node, head)
  771 + if (pos-- == 0)
  772 + return node;
  773 + return NULL;
  774 +}
  775 +EXPORT_SYMBOL(seq_hlist_start_rcu);
  776 +
  777 +/**
  778 + * seq_hlist_start_head_rcu - start an iteration of a hlist protected by RCU
  779 + * @head: the head of the hlist
  780 + * @pos: the start position of the sequence
  781 + *
  782 + * Called at seq_file->op->start(). Call this function if you want to
  783 + * print a header at the top of the output.
  784 + *
  785 + * This list-traversal primitive may safely run concurrently with
  786 + * the _rcu list-mutation primitives such as hlist_add_head_rcu()
  787 + * as long as the traversal is guarded by rcu_read_lock().
  788 + */
  789 +struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head,
  790 + loff_t pos)
  791 +{
  792 + if (!pos)
  793 + return SEQ_START_TOKEN;
  794 +
  795 + return seq_hlist_start_rcu(head, pos - 1);
  796 +}
  797 +EXPORT_SYMBOL(seq_hlist_start_head_rcu);
  798 +
  799 +/**
  800 + * seq_hlist_next_rcu - move to the next position of the hlist protected by RCU
  801 + * @v: the current iterator
  802 + * @head: the head of the hlist
  803 + * @pos: the current posision
  804 + *
  805 + * Called at seq_file->op->next().
  806 + *
  807 + * This list-traversal primitive may safely run concurrently with
  808 + * the _rcu list-mutation primitives such as hlist_add_head_rcu()
  809 + * as long as the traversal is guarded by rcu_read_lock().
  810 + */
  811 +struct hlist_node *seq_hlist_next_rcu(void *v,
  812 + struct hlist_head *head,
  813 + loff_t *ppos)
  814 +{
  815 + struct hlist_node *node = v;
  816 +
  817 + ++*ppos;
  818 + if (v == SEQ_START_TOKEN)
  819 + return rcu_dereference(head->first);
  820 + else
  821 + return rcu_dereference(node->next);
  822 +}
  823 +EXPORT_SYMBOL(seq_hlist_next_rcu);
include/linux/rculist.h
... ... @@ -406,6 +406,11 @@
406 406 n->next->pprev = &n->next;
407 407 }
408 408  
  409 +#define __hlist_for_each_rcu(pos, head) \
  410 + for (pos = rcu_dereference((head)->first); \
  411 + pos && ({ prefetch(pos->next); 1; }); \
  412 + pos = rcu_dereference(pos->next))
  413 +
409 414 /**
410 415 * hlist_for_each_entry_rcu - iterate over rcu list of given type
411 416 * @tpos: the type * to use as a loop cursor.
include/linux/seq_file.h
... ... @@ -140,11 +140,18 @@
140 140 */
141 141  
142 142 extern struct hlist_node *seq_hlist_start(struct hlist_head *head,
143   - loff_t pos);
  143 + loff_t pos);
144 144 extern struct hlist_node *seq_hlist_start_head(struct hlist_head *head,
145   - loff_t pos);
  145 + loff_t pos);
146 146 extern struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head,
147   - loff_t *ppos);
  147 + loff_t *ppos);
148 148  
  149 +extern struct hlist_node *seq_hlist_start_rcu(struct hlist_head *head,
  150 + loff_t pos);
  151 +extern struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head,
  152 + loff_t pos);
  153 +extern struct hlist_node *seq_hlist_next_rcu(void *v,
  154 + struct hlist_head *head,
  155 + loff_t *ppos);
149 156 #endif