Improve list.h documentation for _rcu() primitives
RFC PATCH 1/1 Improve list.h documentation for _rcu() primitives
The attached patch improves the documentation of the _rcu list primitives, as suggested off-list.
Thanx, Paul
include/linux/list.h +73 -0
@@ -104,6 +104,14 @@* * Insert a new entry after the specified head. * This is good for implementing stacks. +* +* The caller must take whatever precautions are necessary +* (such as holding appropriate locks) to avoid racing +* with another list-mutation primitive, such as list_add_rcu() +* or list_del_rcu(), running on this same list. +* However, it is perfectly legal to race against any +* of the _rcu list-traversal primitives, such as +* list_for_each_entry_rcu(). */ static __inline__void list_add_rcu (struct list_head *new,struct list_head *head) {
@@ -117,6 +125,14 @@* * Insert a new entry before the specified head. * This is useful for implementing queues. +* +* The caller must take whatever precautions are necessary +* (such as holding appropriate locks) to avoid racing +* with another list-mutation primitive, such as list_add_tail_rcu() +* or list_del_rcu(), running on this same list. +* However, it is perfectly legal to race against any +* of the _rcu list-traversal primitives, such as +* list_for_each_entry_rcu(). */ static __inline__void list_add_tail_rcu (struct list_head *new,struct list_head *head) {
@@ -159,6 +175,19 @@* * In particular, it means that we can not poison the forward * pointers that may still be used for walking the list. +* +* The caller must take whatever precautions are necessary +* (such as holding appropriate locks) to avoid racing +* with another list-mutation primitive, such as list_del_rcu() +* or list_add_rcu(), running on this same list. +* However, it is perfectly legal to race against any +* of the _rcu list-traversal primitives, such as +* list_for_each_entry_rcu(). +* +* Note that the caller is not permitted to immediately free +* the newly deleted entry. Instead, either synchronize_kernel() +* or call_rcu() must be used to defer freeing until an RCU +* grace period has elapsed. */ static inline void list_del_rcu (struct list_head *entry) {
@@ -384,6 +413,10 @@* list_for_each_rcu - iterate over an rcu-protected list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. +* +* This list-traversal primitive may safely race against +* the _rcu list-mutation primitives such as list_add_rcu() +* as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_rcu (pos, head) \ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
@@ -399,6 +432,10 @@* @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. +* +* This list-traversal primitive may safely race against +* the _rcu list-mutation primitives such as list_add_rcu() +* as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_safe_rcu (pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \
@@ -409,6 +446,10 @@* @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. +* +* This list-traversal primitive may safely race against +* the _rcu list-mutation primitives such as list_add_rcu() +* as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_entry_rcu (pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \
@@ -424,6 +465,10 @@* continuing after existing point. * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. +* +* This list-traversal primitive may safely race against +* the _rcu list-mutation primitives such as list_add_rcu() +* as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_continue_rcu (pos, head) \ for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
@@ -485,6 +530,14 @@* * 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_add_head_rcu() +* or hlist_del_rcu(), running on this same list. +* However, it is perfectly legal to race against any +* of the _rcu list-traversal primitives, such as +* hlist_for_each_entry(). */ static inline void hlist_del_rcu (struct hlist_node *n) {
@@ -512,6 +565,26 @@ n->pprev = &h->first; } + +/** +* hlist_add_head_rcu - adds the specified element to the specified hlist, +* while permitting racing traversals. +* @n: the element to add to the hash list. +* @h: the list to add to. +* +* The caller must take whatever precautions are necessary +* (such as holding appropriate locks) to avoid racing +* with another list-mutation primitive, such as hlist_add_head_rcu() +* or hlist_del_rcu(), running on this same list. +* However, it is perfectly legal to race against any +* of the _rcu list-traversal primitives, such as +* hlist_for_each_entry(), but only if smp_read_barrier_depends() +* is 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(). +* +* OK, so why don't we have an hlist_for_each_entry_rcu()??? +*/ static __inline__void hlist_add_head_rcu (struct hlist_node *n,struct hlist_head *h) {struct hlist_node *first = h->first;
include/linux/list.h.orig +606 -0
606 lines not on this page · raw message
Quoted 2 lines · Paul E. McKenney
The attached patch improves the documentation of the
_rculist primitives, as suggested off-list.
Updated based on feedback received off-list.
Thanx, Paul
include/linux/list.h +73 -0
@@ -104,6 +104,14 @@* * Insert a new entry after the specified head. * This is good for implementing stacks. +* +* The caller must take whatever precautions are necessary +* (such as holding appropriate locks) to avoid racing +* with another list-mutation primitive, such as list_add_rcu() +* or list_del_rcu(), running on this same list. +* However, it is perfectly legal to run concurrently with +* the _rcu list-traversal primitives, such as +* list_for_each_entry_rcu(). */ static __inline__void list_add_rcu (struct list_head *new,struct list_head *head) {
@@ -117,6 +125,14 @@* * Insert a new entry before the specified head. * This is useful for implementing queues. +* +* The caller must take whatever precautions are necessary +* (such as holding appropriate locks) to avoid racing +* with another list-mutation primitive, such as list_add_tail_rcu() +* or list_del_rcu(), running on this same list. +* However, it is perfectly legal to run concurrently with +* the _rcu list-traversal primitives, such as +* list_for_each_entry_rcu(). */ static __inline__void list_add_tail_rcu (struct list_head *new,struct list_head *head) {
@@ -159,6 +175,19 @@* * In particular, it means that we can not poison the forward * pointers that may still be used for walking the list. +* +* The caller must take whatever precautions are necessary +* (such as holding appropriate locks) to avoid racing +* with another list-mutation primitive, such as list_del_rcu() +* or list_add_rcu(), running on this same list. +* However, it is perfectly legal to run concurrently with +* the _rcu list-traversal primitives, such as +* list_for_each_entry_rcu(). +* +* Note that the caller is not permitted to immediately free +* the newly deleted entry. Instead, either synchronize_kernel() +* or call_rcu() must be used to defer freeing until an RCU +* grace period has elapsed. */ static inline void list_del_rcu (struct list_head *entry) {
@@ -384,6 +413,10 @@* list_for_each_rcu - iterate over an rcu-protected list * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. +* +* This list-traversal primitive may safely run concurrently with +* the _rcu list-mutation primitives such as list_add_rcu() +* as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_rcu (pos, head) \ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
@@ -399,6 +432,10 @@* @pos: the &struct list_head to use as a loop counter. * @n: another &struct list_head to use as temporary storage * @head: the head for your list. +* +* This list-traversal primitive may safely run concurrently with +* the _rcu list-mutation primitives such as list_add_rcu() +* as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_safe_rcu (pos, n, head) \ for (pos = (head)->next, n = pos->next; pos != (head); \
@@ -409,6 +446,10 @@* @pos: the type * to use as a loop counter. * @head: the head for your list. * @member: the name of the list_struct within the struct. +* +* This list-traversal primitive may safely run concurrently with +* the _rcu list-mutation primitives such as list_add_rcu() +* as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_entry_rcu (pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member), \
@@ -424,6 +465,10 @@* continuing after existing point. * @pos: the &struct list_head to use as a loop counter. * @head: the head for your list. +* +* This list-traversal primitive may safely run concurrently with +* the _rcu list-mutation primitives such as list_add_rcu() +* as long as the traversal is guarded by rcu_read_lock(). */ #define list_for_each_continue_rcu (pos, head) \ for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
@@ -485,6 +530,14 @@* * 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_add_head_rcu() +* or hlist_del_rcu(), running on this same list. +* However, it is perfectly legal to run concurrently with +* the _rcu list-traversal primitives, such as +* hlist_for_each_entry(). */ static inline void hlist_del_rcu (struct hlist_node *n) {
@@ -512,6 +565,26 @@ n->pprev = &h->first; } + +/** +* hlist_add_head_rcu - adds the specified element to the specified hlist, +* while permitting racing traversals. +* @n: the element to add to the hash list. +* @h: the list to add to. +* +* The caller must take whatever precautions are necessary +* (such as holding appropriate locks) to avoid racing +* with another list-mutation primitive, such as hlist_add_head_rcu() +* or hlist_del_rcu(), running on this same list. +* However, it is perfectly legal to run concurrently with +* the _rcu list-traversal primitives, such as +* hlist_for_each_entry(), but only if smp_read_barrier_depends() +* is 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(). +* +* OK, so why don't we have an hlist_for_each_entry_rcu()??? +*/ static __inline__void hlist_add_head_rcu (struct hlist_node *n,struct hlist_head *h) {struct hlist_node *first = h->first;
include/linux/list.h.orig +606 -0
606 lines not on this page · raw message
Quoted 4 lines · Paul E. McKenney
The attached patch improves the documentation of the
_rculist primitives, as suggested off-list.Thanx, Paul
Thanks for making these changes!
I recently used the _rcu list primitives for the audit framework and I found that, even though I read the header file comments and the papers that were referenced, and even though I then had a good understanding of RCU, I missed some implementation details about how the primitives themselves should be used inside the Linux kernel.
These new comments fill in those missing details -- I hope they are accepted into the kernel.