Re: [PATCH] Introduces generic __list_splice_init_rcu();

From: Paul E. McKenney
Date: Fri Oct 09 2015 - 14:27:04 EST


On Thu, Oct 08, 2015 at 04:02:19PM -0400, Mimi Zohar wrote:
> On Tue, 2015-10-06 at 11:37 -0700, Paul E. McKenney wrote:
> > On Sun, Sep 27, 2015 at 06:10:28PM +0300, Petko Manolov wrote:
> > > __list_splice_init_rcu() can be used to splice lists forming both stack and
> > > queue structures, depending on its arguments. It is based on the initial
> > > list_splice_init_rcu() with a few minor modifications to help abstracting it.
> > >
> > > Signed-off-by: Petko Manolov <petkan@xxxxxxxxxxxx>
> >
> > At first glance, this looks sane.
> >
> > But who is using the new list_splice_tail_init_rcu() function?
>
> Hi, Paul. Up to now a single policy was loaded, normally in the
> initramfs, and never changed. Petko is adding support to extend the
> policy rules. The additional policies would be appended to the existing
> list, only after verifying the new set of rules are good.
>
> list.h contains list_splice() and list_splice_tail(), but the RCU
> equivalent functions don't exist.

OK, I have queued Petko's patch, updating the subject and changelog
as shown below. I added you as Cc. If testing goes well, I will
submit this for v4.5 (the merge window after next).

Thanx, Paul

------------------------------------------------------------------------

commit a7916adc2cc47e918ee66b9225c00d585ccd3a91
Author: Petko Manolov <petkan@xxxxxxxxxxxx>
Date: Sun Sep 27 18:10:28 2015 +0300

Introduce 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@xxxxxxxxxxxx>
Cc: Mimi Zohar <zohar@xxxxxxxxxxxxxxxxxx>
Signed-off-by: Paul E. McKenney <paulmck@xxxxxxxxxxxxxxxxxx>

diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index 5ed540986019..bbde2837d6be 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -178,33 +178,13 @@ static inline void list_replace_rcu(struct list_head *old,
old->prev = LIST_POISON2;
}

-/**
- * list_splice_init_rcu - splice an RCU-protected list into an existing list.
- * @list: the RCU-protected list to splice
- * @head: the place in the list to splice the first list into
- * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ...
- *
- * @head can be RCU-read traversed concurrently with this function.
- *
- * Note that this function blocks.
- *
- * Important note: the caller must take whatever action is necessary to
- * prevent any other updates to @head. In principle, it is possible
- * to modify the list as soon as sync() begins execution.
- * If this sort of thing becomes necessary, an alternative version
- * based on call_rcu() could be created. But only if -really-
- * needed -- there is no shortage of RCU API members.
- */
-static inline void list_splice_init_rcu(struct list_head *list,
- struct list_head *head,
- void (*sync)(void))
+static inline void __list_splice_init_rcu(struct list_head *list,
+ struct list_head *prev,
+ struct list_head *next,
+ void (*sync)(void))
{
struct list_head *first = list->next;
struct list_head *last = list->prev;
- struct list_head *at = head->next;
-
- if (list_empty(list))
- return;

/*
* "first" and "last" tracking list, so initialize it. RCU readers
@@ -231,10 +211,46 @@ static inline void list_splice_init_rcu(struct list_head *list,
* this function.
*/

- last->next = at;
- rcu_assign_pointer(list_next_rcu(head), first);
- first->prev = head;
- at->prev = last;
+ last->next = next;
+ rcu_assign_pointer(list_next_rcu(prev), first);
+ first->prev = prev;
+ next->prev = last;
+}
+
+/**
+ * list_splice_init_rcu - splice an RCU-protected list into an existing list.
+ * @list: the RCU-protected list to splice
+ * @head: the place in the list to splice the first list into
+ * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ...
+ *
+ * @head can be RCU-read traversed concurrently with this function.
+ *
+ * Note that this function blocks.
+ *
+ * Important note: the caller must take whatever action is necessary to
+ * prevent any other updates to @head. In principle, it is possible
+ * to modify the list as soon as sync() begins execution.
+ * If this sort of thing becomes necessary, an alternative version
+ * based on call_rcu() could be created. But only if -really-
+ * needed -- there is no shortage of RCU API members.
+ */
+static inline void list_splice_init_rcu(struct list_head *list,
+ struct list_head *head,
+ void (*sync)(void))
+{
+ if (!list_empty(list))
+ __list_splice_init_rcu(list, head, head->next, sync);
+}
+
+/**
+ * list_splice_tail_init_rcu - same as above, but creates a queue
+ */
+static inline void list_splice_tail_init_rcu(struct list_head *list,
+ struct list_head *head,
+ void (*sync)(void))
+{
+ if (!list_empty(list))
+ __list_splice_init_rcu(list, head->prev, head, sync);
}

/**

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/