Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1255749 > unrolled thread
| Started by | Ingo Molnar <mingo@kernel.org> |
|---|---|
| First post | 2015-10-26 09:50 +0100 |
| Last post | 2015-10-27 06:40 +0100 |
| Articles | 12 — 6 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() Ingo Molnar <mingo@kernel.org> - 2015-10-26 09:50 +0100
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2015-10-26 16:00 +0100
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() Ingo Molnar <mingo@kernel.org> - 2015-10-26 19:10 +0100
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() Linus Torvalds <torvalds@linux-foundation.org> - 2015-10-27 04:40 +0100
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() Tejun Heo <tj@kernel.org> - 2015-10-27 06:20 +0100
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2015-10-27 06:40 +0100
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() Ingo Molnar <mingo@kernel.org> - 2015-10-28 09:40 +0100
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() Patrick Marlier <patrick.marlier@gmail.com> - 2015-10-28 21:40 +0100
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2015-10-29 01:10 +0100
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() Tejun Heo <tj@kernel.org> - 2015-10-29 03:20 +0100
[tip:core/rcu] fs/writeback, rcu: Don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs() tip-bot for Tejun Heo <tipbot@zytor.com> - 2015-10-28 22:00 +0100
Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> - 2015-10-27 06:40 +0100
| From | Ingo Molnar <mingo@kernel.org> |
|---|---|
| Date | 2015-10-26 09:50 +0100 |
| Subject | Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() |
| Message-ID | <qnLDz-60G-1@gated-at.bofh.it> |
* Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:
> From: Patrick Marlier <patrick.marlier@gmail.com>
>
> The current list_entry_rcu() implementation copies the pointer to a stack
> variable, then invokes rcu_dereference_raw() on it. This results in an
> additional store-load pair. Now, most compilers will emit normal store
> and load instructions, which might seem to be of negligible overhead,
> but this results in a load-hit-store situation that can cause surprisingly
> long pipeline stalls, even on modern microprocessors. The problem is
> that it takes time for the store to get the store buffer updated, which
> can delay the subsequent load, which immediately follows.
>
> This commit therefore switches to the lockless_dereference() primitive,
> which does not expect the __rcu annotations (that are anyway not present
> in the list_head structure) and which, like rcu_dereference_raw(),
> does not check for an enclosing RCU read-side critical section.
> Most importantly, it does not copy the pointer, thus avoiding the
> load-hit-store overhead.
>
> Signed-off-by: Patrick Marlier <patrick.marlier@gmail.com>
> [ paulmck: Switched to lockless_dereference() to suppress sparse warnings. ]
> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> ---
> include/linux/rculist.h | 5 +----
> 1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/include/linux/rculist.h b/include/linux/rculist.h
> index 17c6b1f84a77..5ed540986019 100644
> --- a/include/linux/rculist.h
> +++ b/include/linux/rculist.h
> @@ -247,10 +247,7 @@ static inline void list_splice_init_rcu(struct list_head *list,
> * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
> */
> #define list_entry_rcu(ptr, type, member) \
> -({ \
> - typeof(*ptr) __rcu *__ptr = (typeof(*ptr) __rcu __force *)ptr; \
> - container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \
> -})
> + container_of(lockless_dereference(ptr), type, member)
So this commit:
8db70b132dd5 ("rculist: Make list_entry_rcu() use lockless_dereference()")
when merged with Linus's latest tree, triggers the following build failure on
allyesconfig/allmodconfig x86:
triton:~/tip> make fs/fs-writeback.o
CHK include/config/kernel.release
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
CHK include/generated/bounds.h
CHK include/generated/timeconst.h
CHK include/generated/asm-offsets.h
CALL scripts/checksyscalls.sh
CC fs/fs-writeback.o
In file included from fs/fs-writeback.c:16:0:
fs/fs-writeback.c: In function ‘bdi_split_work_to_wbs’:
include/linux/compiler.h:281:20: error: lvalue required as unary ‘&’ operand
__read_once_size(&(x), __u.__c, sizeof(x)); \
^
include/linux/kernel.h:811:49: note: in definition of macro ‘container_of’
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
^
include/linux/compiler.h:286:22: note: in expansion of macro ‘__READ_ONCE’
#define READ_ONCE(x) __READ_ONCE(x, 1)
^
include/linux/compiler.h:533:26: note: in expansion of macro ‘READ_ONCE’
typeof(p) _________p1 = READ_ONCE(p); \
^
include/linux/rculist.h:250:15: note: in expansion of macro ‘lockless_dereference’
container_of(lockless_dereference(ptr), type, member)
^
fs/fs-writeback.c:782:29: note: in expansion of macro ‘list_entry_rcu’
struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
^
include/linux/compiler.h:283:28: error: lvalue required as unary ‘&’ operand
__read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \
^
include/linux/kernel.h:811:49: note: in definition of macro ‘container_of’
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
^
include/linux/compiler.h:286:22: note: in expansion of macro ‘__READ_ONCE’
#define READ_ONCE(x) __READ_ONCE(x, 1)
^
include/linux/compiler.h:533:26: note: in expansion of macro ‘READ_ONCE’
typeof(p) _________p1 = READ_ONCE(p); \
^
include/linux/rculist.h:250:15: note: in expansion of macro ‘lockless_dereference’
container_of(lockless_dereference(ptr), type, member)
^
fs/fs-writeback.c:782:29: note: in expansion of macro ‘list_entry_rcu’
struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
^
scripts/Makefile.build:258: recipe for target 'fs/fs-writeback.o' failed
make[1]: *** [fs/fs-writeback.o] Error 1
Makefile:1526: recipe for target 'fs/fs-writeback.o' failed
make: *** [fs/fs-writeback.o] Error 2
It's this new usage in fs/fs-writeback.c:
static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
struct wb_writeback_work *base_work,
bool skip_if_busy)
{
struct bdi_writeback *last_wb = NULL;
struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
struct bdi_writeback, bdi_node);
so AFAICS the problem is lockless_dereference() not being able to take this valid
but non-lvalue list head, because READ_ONCE() does not take non-lvalues. All other
existing uses of list_entry_rcu() happen to use lvalues, so this bug didn't get
triggered before.
For now I've reverted this commit locally, to make the kernel build and so, but we
need a cleaner solution I suspect.
Thanks,
Ingo
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [next] | [standalone]
| From | "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> |
|---|---|
| Date | 2015-10-26 16:00 +0100 |
| Message-ID | <qnRpD-143-5@gated-at.bofh.it> |
| In reply to | #1255749 |
On Mon, Oct 26, 2015 at 09:45:06AM +0100, Ingo Molnar wrote:
>
> * Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:
>
> > From: Patrick Marlier <patrick.marlier@gmail.com>
> >
> > The current list_entry_rcu() implementation copies the pointer to a stack
> > variable, then invokes rcu_dereference_raw() on it. This results in an
> > additional store-load pair. Now, most compilers will emit normal store
> > and load instructions, which might seem to be of negligible overhead,
> > but this results in a load-hit-store situation that can cause surprisingly
> > long pipeline stalls, even on modern microprocessors. The problem is
> > that it takes time for the store to get the store buffer updated, which
> > can delay the subsequent load, which immediately follows.
> >
> > This commit therefore switches to the lockless_dereference() primitive,
> > which does not expect the __rcu annotations (that are anyway not present
> > in the list_head structure) and which, like rcu_dereference_raw(),
> > does not check for an enclosing RCU read-side critical section.
> > Most importantly, it does not copy the pointer, thus avoiding the
> > load-hit-store overhead.
> >
> > Signed-off-by: Patrick Marlier <patrick.marlier@gmail.com>
> > [ paulmck: Switched to lockless_dereference() to suppress sparse warnings. ]
> > Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> > ---
> > include/linux/rculist.h | 5 +----
> > 1 file changed, 1 insertion(+), 4 deletions(-)
> >
> > diff --git a/include/linux/rculist.h b/include/linux/rculist.h
> > index 17c6b1f84a77..5ed540986019 100644
> > --- a/include/linux/rculist.h
> > +++ b/include/linux/rculist.h
> > @@ -247,10 +247,7 @@ static inline void list_splice_init_rcu(struct list_head *list,
> > * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock().
> > */
> > #define list_entry_rcu(ptr, type, member) \
> > -({ \
> > - typeof(*ptr) __rcu *__ptr = (typeof(*ptr) __rcu __force *)ptr; \
> > - container_of((typeof(ptr))rcu_dereference_raw(__ptr), type, member); \
> > -})
> > + container_of(lockless_dereference(ptr), type, member)
>
> So this commit:
>
> 8db70b132dd5 ("rculist: Make list_entry_rcu() use lockless_dereference()")
>
> when merged with Linus's latest tree, triggers the following build failure on
> allyesconfig/allmodconfig x86:
>
> triton:~/tip> make fs/fs-writeback.o
> CHK include/config/kernel.release
> CHK include/generated/uapi/linux/version.h
> CHK include/generated/utsrelease.h
> CHK include/generated/bounds.h
> CHK include/generated/timeconst.h
> CHK include/generated/asm-offsets.h
> CALL scripts/checksyscalls.sh
> CC fs/fs-writeback.o
> In file included from fs/fs-writeback.c:16:0:
> fs/fs-writeback.c: In function ‘bdi_split_work_to_wbs’:
> include/linux/compiler.h:281:20: error: lvalue required as unary ‘&’ operand
> __read_once_size(&(x), __u.__c, sizeof(x)); \
> ^
> include/linux/kernel.h:811:49: note: in definition of macro ‘container_of’
> const typeof( ((type *)0)->member ) *__mptr = (ptr); \
> ^
> include/linux/compiler.h:286:22: note: in expansion of macro ‘__READ_ONCE’
> #define READ_ONCE(x) __READ_ONCE(x, 1)
> ^
> include/linux/compiler.h:533:26: note: in expansion of macro ‘READ_ONCE’
> typeof(p) _________p1 = READ_ONCE(p); \
> ^
> include/linux/rculist.h:250:15: note: in expansion of macro ‘lockless_dereference’
> container_of(lockless_dereference(ptr), type, member)
> ^
> fs/fs-writeback.c:782:29: note: in expansion of macro ‘list_entry_rcu’
> struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
> ^
> include/linux/compiler.h:283:28: error: lvalue required as unary ‘&’ operand
> __read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \
> ^
> include/linux/kernel.h:811:49: note: in definition of macro ‘container_of’
> const typeof( ((type *)0)->member ) *__mptr = (ptr); \
> ^
> include/linux/compiler.h:286:22: note: in expansion of macro ‘__READ_ONCE’
> #define READ_ONCE(x) __READ_ONCE(x, 1)
> ^
> include/linux/compiler.h:533:26: note: in expansion of macro ‘READ_ONCE’
> typeof(p) _________p1 = READ_ONCE(p); \
> ^
> include/linux/rculist.h:250:15: note: in expansion of macro ‘lockless_dereference’
> container_of(lockless_dereference(ptr), type, member)
> ^
> fs/fs-writeback.c:782:29: note: in expansion of macro ‘list_entry_rcu’
> struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
> ^
> scripts/Makefile.build:258: recipe for target 'fs/fs-writeback.o' failed
> make[1]: *** [fs/fs-writeback.o] Error 1
> Makefile:1526: recipe for target 'fs/fs-writeback.o' failed
> make: *** [fs/fs-writeback.o] Error 2
>
> It's this new usage in fs/fs-writeback.c:
>
> static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
> struct wb_writeback_work *base_work,
> bool skip_if_busy)
> {
> struct bdi_writeback *last_wb = NULL;
> struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
I believe that the above should instead be:
struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,
After all, RCU read-side list primitives need to fetch pointers in order
to traverse those pointers in an RCU-safe manner. The patch below clears
this up for me, does it also work for you?
Thanx, Paul
------------------------------------------------------------------------
commit 9221c4e78cc3511cd15b1433617ae2548ad8f631
Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Date: Mon Oct 26 07:47:20 2015 -0700
fs: Fix argument to list_entry_rcu()
The list_entry_rcu() macro requires that its first argument be the
pointer to the list_head contained in the structure whose pointer is to
be returned, but fetched in an RCU-safe manner. This commit therefore
fixes the use in bdi_split_work_to_wbs() to follow this convention.
Reported-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 29e4599f6fc1..126d4de8faad 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -779,7 +779,7 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
bool skip_if_busy)
{
struct bdi_writeback *last_wb = NULL;
- struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
+ struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,
struct bdi_writeback, bdi_node);
might_sleep();
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ingo Molnar <mingo@kernel.org> |
|---|---|
| Date | 2015-10-26 19:10 +0100 |
| Message-ID | <qnUnw-35z-7@gated-at.bofh.it> |
| In reply to | #1256088 |
* Paul E. McKenney <paulmck@linux.vnet.ibm.com> wrote:
> > It's this new usage in fs/fs-writeback.c:
> >
> > static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
> > struct wb_writeback_work *base_work,
> > bool skip_if_busy)
> > {
> > struct bdi_writeback *last_wb = NULL;
> > struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
>
> I believe that the above should instead be:
>
> struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,
>
> After all, RCU read-side list primitives need to fetch pointers in order to
> traverse those pointers in an RCU-safe manner. The patch below clears this up
> for me, does it also work for you?
Are you sure about that?
I considered this solution too, but the code goes like this:
static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
struct wb_writeback_work *base_work,
bool skip_if_busy)
{
struct bdi_writeback *last_wb = NULL;
struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
struct bdi_writeback, bdi_node);
might_sleep();
restart:
rcu_read_lock();
list_for_each_entry_continue_rcu(wb, &bdi->wb_list, bdi_node) {
and list_for_each_entry_continue_rcu() will start the iteration with the next
entry. So if you initialize the head with .next, then we'll start with
.next->next, i.e. we skip the first entry.
That seems to change behavior and break the logic.
Another solution I considered is to use bd->wb_list.next->prev, but that, beyond
being ugly, causes actual extra runtime overhead - for something that seems
academical.
Thanks,
Ingo
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Linus Torvalds <torvalds@linux-foundation.org> |
|---|---|
| Date | 2015-10-27 04:40 +0100 |
| Subject | Re: [PATCH tip/core/rcu 11/13] rculist: Make list_entry_rcu() use lockless_dereference() |
| Message-ID | <qo3h7-7h-3@gated-at.bofh.it> |
| In reply to | #1256088 |
On Mon, Oct 26, 2015 at 11:55 PM, Paul E. McKenney
<paulmck@linux.vnet.ibm.com> wrote:
>> struct bdi_writeback *last_wb = NULL;
>> struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
>
> I believe that the above should instead be:
>
> struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,
I don't think you can do that.
You haven't even taken the RCU read lock yet at this point.
What the code seems to try to do is to get the "head pointer" of the
list before taking the read lock (since _that_ is stable), and then
follow the list under the lock.
You're making it actually follow the first RCU pointer too early.
That said, I'm not sure why it doesn't just do the normal
rcu_read_lock();
list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node) {
....
}
rcu_read_unlock();
like the other places do. It looks like it wants that
"list_for_each_entry_continue_rcu()" because it does that odd "pin
entry and drop rcu lock and retake it and continue where you left
off", but I'm not sure why the continue version would be so
different.. It's going to do that "follow next entry" regardless, and
the "goto restart" doesn't look like it actually adds anything. If
following the next pointer is ok even after having released the RCU
read lock, then I'm not seeing why the end of the loop couldn't just
do
rcu_read_unlock();
wb_wait_for_completion(bdi, &fallback_work_done);
rcu_read_lock();
and just continue the loop (and the pinning of "wb" and releasing the
"last_wb" thing in the *next* iteration should make it all work the
same).
Adding Tejun to the cc, because this is his code and there's probably
something subtle I'm missing. Tejun, can you take a look? It's
bdi_split_work_to_wbs() in fs/fs-writeback.c.
Linus
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2015-10-27 06:20 +0100 |
| Message-ID | <qo4PT-18r-9@gated-at.bofh.it> |
| In reply to | #1256445 |
Hello,
On Tue, Oct 27, 2015 at 12:37:16PM +0900, Linus Torvalds wrote:
> > I believe that the above should instead be:
> >
> > struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,
I should have just used list_entry() here. It's just offseting the
pointer to set up the initial iteration point.
...
> That said, I'm not sure why it doesn't just do the normal
>
> rcu_read_lock();
> list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node) {
> ....
> }
> rcu_read_unlock();
>
> like the other places do. It looks like it wants that
> "list_for_each_entry_continue_rcu()" because it does that odd "pin
> entry and drop rcu lock and retake it and continue where you left
> off", but I'm not sure why the continue version would be so
> different.. It's going to do that "follow next entry" regardless, and
> the "goto restart" doesn't look like it actually adds anything. If
> following the next pointer is ok even after having released the RCU
> read lock, then I'm not seeing why the end of the loop couldn't just
> do
>
> rcu_read_unlock();
> wb_wait_for_completion(bdi, &fallback_work_done);
> rcu_read_lock();
>
> and just continue the loop (and the pinning of "wb" and releasing the
> "last_wb" thing in the *next* iteration should make it all work the
> same).
>
> Adding Tejun to the cc, because this is his code and there's probably
> something subtle I'm missing. Tejun, can you take a look? It's
> bdi_split_work_to_wbs() in fs/fs-writeback.c.
Yeah, just releasing and regrabbing should work too as the iterator
doesn't depend on anything other than the current entry (e.g. as
opposed to imaginary list_for_each_entry_safe_rcu()). It's slightly
icky to meddle with locking behind the iterator's back tho. Either
way should be fine but how about something like the following?
Subject: writeback: don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs()
bdi_split_work_to_wbs() uses list_for_each_entry_rcu_continue() to
walk @bdi->wb_list. To set up the initial iteration condition, it
uses list_entry_rcu() to calculate the entry pointer corresponding to
the list head; however, this isn't an actual RCU dereference and using
list_entry_rcu() for it ended up breaking a proposed list_entry_rcu()
change because it was feeding an non-lvalue pointer into the macro.
Don't use the RCU variant for simple pointer offsetting. Use
list_entry() instead.
Signed-off-by: Tejun Heo <tj@kernel.org>
---
fs/fs-writeback.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 29e4599..7378169 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
bool skip_if_busy)
{
struct bdi_writeback *last_wb = NULL;
- struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
- struct bdi_writeback, bdi_node);
+ struct bdi_writeback *wb = list_entry(&bdi->wb_list,
+ struct bdi_writeback, bdi_node);
might_sleep();
restart:
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> |
|---|---|
| Date | 2015-10-27 06:40 +0100 |
| Message-ID | <qo59g-1gU-21@gated-at.bofh.it> |
| In reply to | #1256463 |
On Tue, Oct 27, 2015 at 02:19:39PM +0900, Tejun Heo wrote:
> Hello,
>
> On Tue, Oct 27, 2015 at 12:37:16PM +0900, Linus Torvalds wrote:
> > > I believe that the above should instead be:
> > >
> > > struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,
>
> I should have just used list_entry() here. It's just offseting the
> pointer to set up the initial iteration point.
OK, that sounds much better!
> ...
> > That said, I'm not sure why it doesn't just do the normal
> >
> > rcu_read_lock();
> > list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node) {
> > ....
> > }
> > rcu_read_unlock();
> >
> > like the other places do. It looks like it wants that
> > "list_for_each_entry_continue_rcu()" because it does that odd "pin
> > entry and drop rcu lock and retake it and continue where you left
> > off", but I'm not sure why the continue version would be so
> > different.. It's going to do that "follow next entry" regardless, and
> > the "goto restart" doesn't look like it actually adds anything. If
> > following the next pointer is ok even after having released the RCU
> > read lock, then I'm not seeing why the end of the loop couldn't just
> > do
> >
> > rcu_read_unlock();
> > wb_wait_for_completion(bdi, &fallback_work_done);
> > rcu_read_lock();
> >
> > and just continue the loop (and the pinning of "wb" and releasing the
> > "last_wb" thing in the *next* iteration should make it all work the
> > same).
> >
> > Adding Tejun to the cc, because this is his code and there's probably
> > something subtle I'm missing. Tejun, can you take a look? It's
> > bdi_split_work_to_wbs() in fs/fs-writeback.c.
>
> Yeah, just releasing and regrabbing should work too as the iterator
> doesn't depend on anything other than the current entry (e.g. as
> opposed to imaginary list_for_each_entry_safe_rcu()). It's slightly
> icky to meddle with locking behind the iterator's back tho. Either
> way should be fine but how about something like the following?
>
> Subject: writeback: don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs()
>
> bdi_split_work_to_wbs() uses list_for_each_entry_rcu_continue() to
> walk @bdi->wb_list. To set up the initial iteration condition, it
> uses list_entry_rcu() to calculate the entry pointer corresponding to
> the list head; however, this isn't an actual RCU dereference and using
> list_entry_rcu() for it ended up breaking a proposed list_entry_rcu()
> change because it was feeding an non-lvalue pointer into the macro.
>
> Don't use the RCU variant for simple pointer offsetting. Use
> list_entry() instead.
>
> Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
> ---
> fs/fs-writeback.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
> index 29e4599..7378169 100644
> --- a/fs/fs-writeback.c
> +++ b/fs/fs-writeback.c
> @@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
> bool skip_if_busy)
> {
> struct bdi_writeback *last_wb = NULL;
> - struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
> - struct bdi_writeback, bdi_node);
> + struct bdi_writeback *wb = list_entry(&bdi->wb_list,
> + struct bdi_writeback, bdi_node);
>
> might_sleep();
> restart:
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Ingo Molnar <mingo@kernel.org> |
|---|---|
| Date | 2015-10-28 09:40 +0100 |
| Message-ID | <qouqZ-dw-13@gated-at.bofh.it> |
| In reply to | #1256463 |
* Tejun Heo <tj@kernel.org> wrote:
> Subject: writeback: don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs()
>
> bdi_split_work_to_wbs() uses list_for_each_entry_rcu_continue() to
> walk @bdi->wb_list. To set up the initial iteration condition, it
> uses list_entry_rcu() to calculate the entry pointer corresponding to
> the list head; however, this isn't an actual RCU dereference and using
> list_entry_rcu() for it ended up breaking a proposed list_entry_rcu()
> change because it was feeding an non-lvalue pointer into the macro.
>
> Don't use the RCU variant for simple pointer offsetting. Use
> list_entry() instead.
>
> Signed-off-by: Tejun Heo <tj@kernel.org>
> ---
> fs/fs-writeback.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
> index 29e4599..7378169 100644
> --- a/fs/fs-writeback.c
> +++ b/fs/fs-writeback.c
> @@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
> bool skip_if_busy)
> {
> struct bdi_writeback *last_wb = NULL;
> - struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
> - struct bdi_writeback, bdi_node);
> + struct bdi_writeback *wb = list_entry(&bdi->wb_list,
> + struct bdi_writeback, bdi_node);
>
> might_sleep();
Any objections against me applying this fix to tip:core/rcu so that I can push the
recent RCU changes towards linux-next without triggering a build failure?
Thanks,
Ingo
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Patrick Marlier <patrick.marlier@gmail.com> |
|---|---|
| Date | 2015-10-28 21:40 +0100 |
| Message-ID | <qoFFM-7u4-3@gated-at.bofh.it> |
| In reply to | #1257794 |
On 10/28/2015 09:33 AM, Ingo Molnar wrote:
>
> * Tejun Heo <tj@kernel.org> wrote:
>
>> Subject: writeback: don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs()
>>
>> bdi_split_work_to_wbs() uses list_for_each_entry_rcu_continue() to
>> walk @bdi->wb_list. To set up the initial iteration condition, it
>> uses list_entry_rcu() to calculate the entry pointer corresponding to
>> the list head; however, this isn't an actual RCU dereference and using
>> list_entry_rcu() for it ended up breaking a proposed list_entry_rcu()
>> change because it was feeding an non-lvalue pointer into the macro.
>>
>> Don't use the RCU variant for simple pointer offsetting. Use
>> list_entry() instead.
>>
>> Signed-off-by: Tejun Heo <tj@kernel.org>
>> ---
>> fs/fs-writeback.c | 4 ++--
>> 1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
>> index 29e4599..7378169 100644
>> --- a/fs/fs-writeback.c
>> +++ b/fs/fs-writeback.c
>> @@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
>> bool skip_if_busy)
>> {
>> struct bdi_writeback *last_wb = NULL;
>> - struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
>> - struct bdi_writeback, bdi_node);
>> + struct bdi_writeback *wb = list_entry(&bdi->wb_list,
>> + struct bdi_writeback, bdi_node);
>>
>> might_sleep();
>
> Any objections against me applying this fix to tip:core/rcu so that I can push the
> recent RCU changes towards linux-next without triggering a build failure?
No objection on my side but probably you are waiting for an ack from
somebody else.
--
Pat
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> |
|---|---|
| Date | 2015-10-29 01:10 +0100 |
| Message-ID | <qoIWZ-1dO-1@gated-at.bofh.it> |
| In reply to | #1258403 |
On Wed, Oct 28, 2015 at 09:35:42PM +0100, Patrick Marlier wrote:
>
>
> On 10/28/2015 09:33 AM, Ingo Molnar wrote:
> >
> >* Tejun Heo <tj@kernel.org> wrote:
> >
> >>Subject: writeback: don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs()
> >>
> >>bdi_split_work_to_wbs() uses list_for_each_entry_rcu_continue() to
> >>walk @bdi->wb_list. To set up the initial iteration condition, it
> >>uses list_entry_rcu() to calculate the entry pointer corresponding to
> >>the list head; however, this isn't an actual RCU dereference and using
> >>list_entry_rcu() for it ended up breaking a proposed list_entry_rcu()
> >>change because it was feeding an non-lvalue pointer into the macro.
> >>
> >>Don't use the RCU variant for simple pointer offsetting. Use
> >>list_entry() instead.
> >>
> >>Signed-off-by: Tejun Heo <tj@kernel.org>
> >>---
> >> fs/fs-writeback.c | 4 ++--
> >> 1 file changed, 2 insertions(+), 2 deletions(-)
> >>
> >>diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
> >>index 29e4599..7378169 100644
> >>--- a/fs/fs-writeback.c
> >>+++ b/fs/fs-writeback.c
> >>@@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
> >> bool skip_if_busy)
> >> {
> >> struct bdi_writeback *last_wb = NULL;
> >>- struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
> >>- struct bdi_writeback, bdi_node);
> >>+ struct bdi_writeback *wb = list_entry(&bdi->wb_list,
> >>+ struct bdi_writeback, bdi_node);
> >>
> >> might_sleep();
> >
> >Any objections against me applying this fix to tip:core/rcu so that I can push the
> >recent RCU changes towards linux-next without triggering a build failure?
>
> No objection on my side but probably you are waiting for an ack from
> somebody else.
I am guessing that he was asking Tejun, but just for the record, I am
OK with it as well:
Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Thanx, Paul
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2015-10-29 03:20 +0100 |
| Message-ID | <qoKYO-2ww-1@gated-at.bofh.it> |
| In reply to | #1258492 |
On Wed, Oct 28, 2015 at 05:00:30PM -0700, Paul E. McKenney wrote: > > >Any objections against me applying this fix to tip:core/rcu so that I can push the > > >recent RCU changes towards linux-next without triggering a build failure? > > > > No objection on my side but probably you are waiting for an ack from > > somebody else. > > I am guessing that he was asking Tejun, but just for the record, I am > OK with it as well: > > Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Oops, sorry, for some reason I thought Ingo was asking someone else. The patch already got applied but yes routing it through -tip sounds good. Thanks. -- tejun -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | tip-bot for Tejun Heo <tipbot@zytor.com> |
|---|---|
| Date | 2015-10-28 22:00 +0100 |
| Subject | [tip:core/rcu] fs/writeback, rcu: Don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs() |
| Message-ID | <qoFZ7-7Bh-11@gated-at.bofh.it> |
| In reply to | #1256463 |
Commit-ID: b33e18f61bd18227a456016a77b1a968f5bc1d65
Gitweb: http://git.kernel.org/tip/b33e18f61bd18227a456016a77b1a968f5bc1d65
Author: Tejun Heo <tj@kernel.org>
AuthorDate: Tue, 27 Oct 2015 14:19:39 +0900
Committer: Ingo Molnar <mingo@kernel.org>
CommitDate: Wed, 28 Oct 2015 13:17:30 +0100
fs/writeback, rcu: Don't use list_entry_rcu() for pointer offsetting in bdi_split_work_to_wbs()
bdi_split_work_to_wbs() uses list_for_each_entry_rcu_continue()
to walk @bdi->wb_list. To set up the initial iteration
condition, it uses list_entry_rcu() to calculate the entry
pointer corresponding to the list head; however, this isn't an
actual RCU dereference and using list_entry_rcu() for it ended
up breaking a proposed list_entry_rcu() change because it was
feeding an non-lvalue pointer into the macro.
Don't use the RCU variant for simple pointer offsetting. Use
list_entry() instead.
Reported-by: Ingo Molnar <mingo@kernel.org>
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Darren Hart <dvhart@linux.intel.com>
Cc: David Howells <dhowells@redhat.com>
Cc: Dipankar Sarma <dipankar@in.ibm.com>
Cc: Eric Dumazet <edumazet@google.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Lai Jiangshan <jiangshanlai@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Patrick Marlier <patrick.marlier@gmail.com>
Cc: Paul McKenney <paulmck@linux.vnet.ibm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: pranith kumar <bobby.prani@gmail.com>
Link: http://lkml.kernel.org/r/20151027051939.GA19355@mtj.duckdns.org
Signed-off-by: Ingo Molnar <mingo@kernel.org>
---
fs/fs-writeback.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 29e4599..7378169 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -779,8 +779,8 @@ static void bdi_split_work_to_wbs(struct backing_dev_info *bdi,
bool skip_if_busy)
{
struct bdi_writeback *last_wb = NULL;
- struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
- struct bdi_writeback, bdi_node);
+ struct bdi_writeback *wb = list_entry(&bdi->wb_list,
+ struct bdi_writeback, bdi_node);
might_sleep();
restart:
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [next] | [standalone]
| From | "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> |
|---|---|
| Date | 2015-10-27 06:40 +0100 |
| Message-ID | <qo59g-1gU-23@gated-at.bofh.it> |
| In reply to | #1256445 |
On Tue, Oct 27, 2015 at 12:37:16PM +0900, Linus Torvalds wrote:
> On Mon, Oct 26, 2015 at 11:55 PM, Paul E. McKenney
> <paulmck@linux.vnet.ibm.com> wrote:
> >> struct bdi_writeback *last_wb = NULL;
> >> struct bdi_writeback *wb = list_entry_rcu(&bdi->wb_list,
> >
> > I believe that the above should instead be:
> >
> > struct bdi_writeback *wb = list_entry_rcu(bdi->wb_list.next,
>
> I don't think you can do that.
>
> You haven't even taken the RCU read lock yet at this point.
>
> What the code seems to try to do is to get the "head pointer" of the
> list before taking the read lock (since _that_ is stable), and then
> follow the list under the lock.
>
> You're making it actually follow the first RCU pointer too early.
Good point, color me dazed and confused. :-/
Thanx, Paul
> That said, I'm not sure why it doesn't just do the normal
>
> rcu_read_lock();
> list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node) {
> ....
> }
> rcu_read_unlock();
>
> like the other places do. It looks like it wants that
> "list_for_each_entry_continue_rcu()" because it does that odd "pin
> entry and drop rcu lock and retake it and continue where you left
> off", but I'm not sure why the continue version would be so
> different.. It's going to do that "follow next entry" regardless, and
> the "goto restart" doesn't look like it actually adds anything. If
> following the next pointer is ok even after having released the RCU
> read lock, then I'm not seeing why the end of the loop couldn't just
> do
>
> rcu_read_unlock();
> wb_wait_for_completion(bdi, &fallback_work_done);
> rcu_read_lock();
>
> and just continue the loop (and the pinning of "wb" and releasing the
> "last_wb" thing in the *next* iteration should make it all work the
> same).
>
> Adding Tejun to the cc, because this is his code and there's probably
> something subtle I'm missing. Tejun, can you take a look? It's
> bdi_split_work_to_wbs() in fs/fs-writeback.c.
>
> Linus
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web