All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
To: Christoph Hellwig <hch@infradead.org>,
	Corey Minyard <minyard@acm.org>, Andrew Morton <akpm@osdl.org>,
	Linux Kernel <linux-kernel@vger.kernel.org>,
	Carol Hebert <cah@us.ibm.com>,
	OpenIPMI Developers <openipmi-developer@lists.sourceforge.net>
Subject: Re: [PATCH] IPMI: fix some RCU problems
Date: Thu, 28 Dec 2006 11:55:04 -0800	[thread overview]
Message-ID: <20061228195504.GC4501@linux.vnet.ibm.com> (raw)
In-Reply-To: <20061228183101.GA2412@infradead.org>

On Thu, Dec 28, 2006 at 06:31:01PM +0000, Christoph Hellwig wrote:
> > +	if (list_empty(&intf->cmd_rcvrs))
> > +		INIT_LIST_HEAD(&list);
> > +	else {
> > +		list.next = intf->cmd_rcvrs.next;
> > +		list.prev = intf->cmd_rcvrs.prev;
> > +		INIT_LIST_HEAD(&intf->cmd_rcvrs);
> > +
> > +		/*
> > +		 * At this point the list body still points to
> > +		 * intf->cmd_rcvrs.  Wait for any readers to finish
> > +		 * using the list before we switch the list body over
> > +		 * to the new list.
> > +		 */
> > +		synchronize_rcu();
> > +
> > +		/* Ready the list for use. */
> > +		list.next->prev = &list;
> > +		list.prev->next = &list;
> > +	}
> 
> This kind of thing must not be opencoded in drivers.  Please add
> a new list_splice_rcu helper to list.h

I must admit that this sounds better than list_privatize_rcu().  But since
the source list gets initialized, so how about list_splice_init_rcu()?
Patch below, untested, probably does not compile.  This takes the sync
function as an argument, so one would do something like:

	INIT_LIST_HEAD(&list);
	list_splice_init_rcu(&intf->cmdrcvrs, &list, synchronize_rcu);

The idea being to keep the RCU API proliferation down to a dull roar.

Thoughts?

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---

 list.h |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff -urpNa -X dontdiff linux-2.6.19/include/linux/list.h linux-2.6.19-lpr/include/linux/list.h
--- linux-2.6.19/include/linux/list.h	2006-11-29 13:57:37.000000000 -0800
+++ linux-2.6.19-lpr/include/linux/list.h	2006-12-28 11:48:31.000000000 -0800
@@ -360,6 +360,64 @@ static inline void list_splice_init(stru
 }
 
 /**
+ * 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))
+{
+	struct list_head *first = list->next;
+	struct list_head *last = list->prev;
+	struct list_head *at = head->next;
+
+	might_sleep();
+	if (list_empty(head)) {
+		return;
+	}
+
+	/* "first" and "last" tracking list, so initialize it. */
+
+	INIT_LIST_HEAD(list);
+
+	/*
+	 * At this point, the list body still points to the source list.
+	 * Wait for any readers to finish using the list before splicing
+	 * the list body into the new list.  Any new readers will see
+	 * an empty list.
+	 */
+
+	sync();
+
+	/*
+	 * Readers are finished with the source list, so perform splice.
+	 * The order is important if the new list is global and accessible
+	 * to concurrent RCU readers.  Note that RCU readers are not
+	 * permitted to traverse the prev pointers without excluding
+	 * this function.
+	 */
+
+	last->next = at;
+	smp_wmb();
+	head->next = first;
+	first->prev = head;
+	at->prev = last;
+}
+
+/**
  * list_entry - get the struct for this entry
  * @ptr:	the &struct list_head pointer.
  * @type:	the type of the struct this is embedded in.

  reply	other threads:[~2006-12-28 19:55 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-12-28 18:24 [PATCH] IPMI: fix some RCU problems Corey Minyard
2006-12-28 18:31 ` Christoph Hellwig
2006-12-28 19:55   ` Paul E. McKenney [this message]
2006-12-28 20:24     ` Randy Dunlap
2006-12-28 22:23       ` Paul E. McKenney
  -- strict thread matches above, loose matches on Subject: below --
2007-01-03 15:31 [PATCH] IPMI: Fix " Corey Minyard
2007-01-03 21:22 ` Andrew Morton

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20061228195504.GC4501@linux.vnet.ibm.com \
    --to=paulmck@linux.vnet.ibm.com \
    --cc=akpm@osdl.org \
    --cc=cah@us.ibm.com \
    --cc=hch@infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=minyard@acm.org \
    --cc=openipmi-developer@lists.sourceforge.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.