From: Martin KaFai Lau <redacted>
The map_lookup_elem used to not acquiring spinlock
in order to optimize the reader.
It was true until commit 557c0c6e7df8 ("bpf: convert stackmap to pre-allocation")
The syscall's map_lookup_elem(stackmap) calls bpf_stackmap_copy().
bpf_stackmap_copy() may find the elem no longer needed after the copy is done.
If that is the case, pcpu_freelist_push() saves this elem for reuse later.
This push requires a spinlock.
If a tracing bpf_prog got run in the middle of the syscall's
map_lookup_elem(stackmap) and this tracing bpf_prog is calling
bpf_get_stackid(stackmap) which also requires the same pcpu_freelist's
spinlock, it may end up with a dead lock situation as reported by
Eric Dumazet in https://patchwork.ozlabs.org/patch/1030266/
The situation is the same as the syscall's map_update_elem() which
needs to acquire the pcpu_freelist's spinlock and could race
with tracing bpf_prog. Hence, this patch fixes it by protecting
bpf_stackmap_copy() with this_cpu_inc(bpf_prog_active)
to prevent tracing bpf_prog from running.
A later syscall's map_lookup_elem commit f1a2e44a3aec ("bpf: add queue and stack maps")
also acquires a spinlock and races with tracing bpf_prog similarly.
Hence, this patch is forward looking and protects the majority
of the map lookups. bpf_map_offload_lookup_elem() is the exception
since it is for network bpf_prog only (i.e. never called by tracing
bpf_prog).
Fixes: 557c0c6e7df8 ("bpf: convert stackmap to pre-allocation")
Reported-by: Eric Dumazet <redacted>
Acked-by: Alexei Starovoitov <ast@kernel.org>
Signed-off-by: Martin KaFai Lau <redacted>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
---
kernel/bpf/syscall.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
On Tue, Jan 29, 2019 at 8:06 PM Alexei Starovoitov [off-list ref] wrote:
In addition to preempt_disable patch for socket filters
https://patchwork.ozlabs.org/patch/1032437/
the first three patches fix various lockdep false positives.
Last patch fixes potential deadlock in stackmap access from
tracing bpf prog and from syscall.
From: Peter Zijlstra <peterz@infradead.org> Date: 2019-01-30 10:11:24
On Tue, Jan 29, 2019 at 08:04:57PM -0800, Alexei Starovoitov wrote:
Lockdep warns about false positive:
The report reads like:
tracepoint_probe_register()
#0 mutex_lock(&tracepoint_mutex)
tracepoint_add_func()
static_key_slow_inc()
#1 cpus_read_lock();
_cpu_up()
#1 cpus_write_lock();
...
perf_event_init_cpu()
#2 mutex_lock(&pmus_lock);
#3 mutex_lock(&ctx->mutex);
perf_ioctl()
#4 perf_event_ctx_lock();
_perf_ioctl(IOC_QUERY_BPF)
perf_event_query_prog_array()
#5 mutex_lock(&bpf_event_mutex);
bpf_probe_register()
#5 mutex_lock(&bpf_event_mutex);
__bpf_probe_register()
tracepoint_probe_register()
#0 mutex_lock(&tracepoint_mutex);
Which to me reads like an entirely valid deadlock scenario.
And note that the first and last can be combined to give:
bpf_probe_register()
#5 mutex_lock(&bpf_event_mutex);
__bpf_probe_register()
tracepoint_probe_register()
#0 mutex_lock(&tracepoint_mutex);
tracepoint_add_func()
static_key_slow_inc()
#1 cpus_read_lock();
Which generates a deadlock even without #0.
Why do you say this is not possible? All you need is 3 CPUs, one doing a
CPU online, one doing a perf ioctl() and one doing that
bpf_probe_register().
From: Peter Zijlstra <peterz@infradead.org> Date: 2019-01-30 10:15:44
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
quoted hunk
[ 11.211460] ------------[ cut here ]------------
[ 11.211936] DEBUG_LOCKS_WARN_ON(depth <= 0)
[ 11.211985] WARNING: CPU: 0 PID: 141 at ../kernel/locking/lockdep.c:3592 lock_release+0x1ad/0x280
[ 11.213134] Modules linked in:
[ 11.213413] CPU: 0 PID: 141 Comm: systemd-journal Not tainted 5.0.0-rc3-00018-g2fa53f892422-dirty #476
[ 11.214191] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.11.0-2.el7 04/01/2014
[ 11.214954] RIP: 0010:lock_release+0x1ad/0x280
[ 11.217036] RSP: 0018:ffff88813ba03f50 EFLAGS: 00010086
[ 11.217516] RAX: 000000000000001f RBX: ffff8881378d8000 RCX: 0000000000000000
[ 11.218179] RDX: ffffffff810d3e9e RSI: 0000000000000001 RDI: ffffffff810d3eb3
[ 11.218851] RBP: ffff8881393e2b08 R08: 0000000000000002 R09: 0000000000000000
[ 11.219504] R10: 0000000000000000 R11: ffff88813ba03d9d R12: ffffffff8118dfa2
[ 11.220162] R13: 0000000000000086 R14: 0000000000000000 R15: 0000000000000000
[ 11.220717] FS: 00007f3c8cf35780(0000) GS:ffff88813ba00000(0000) knlGS:0000000000000000
[ 11.221348] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 11.221822] CR2: 00007f5825d92080 CR3: 00000001378c8005 CR4: 00000000003606f0
[ 11.222381] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 11.222951] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
[ 11.223508] Call Trace:
[ 11.223705] <IRQ>
[ 11.223874] ? __local_bh_enable+0x7a/0x80
[ 11.224199] up_read+0x1c/0xa0
[ 11.224446] do_up_read+0x12/0x20
[ 11.224713] irq_work_run_list+0x43/0x70
[ 11.225030] irq_work_run+0x26/0x50
[ 11.225310] smp_irq_work_interrupt+0x57/0x1f0
[ 11.225662] irq_work_interrupt+0xf/0x20
since rw_semaphore is released in a different task vs task that locked the sema.
It is expected behavior.
Silence the warning by using up_read_non_owner().
Fixes: bae77c5eb5b2 ("bpf: enable stackmap with build_id in nmi context")
Acked-by: Martin KaFai Lau <redacted>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
---
kernel/bpf/stackmap.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Please, no external references like that. The best option is to fully
include the explanation here so that a future software archeology
student (note, this might be yourself in a years time) can find all
relevant information in the git history.
Or, if you _really_ _really_ have to refer to external sources, use:
https://lkml.kernel.org/r/${msg_id}
which is a controlled URL and can be made to point to any archive
(currently, and sadly, lore.kernel.org).
Also, since it includes the whole msg_id, people can trivially find the
email in their local archive.
While I agree that lkml.org is a _MUCH_ saner interface than lore (which
causes eye and brain cancer for just looking at it), it is a _really_
flaky website and the url contains no clues for finding it in the local
archive.
Recap:
- stackmap uses pcpu_freelist
- The lock in pcpu_freelist is a percpu lock
- stackmap is only used by tracing bpf_prog
- A tracing bpf_prog cannot be run if another bpf_prog
has already been running (ensured by the percpu bpf_prog_active counter).
Sorry, that's #3, and then do s/#5/#4/ on the rest of the text.
_perf_ioctl(IOC_QUERY_BPF)
perf_event_query_prog_array()
#5 mutex_lock(&bpf_event_mutex);
bpf_probe_register()
#5 mutex_lock(&bpf_event_mutex);
__bpf_probe_register()
tracepoint_probe_register()
#0 mutex_lock(&tracepoint_mutex);
Which to me reads like an entirely valid deadlock scenario.
And note that the first and last can be combined to give:
bpf_probe_register()
#5 mutex_lock(&bpf_event_mutex);
__bpf_probe_register()
tracepoint_probe_register()
#0 mutex_lock(&tracepoint_mutex);
tracepoint_add_func()
static_key_slow_inc()
#1 cpus_read_lock();
Which generates a deadlock even without #0.
Why do you say this is not possible? All you need is 3 CPUs, one doing a
CPU online, one doing a perf ioctl() and one doing that
bpf_probe_register().
Please, no external references like that. The best option is to fully
I strongly disagree.
We allowed all kinds of external links in bpf tree in the past and
going to continue doing so in the future.
I'm perfectly aware that some of them will go stale in a day or
in a year.
On Wed, Jan 30, 2019 at 11:15:30AM +0100, Peter Zijlstra wrote:
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
quoted
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
Can you point out in the code the spin bit?
As far as I can see sem->owner is debug only feature.
All owner checks are done under CONFIG_DEBUG_RWSEMS.
Also there is no down_read_trylock_non_owner() at the moment.
We can argue about it for -next, but I'd rather silence lockdep
with this patch today.
On Wed, Jan 30, 2019 at 11:10:58AM +0100, Peter Zijlstra wrote:
Why do you say this is not possible? All you need is 3 CPUs, one doing a
CPU online, one doing a perf ioctl() and one doing that
bpf_probe_register().
yeah. indeed. I'm impressed that lockdep figured it out
while I missed it manually looking through the code and stack traces.
Will reword the commit log.
From: Waiman Long <longman@redhat.com> Date: 2019-01-30 19:42:27
On 01/30/2019 02:30 PM, Alexei Starovoitov wrote:
On Wed, Jan 30, 2019 at 11:15:30AM +0100, Peter Zijlstra wrote:
quoted
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
quoted
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
Can you point out in the code the spin bit?
As far as I can see sem->owner is debug only feature.
All owner checks are done under CONFIG_DEBUG_RWSEMS.
No, sem->owner is mainly for performing optimistic spinning which is a
performance feature to make rwsem writer-lock performs similar to mutex.
The debugging part is just an add-on. It is not the reason for the
presence of sem->owner.
Also there is no down_read_trylock_non_owner() at the moment.
We can argue about it for -next, but I'd rather silence lockdep
with this patch today.
We can add down_read_trylock_non_owner() if there is a need for it. It
should be easy to do.
Cheers,
Longman
down_read_trylock_non_owner(
From: Peter Zijlstra <peterz@infradead.org> Date: 2019-01-30 19:44:26
On Wed, Jan 30, 2019 at 11:30:41AM -0800, Alexei Starovoitov wrote:
On Wed, Jan 30, 2019 at 11:15:30AM +0100, Peter Zijlstra wrote:
quoted
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
quoted
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
Can you point out in the code the spin bit?
Hurmph, looks like you're right. I got lost in that stuff again. I hate
that rwsem code :/
Rewriting that all is on the todo list somewhere, but it's far down :/
As far as I can see sem->owner is debug only feature.
All owner checks are done under CONFIG_DEBUG_RWSEMS.
Also there is no down_read_trylock_non_owner() at the moment.
We can argue about it for -next, but I'd rather silence lockdep
with this patch today.
I don't agree with calling is silencing; it fixes an mis-use of the API.
But yes, keep the patch as is for now.
Please, no external references like that. The best option is to fully
I strongly disagree.
We allowed all kinds of external links in bpf tree in the past and
going to continue doing so in the future.
I'm perfectly aware that some of them will go stale in a day or
in a year.
What's the point of adding URLs if you know they'll not be useful later?
Anyway, your tree, so you get to make the rules, but personally I've
cursed about this exact issue a fair few times.
See for example the x86 tree policy of creating BZ entries to store
Intel documents to refer to them from commits because the Intel website
is notoriously flaky wrt persistence.
There's nothing worse than references to a document you can no longer
find while trying to make sense of this 3 year old code that suddenly
comes apart.
From: Waiman Long <longman@redhat.com> Date: 2019-01-30 20:05:27
On 01/30/2019 02:44 PM, Peter Zijlstra wrote:
On Wed, Jan 30, 2019 at 11:30:41AM -0800, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 11:15:30AM +0100, Peter Zijlstra wrote:
quoted
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
quoted
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
Can you point out in the code the spin bit?
Hurmph, looks like you're right. I got lost in that stuff again. I hate
that rwsem code :/
It is actually related to how the lockdep code track if a lock is
acquired or released. It is not actually related to how the rwsem code work.
Rewriting that all is on the todo list somewhere, but it's far down :/
I am actually planning to rewrite it. Hopefully, I can send out the
patch soon.
Cheers,
Longman
On Wed, Jan 30, 2019 at 02:42:23PM -0500, Waiman Long wrote:
On 01/30/2019 02:30 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 11:15:30AM +0100, Peter Zijlstra wrote:
quoted
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
quoted
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
Can you point out in the code the spin bit?
As far as I can see sem->owner is debug only feature.
All owner checks are done under CONFIG_DEBUG_RWSEMS.
No, sem->owner is mainly for performing optimistic spinning which is a
performance feature to make rwsem writer-lock performs similar to mutex.
The debugging part is just an add-on. It is not the reason for the
presence of sem->owner.
I see. Got it.
quoted
Also there is no down_read_trylock_non_owner() at the moment.
We can argue about it for -next, but I'd rather silence lockdep
with this patch today.
We can add down_read_trylock_non_owner() if there is a need for it. It
should be easy to do.
Yes, but looking through the code it's not clear to me that it's safe
to mix non_owner() versions with regular.
bpf/stackmap.c does down_read_trylock + up_read.
If we add new down_read_trylock_non_owner that set the owner to
NULL | RWSEM_* bits is this safe with conccurent read/write
that do regular versions?
rwsem_can_spin_on_owner() does:
if (owner) {
ret = is_rwsem_owner_spinnable(owner) &&
owner_on_cpu(owner);
that looks correct.
For a second I thought there could be fault here due to non_owner.
But there could be other places where it's assumed that owner
is never null?
May be we should live with this lockdep warn in bpf tree
and fix it only in bpf-next?
Please, no external references like that. The best option is to fully
I strongly disagree.
We allowed all kinds of external links in bpf tree in the past and
going to continue doing so in the future.
I'm perfectly aware that some of them will go stale in a day or
in a year.
What's the point of adding URLs if you know they'll not be useful later?
Anyway, your tree, so you get to make the rules, but personally I've
cursed about this exact issue a fair few times.
See for example the x86 tree policy of creating BZ entries to store
Intel documents to refer to them from commits because the Intel website
is notoriously flaky wrt persistence.
well. yes. it's case by case.
Not every link would be acceptable.
URL to a news website wouldn't appropriate a git tree :)
but pointer to github.com or a corporate website likely going to be alive
for some time.
There's nothing worse than references to a document you can no longer
find while trying to make sense of this 3 year old code that suddenly
comes apart.
true. I'm not saying that it's ok to put all info on the website
and keep commit minimal. Quite the opposite.
The commit log should be descriptive and contain all information
to explain the change. Extra url is an additional info.
From: Waiman Long <longman@redhat.com> Date: 2019-01-30 21:11:22
On 01/30/2019 03:10 PM, Alexei Starovoitov wrote:
On Wed, Jan 30, 2019 at 02:42:23PM -0500, Waiman Long wrote:
quoted
On 01/30/2019 02:30 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 11:15:30AM +0100, Peter Zijlstra wrote:
quoted
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
quoted
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
Can you point out in the code the spin bit?
As far as I can see sem->owner is debug only feature.
All owner checks are done under CONFIG_DEBUG_RWSEMS.
No, sem->owner is mainly for performing optimistic spinning which is a
performance feature to make rwsem writer-lock performs similar to mutex.
The debugging part is just an add-on. It is not the reason for the
presence of sem->owner.
I see. Got it.
quoted
quoted
Also there is no down_read_trylock_non_owner() at the moment.
We can argue about it for -next, but I'd rather silence lockdep
with this patch today.
We can add down_read_trylock_non_owner() if there is a need for it. It
should be easy to do.
Yes, but looking through the code it's not clear to me that it's safe
to mix non_owner() versions with regular.
bpf/stackmap.c does down_read_trylock + up_read.
If we add new down_read_trylock_non_owner that set the owner to
NULL | RWSEM_* bits is this safe with conccurent read/write
that do regular versions?
rwsem_can_spin_on_owner() does:
if (owner) {
ret = is_rwsem_owner_spinnable(owner) &&
owner_on_cpu(owner);
that looks correct.
For a second I thought there could be fault here due to non_owner.
But there could be other places where it's assumed that owner
is never null?
The content of owner is not the cause of the lockdep warning. The
lockdep code assumes that the task that acquires the lock will release
it some time later. That is not the case when you need to acquire the
lock by one task and released by another. In this case, you have to use
the non_owner version of down/up_read which disable the lockdep
acquire/release tracking. That will be the only difference between the
two set of APIs.
Cheers,
Longman
May be we should live with this lockdep warn in bpf tree
and fix it only in bpf-next?
From: Waiman Long <longman@redhat.com> Date: 2019-01-30 21:32:16
On 01/30/2019 04:11 PM, Waiman Long wrote:
On 01/30/2019 03:10 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 02:42:23PM -0500, Waiman Long wrote:
quoted
On 01/30/2019 02:30 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 11:15:30AM +0100, Peter Zijlstra wrote:
quoted
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
quoted
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
Can you point out in the code the spin bit?
As far as I can see sem->owner is debug only feature.
All owner checks are done under CONFIG_DEBUG_RWSEMS.
No, sem->owner is mainly for performing optimistic spinning which is a
performance feature to make rwsem writer-lock performs similar to mutex.
The debugging part is just an add-on. It is not the reason for the
presence of sem->owner.
I see. Got it.
quoted
quoted
Also there is no down_read_trylock_non_owner() at the moment.
We can argue about it for -next, but I'd rather silence lockdep
with this patch today.
We can add down_read_trylock_non_owner() if there is a need for it. It
should be easy to do.
Yes, but looking through the code it's not clear to me that it's safe
to mix non_owner() versions with regular.
bpf/stackmap.c does down_read_trylock + up_read.
If we add new down_read_trylock_non_owner that set the owner to
NULL | RWSEM_* bits is this safe with conccurent read/write
that do regular versions?
rwsem_can_spin_on_owner() does:
if (owner) {
ret = is_rwsem_owner_spinnable(owner) &&
owner_on_cpu(owner);
that looks correct.
For a second I thought there could be fault here due to non_owner.
But there could be other places where it's assumed that owner
is never null?
The content of owner is not the cause of the lockdep warning. The
lockdep code assumes that the task that acquires the lock will release
it some time later. That is not the case when you need to acquire the
lock by one task and released by another. In this case, you have to use
the non_owner version of down/up_read which disable the lockdep
acquire/release tracking. That will be the only difference between the
two set of APIs.
Cheers,
Longman
BTW, you may want to do something like that to make sure that the lock
ownership is probably tracked.
-Longman
bpf_stack_
} else {
work->sem = ¤t->mm->mmap_sem;
irq_work_queue(&work->irq_work);
+
+ /*
+ * The irq_work will release the mmap_sem with
+ * up_read_non_owner(). The rwsem_release() is called
+ * here to release the lock from lockdep's perspective.
+ */
+ rwsem_release(¤t->mm->mmap_sem.dep_map, 1, _RET_IP_);
}
}
On Wed, Jan 30, 2019 at 04:32:12PM -0500, Waiman Long wrote:
quoted hunk
On 01/30/2019 04:11 PM, Waiman Long wrote:
quoted
On 01/30/2019 03:10 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 02:42:23PM -0500, Waiman Long wrote:
quoted
On 01/30/2019 02:30 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 11:15:30AM +0100, Peter Zijlstra wrote:
quoted
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
quoted
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
Can you point out in the code the spin bit?
As far as I can see sem->owner is debug only feature.
All owner checks are done under CONFIG_DEBUG_RWSEMS.
No, sem->owner is mainly for performing optimistic spinning which is a
performance feature to make rwsem writer-lock performs similar to mutex.
The debugging part is just an add-on. It is not the reason for the
presence of sem->owner.
I see. Got it.
quoted
quoted
Also there is no down_read_trylock_non_owner() at the moment.
We can argue about it for -next, but I'd rather silence lockdep
with this patch today.
We can add down_read_trylock_non_owner() if there is a need for it. It
should be easy to do.
Yes, but looking through the code it's not clear to me that it's safe
to mix non_owner() versions with regular.
bpf/stackmap.c does down_read_trylock + up_read.
If we add new down_read_trylock_non_owner that set the owner to
NULL | RWSEM_* bits is this safe with conccurent read/write
that do regular versions?
rwsem_can_spin_on_owner() does:
if (owner) {
ret = is_rwsem_owner_spinnable(owner) &&
owner_on_cpu(owner);
that looks correct.
For a second I thought there could be fault here due to non_owner.
But there could be other places where it's assumed that owner
is never null?
The content of owner is not the cause of the lockdep warning. The
lockdep code assumes that the task that acquires the lock will release
it some time later. That is not the case when you need to acquire the
lock by one task and released by another. In this case, you have to use
the non_owner version of down/up_read which disable the lockdep
acquire/release tracking. That will be the only difference between the
two set of APIs.
Cheers,
Longman
BTW, you may want to do something like that to make sure that the lock
ownership is probably tracked.
-Longman
bpf_stack_
} else {
work->sem = ¤t->mm->mmap_sem;
irq_work_queue(&work->irq_work);
+
+ /*
+ * The irq_work will release the mmap_sem with
+ * up_read_non_owner(). The rwsem_release() is called
+ * here to release the lock from lockdep's perspective.
+ */
+ rwsem_release(¤t->mm->mmap_sem.dep_map, 1, _RET_IP_);
are you saying the above is enough coupled with up_read_non_owner?
Looking at how amdgpu is using this api... I think they just use non_owner
version when doing things from different task.
So I don't think pairing non_owner with non_owner is strictly necessary.
It seems fine to use down_read_trylock() with above rwsem_release() hack
plus up_read_non_owner().
Am I missing something?
From: Waiman Long <longman@redhat.com> Date: 2019-01-31 02:48:33
On 01/30/2019 09:01 PM, Alexei Starovoitov wrote:
On Wed, Jan 30, 2019 at 04:32:12PM -0500, Waiman Long wrote:
quoted
On 01/30/2019 04:11 PM, Waiman Long wrote:
quoted
On 01/30/2019 03:10 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 02:42:23PM -0500, Waiman Long wrote:
quoted
On 01/30/2019 02:30 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 11:15:30AM +0100, Peter Zijlstra wrote:
quoted
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
quoted
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
Can you point out in the code the spin bit?
As far as I can see sem->owner is debug only feature.
All owner checks are done under CONFIG_DEBUG_RWSEMS.
No, sem->owner is mainly for performing optimistic spinning which is a
performance feature to make rwsem writer-lock performs similar to mutex.
The debugging part is just an add-on. It is not the reason for the
presence of sem->owner.
I see. Got it.
quoted
quoted
Also there is no down_read_trylock_non_owner() at the moment.
We can argue about it for -next, but I'd rather silence lockdep
with this patch today.
We can add down_read_trylock_non_owner() if there is a need for it. It
should be easy to do.
Yes, but looking through the code it's not clear to me that it's safe
to mix non_owner() versions with regular.
bpf/stackmap.c does down_read_trylock + up_read.
If we add new down_read_trylock_non_owner that set the owner to
NULL | RWSEM_* bits is this safe with conccurent read/write
that do regular versions?
rwsem_can_spin_on_owner() does:
if (owner) {
ret = is_rwsem_owner_spinnable(owner) &&
owner_on_cpu(owner);
that looks correct.
For a second I thought there could be fault here due to non_owner.
But there could be other places where it's assumed that owner
is never null?
The content of owner is not the cause of the lockdep warning. The
lockdep code assumes that the task that acquires the lock will release
it some time later. That is not the case when you need to acquire the
lock by one task and released by another. In this case, you have to use
the non_owner version of down/up_read which disable the lockdep
acquire/release tracking. That will be the only difference between the
two set of APIs.
Cheers,
Longman
BTW, you may want to do something like that to make sure that the lock
ownership is probably tracked.
-Longman
bpf_stack_
} else {
work->sem = ¤t->mm->mmap_sem;
irq_work_queue(&work->irq_work);
+
+ /*
+ * The irq_work will release the mmap_sem with
+ * up_read_non_owner(). The rwsem_release() is called
+ * here to release the lock from lockdep's perspective.
+ */
+ rwsem_release(¤t->mm->mmap_sem.dep_map, 1, _RET_IP_);
are you saying the above is enough coupled with up_read_non_owner?
Looking at how amdgpu is using this api... I think they just use non_owner
version when doing things from different task.
So I don't think pairing non_owner with non_owner is strictly necessary.
It seems fine to use down_read_trylock() with above rwsem_release() hack
plus up_read_non_owner().
Am I missing something?
The statement above is to clear the state for the lockdep so that it
knows that the task no longer owns the lock. Without doing that, there
is a possibility of some other kind of incorrect lockdep warning may be
produced because the code will still think the task hold a read-lock on
the mmap_sem. It is also possible no warning will be reported.
The bpf code is kind of special that it acquires the mmap_sem. Later on,
it either releases it itself (non-NMI) or request irq_work to release it
(NMI). So either, you use the _non_owner versions for both acquire and
release or fake the release like the code segment above.
Peter, please chime in if you have other suggestion.
Cheers,
Longman
From: Eric Dumazet <hidden> Date: 2019-02-06 03:23:04
On 01/30/2019 06:48 PM, Waiman Long wrote:
On 01/30/2019 09:01 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 04:32:12PM -0500, Waiman Long wrote:
quoted
On 01/30/2019 04:11 PM, Waiman Long wrote:
quoted
On 01/30/2019 03:10 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 02:42:23PM -0500, Waiman Long wrote:
quoted
On 01/30/2019 02:30 PM, Alexei Starovoitov wrote:
quoted
On Wed, Jan 30, 2019 at 11:15:30AM +0100, Peter Zijlstra wrote:
quoted
On Tue, Jan 29, 2019 at 08:04:56PM -0800, Alexei Starovoitov wrote:
quoted
Lockdep warns about false positive:
This is not a false positive, and you probably also need to use
down_read_non_owner() to match this up_read_non_owner().
{up,down}_read() and {up,down}_read_non_owner() are not only different
in the lockdep annotation; there is also optimistic spin stuff that
relies on 'owner' tracking.
Can you point out in the code the spin bit?
As far as I can see sem->owner is debug only feature.
All owner checks are done under CONFIG_DEBUG_RWSEMS.
No, sem->owner is mainly for performing optimistic spinning which is a
performance feature to make rwsem writer-lock performs similar to mutex.
The debugging part is just an add-on. It is not the reason for the
presence of sem->owner.
I see. Got it.
quoted
quoted
Also there is no down_read_trylock_non_owner() at the moment.
We can argue about it for -next, but I'd rather silence lockdep
with this patch today.
We can add down_read_trylock_non_owner() if there is a need for it. It
should be easy to do.
Yes, but looking through the code it's not clear to me that it's safe
to mix non_owner() versions with regular.
bpf/stackmap.c does down_read_trylock + up_read.
If we add new down_read_trylock_non_owner that set the owner to
NULL | RWSEM_* bits is this safe with conccurent read/write
that do regular versions?
rwsem_can_spin_on_owner() does:
if (owner) {
ret = is_rwsem_owner_spinnable(owner) &&
owner_on_cpu(owner);
that looks correct.
For a second I thought there could be fault here due to non_owner.
But there could be other places where it's assumed that owner
is never null?
The content of owner is not the cause of the lockdep warning. The
lockdep code assumes that the task that acquires the lock will release
it some time later. That is not the case when you need to acquire the
lock by one task and released by another. In this case, you have to use
the non_owner version of down/up_read which disable the lockdep
acquire/release tracking. That will be the only difference between the
two set of APIs.
Cheers,
Longman
BTW, you may want to do something like that to make sure that the lock
ownership is probably tracked.
-Longman
bpf_stack_
} else {
work->sem = ¤t->mm->mmap_sem;
irq_work_queue(&work->irq_work);
+
+ /*
+ * The irq_work will release the mmap_sem with
+ * up_read_non_owner(). The rwsem_release() is called
+ * here to release the lock from lockdep's perspective.
+ */
+ rwsem_release(¤t->mm->mmap_sem.dep_map, 1, _RET_IP_);
are you saying the above is enough coupled with up_read_non_owner?
Looking at how amdgpu is using this api... I think they just use non_owner
version when doing things from different task.
So I don't think pairing non_owner with non_owner is strictly necessary.
It seems fine to use down_read_trylock() with above rwsem_release() hack
plus up_read_non_owner().
Am I missing something?
The statement above is to clear the state for the lockdep so that it
knows that the task no longer owns the lock. Without doing that, there
is a possibility of some other kind of incorrect lockdep warning may be
produced because the code will still think the task hold a read-lock on
the mmap_sem. It is also possible no warning will be reported.
The bpf code is kind of special that it acquires the mmap_sem. Later on,
it either releases it itself (non-NMI) or request irq_work to release it
(NMI). So either, you use the _non_owner versions for both acquire and
release or fake the release like the code segment above.
Peter, please chime in if you have other suggestion.
bpf_stack_
} else {
work->sem = ¤t->mm->mmap_sem;
irq_work_queue(&work->irq_work);
+
+ /*
+ * The irq_work will release the mmap_sem with
+ * up_read_non_owner(). The rwsem_release() is called
+ * here to release the lock from lockdep's perspective.
+ */
+ rwsem_release(¤t->mm->mmap_sem.dep_map, 1, _RET_IP_);
are you saying the above is enough coupled with up_read_non_owner?
Looking at how amdgpu is using this api... I think they just use non_owner
version when doing things from different task.
So I don't think pairing non_owner with non_owner is strictly necessary.
It seems fine to use down_read_trylock() with above rwsem_release() hack
plus up_read_non_owner().
Am I missing something?
The statement above is to clear the state for the lockdep so that it
knows that the task no longer owns the lock. Without doing that, there
is a possibility of some other kind of incorrect lockdep warning may be
produced because the code will still think the task hold a read-lock on
the mmap_sem. It is also possible no warning will be reported.
The bpf code is kind of special that it acquires the mmap_sem. Later on,
it either releases it itself (non-NMI) or request irq_work to release it
(NMI). So either, you use the _non_owner versions for both acquire and
release or fake the release like the code segment above.
Peter, please chime in if you have other suggestion.
Hi guys
What are the plans to address the issue then ?
Latest net tree exhibits this trace :
Thanks for the reminder :)
I've been waiting for Peter's direction on this one.
Happy to fix it whichever way.
To recap:
Approach 1:
s/up_read/up_read_non_owner/ from irq_work + rwsem_release as Longman proposed.
Apporach 2:
introduce down_read_trylock_non_owner and pair it with up_read_non_owner
in both irq_work and normal.
My preference is 1. I think Longman's as well.
From: Eric Dumazet <hidden> Date: 2019-02-06 03:40:25
On 02/05/2019 07:30 PM, Alexei Starovoitov wrote:
Thanks for the reminder :)
I've been waiting for Peter's direction on this one.
Happy to fix it whichever way.
To recap:
Approach 1:
s/up_read/up_read_non_owner/ from irq_work + rwsem_release as Longman proposed.
Apporach 2:
introduce down_read_trylock_non_owner and pair it with up_read_non_owner
in both irq_work and normal.
My preference is 1. I think Longman's as well.
Unless we envision other uses for down_read_trylock_non_owner() and up_read_non_owner(),
I agree 1) seems good enough, at least for the short term.
Thanks !