* [PATCH 1/2] rcu: introduce list_last_or_null_rcu
@ 2015-05-28 20:35 Dan Streetman
2015-05-28 20:36 ` [PATCH 2/2] list: introduce list_last_entry_or_null Dan Streetman
` (2 more replies)
0 siblings, 3 replies; 23+ messages in thread
From: Dan Streetman @ 2015-05-28 20:35 UTC (permalink / raw)
To: Andrew Morton, Paul E. McKenney, Josh Triplett
Cc: Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, linux-kernel,
Dan Streetman
Add list_last_or_null_rcu(), to simplify getting the last entry from a
rcu-protected list. The standard list_last_entry() can't be used as it
is not rcu-protected; the list may be modified concurrently. And the
->prev pointer can't be used, as only the ->next pointers are protected
by rcu.
This simply iterates forward through the entire list, to get to the last
entry. If the list is empty, it returns NULL.
Signed-off-by: Dan Streetman <ddstreet@ieee.org>
---
include/linux/rculist.h | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/include/linux/rculist.h b/include/linux/rculist.h
index a18b16f..954fde5 100644
--- a/include/linux/rculist.h
+++ b/include/linux/rculist.h
@@ -293,6 +293,27 @@ static inline void list_splice_init_rcu(struct list_head *list,
})
/**
+ * list_last_or_null_rcu - get the last element from a list
+ * @ptr: the list head to take the element from.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_head within the struct.
+ *
+ * Note that if the list is empty, it returns NULL.
+ *
+ * This primitive may safely run concurrently with the _rcu list-mutation
+ * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
+ */
+#define list_last_or_null_rcu(ptr, type, member) \
+({ \
+ struct list_head *__ptr = (ptr); \
+ struct list_head *__last = __ptr; \
+ struct list_head *__entry = list_next_rcu(__ptr); \
+ for (; __entry != __ptr; __entry = list_next_rcu(__entry)) \
+ __last = __entry; \
+ likely(__ptr != __last) ? list_entry_rcu(__last, type, member) : NULL; \
+})
+
+/**
* list_for_each_entry_rcu - iterate over rcu list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
--
2.1.0
^ permalink raw reply related [flat|nested] 23+ messages in thread* [PATCH 2/2] list: introduce list_last_entry_or_null 2015-05-28 20:35 [PATCH 1/2] rcu: introduce list_last_or_null_rcu Dan Streetman @ 2015-05-28 20:36 ` Dan Streetman 2015-05-28 20:39 ` [PATCH 1/2] rcu: introduce list_last_or_null_rcu josh 2015-05-28 21:05 ` Steven Rostedt 2 siblings, 0 replies; 23+ messages in thread From: Dan Streetman @ 2015-05-28 20:36 UTC (permalink / raw) To: Andrew Morton, Paul E. McKenney Cc: Steven Rostedt, Ken Helias, Mauro Carvalho Chehab, Andrey Utkin, Masahiro Yamada, linux-kernel, Dan Streetman non-rcu variant of list_last_or_null_rcu Signed-off-by: Dan Streetman <ddstreet@ieee.org> --- include/linux/list.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/linux/list.h b/include/linux/list.h index feb773c..38577f89 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -385,6 +385,17 @@ static inline void list_splice_tail_init(struct list_head *list, (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL) /** + * list_last_entry_or_null - get the last element from a list + * @ptr: the list head to take the element from. + * @type: the type of the struct this is embedded in. + * @member: the name of the list_head within the struct. + * + * Note that if the list is empty, it returns NULL. + */ +#define list_last_entry_or_null(ptr, type, member) \ + (!list_empty(ptr) ? list_last_entry(ptr, type, member) : NULL) + +/** * list_next_entry - get the next element in list * @pos: the type * to cursor * @member: the name of the list_head within the struct. -- 2.1.0 ^ permalink raw reply related [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 20:35 [PATCH 1/2] rcu: introduce list_last_or_null_rcu Dan Streetman 2015-05-28 20:36 ` [PATCH 2/2] list: introduce list_last_entry_or_null Dan Streetman @ 2015-05-28 20:39 ` josh 2015-05-28 20:42 ` Dan Streetman 2015-05-28 21:05 ` Steven Rostedt 2 siblings, 1 reply; 23+ messages in thread From: josh @ 2015-05-28 20:39 UTC (permalink / raw) To: Dan Streetman Cc: Andrew Morton, Paul E. McKenney, Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 04:35:27PM -0400, Dan Streetman wrote: > Add list_last_or_null_rcu(), to simplify getting the last entry from a > rcu-protected list. The standard list_last_entry() can't be used as it > is not rcu-protected; the list may be modified concurrently. And the > ->prev pointer can't be used, as only the ->next pointers are protected > by rcu. > > This simply iterates forward through the entire list, to get to the last > entry. If the list is empty, it returns NULL. > > Signed-off-by: Dan Streetman <ddstreet@ieee.org> The list iteration functions are macros because they introduce a loop with attached loop block. For this, is there any reason not to make it an inline function instead of a macro? > include/linux/rculist.h | 21 +++++++++++++++++++++ > 1 file changed, 21 insertions(+) > > diff --git a/include/linux/rculist.h b/include/linux/rculist.h > index a18b16f..954fde5 100644 > --- a/include/linux/rculist.h > +++ b/include/linux/rculist.h > @@ -293,6 +293,27 @@ static inline void list_splice_init_rcu(struct list_head *list, > }) > > /** > + * list_last_or_null_rcu - get the last element from a list > + * @ptr: the list head to take the element from. > + * @type: the type of the struct this is embedded in. > + * @member: the name of the list_head within the struct. > + * > + * Note that if the list is empty, it returns NULL. > + * > + * This primitive may safely run concurrently with the _rcu list-mutation > + * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). > + */ > +#define list_last_or_null_rcu(ptr, type, member) \ > +({ \ > + struct list_head *__ptr = (ptr); \ > + struct list_head *__last = __ptr; \ > + struct list_head *__entry = list_next_rcu(__ptr); \ > + for (; __entry != __ptr; __entry = list_next_rcu(__entry)) \ > + __last = __entry; \ > + likely(__ptr != __last) ? list_entry_rcu(__last, type, member) : NULL; \ > +}) > + > +/** > * list_for_each_entry_rcu - iterate over rcu list of given type > * @pos: the type * to use as a loop cursor. > * @head: the head for your list. > -- > 2.1.0 > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 20:39 ` [PATCH 1/2] rcu: introduce list_last_or_null_rcu josh @ 2015-05-28 20:42 ` Dan Streetman 2015-05-28 20:44 ` Dan Streetman 2015-05-28 21:05 ` Paul E. McKenney 0 siblings, 2 replies; 23+ messages in thread From: Dan Streetman @ 2015-05-28 20:42 UTC (permalink / raw) To: josh Cc: Andrew Morton, Paul E. McKenney, Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 4:39 PM, <josh@joshtriplett.org> wrote: > On Thu, May 28, 2015 at 04:35:27PM -0400, Dan Streetman wrote: >> Add list_last_or_null_rcu(), to simplify getting the last entry from a >> rcu-protected list. The standard list_last_entry() can't be used as it >> is not rcu-protected; the list may be modified concurrently. And the >> ->prev pointer can't be used, as only the ->next pointers are protected >> by rcu. >> >> This simply iterates forward through the entire list, to get to the last >> entry. If the list is empty, it returns NULL. >> >> Signed-off-by: Dan Streetman <ddstreet@ieee.org> > > The list iteration functions are macros because they introduce a loop > with attached loop block. For this, is there any reason not to make it > an inline function instead of a macro? true, there's no reason i can see not to make it inline, let me send an updated patch. > >> include/linux/rculist.h | 21 +++++++++++++++++++++ >> 1 file changed, 21 insertions(+) >> >> diff --git a/include/linux/rculist.h b/include/linux/rculist.h >> index a18b16f..954fde5 100644 >> --- a/include/linux/rculist.h >> +++ b/include/linux/rculist.h >> @@ -293,6 +293,27 @@ static inline void list_splice_init_rcu(struct list_head *list, >> }) >> >> /** >> + * list_last_or_null_rcu - get the last element from a list >> + * @ptr: the list head to take the element from. >> + * @type: the type of the struct this is embedded in. >> + * @member: the name of the list_head within the struct. >> + * >> + * Note that if the list is empty, it returns NULL. >> + * >> + * This primitive may safely run concurrently with the _rcu list-mutation >> + * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). >> + */ >> +#define list_last_or_null_rcu(ptr, type, member) \ >> +({ \ >> + struct list_head *__ptr = (ptr); \ >> + struct list_head *__last = __ptr; \ >> + struct list_head *__entry = list_next_rcu(__ptr); \ >> + for (; __entry != __ptr; __entry = list_next_rcu(__entry)) \ >> + __last = __entry; \ >> + likely(__ptr != __last) ? list_entry_rcu(__last, type, member) : NULL; \ >> +}) >> + >> +/** >> * list_for_each_entry_rcu - iterate over rcu list of given type >> * @pos: the type * to use as a loop cursor. >> * @head: the head for your list. >> -- >> 2.1.0 >> ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 20:42 ` Dan Streetman @ 2015-05-28 20:44 ` Dan Streetman 2015-05-28 21:06 ` Paul E. McKenney 2015-05-28 21:10 ` josh 2015-05-28 21:05 ` Paul E. McKenney 1 sibling, 2 replies; 23+ messages in thread From: Dan Streetman @ 2015-05-28 20:44 UTC (permalink / raw) To: Josh Triplett Cc: Andrew Morton, Paul E. McKenney, Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 4:42 PM, Dan Streetman <ddstreet@ieee.org> wrote: > On Thu, May 28, 2015 at 4:39 PM, <josh@joshtriplett.org> wrote: >> On Thu, May 28, 2015 at 04:35:27PM -0400, Dan Streetman wrote: >>> Add list_last_or_null_rcu(), to simplify getting the last entry from a >>> rcu-protected list. The standard list_last_entry() can't be used as it >>> is not rcu-protected; the list may be modified concurrently. And the >>> ->prev pointer can't be used, as only the ->next pointers are protected >>> by rcu. >>> >>> This simply iterates forward through the entire list, to get to the last >>> entry. If the list is empty, it returns NULL. >>> >>> Signed-off-by: Dan Streetman <ddstreet@ieee.org> >> >> The list iteration functions are macros because they introduce a loop >> with attached loop block. For this, is there any reason not to make it >> an inline function instead of a macro? > > true, there's no reason i can see not to make it inline, let me send > an updated patch. ha, as soon as i sent that email, i realized it can't be an inline function, because the return value is (type *), not a predefined value. Of course it could return void*, but unless there's a benefit of making it an inline function, it seems to me like it would be better as a #define. > >> >>> include/linux/rculist.h | 21 +++++++++++++++++++++ >>> 1 file changed, 21 insertions(+) >>> >>> diff --git a/include/linux/rculist.h b/include/linux/rculist.h >>> index a18b16f..954fde5 100644 >>> --- a/include/linux/rculist.h >>> +++ b/include/linux/rculist.h >>> @@ -293,6 +293,27 @@ static inline void list_splice_init_rcu(struct list_head *list, >>> }) >>> >>> /** >>> + * list_last_or_null_rcu - get the last element from a list >>> + * @ptr: the list head to take the element from. >>> + * @type: the type of the struct this is embedded in. >>> + * @member: the name of the list_head within the struct. >>> + * >>> + * Note that if the list is empty, it returns NULL. >>> + * >>> + * This primitive may safely run concurrently with the _rcu list-mutation >>> + * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). >>> + */ >>> +#define list_last_or_null_rcu(ptr, type, member) \ >>> +({ \ >>> + struct list_head *__ptr = (ptr); \ >>> + struct list_head *__last = __ptr; \ >>> + struct list_head *__entry = list_next_rcu(__ptr); \ >>> + for (; __entry != __ptr; __entry = list_next_rcu(__entry)) \ >>> + __last = __entry; \ >>> + likely(__ptr != __last) ? list_entry_rcu(__last, type, member) : NULL; \ >>> +}) >>> + >>> +/** >>> * list_for_each_entry_rcu - iterate over rcu list of given type >>> * @pos: the type * to use as a loop cursor. >>> * @head: the head for your list. >>> -- >>> 2.1.0 >>> ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 20:44 ` Dan Streetman @ 2015-05-28 21:06 ` Paul E. McKenney 2015-05-28 21:10 ` josh 1 sibling, 0 replies; 23+ messages in thread From: Paul E. McKenney @ 2015-05-28 21:06 UTC (permalink / raw) To: Dan Streetman Cc: Josh Triplett, Andrew Morton, Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 04:44:59PM -0400, Dan Streetman wrote: > On Thu, May 28, 2015 at 4:42 PM, Dan Streetman <ddstreet@ieee.org> wrote: > > On Thu, May 28, 2015 at 4:39 PM, <josh@joshtriplett.org> wrote: > >> On Thu, May 28, 2015 at 04:35:27PM -0400, Dan Streetman wrote: > >>> Add list_last_or_null_rcu(), to simplify getting the last entry from a > >>> rcu-protected list. The standard list_last_entry() can't be used as it > >>> is not rcu-protected; the list may be modified concurrently. And the > >>> ->prev pointer can't be used, as only the ->next pointers are protected > >>> by rcu. > >>> > >>> This simply iterates forward through the entire list, to get to the last > >>> entry. If the list is empty, it returns NULL. > >>> > >>> Signed-off-by: Dan Streetman <ddstreet@ieee.org> > >> > >> The list iteration functions are macros because they introduce a loop > >> with attached loop block. For this, is there any reason not to make it > >> an inline function instead of a macro? > > > > true, there's no reason i can see not to make it inline, let me send > > an updated patch. > > ha, as soon as i sent that email, i realized it can't be an inline > function, because the return value is (type *), not a predefined > value. Of course it could return void*, but unless there's a benefit > of making it an inline function, it seems to me like it would be > better as a #define. Hey, I was hoping... ;-) Thanx, Paul ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 20:44 ` Dan Streetman 2015-05-28 21:06 ` Paul E. McKenney @ 2015-05-28 21:10 ` josh 1 sibling, 0 replies; 23+ messages in thread From: josh @ 2015-05-28 21:10 UTC (permalink / raw) To: Dan Streetman Cc: Andrew Morton, Paul E. McKenney, Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 04:44:59PM -0400, Dan Streetman wrote: > On Thu, May 28, 2015 at 4:42 PM, Dan Streetman <ddstreet@ieee.org> wrote: > > On Thu, May 28, 2015 at 4:39 PM, <josh@joshtriplett.org> wrote: > >> On Thu, May 28, 2015 at 04:35:27PM -0400, Dan Streetman wrote: > >>> Add list_last_or_null_rcu(), to simplify getting the last entry from a > >>> rcu-protected list. The standard list_last_entry() can't be used as it > >>> is not rcu-protected; the list may be modified concurrently. And the > >>> ->prev pointer can't be used, as only the ->next pointers are protected > >>> by rcu. > >>> > >>> This simply iterates forward through the entire list, to get to the last > >>> entry. If the list is empty, it returns NULL. > >>> > >>> Signed-off-by: Dan Streetman <ddstreet@ieee.org> > >> > >> The list iteration functions are macros because they introduce a loop > >> with attached loop block. For this, is there any reason not to make it > >> an inline function instead of a macro? > > > > true, there's no reason i can see not to make it inline, let me send > > an updated patch. > > ha, as soon as i sent that email, i realized it can't be an inline > function, because the return value is (type *), not a predefined > value. Of course it could return void*, but unless there's a benefit > of making it an inline function, it seems to me like it would be > better as a #define. Fair enough. Sigh, C. - Josh Triplett ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 20:42 ` Dan Streetman 2015-05-28 20:44 ` Dan Streetman @ 2015-05-28 21:05 ` Paul E. McKenney 2015-05-28 21:14 ` Dan Streetman 1 sibling, 1 reply; 23+ messages in thread From: Paul E. McKenney @ 2015-05-28 21:05 UTC (permalink / raw) To: Dan Streetman Cc: josh, Andrew Morton, Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 04:42:20PM -0400, Dan Streetman wrote: > On Thu, May 28, 2015 at 4:39 PM, <josh@joshtriplett.org> wrote: > > On Thu, May 28, 2015 at 04:35:27PM -0400, Dan Streetman wrote: > >> Add list_last_or_null_rcu(), to simplify getting the last entry from a > >> rcu-protected list. The standard list_last_entry() can't be used as it > >> is not rcu-protected; the list may be modified concurrently. And the > >> ->prev pointer can't be used, as only the ->next pointers are protected > >> by rcu. > >> > >> This simply iterates forward through the entire list, to get to the last > >> entry. If the list is empty, it returns NULL. > >> > >> Signed-off-by: Dan Streetman <ddstreet@ieee.org> > > > > The list iteration functions are macros because they introduce a loop > > with attached loop block. For this, is there any reason not to make it > > an inline function instead of a macro? > > true, there's no reason i can see not to make it inline, let me send > an updated patch. Hmmm... If we can now do type-generic inline functions, it might make sense to convert some of the others as well. Thanx, Paul > >> include/linux/rculist.h | 21 +++++++++++++++++++++ > >> 1 file changed, 21 insertions(+) > >> > >> diff --git a/include/linux/rculist.h b/include/linux/rculist.h > >> index a18b16f..954fde5 100644 > >> --- a/include/linux/rculist.h > >> +++ b/include/linux/rculist.h > >> @@ -293,6 +293,27 @@ static inline void list_splice_init_rcu(struct list_head *list, > >> }) > >> > >> /** > >> + * list_last_or_null_rcu - get the last element from a list > >> + * @ptr: the list head to take the element from. > >> + * @type: the type of the struct this is embedded in. > >> + * @member: the name of the list_head within the struct. > >> + * > >> + * Note that if the list is empty, it returns NULL. > >> + * > >> + * This primitive may safely run concurrently with the _rcu list-mutation > >> + * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). > >> + */ > >> +#define list_last_or_null_rcu(ptr, type, member) \ > >> +({ \ > >> + struct list_head *__ptr = (ptr); \ > >> + struct list_head *__last = __ptr; \ > >> + struct list_head *__entry = list_next_rcu(__ptr); \ > >> + for (; __entry != __ptr; __entry = list_next_rcu(__entry)) \ > >> + __last = __entry; \ > >> + likely(__ptr != __last) ? list_entry_rcu(__last, type, member) : NULL; \ > >> +}) > >> + > >> +/** > >> * list_for_each_entry_rcu - iterate over rcu list of given type > >> * @pos: the type * to use as a loop cursor. > >> * @head: the head for your list. > >> -- > >> 2.1.0 > >> > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 21:05 ` Paul E. McKenney @ 2015-05-28 21:14 ` Dan Streetman 2015-05-28 21:17 ` Paul E. McKenney 0 siblings, 1 reply; 23+ messages in thread From: Dan Streetman @ 2015-05-28 21:14 UTC (permalink / raw) To: Paul E. McKenney Cc: Josh Triplett, Andrew Morton, Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 5:05 PM, Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote: > On Thu, May 28, 2015 at 04:42:20PM -0400, Dan Streetman wrote: >> On Thu, May 28, 2015 at 4:39 PM, <josh@joshtriplett.org> wrote: >> > On Thu, May 28, 2015 at 04:35:27PM -0400, Dan Streetman wrote: >> >> Add list_last_or_null_rcu(), to simplify getting the last entry from a >> >> rcu-protected list. The standard list_last_entry() can't be used as it >> >> is not rcu-protected; the list may be modified concurrently. And the >> >> ->prev pointer can't be used, as only the ->next pointers are protected >> >> by rcu. >> >> >> >> This simply iterates forward through the entire list, to get to the last >> >> entry. If the list is empty, it returns NULL. >> >> >> >> Signed-off-by: Dan Streetman <ddstreet@ieee.org> >> > >> > The list iteration functions are macros because they introduce a loop >> > with attached loop block. For this, is there any reason not to make it >> > an inline function instead of a macro? >> >> true, there's no reason i can see not to make it inline, let me send >> an updated patch. > > Hmmm... If we can now do type-generic inline functions, it might make > sense to convert some of the others as well. oh, ok. how do we do type-generic inline funcs? return void*? > > Thanx, Paul > >> >> include/linux/rculist.h | 21 +++++++++++++++++++++ >> >> 1 file changed, 21 insertions(+) >> >> >> >> diff --git a/include/linux/rculist.h b/include/linux/rculist.h >> >> index a18b16f..954fde5 100644 >> >> --- a/include/linux/rculist.h >> >> +++ b/include/linux/rculist.h >> >> @@ -293,6 +293,27 @@ static inline void list_splice_init_rcu(struct list_head *list, >> >> }) >> >> >> >> /** >> >> + * list_last_or_null_rcu - get the last element from a list >> >> + * @ptr: the list head to take the element from. >> >> + * @type: the type of the struct this is embedded in. >> >> + * @member: the name of the list_head within the struct. >> >> + * >> >> + * Note that if the list is empty, it returns NULL. >> >> + * >> >> + * This primitive may safely run concurrently with the _rcu list-mutation >> >> + * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). >> >> + */ >> >> +#define list_last_or_null_rcu(ptr, type, member) \ >> >> +({ \ >> >> + struct list_head *__ptr = (ptr); \ >> >> + struct list_head *__last = __ptr; \ >> >> + struct list_head *__entry = list_next_rcu(__ptr); \ >> >> + for (; __entry != __ptr; __entry = list_next_rcu(__entry)) \ >> >> + __last = __entry; \ >> >> + likely(__ptr != __last) ? list_entry_rcu(__last, type, member) : NULL; \ >> >> +}) >> >> + >> >> +/** >> >> * list_for_each_entry_rcu - iterate over rcu list of given type >> >> * @pos: the type * to use as a loop cursor. >> >> * @head: the head for your list. >> >> -- >> >> 2.1.0 >> >> >> > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 21:14 ` Dan Streetman @ 2015-05-28 21:17 ` Paul E. McKenney 2015-05-28 21:19 ` Dan Streetman 0 siblings, 1 reply; 23+ messages in thread From: Paul E. McKenney @ 2015-05-28 21:17 UTC (permalink / raw) To: Dan Streetman Cc: Josh Triplett, Andrew Morton, Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 05:14:25PM -0400, Dan Streetman wrote: > On Thu, May 28, 2015 at 5:05 PM, Paul E. McKenney > <paulmck@linux.vnet.ibm.com> wrote: > > On Thu, May 28, 2015 at 04:42:20PM -0400, Dan Streetman wrote: > >> On Thu, May 28, 2015 at 4:39 PM, <josh@joshtriplett.org> wrote: > >> > On Thu, May 28, 2015 at 04:35:27PM -0400, Dan Streetman wrote: > >> >> Add list_last_or_null_rcu(), to simplify getting the last entry from a > >> >> rcu-protected list. The standard list_last_entry() can't be used as it > >> >> is not rcu-protected; the list may be modified concurrently. And the > >> >> ->prev pointer can't be used, as only the ->next pointers are protected > >> >> by rcu. > >> >> > >> >> This simply iterates forward through the entire list, to get to the last > >> >> entry. If the list is empty, it returns NULL. > >> >> > >> >> Signed-off-by: Dan Streetman <ddstreet@ieee.org> > >> > > >> > The list iteration functions are macros because they introduce a loop > >> > with attached loop block. For this, is there any reason not to make it > >> > an inline function instead of a macro? > >> > >> true, there's no reason i can see not to make it inline, let me send > >> an updated patch. > > > > Hmmm... If we can now do type-generic inline functions, it might make > > sense to convert some of the others as well. > > oh, ok. how do we do type-generic inline funcs? return void*? I was hoping that you would tell me. I use macros in that case. Thanx, Paul ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 21:17 ` Paul E. McKenney @ 2015-05-28 21:19 ` Dan Streetman 2015-05-28 21:28 ` Steven Rostedt 0 siblings, 1 reply; 23+ messages in thread From: Dan Streetman @ 2015-05-28 21:19 UTC (permalink / raw) To: Paul McKenney Cc: Josh Triplett, Andrew Morton, Steven Rostedt, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 5:17 PM, Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote: > On Thu, May 28, 2015 at 05:14:25PM -0400, Dan Streetman wrote: >> On Thu, May 28, 2015 at 5:05 PM, Paul E. McKenney >> <paulmck@linux.vnet.ibm.com> wrote: >> > On Thu, May 28, 2015 at 04:42:20PM -0400, Dan Streetman wrote: >> >> On Thu, May 28, 2015 at 4:39 PM, <josh@joshtriplett.org> wrote: >> >> > On Thu, May 28, 2015 at 04:35:27PM -0400, Dan Streetman wrote: >> >> >> Add list_last_or_null_rcu(), to simplify getting the last entry from a >> >> >> rcu-protected list. The standard list_last_entry() can't be used as it >> >> >> is not rcu-protected; the list may be modified concurrently. And the >> >> >> ->prev pointer can't be used, as only the ->next pointers are protected >> >> >> by rcu. >> >> >> >> >> >> This simply iterates forward through the entire list, to get to the last >> >> >> entry. If the list is empty, it returns NULL. >> >> >> >> >> >> Signed-off-by: Dan Streetman <ddstreet@ieee.org> >> >> > >> >> > The list iteration functions are macros because they introduce a loop >> >> > with attached loop block. For this, is there any reason not to make it >> >> > an inline function instead of a macro? >> >> >> >> true, there's no reason i can see not to make it inline, let me send >> >> an updated patch. >> > >> > Hmmm... If we can now do type-generic inline functions, it might make >> > sense to convert some of the others as well. >> >> oh, ok. how do we do type-generic inline funcs? return void*? > > I was hoping that you would tell me. I use macros in that case. ha, if I ever get to the point where i think i know more than you, i'll let you know ;-) > > Thanx, Paul > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 21:19 ` Dan Streetman @ 2015-05-28 21:28 ` Steven Rostedt 2015-05-28 21:30 ` Dan Streetman 0 siblings, 1 reply; 23+ messages in thread From: Steven Rostedt @ 2015-05-28 21:28 UTC (permalink / raw) To: Dan Streetman Cc: Paul McKenney, Josh Triplett, Andrew Morton, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, 28 May 2015 17:19:40 -0400 Dan Streetman <ddstreet@ieee.org> wrote: > >> oh, ok. how do we do type-generic inline funcs? return void*? > > > > I was hoping that you would tell me. I use macros in that case. > > ha, if I ever get to the point where i think i know more than you, > i'll let you know ;-) static inline struct list_head * list_last_or_null_rcu(struct list_head *ptr) { struct list_head *entry; struct list_head *last; for (entry = list_next_rcu(ptr); entry != ptr; entry = list_next_rcu(entry)) last = __entry; if (last != ptr) return last; return NULL; } #define list_last_or_null_entry_rcu(ptr, type, member) \ ({ \ struct list_head *__ptr = list_last_or_null_rcu(ptr); \ __ptr ? list_entry_rcu(__ptr, type, member) : NULL; \ }) -- Steve ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 21:28 ` Steven Rostedt @ 2015-05-28 21:30 ` Dan Streetman 2015-05-28 21:33 ` Dan Streetman 0 siblings, 1 reply; 23+ messages in thread From: Dan Streetman @ 2015-05-28 21:30 UTC (permalink / raw) To: Steven Rostedt Cc: Paul McKenney, Josh Triplett, Andrew Morton, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 5:28 PM, Steven Rostedt <rostedt@goodmis.org> wrote: > On Thu, 28 May 2015 17:19:40 -0400 > Dan Streetman <ddstreet@ieee.org> wrote: > >> >> oh, ok. how do we do type-generic inline funcs? return void*? >> > >> > I was hoping that you would tell me. I use macros in that case. >> >> ha, if I ever get to the point where i think i know more than you, >> i'll let you know ;-) > > static inline struct list_head * > list_last_or_null_rcu(struct list_head *ptr) > { > struct list_head *entry; > struct list_head *last; > > for (entry = list_next_rcu(ptr); > entry != ptr; entry = list_next_rcu(entry)) > last = __entry; > if (last != ptr) > return last; > return NULL; > } > > #define list_last_or_null_entry_rcu(ptr, type, member) \ > ({ \ > struct list_head *__ptr = list_last_or_null_rcu(ptr); \ > __ptr ? list_entry_rcu(__ptr, type, member) : NULL; \ > }) well sure :-) however, the rcu list function currently doesn't include "entry" in the function name, but returns the list entry (not the list_head). that could be changed, but all callers would need to change, too. > > -- Steve ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 21:30 ` Dan Streetman @ 2015-05-28 21:33 ` Dan Streetman 0 siblings, 0 replies; 23+ messages in thread From: Dan Streetman @ 2015-05-28 21:33 UTC (permalink / raw) To: Steven Rostedt Cc: Paul McKenney, Josh Triplett, Andrew Morton, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 5:30 PM, Dan Streetman <ddstreet@ieee.org> wrote: > On Thu, May 28, 2015 at 5:28 PM, Steven Rostedt <rostedt@goodmis.org> wrote: >> On Thu, 28 May 2015 17:19:40 -0400 >> Dan Streetman <ddstreet@ieee.org> wrote: >> >>> >> oh, ok. how do we do type-generic inline funcs? return void*? >>> > >>> > I was hoping that you would tell me. I use macros in that case. >>> >>> ha, if I ever get to the point where i think i know more than you, >>> i'll let you know ;-) >> >> static inline struct list_head * >> list_last_or_null_rcu(struct list_head *ptr) >> { >> struct list_head *entry; >> struct list_head *last; >> >> for (entry = list_next_rcu(ptr); >> entry != ptr; entry = list_next_rcu(entry)) >> last = __entry; >> if (last != ptr) >> return last; >> return NULL; >> } >> >> #define list_last_or_null_entry_rcu(ptr, type, member) \ >> ({ \ >> struct list_head *__ptr = list_last_or_null_rcu(ptr); \ >> __ptr ? list_entry_rcu(__ptr, type, member) : NULL; \ >> }) > > well sure :-) > > however, the rcu list function currently doesn't include "entry" in > the function name, but returns the list entry (not the list_head). > that could be changed, but all callers would need to change, too. to clarify, list_first_or_null_rcu() returns the list entry, not the list_head; list_last_or_null_rcu() should likewise return the same type. git grep only shows 12 users of list_first_or_null_rcu(), so maybe changing the name to list_first_entry_or_null_rcu() makes sense, which would then use a new inline list_first_or_null_rcu() that returns list_head instead of the entry type... > >> >> -- Steve ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 20:35 [PATCH 1/2] rcu: introduce list_last_or_null_rcu Dan Streetman 2015-05-28 20:36 ` [PATCH 2/2] list: introduce list_last_entry_or_null Dan Streetman 2015-05-28 20:39 ` [PATCH 1/2] rcu: introduce list_last_or_null_rcu josh @ 2015-05-28 21:05 ` Steven Rostedt 2015-05-28 21:12 ` Dan Streetman 2 siblings, 1 reply; 23+ messages in thread From: Steven Rostedt @ 2015-05-28 21:05 UTC (permalink / raw) To: Dan Streetman Cc: Andrew Morton, Paul E. McKenney, Josh Triplett, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, 28 May 2015 16:35:27 -0400 Dan Streetman <ddstreet@ieee.org> wrote: > Add list_last_or_null_rcu(), to simplify getting the last entry from a > rcu-protected list. The standard list_last_entry() can't be used as it > is not rcu-protected; the list may be modified concurrently. And the > ->prev pointer can't be used, as only the ->next pointers are protected > by rcu. > > This simply iterates forward through the entire list, to get to the last > entry. If the list is empty, it returns NULL. May I asked what this would be used for? It seems awfully inefficient in its implementation. What use cases would this be for? I hate to add something like this as a generic function which would encourage people to use it. Iterating over an entire list to find the last element is just nasty. -- Steve ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 21:05 ` Steven Rostedt @ 2015-05-28 21:12 ` Dan Streetman 2015-05-28 21:16 ` Paul E. McKenney 0 siblings, 1 reply; 23+ messages in thread From: Dan Streetman @ 2015-05-28 21:12 UTC (permalink / raw) To: Steven Rostedt Cc: Andrew Morton, Paul E. McKenney, Josh Triplett, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 5:05 PM, Steven Rostedt <rostedt@goodmis.org> wrote: > On Thu, 28 May 2015 16:35:27 -0400 > Dan Streetman <ddstreet@ieee.org> wrote: > >> Add list_last_or_null_rcu(), to simplify getting the last entry from a >> rcu-protected list. The standard list_last_entry() can't be used as it >> is not rcu-protected; the list may be modified concurrently. And the >> ->prev pointer can't be used, as only the ->next pointers are protected >> by rcu. >> >> This simply iterates forward through the entire list, to get to the last >> entry. If the list is empty, it returns NULL. > > May I asked what this would be used for? It seems awfully inefficient > in its implementation. What use cases would this be for? I hate to add > something like this as a generic function which would encourage people > to use it. Iterating over an entire list to find the last element is > just nasty. i have a patch series that will update zswap to be able to change its parameters at runtime, instead of only at boot time. To do that, it creates new "pools" dynamically, and keeps them all in a list, with only the 1st pool being actively used; any following pools still have everything that was stored in them, but they aren't added to. When zswap has to "shrink" - by telling one of the pools to get rid of 1 or more items - it picks the last on the list. Once a pool is empty, it's removed/freed. So zswap *could* just manually iterate the list to the last element, instead of using this new function. But if rcu lists are ever improved later on, e.g. if ->prev is somehow rcu-protected as well as ->next, then this function should be faster than manually iterating. if there's a better rcu-way to get to the last list entry, then we should definitely use it, although based on my understanding of the rcu list implementation, you can only iterate forwards, safely (without locking). > > -- Steve > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 21:12 ` Dan Streetman @ 2015-05-28 21:16 ` Paul E. McKenney 2015-05-28 21:24 ` Dan Streetman 0 siblings, 1 reply; 23+ messages in thread From: Paul E. McKenney @ 2015-05-28 21:16 UTC (permalink / raw) To: Dan Streetman Cc: Steven Rostedt, Andrew Morton, Josh Triplett, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 05:12:00PM -0400, Dan Streetman wrote: > On Thu, May 28, 2015 at 5:05 PM, Steven Rostedt <rostedt@goodmis.org> wrote: > > On Thu, 28 May 2015 16:35:27 -0400 > > Dan Streetman <ddstreet@ieee.org> wrote: > > > >> Add list_last_or_null_rcu(), to simplify getting the last entry from a > >> rcu-protected list. The standard list_last_entry() can't be used as it > >> is not rcu-protected; the list may be modified concurrently. And the > >> ->prev pointer can't be used, as only the ->next pointers are protected > >> by rcu. > >> > >> This simply iterates forward through the entire list, to get to the last > >> entry. If the list is empty, it returns NULL. > > > > May I asked what this would be used for? It seems awfully inefficient > > in its implementation. What use cases would this be for? I hate to add > > something like this as a generic function which would encourage people > > to use it. Iterating over an entire list to find the last element is > > just nasty. > > i have a patch series that will update zswap to be able to change its > parameters at runtime, instead of only at boot time. To do that, it > creates new "pools" dynamically, and keeps them all in a list, with > only the 1st pool being actively used; any following pools still have > everything that was stored in them, but they aren't added to. When > zswap has to "shrink" - by telling one of the pools to get rid of 1 or > more items - it picks the last on the list. Once a pool is empty, > it's removed/freed. > > So zswap *could* just manually iterate the list to the last element, > instead of using this new function. But if rcu lists are ever > improved later on, e.g. if ->prev is somehow rcu-protected as well as > ->next, then this function should be faster than manually iterating. > > if there's a better rcu-way to get to the last list entry, then we > should definitely use it, although based on my understanding of the > rcu list implementation, you can only iterate forwards, safely > (without locking). The usual approach would be to maintain a tail pointer. How big are these lists likely to get? Thanx, Paul ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 21:16 ` Paul E. McKenney @ 2015-05-28 21:24 ` Dan Streetman 2015-05-28 22:29 ` Paul E. McKenney 0 siblings, 1 reply; 23+ messages in thread From: Dan Streetman @ 2015-05-28 21:24 UTC (permalink / raw) To: Paul McKenney Cc: Steven Rostedt, Andrew Morton, Josh Triplett, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 5:16 PM, Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote: > On Thu, May 28, 2015 at 05:12:00PM -0400, Dan Streetman wrote: >> On Thu, May 28, 2015 at 5:05 PM, Steven Rostedt <rostedt@goodmis.org> wrote: >> > On Thu, 28 May 2015 16:35:27 -0400 >> > Dan Streetman <ddstreet@ieee.org> wrote: >> > >> >> Add list_last_or_null_rcu(), to simplify getting the last entry from a >> >> rcu-protected list. The standard list_last_entry() can't be used as it >> >> is not rcu-protected; the list may be modified concurrently. And the >> >> ->prev pointer can't be used, as only the ->next pointers are protected >> >> by rcu. >> >> >> >> This simply iterates forward through the entire list, to get to the last >> >> entry. If the list is empty, it returns NULL. >> > >> > May I asked what this would be used for? It seems awfully inefficient >> > in its implementation. What use cases would this be for? I hate to add >> > something like this as a generic function which would encourage people >> > to use it. Iterating over an entire list to find the last element is >> > just nasty. >> >> i have a patch series that will update zswap to be able to change its >> parameters at runtime, instead of only at boot time. To do that, it >> creates new "pools" dynamically, and keeps them all in a list, with >> only the 1st pool being actively used; any following pools still have >> everything that was stored in them, but they aren't added to. When >> zswap has to "shrink" - by telling one of the pools to get rid of 1 or >> more items - it picks the last on the list. Once a pool is empty, >> it's removed/freed. >> >> So zswap *could* just manually iterate the list to the last element, >> instead of using this new function. But if rcu lists are ever >> improved later on, e.g. if ->prev is somehow rcu-protected as well as >> ->next, then this function should be faster than manually iterating. >> >> if there's a better rcu-way to get to the last list entry, then we >> should definitely use it, although based on my understanding of the >> rcu list implementation, you can only iterate forwards, safely >> (without locking). > > The usual approach would be to maintain a tail pointer. How big are > these lists likely to get? in the vast majority of cases, it'll only be 1 entry; the list is only added to when the user decides to change the pool type or compression function, which during normal operation will probably happen very rarely. So in most situations, the function will just be a 1-step for loop. I'm only proposing this function since it may be useful to optimize last-rcu-entry access later, and maybe for other users. re: keeping a rcu-safe tail pointer, how is that done? i assume since head->prev isn't rcu protected (is it?), it would need to be separate from the list, and thus would need to be spinlock-protected and updated at each list update? > > Thanx, Paul > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 21:24 ` Dan Streetman @ 2015-05-28 22:29 ` Paul E. McKenney 2015-05-28 23:22 ` Dan Streetman 2015-05-29 13:40 ` Dan Streetman 0 siblings, 2 replies; 23+ messages in thread From: Paul E. McKenney @ 2015-05-28 22:29 UTC (permalink / raw) To: Dan Streetman Cc: Steven Rostedt, Andrew Morton, Josh Triplett, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 05:24:14PM -0400, Dan Streetman wrote: > On Thu, May 28, 2015 at 5:16 PM, Paul E. McKenney > <paulmck@linux.vnet.ibm.com> wrote: > > On Thu, May 28, 2015 at 05:12:00PM -0400, Dan Streetman wrote: > >> On Thu, May 28, 2015 at 5:05 PM, Steven Rostedt <rostedt@goodmis.org> wrote: > >> > On Thu, 28 May 2015 16:35:27 -0400 > >> > Dan Streetman <ddstreet@ieee.org> wrote: > >> > > >> >> Add list_last_or_null_rcu(), to simplify getting the last entry from a > >> >> rcu-protected list. The standard list_last_entry() can't be used as it > >> >> is not rcu-protected; the list may be modified concurrently. And the > >> >> ->prev pointer can't be used, as only the ->next pointers are protected > >> >> by rcu. > >> >> > >> >> This simply iterates forward through the entire list, to get to the last > >> >> entry. If the list is empty, it returns NULL. > >> > > >> > May I asked what this would be used for? It seems awfully inefficient > >> > in its implementation. What use cases would this be for? I hate to add > >> > something like this as a generic function which would encourage people > >> > to use it. Iterating over an entire list to find the last element is > >> > just nasty. > >> > >> i have a patch series that will update zswap to be able to change its > >> parameters at runtime, instead of only at boot time. To do that, it > >> creates new "pools" dynamically, and keeps them all in a list, with > >> only the 1st pool being actively used; any following pools still have > >> everything that was stored in them, but they aren't added to. When > >> zswap has to "shrink" - by telling one of the pools to get rid of 1 or > >> more items - it picks the last on the list. Once a pool is empty, > >> it's removed/freed. > >> > >> So zswap *could* just manually iterate the list to the last element, > >> instead of using this new function. But if rcu lists are ever > >> improved later on, e.g. if ->prev is somehow rcu-protected as well as > >> ->next, then this function should be faster than manually iterating. > >> > >> if there's a better rcu-way to get to the last list entry, then we > >> should definitely use it, although based on my understanding of the > >> rcu list implementation, you can only iterate forwards, safely > >> (without locking). > > > > The usual approach would be to maintain a tail pointer. How big are > > these lists likely to get? > > in the vast majority of cases, it'll only be 1 entry; the list is only > added to when the user decides to change the pool type or compression > function, which during normal operation will probably happen very > rarely. So in most situations, the function will just be a 1-step for > loop. I'm only proposing this function since it may be useful to > optimize last-rcu-entry access later, and maybe for other users. Fair enough. > re: keeping a rcu-safe tail pointer, how is that done? i assume since > head->prev isn't rcu protected (is it?), it would need to be separate > from the list, and thus would need to be spinlock-protected and > updated at each list update? Yep, each update that changed the tail would need to change the tail pointer, and that would need to be protected from other updates. But if the lists were long, one approach would be to provide a list_del_rcu_bidir() or some such that didn't poison the ->prev pointer, and then use rcu_dereference() to traverse the head element's ->prev pointer, as you suggested above. I have resisted doing that due to debugging issues, but if there turns out to be a strong need, let's talk. Thanx, Paul ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 22:29 ` Paul E. McKenney @ 2015-05-28 23:22 ` Dan Streetman 2015-05-29 13:40 ` Dan Streetman 1 sibling, 0 replies; 23+ messages in thread From: Dan Streetman @ 2015-05-28 23:22 UTC (permalink / raw) To: Paul McKenney Cc: Steven Rostedt, Andrew Morton, Josh Triplett, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 6:29 PM, Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote: > On Thu, May 28, 2015 at 05:24:14PM -0400, Dan Streetman wrote: >> On Thu, May 28, 2015 at 5:16 PM, Paul E. McKenney >> <paulmck@linux.vnet.ibm.com> wrote: >> > On Thu, May 28, 2015 at 05:12:00PM -0400, Dan Streetman wrote: >> >> On Thu, May 28, 2015 at 5:05 PM, Steven Rostedt <rostedt@goodmis.org> wrote: >> >> > On Thu, 28 May 2015 16:35:27 -0400 >> >> > Dan Streetman <ddstreet@ieee.org> wrote: >> >> > >> >> >> Add list_last_or_null_rcu(), to simplify getting the last entry from a >> >> >> rcu-protected list. The standard list_last_entry() can't be used as it >> >> >> is not rcu-protected; the list may be modified concurrently. And the >> >> >> ->prev pointer can't be used, as only the ->next pointers are protected >> >> >> by rcu. >> >> >> >> >> >> This simply iterates forward through the entire list, to get to the last >> >> >> entry. If the list is empty, it returns NULL. >> >> > >> >> > May I asked what this would be used for? It seems awfully inefficient >> >> > in its implementation. What use cases would this be for? I hate to add >> >> > something like this as a generic function which would encourage people >> >> > to use it. Iterating over an entire list to find the last element is >> >> > just nasty. >> >> >> >> i have a patch series that will update zswap to be able to change its >> >> parameters at runtime, instead of only at boot time. To do that, it >> >> creates new "pools" dynamically, and keeps them all in a list, with >> >> only the 1st pool being actively used; any following pools still have >> >> everything that was stored in them, but they aren't added to. When >> >> zswap has to "shrink" - by telling one of the pools to get rid of 1 or >> >> more items - it picks the last on the list. Once a pool is empty, >> >> it's removed/freed. >> >> >> >> So zswap *could* just manually iterate the list to the last element, >> >> instead of using this new function. But if rcu lists are ever >> >> improved later on, e.g. if ->prev is somehow rcu-protected as well as >> >> ->next, then this function should be faster than manually iterating. >> >> >> >> if there's a better rcu-way to get to the last list entry, then we >> >> should definitely use it, although based on my understanding of the >> >> rcu list implementation, you can only iterate forwards, safely >> >> (without locking). >> > >> > The usual approach would be to maintain a tail pointer. How big are >> > these lists likely to get? >> >> in the vast majority of cases, it'll only be 1 entry; the list is only >> added to when the user decides to change the pool type or compression >> function, which during normal operation will probably happen very >> rarely. So in most situations, the function will just be a 1-step for >> loop. I'm only proposing this function since it may be useful to >> optimize last-rcu-entry access later, and maybe for other users. > > Fair enough. > >> re: keeping a rcu-safe tail pointer, how is that done? i assume since >> head->prev isn't rcu protected (is it?), it would need to be separate >> from the list, and thus would need to be spinlock-protected and >> updated at each list update? > > Yep, each update that changed the tail would need to change the tail > pointer, and that would need to be protected from other updates. > > But if the lists were long, one approach would be to provide a > list_del_rcu_bidir() or some such that didn't poison the ->prev pointer, > and then use rcu_dereference() to traverse the head element's ->prev > pointer, as you suggested above. I have resisted doing that due to > debugging issues, but if there turns out to be a strong need, let's talk. In my case, there's certainly no strong need. So this patch can be ignored. Thnx! > > Thanx, Paul > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-28 22:29 ` Paul E. McKenney 2015-05-28 23:22 ` Dan Streetman @ 2015-05-29 13:40 ` Dan Streetman 2015-06-01 18:17 ` Paul E. McKenney 1 sibling, 1 reply; 23+ messages in thread From: Dan Streetman @ 2015-05-29 13:40 UTC (permalink / raw) To: Paul McKenney Cc: Steven Rostedt, Andrew Morton, Josh Triplett, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Thu, May 28, 2015 at 6:29 PM, Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote: > On Thu, May 28, 2015 at 05:24:14PM -0400, Dan Streetman wrote: >> On Thu, May 28, 2015 at 5:16 PM, Paul E. McKenney >> <paulmck@linux.vnet.ibm.com> wrote: >> > On Thu, May 28, 2015 at 05:12:00PM -0400, Dan Streetman wrote: >> >> On Thu, May 28, 2015 at 5:05 PM, Steven Rostedt <rostedt@goodmis.org> wrote: >> >> > On Thu, 28 May 2015 16:35:27 -0400 >> >> > Dan Streetman <ddstreet@ieee.org> wrote: >> >> > >> >> >> Add list_last_or_null_rcu(), to simplify getting the last entry from a >> >> >> rcu-protected list. The standard list_last_entry() can't be used as it >> >> >> is not rcu-protected; the list may be modified concurrently. And the >> >> >> ->prev pointer can't be used, as only the ->next pointers are protected >> >> >> by rcu. >> >> >> >> >> >> This simply iterates forward through the entire list, to get to the last >> >> >> entry. If the list is empty, it returns NULL. >> >> > >> >> > May I asked what this would be used for? It seems awfully inefficient >> >> > in its implementation. What use cases would this be for? I hate to add >> >> > something like this as a generic function which would encourage people >> >> > to use it. Iterating over an entire list to find the last element is >> >> > just nasty. >> >> >> >> i have a patch series that will update zswap to be able to change its >> >> parameters at runtime, instead of only at boot time. To do that, it >> >> creates new "pools" dynamically, and keeps them all in a list, with >> >> only the 1st pool being actively used; any following pools still have >> >> everything that was stored in them, but they aren't added to. When >> >> zswap has to "shrink" - by telling one of the pools to get rid of 1 or >> >> more items - it picks the last on the list. Once a pool is empty, >> >> it's removed/freed. >> >> >> >> So zswap *could* just manually iterate the list to the last element, >> >> instead of using this new function. But if rcu lists are ever >> >> improved later on, e.g. if ->prev is somehow rcu-protected as well as >> >> ->next, then this function should be faster than manually iterating. >> >> >> >> if there's a better rcu-way to get to the last list entry, then we >> >> should definitely use it, although based on my understanding of the >> >> rcu list implementation, you can only iterate forwards, safely >> >> (without locking). >> > >> > The usual approach would be to maintain a tail pointer. How big are >> > these lists likely to get? >> >> in the vast majority of cases, it'll only be 1 entry; the list is only >> added to when the user decides to change the pool type or compression >> function, which during normal operation will probably happen very >> rarely. So in most situations, the function will just be a 1-step for >> loop. I'm only proposing this function since it may be useful to >> optimize last-rcu-entry access later, and maybe for other users. > > Fair enough. > >> re: keeping a rcu-safe tail pointer, how is that done? i assume since >> head->prev isn't rcu protected (is it?), it would need to be separate >> from the list, and thus would need to be spinlock-protected and >> updated at each list update? > > Yep, each update that changed the tail would need to change the tail > pointer, and that would need to be protected from other updates. > > But if the lists were long, one approach would be to provide a > list_del_rcu_bidir() or some such that didn't poison the ->prev pointer, > and then use rcu_dereference() to traverse the head element's ->prev > pointer, as you suggested above. I have resisted doing that due to > debugging issues, but if there turns out to be a strong need, let's talk. I was thinking; since the head element is never removed, its ->prev pointer will never be poisoned; is something like this safe? /* this can only be called on the head, not on any entry; * specifically this is not safe to call on any entry that * may be removed with list_del_rcu() or list_replace_rcu(). */ #define list_last_or_null_rcu(head, type, member) \ ({ \ struct list_head *__last = (head)->prev; \ __last != (head) ? list_entry_rcu(__last) : NULL; \ }) I was thinking that's unsafe because the head->prev pointer can be updated directly, such as during list_del_rcu(last_entry) which will directly reassign head->prev to the new last entry; but maybe that is ok since list_del_rcu(first_entry) also directly reassigns head->next to the new first entry? > > Thanx, Paul > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-05-29 13:40 ` Dan Streetman @ 2015-06-01 18:17 ` Paul E. McKenney 2015-06-01 22:11 ` Dan Streetman 0 siblings, 1 reply; 23+ messages in thread From: Paul E. McKenney @ 2015-06-01 18:17 UTC (permalink / raw) To: Dan Streetman Cc: Steven Rostedt, Andrew Morton, Josh Triplett, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Fri, May 29, 2015 at 09:40:43AM -0400, Dan Streetman wrote: > On Thu, May 28, 2015 at 6:29 PM, Paul E. McKenney > <paulmck@linux.vnet.ibm.com> wrote: > > On Thu, May 28, 2015 at 05:24:14PM -0400, Dan Streetman wrote: > >> On Thu, May 28, 2015 at 5:16 PM, Paul E. McKenney > >> <paulmck@linux.vnet.ibm.com> wrote: > >> > On Thu, May 28, 2015 at 05:12:00PM -0400, Dan Streetman wrote: > >> >> On Thu, May 28, 2015 at 5:05 PM, Steven Rostedt <rostedt@goodmis.org> wrote: > >> >> > On Thu, 28 May 2015 16:35:27 -0400 > >> >> > Dan Streetman <ddstreet@ieee.org> wrote: > >> >> > > >> >> >> Add list_last_or_null_rcu(), to simplify getting the last entry from a > >> >> >> rcu-protected list. The standard list_last_entry() can't be used as it > >> >> >> is not rcu-protected; the list may be modified concurrently. And the > >> >> >> ->prev pointer can't be used, as only the ->next pointers are protected > >> >> >> by rcu. > >> >> >> > >> >> >> This simply iterates forward through the entire list, to get to the last > >> >> >> entry. If the list is empty, it returns NULL. > >> >> > > >> >> > May I asked what this would be used for? It seems awfully inefficient > >> >> > in its implementation. What use cases would this be for? I hate to add > >> >> > something like this as a generic function which would encourage people > >> >> > to use it. Iterating over an entire list to find the last element is > >> >> > just nasty. > >> >> > >> >> i have a patch series that will update zswap to be able to change its > >> >> parameters at runtime, instead of only at boot time. To do that, it > >> >> creates new "pools" dynamically, and keeps them all in a list, with > >> >> only the 1st pool being actively used; any following pools still have > >> >> everything that was stored in them, but they aren't added to. When > >> >> zswap has to "shrink" - by telling one of the pools to get rid of 1 or > >> >> more items - it picks the last on the list. Once a pool is empty, > >> >> it's removed/freed. > >> >> > >> >> So zswap *could* just manually iterate the list to the last element, > >> >> instead of using this new function. But if rcu lists are ever > >> >> improved later on, e.g. if ->prev is somehow rcu-protected as well as > >> >> ->next, then this function should be faster than manually iterating. > >> >> > >> >> if there's a better rcu-way to get to the last list entry, then we > >> >> should definitely use it, although based on my understanding of the > >> >> rcu list implementation, you can only iterate forwards, safely > >> >> (without locking). > >> > > >> > The usual approach would be to maintain a tail pointer. How big are > >> > these lists likely to get? > >> > >> in the vast majority of cases, it'll only be 1 entry; the list is only > >> added to when the user decides to change the pool type or compression > >> function, which during normal operation will probably happen very > >> rarely. So in most situations, the function will just be a 1-step for > >> loop. I'm only proposing this function since it may be useful to > >> optimize last-rcu-entry access later, and maybe for other users. > > > > Fair enough. > > > >> re: keeping a rcu-safe tail pointer, how is that done? i assume since > >> head->prev isn't rcu protected (is it?), it would need to be separate > >> from the list, and thus would need to be spinlock-protected and > >> updated at each list update? > > > > Yep, each update that changed the tail would need to change the tail > > pointer, and that would need to be protected from other updates. > > > > But if the lists were long, one approach would be to provide a > > list_del_rcu_bidir() or some such that didn't poison the ->prev pointer, > > and then use rcu_dereference() to traverse the head element's ->prev > > pointer, as you suggested above. I have resisted doing that due to > > debugging issues, but if there turns out to be a strong need, let's talk. > > I was thinking; since the head element is never removed, its ->prev > pointer will never be poisoned; is something like this safe? > > /* this can only be called on the head, not on any entry; > * specifically this is not safe to call on any entry that > * may be removed with list_del_rcu() or list_replace_rcu(). > */ > #define list_last_or_null_rcu(head, type, member) \ > ({ \ > struct list_head *__last = (head)->prev; \ > __last != (head) ? list_entry_rcu(__last) : NULL; \ > }) > > I was thinking that's unsafe because the head->prev pointer can be > updated directly, such as during list_del_rcu(last_entry) which will > directly reassign head->prev to the new last entry; but maybe that is > ok since list_del_rcu(first_entry) also directly reassigns head->next > to the new first entry? In your particular case, it would be safe, but people can and do call list_del_rcu() on the header in order to remove the entire list, which would poison the header's ->prev pointer. So if you really want to do this in your own code, fine, but please: (1) include a big fat comment saying what you are doing and the resulting restrictions and (2) Name it something specific to your code. If multiple similar use cases show up, maybe we can add something to the rculist_nulls.h file. Thanx, Paul ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: [PATCH 1/2] rcu: introduce list_last_or_null_rcu 2015-06-01 18:17 ` Paul E. McKenney @ 2015-06-01 22:11 ` Dan Streetman 0 siblings, 0 replies; 23+ messages in thread From: Dan Streetman @ 2015-06-01 22:11 UTC (permalink / raw) To: Paul McKenney Cc: Steven Rostedt, Andrew Morton, Josh Triplett, Mathieu Desnoyers, Lai Jiangshan, linux-kernel On Mon, Jun 1, 2015 at 2:17 PM, Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote: > On Fri, May 29, 2015 at 09:40:43AM -0400, Dan Streetman wrote: >> On Thu, May 28, 2015 at 6:29 PM, Paul E. McKenney >> <paulmck@linux.vnet.ibm.com> wrote: >> > On Thu, May 28, 2015 at 05:24:14PM -0400, Dan Streetman wrote: >> >> On Thu, May 28, 2015 at 5:16 PM, Paul E. McKenney >> >> <paulmck@linux.vnet.ibm.com> wrote: >> >> > On Thu, May 28, 2015 at 05:12:00PM -0400, Dan Streetman wrote: >> >> >> On Thu, May 28, 2015 at 5:05 PM, Steven Rostedt <rostedt@goodmis.org> wrote: >> >> >> > On Thu, 28 May 2015 16:35:27 -0400 >> >> >> > Dan Streetman <ddstreet@ieee.org> wrote: >> >> >> > >> >> >> >> Add list_last_or_null_rcu(), to simplify getting the last entry from a >> >> >> >> rcu-protected list. The standard list_last_entry() can't be used as it >> >> >> >> is not rcu-protected; the list may be modified concurrently. And the >> >> >> >> ->prev pointer can't be used, as only the ->next pointers are protected >> >> >> >> by rcu. >> >> >> >> >> >> >> >> This simply iterates forward through the entire list, to get to the last >> >> >> >> entry. If the list is empty, it returns NULL. >> >> >> > >> >> >> > May I asked what this would be used for? It seems awfully inefficient >> >> >> > in its implementation. What use cases would this be for? I hate to add >> >> >> > something like this as a generic function which would encourage people >> >> >> > to use it. Iterating over an entire list to find the last element is >> >> >> > just nasty. >> >> >> >> >> >> i have a patch series that will update zswap to be able to change its >> >> >> parameters at runtime, instead of only at boot time. To do that, it >> >> >> creates new "pools" dynamically, and keeps them all in a list, with >> >> >> only the 1st pool being actively used; any following pools still have >> >> >> everything that was stored in them, but they aren't added to. When >> >> >> zswap has to "shrink" - by telling one of the pools to get rid of 1 or >> >> >> more items - it picks the last on the list. Once a pool is empty, >> >> >> it's removed/freed. >> >> >> >> >> >> So zswap *could* just manually iterate the list to the last element, >> >> >> instead of using this new function. But if rcu lists are ever >> >> >> improved later on, e.g. if ->prev is somehow rcu-protected as well as >> >> >> ->next, then this function should be faster than manually iterating. >> >> >> >> >> >> if there's a better rcu-way to get to the last list entry, then we >> >> >> should definitely use it, although based on my understanding of the >> >> >> rcu list implementation, you can only iterate forwards, safely >> >> >> (without locking). >> >> > >> >> > The usual approach would be to maintain a tail pointer. How big are >> >> > these lists likely to get? >> >> >> >> in the vast majority of cases, it'll only be 1 entry; the list is only >> >> added to when the user decides to change the pool type or compression >> >> function, which during normal operation will probably happen very >> >> rarely. So in most situations, the function will just be a 1-step for >> >> loop. I'm only proposing this function since it may be useful to >> >> optimize last-rcu-entry access later, and maybe for other users. >> > >> > Fair enough. >> > >> >> re: keeping a rcu-safe tail pointer, how is that done? i assume since >> >> head->prev isn't rcu protected (is it?), it would need to be separate >> >> from the list, and thus would need to be spinlock-protected and >> >> updated at each list update? >> > >> > Yep, each update that changed the tail would need to change the tail >> > pointer, and that would need to be protected from other updates. >> > >> > But if the lists were long, one approach would be to provide a >> > list_del_rcu_bidir() or some such that didn't poison the ->prev pointer, >> > and then use rcu_dereference() to traverse the head element's ->prev >> > pointer, as you suggested above. I have resisted doing that due to >> > debugging issues, but if there turns out to be a strong need, let's talk. >> >> I was thinking; since the head element is never removed, its ->prev >> pointer will never be poisoned; is something like this safe? >> >> /* this can only be called on the head, not on any entry; >> * specifically this is not safe to call on any entry that >> * may be removed with list_del_rcu() or list_replace_rcu(). >> */ >> #define list_last_or_null_rcu(head, type, member) \ >> ({ \ >> struct list_head *__last = (head)->prev; \ >> __last != (head) ? list_entry_rcu(__last) : NULL; \ >> }) >> >> I was thinking that's unsafe because the head->prev pointer can be >> updated directly, such as during list_del_rcu(last_entry) which will >> directly reassign head->prev to the new last entry; but maybe that is >> ok since list_del_rcu(first_entry) also directly reassigns head->next >> to the new first entry? > > In your particular case, it would be safe, but people can and do call > list_del_rcu() on the header in order to remove the entire list, which > would poison the header's ->prev pointer. So if you really want to do > this in your own code, fine, but please: (1) include a big fat comment > saying what you are doing and the resulting restrictions and (2) Name > it something specific to your code. Ok. Since in my case there will only be 1 entry (or at worst just a few) in the list in the majority of cases, I'll just stick to manually iterating to the last entry. It's easy and clear. Thanks! > > If multiple similar use cases show up, maybe we can add something to > the rculist_nulls.h file. > > Thanx, Paul > ^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2015-06-01 22:12 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2015-05-28 20:35 [PATCH 1/2] rcu: introduce list_last_or_null_rcu Dan Streetman 2015-05-28 20:36 ` [PATCH 2/2] list: introduce list_last_entry_or_null Dan Streetman 2015-05-28 20:39 ` [PATCH 1/2] rcu: introduce list_last_or_null_rcu josh 2015-05-28 20:42 ` Dan Streetman 2015-05-28 20:44 ` Dan Streetman 2015-05-28 21:06 ` Paul E. McKenney 2015-05-28 21:10 ` josh 2015-05-28 21:05 ` Paul E. McKenney 2015-05-28 21:14 ` Dan Streetman 2015-05-28 21:17 ` Paul E. McKenney 2015-05-28 21:19 ` Dan Streetman 2015-05-28 21:28 ` Steven Rostedt 2015-05-28 21:30 ` Dan Streetman 2015-05-28 21:33 ` Dan Streetman 2015-05-28 21:05 ` Steven Rostedt 2015-05-28 21:12 ` Dan Streetman 2015-05-28 21:16 ` Paul E. McKenney 2015-05-28 21:24 ` Dan Streetman 2015-05-28 22:29 ` Paul E. McKenney 2015-05-28 23:22 ` Dan Streetman 2015-05-29 13:40 ` Dan Streetman 2015-06-01 18:17 ` Paul E. McKenney 2015-06-01 22:11 ` Dan Streetman
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox