Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1491941 > unrolled thread
| Started by | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> |
|---|---|
| First post | 2016-09-27 16:30 +0200 |
| Last post | 2016-10-04 13:40 +0200 |
| Articles | 15 on this page of 35 — 3 participants |
Back to article view | Back to linux.kernel
[RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2016-09-27 16:30 +0200
[RFC][PATCH 5/7] printk: drop vprintk_func function Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2016-09-27 16:30 +0200
[RFC][PATCH 3/7] printk: introduce per-cpu alt_print seq buffer Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2016-09-27 16:30 +0200
Re: [RFC][PATCH 3/7] printk: introduce per-cpu alt_print seq buffer Petr Mladek <pmladek@suse.com> - 2016-09-29 14:30 +0200
Re: [RFC][PATCH 3/7] printk: introduce per-cpu alt_print seq buffer Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-09-30 03:10 +0200
Re: [RFC][PATCH 3/7] printk: introduce per-cpu alt_print seq buffer Petr Mladek <pmladek@suse.com> - 2016-09-30 13:40 +0200
[RFC][PATCH 1/7] printk: use vprintk_func in vprintk() Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2016-09-27 16:30 +0200
[RFC][PATCH 2/7] printk: rename nmi.c and exported api Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2016-09-27 16:30 +0200
[RFC][PATCH 6/7] printk: use alternative printk buffers Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2016-09-27 16:30 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Petr Mladek <pmladek@suse.com> - 2016-09-29 15:10 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-09-30 03:20 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Petr Mladek <pmladek@suse.com> - 2016-09-30 13:20 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-10-01 04:50 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Petr Mladek <pmladek@suse.com> - 2016-10-04 14:30 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-10-05 03:40 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Petr Mladek <pmladek@suse.com> - 2016-10-05 12:20 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2016-10-03 10:00 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Petr Mladek <pmladek@suse.com> - 2016-10-04 17:00 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-10-05 03:30 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Petr Mladek <pmladek@suse.com> - 2016-10-05 12:00 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-10-06 06:30 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Petr Mladek <pmladek@suse.com> - 2016-10-06 13:40 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-10-10 06:20 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Petr Mladek <pmladek@suse.com> - 2016-10-10 13:20 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-10-11 09:40 +0200
Re: [RFC][PATCH 6/7] printk: use alternative printk buffers Petr Mladek <pmladek@suse.com> - 2016-10-11 11:40 +0200
[RFC][PATCH 4/7] printk: make alt_printk available when config printk set Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2016-09-27 16:30 +0200
[RFC][PATCH 7/7] printk: new printk() recursion detection Sergey Senozhatsky <sergey.senozhatsky@gmail.com> - 2016-09-27 16:30 +0200
Re: [RFC][PATCH 7/7] printk: new printk() recursion detection Petr Mladek <pmladek@suse.com> - 2016-09-29 15:30 +0200
Re: [RFC][PATCH 7/7] printk: new printk() recursion detection Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-09-30 04:10 +0200
Re: [RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls Petr Mladek <pmladek@suse.com> - 2016-09-29 15:30 +0200
Re: [RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-09-30 04:50 +0200
Re: [RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls Petr Mladek <pmladek@suse.com> - 2016-09-30 13:30 +0200
Re: [RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> - 2016-10-01 05:10 +0200
Re: [RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls Petr Mladek <pmladek@suse.com> - 2016-10-04 13:40 +0200
Page 2 of 2 — ← Prev page 1 [2]
| From | Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> |
|---|---|
| Date | 2016-10-06 06:30 +0200 |
| Subject | Re: [RFC][PATCH 6/7] printk: use alternative printk buffers |
| Message-ID | <sp8tH-3wt-1@gated-at.bofh.it> |
| In reply to | #1495787 |
On (10/05/16 11:50), Petr Mladek wrote:
[..]
> > well, it solves a number of problems that the existing implementation
> > cannot handle.
>
> Please, provide a summary. I wonder if these are real life problems.
anything that starts from printk().
I'm trying to address printk() recursion only, by handling the top-most
recursion - printk -> printk, which causes all of the dependent recursions:
printk -> spin_lock(logbuf) -> printk() -> spin_lock(logbuf)
printk -> sem->lock() -> printk() -> sem->lock()
and so on.
I'm not building a lock dependency graph/etc.
the existing recursion detection logic is racy and quite limited in
scope: not only it protects only a tiny bit of printk, but it doesn't
even protect it fully. the very moment we do `logbuf_cpu = UINT_MAX;'
it's over - we still own the lock, but we don't remember it anymore.
a spin_dump() from raw_spin_unlock(&logbuf_lock) will kill us.
** a very quick list **
// a mixed list of theoretical and real problems can also be found
// in the patch set cover letter.
public reports:
1) some pathces/reports from Byungchul Park
the first one in my mailbox (seems to be)
https://marc.info/?l=linux-kernel&m=145406977822244
20160129121545.GH31266@X58A-UD3R
or here
https://marc.info/?l=linux-kernel&m=145570036513749
in his case, I believe, the lock was fine (not corrupted). it just he had
a spin_lock lockup on console semaphore spin_lock coming from:
static void __spin_lock_debug(raw_spinlock_t *lock)
{
u64 i;
u64 loops = loops_per_jiffy * HZ;
for (i = 0; i < loops; i++) {
if (arch_spin_trylock(&lock->raw_lock))
return;
__delay(1);
}
/* lockup suspected: */
spin_dump(lock, "lockup suspected");
which ended up in an infinite recursion.
https://marc.info/?l=linux-kernel&m=145449014308161
2) a report from Viresh Kumar.
frankly, we were lucky to have Viresh on this: a less experienced developer
would probably give up. So would probably do a developer with no appropriate
hardware: jtag debugger/serial console/etc. and I don't know how much would
we spend on meditations to figure out it was a WARN from timekeeping. we
better be 'more prepared'.
=======
reports (unique occurrences only) that I have in internal bugzilla
4) sleeping function called from inside logbuf lock
which resulted in spin_dump() call from spin_unlock(&logbuf_lock)
when:
a) we still owned the logbuf_lock
b) yet logbuf_cpu was already reset, so printk recursion
detection was helpless
'a + b' leave us no chances to survive.
5) ARM specific
an imprecise abort (http://infocenter.arm.com/help/topic/com.arm.doc.faqs/14809.html)
hit the CPU while it was holding the printk-related spin-lock.
that deadlocked the system, because abort handler attempted to
printk() a message.
6) logbuf_lock corruption
well, no cookies for us. un-fixable at the moment. we can probably
do something about it. have a spinlock-debug bool function that would
tell us whether the lock is corrupted, so we can re-init logbuf_lock,
perhaps.
> Note that we need to put aside all problems that are solvable
> with printk_deferred(). It seems that printk_deferred() will
> need to stay because it avoids the deadlock caused by
> scheduler/timekeeping code locks.
agree. printk_deferred() takes only one lock and avoids console_unlock()
loop. as long as logbuf_lock is not on it's way printk_deferred() may be
helpful.
> By other words, if there is a missing printk_deferred() we
> need to put it there anyway because the same code might get
> first called outside printk().
right. and I'm not addressing this. there are just too many locks
that can be acquired out of order. not only timekeeping and sched
locks, but any of serial console locks adn so on. we need something
like lockdep locks graph here that would not report the issues (any
printk() can result in deadlock when we detect that at least one of
printk related locks was acquired out of order), but instead would
somehow selectively fix/workaround them.
can we somehow transparently for the rest of the system (just in
printk()) detect that we are in a potentially risky situation? hmm,
I don't know...
something *very* radical?
vprintk_func()
{
if (this_cpu_read(alt_printk_ctx) & ALT_PRINTK_NMI_CONTEXT_MASK)
return vprintk_nmi(fmt, args);
if (in_atomic() ||
/* ^^^^^^^^^^^^ */
this_cpu_read(alt_printk_ctx) & ALT_PRINTK_CONTEXT_MASK)
return vprintk_alt(fmt, args);
return vprintk_default(fmt, args);
}
-ss
[toc] | [prev] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-10-06 13:40 +0200 |
| Subject | Re: [RFC][PATCH 6/7] printk: use alternative printk buffers |
| Message-ID | <spfbQ-7Yg-13@gated-at.bofh.it> |
| In reply to | #1496155 |
On Thu 2016-10-06 13:22:48, Sergey Senozhatsky wrote:
> On (10/05/16 11:50), Petr Mladek wrote:
> [..]
> > > well, it solves a number of problems that the existing implementation
> > > cannot handle.
> >
> > Please, provide a summary. I wonder if these are real life problems.
>
> 1) some pathces/reports from Byungchul Park
> 2) a report from Viresh Kumar.
> 4) sleeping function called from inside logbuf lock
> 5) ARM specific
> 6) logbuf_lock corruption
It is great that you have such a list in hands. It might help
to push this solution.
I actually have one more reason for this approach:
It seems that we will need to keep printk_deferred()/WARN_*DEFERRED().
We do not know about a better solution for the deadlocks caused
by scheduler/timekeeping/console_drivers locks.
The pain is that the list of affected locations is hard to maintain.
It would definitely help if such problems are reported by lockdep
in advance. But lockdep is disabled because it creates the deadlock
on its own.
The alternative printk() allows to enable lockdep and effectively
hunt other possible bugs.
Also the printk context per-CPU variable perfectly fits the
lockdep approach. It will allow to monitor in which printk context
all the other locks are taken and detect possible problems.
> can we somehow transparently for the rest of the system (just in
> printk()) detect that we are in a potentially risky situation? hmm,
> I don't know...
>
> something *very* radical?
>
> vprintk_func()
> {
> if (this_cpu_read(alt_printk_ctx) & ALT_PRINTK_NMI_CONTEXT_MASK)
> return vprintk_nmi(fmt, args);
>
> if (in_atomic() ||
> /* ^^^^^^^^^^^^ */
> this_cpu_read(alt_printk_ctx) & ALT_PRINTK_CONTEXT_MASK)
> return vprintk_alt(fmt, args);
>
> return vprintk_default(fmt, args);
> }
This would affect too many messages. If the error is too serious,
there is a risk that the messages from the alternative per-CPU
buffers will not appear in the main log buffer and the console.
IMHO, this is acceptable for printk-related errors. But people
would complain if other bugs are harder to debug because
the error messages were hidden.
I am going to continue reviewing v2 of the patch set.
BTW: I would like to ask you to slow down a bit. More versions
of such a non-trivial patchset, that are sent within few days,
are far too much. I have some other tasks that I need to work on.
Also I would like to hear opinion from other people. Note that
many people are busy with the merge window at the moment.
Best Regards,
Petr
[toc] | [prev] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> |
|---|---|
| Date | 2016-10-10 06:20 +0200 |
| Subject | Re: [RFC][PATCH 6/7] printk: use alternative printk buffers |
| Message-ID | <sqAed-4Wd-7@gated-at.bofh.it> |
| In reply to | #1496607 |
On (10/06/16 13:32), Petr Mladek wrote:
> On Thu 2016-10-06 13:22:48, Sergey Senozhatsky wrote:
> > On (10/05/16 11:50), Petr Mladek wrote:
> > [..]
> > > > well, it solves a number of problems that the existing implementation
> > > > cannot handle.
> > >
> > > Please, provide a summary. I wonder if these are real life problems.
> >
> > 1) some pathces/reports from Byungchul Park
> > 2) a report from Viresh Kumar.
> > 4) sleeping function called from inside logbuf lock
> > 5) ARM specific
> > 6) logbuf_lock corruption
>
> It is great that you have such a list in hands. It might help
> to push this solution.
>
> I actually have one more reason for this approach:
>
> It seems that we will need to keep printk_deferred()/WARN_*DEFERRED().
> We do not know about a better solution for the deadlocks caused
> by scheduler/timekeeping/console_drivers locks.
yes, seems so.
> The pain is that the list of affected locations is hard to maintain.
> It would definitely help if such problems are reported by lockdep
> in advance. But lockdep is disabled because it creates the deadlock
> on its own.
right. another issue is that those potentially recursive printk/WARN_ON
calls may be coming from error-handling branches, not all of which are
easily reachable for automated solutions. so in order to find out there
is a problem we must hit it [in some cases].
it may look that lockdep *probably* can report the issues via 'safe' printk,
but that's a notably huge behavior breakage -- if lockdep report comes from
an about-to-deadlock irq handler, then we won't see anything from that CPU
unless there is a panic/nmi panic.
so it probably has to be semi-automatic/semi-manual:
- add might_printk() that would acquire/release console sem; or
logbuf_lock (which is probably even better)
- find all functions that do printk/WARN in kernel/time and kernel/sched
- add might_printk() to those functions (just like might_sleep())
- run the kernel
- ...
- profit
#ifdef CONFIG_VALIDATE_PRINTK_CALLS
#define might_printk() \
do { \
if (!printk_in_safe_mode()) { \
unsigned long flags; \
\
printk_safe_enter(flags); \
mutex_acquire(&console_lock_dep_map...); \
mutex_release(&console_lock_dep_map...); \
/* \
* or printk_deferred(""); \
*/ \
printk_safe_exit(flags); \
} \
} while (0)
#else
#define might_printk()
#endif
may be that will make it easier. need to think more.
> BTW: I would like to ask you to slow down a bit. More versions
> of such a non-trivial patchset, that are sent within few days,
> are far too much. I have some other tasks that I need to work on.
> Also I would like to hear opinion from other people. Note that
> many people are busy with the merge window at the moment.
sure, sorry about that! wasn't really happy with that as well.
and thanks for your help.
-ss
[toc] | [prev] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-10-10 13:20 +0200 |
| Subject | Re: [RFC][PATCH 6/7] printk: use alternative printk buffers |
| Message-ID | <sqGMF-zG-15@gated-at.bofh.it> |
| In reply to | #1498084 |
On Mon 2016-10-10 13:09:57, Sergey Senozhatsky wrote: > On (10/06/16 13:32), Petr Mladek wrote: > > On Thu 2016-10-06 13:22:48, Sergey Senozhatsky wrote: > > > On (10/05/16 11:50), Petr Mladek wrote: > > > [..] > > > > > well, it solves a number of problems that the existing implementation > > > > > cannot handle. > > > > > > > > Please, provide a summary. I wonder if these are real life problems. > > > > > > 1) some pathces/reports from Byungchul Park > > > 2) a report from Viresh Kumar. > > > 4) sleeping function called from inside logbuf lock > > > 5) ARM specific > > > 6) logbuf_lock corruption > > > > It is great that you have such a list in hands. It might help > > to push this solution. > > > > I actually have one more reason for this approach: > > > > It seems that we will need to keep printk_deferred()/WARN_*DEFERRED(). > > We do not know about a better solution for the deadlocks caused > > by scheduler/timekeeping/console_drivers locks. > > yes, seems so. > > > The pain is that the list of affected locations is hard to maintain. > > It would definitely help if such problems are reported by lockdep > > in advance. But lockdep is disabled because it creates the deadlock > > on its own. > > right. another issue is that those potentially recursive printk/WARN_ON > calls may be coming from error-handling branches, not all of which are > easily reachable for automated solutions. so in order to find out there > is a problem we must hit it [in some cases]. yes > it may look that lockdep *probably* can report the issues via 'safe' printk, > but that's a notably huge behavior breakage -- if lockdep report comes from > an about-to-deadlock irq handler, then we won't see anything from that CPU > unless there is a panic/nmi panic. > > so it probably has to be semi-automatic/semi-manual: > - add might_printk() that would acquire/release console sem; or > logbuf_lock (which is probably even better) > - find all functions that do printk/WARN in kernel/time and kernel/sched > - add might_printk() to those functions (just like might_sleep()) > - run the kernel > - ... > - profit I like the idea with might_printk(). I hope that it will be acceptable for the scheduler/timekeeping people. JFYI, I could work on the printk-context handling in lockdep. I am just working on a lockdep support in NMI and am getting kind of familiar with that code. Best Regards, Petr
[toc] | [prev] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> |
|---|---|
| Date | 2016-10-11 09:40 +0200 |
| Subject | Re: [RFC][PATCH 6/7] printk: use alternative printk buffers |
| Message-ID | <sqZPk-3Ko-21@gated-at.bofh.it> |
| In reply to | #1498238 |
On (10/10/16 13:17), Petr Mladek wrote: [..] > > it may look that lockdep *probably* can report the issues via 'safe' printk, > > but that's a notably huge behavior breakage -- if lockdep report comes from > > an about-to-deadlock irq handler, then we won't see anything from that CPU > > unless there is a panic/nmi panic. > > > > so it probably has to be semi-automatic/semi-manual: > > - add might_printk() that would acquire/release console sem; or > > logbuf_lock (which is probably even better) > > - find all functions that do printk/WARN in kernel/time and kernel/sched > > - add might_printk() to those functions (just like might_sleep()) > > - run the kernel > > - ... > > - profit > > I like the idea with might_printk(). I hope that it will be acceptable > for the scheduler/timekeeping people. > > JFYI, I could work on the printk-context handling in lockdep. > I am just working on a lockdep support in NMI and am getting > kind of familiar with that code. sorry, what do you mean by 'printk-context handling in lockdep'? wouldn't `lockdep + might_printk() + printk_safe' be enough? am I missing something? -ss
[toc] | [prev] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-10-11 11:40 +0200 |
| Subject | Re: [RFC][PATCH 6/7] printk: use alternative printk buffers |
| Message-ID | <sr1Hr-4Wf-5@gated-at.bofh.it> |
| In reply to | #1498640 |
On Tue 2016-10-11 16:35:28, Sergey Senozhatsky wrote: > On (10/10/16 13:17), Petr Mladek wrote: > [..] > > > it may look that lockdep *probably* can report the issues via 'safe' printk, > > > but that's a notably huge behavior breakage -- if lockdep report comes from > > > an about-to-deadlock irq handler, then we won't see anything from that CPU > > > unless there is a panic/nmi panic. > > > > > > so it probably has to be semi-automatic/semi-manual: > > > - add might_printk() that would acquire/release console sem; or > > > logbuf_lock (which is probably even better) > > > - find all functions that do printk/WARN in kernel/time and kernel/sched > > > - add might_printk() to those functions (just like might_sleep()) > > > - run the kernel > > > - ... > > > - profit > > > > I like the idea with might_printk(). I hope that it will be acceptable > > for the scheduler/timekeeping people. > > > > JFYI, I could work on the printk-context handling in lockdep. > > I am just working on a lockdep support in NMI and am getting > > kind of familiar with that code. > > sorry, what do you mean by 'printk-context handling in lockdep'? > wouldn't `lockdep + might_printk() + printk_safe' be enough? am I > missing something? Good question. It was my intuition that we would need some extra support in lockdep. It is quite complicated and I have not thought about it deep enough yet. Let's unwind some of my thoughts: Well, the nice thing about the lockdep is that it is able to detect dangerous lock chains in advance. It means even without being in the deadlock situation. IMHO, the printk-related deadlocks will be solved in two ways. Either by replacing the classic printk() with the deferred variant or by surrounding a problematic code with printk_safe_enter()/exit() calls. If we do the fix correctly, the lockdep warning should disappear. Now, replacing printk() with printk_deferred() will have effect even with the current lockdep code. It is because printk_deferred() will not longer take the console-related locks, so they will not longer appear in the call chain. But what about adding printk_safe_enter()/exit()? Of course, if we do it correctly, it will prevent a deadlock. But lockdep is supposed to detect this in advance. And these functions just handle the printk_context variable. The guarded code will still take the same locks. Therefore my feeling is that lockdep will need to be aware of the printk_context. It would have similar effect like taking lock with interrupts enabled or disabled. By other words, safe printk context would prevent entering the same chain of locks recursively. It is like the disabled interrupts prevent a recursion. Finally, note that the proposed might_printk() emulates the classic printk() call. It the classic printk() causes problems somewhere, it will be replaced by printk_deferred() and might_printk() will be removed. By other words, might_printk() shows where we need the first solution (using printk_deferred) but it does not tell the lockdep about the entire story. I am not sure if the above makes sense. I need much more coffee, sleep, and thinking to sort the problem completely. Let me look at it from a slightly different angle: The deadlock is caused by a chain of taken locks. lockdep is able to warn about it in advance because it knows that two partial lock chains might eventually happen together. For this, the information about the interrupt context and disabled interrupts is important. It tells what chains of locks might happen together and what are prevented. IMHO, the printk_context has similar effect like the interrupt context stuff. Well, there is a difference. Being in interrupt context and having disabled interrupts are two separate values. printk_context defines just one value. It either means that the situation with printk is easier or that we will need one more variable for the lockdep handling of the printk state. Anyway, I would not solve lockdep in this patchset. Let's keep it as another challenge. Best Regards, Petr
[toc] | [prev] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> |
|---|---|
| Date | 2016-09-27 16:30 +0200 |
| Subject | [RFC][PATCH 4/7] printk: make alt_printk available when config printk set |
| Message-ID | <sm1yq-29m-23@gated-at.bofh.it> |
| In reply to | #1491941 |
alt_printk must be enabled on systems that have CONFIG_PRINTK set,
while NMI related functions must depend on CONFIG_PRINTK_NMI.
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
include/linux/printk.h | 14 ++++++++------
kernel/printk/Makefile | 2 +-
kernel/printk/alt_printk.c | 23 +++++++++++++++++------
kernel/printk/internal.h | 31 +++++++++++++------------------
4 files changed, 39 insertions(+), 31 deletions(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index 7510613..fae308a 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -131,17 +131,11 @@ void early_printk(const char *s, ...) { }
#endif
#ifdef CONFIG_PRINTK_NMI
-extern void alt_printk_init(void);
extern void printk_nmi_enter(void);
extern void printk_nmi_exit(void);
-extern void alt_printk_flush(void);
-extern void alt_printk_flush_on_panic(void);
#else
-static inline void alt_printk_init(void) { }
static inline void printk_nmi_enter(void) { }
static inline void printk_nmi_exit(void) { }
-static inline void alt_printk_flush(void) { }
-static inline void alt_printk_flush_on_panic(void) { }
#endif /* PRINTK_NMI */
#ifdef CONFIG_PRINTK
@@ -193,6 +187,10 @@ void __init setup_log_buf(int early);
__printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...);
void dump_stack_print_info(const char *log_lvl);
void show_regs_print_info(const char *log_lvl);
+
+extern void alt_printk_init(void);
+extern void alt_printk_flush(void);
+extern void alt_printk_flush_on_panic(void);
#else
static inline __printf(1, 0)
int vprintk(const char *s, va_list args)
@@ -252,6 +250,10 @@ static inline void dump_stack_print_info(const char *log_lvl)
static inline void show_regs_print_info(const char *log_lvl)
{
}
+
+static inline void alt_printk_init(void) { }
+static inline void alt_printk_flush(void) { }
+static inline void alt_printk_flush_on_panic(void) { }
#endif
extern asmlinkage void dump_stack(void) __cold;
diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile
index 3fc5e4e..d11838c 100644
--- a/kernel/printk/Makefile
+++ b/kernel/printk/Makefile
@@ -1,3 +1,3 @@
obj-y = printk.o
-obj-$(CONFIG_PRINTK_NMI) += alt_printk.o
+obj-$(CONFIG_PRINTK) += alt_printk.o
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
diff --git a/kernel/printk/alt_printk.c b/kernel/printk/alt_printk.c
index 8978390..8ac1daa 100644
--- a/kernel/printk/alt_printk.c
+++ b/kernel/printk/alt_printk.c
@@ -40,7 +40,6 @@
*/
DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
static int alt_printk_irq_ready;
-atomic_t nmi_message_lost;
#define ALT_LOG_BUF_LEN ((1 << CONFIG_ALT_PRINTK_LOG_BUF_SHIFT) - \
sizeof(atomic_t) - sizeof(struct irq_work))
@@ -50,7 +49,11 @@ struct alt_printk_seq_buf {
struct irq_work work; /* IRQ work that flushes the buffer */
unsigned char buffer[ALT_LOG_BUF_LEN];
};
+
+#ifdef CONFIG_PRINTK_NMI
static DEFINE_PER_CPU(struct alt_printk_seq_buf, nmi_print_seq);
+atomic_t nmi_message_lost;
+#endif
/*
* There can be two alt_printk contexts at most - a `normal' alt_printk
@@ -320,8 +323,12 @@ void alt_printk_flush(void)
{
int cpu;
- for_each_possible_cpu(cpu)
- __alt_printk_flush(&per_cpu(nmi_print_seq, cpu).work);
+ for_each_possible_cpu(cpu) {
+ if (IS_ENABLED(CONFIG_PRINTK_NMI))
+ __alt_printk_flush(&per_cpu(nmi_print_seq, cpu).work);
+
+ __alt_printk_flush(&per_cpu(alt_print_seq, cpu).work);
+ }
}
/**
@@ -356,12 +363,14 @@ void __init alt_printk_init(void)
int cpu;
for_each_possible_cpu(cpu) {
- struct alt_printk_seq_buf *s = &per_cpu(nmi_print_seq, cpu);
+ struct alt_printk_seq_buf *s = &per_cpu(alt_print_seq, cpu);
init_irq_work(&s->work, __alt_printk_flush);
- s = &per_cpu(alt_print_seq, cpu);
- init_irq_work(&s->work, __alt_printk_flush);
+ if (IS_ENABLED(CONFIG_PRINTK_NMI)) {
+ s = &per_cpu(nmi_print_seq, cpu);
+ init_irq_work(&s->work, __alt_printk_flush);
+ }
}
/* Make sure that IRQ works are initialized before enabling. */
@@ -372,6 +381,7 @@ void __init alt_printk_init(void)
alt_printk_flush();
}
+#ifdef CONFIG_PRINTK_NMI
/*
* Safe printk() for NMI context. It uses a per-CPU buffer to
* store the message. NMIs are not nested, so there is always only
@@ -399,3 +409,4 @@ void printk_nmi_exit(void)
{
__lockless_printk_exit();
}
+#endif /* CONFIG_PRINTK_NMI */
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index c5f970e..3eebf6d 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -18,21 +18,9 @@
typedef __printf(1, 0) int (*printk_func_t)(const char *fmt, va_list args);
-int __printf(1, 0) vprintk_default(const char *fmt, va_list args);
-
#ifdef CONFIG_PRINTK
-void alt_printk_enter(void);
-void alt_printk_exit(void);
-
-#else
-
-void alt_printk_enter(void) { }
-void alt_printk_exit(void) { }
-
-#endif /* CONFIG_PRINTK */
-
-#ifdef CONFIG_PRINTK_NMI
+int __printf(1, 0) vprintk_default(const char *fmt, va_list args);
extern raw_spinlock_t logbuf_lock;
@@ -48,6 +36,18 @@ static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
return this_cpu_read(printk_func)(fmt, args);
}
+void alt_printk_enter(void);
+void alt_printk_exit(void);
+
+#else
+
+void alt_printk_enter(void) { }
+void alt_printk_exit(void) { }
+
+#endif /* CONFIG_PRINTK */
+
+#ifdef CONFIG_PRINTK_NMI
+
extern atomic_t nmi_message_lost;
static inline int get_nmi_message_lost(void)
{
@@ -56,11 +56,6 @@ static inline int get_nmi_message_lost(void)
#else /* CONFIG_PRINTK_NMI */
-static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
-{
- return vprintk_default(fmt, args);
-}
-
static inline int get_nmi_message_lost(void)
{
return 0;
--
2.10.0.372.g6fe1b14
[toc] | [prev] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky@gmail.com> |
|---|---|
| Date | 2016-09-27 16:30 +0200 |
| Subject | [RFC][PATCH 7/7] printk: new printk() recursion detection |
| Message-ID | <sm1yq-29m-21@gated-at.bofh.it> |
| In reply to | #1491941 |
We can't use alt_printk when we are flushing alt_printk buffers to logbuf,
because otherwise we would just flush messages back to alt_printk buffers.
At the same time, this opens a door for potential deadlock, should flushing
endup in recursive printk() call:
irq_work_run()
alt_printk_flush_line()
printk()
WARN_ON()
^^^^^^^^^
depending on circumstances this can result in printk-deadlock.
To cope with it, we can use alt_printk context ->entry_count:
- __alt_printk_flush() sets ->entry_count to 1
- every printk() call from alt_printk_flush_foo() calls
alt_printk_enter() and alt_printk_exit()
- alt_printk_enter() increments ->entry_count and tests the value:
- if it's `==2' then we are in normal alt_printk_flush()->printk() path
- if it's `>=3' then we are in recursion. The first time we detect
recursion (->entry_count == 3) we switch from default printk() to
alt_printk(), to avoid possible deadlocks.
- in alt_printk_exit() we test if we were in normal printk() path or
in printk() recursion and rollback to default printk() if so;
and decrement ->entry_count.
->entry_count is a per-cpu variable, which must be touched only with
local IRQs disabled. NMI should never touch ->entry_count.
An example:
WARN_ON() from printk() while alt_printk_flush() flushed messages
from alt_printk buffer to a logbuf:
------------[ cut here ]------------
WARNING: CPU: 1 PID: 332 at kernel/printk/printk.c:1775 vprintk_emit+0x73/0x398
CPU: 1 PID: 332 Comm: bash
Call Trace:
<IRQ> [<ffffffff811f23ae>] dump_stack+0x68/0x92
[<ffffffff8103d649>] __warn+0xb8/0xd3
[<ffffffff8103d6ca>] warn_slowpath_null+0x18/0x1a
[<ffffffff8107fdb6>] vprintk_emit+0x73/0x398
[<ffffffff8108023d>] vprintk_default+0x18/0x1a
[<ffffffff810c7fa5>] printk+0x43/0x4b
[<ffffffff81080fc3>] alt_printk_flush_line+0x27/0x29
[<ffffffff810810e1>] __alt_printk_flush+0xd7/0x12d
[<ffffffff810b6356>] irq_work_run_list+0x43/0x67
[<ffffffff810b6595>] irq_work_run+0x2a/0x44
[<ffffffff81016925>] smp_trace_irq_work_interrupt+0x29/0x30
[<ffffffff81016935>] smp_irq_work_interrupt+0x9/0xb
[<ffffffff814c3fe6>] irq_work_interrupt+0x86/0x90
<EOI> [<ffffffff814c2577>] ? _raw_spin_unlock+0x2c/0x3f
[<ffffffff8107fd12>] ? console_unlock+0x528/0x559
[<ffffffff810800ca>] vprintk_emit+0x387/0x398
[<ffffffff8108023d>] vprintk_default+0x18/0x1a
[<ffffffff810c7fa5>] printk+0x43/0x4b
[..]
[<ffffffff814c2daa>] entry_SYSCALL_64_fastpath+0x18/0xad
---[ end trace ]---
Signed-off-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
---
kernel/printk/alt_printk.c | 26 +++++++++++++++++++++++---
kernel/printk/internal.h | 5 +++++
kernel/printk/printk.c | 38 ++------------------------------------
3 files changed, 30 insertions(+), 39 deletions(-)
diff --git a/kernel/printk/alt_printk.c b/kernel/printk/alt_printk.c
index 8ac1daa..0302ea3 100644
--- a/kernel/printk/alt_printk.c
+++ b/kernel/printk/alt_printk.c
@@ -69,6 +69,9 @@ atomic_t nmi_message_lost;
#define MAX_ALT_PRINTK_CTX 1
#endif
+#define CTX_ENTRY_FLUSHING 2
+#define CTX_ENTRY_FLUSHING_RECURSION (CTX_ENTRY_FLUSHING + 1)
+
struct alt_printk_ctx {
atomic_t idx;
unsigned int entry_count;
@@ -189,10 +192,15 @@ void alt_printk_enter(void)
* will see ->entry_count > 2.
*/
ctx->entry_count++;
- if (ctx->entry_count > 1)
+ if (ctx->entry_count == CTX_ENTRY_FLUSHING)
return;
- /* @TODO: do something sensible in case of printk() recursion */
+ /*
+ * Once ->entry_coun == CTX_ENTRY_FLUSHING_RECURSION printk()
+ * switches to alt_printk() buffers.
+ */
+ if (ctx->entry_count > CTX_ENTRY_FLUSHING_RECURSION)
+ return;
__lockless_printk_enter(vprintk_alt);
}
@@ -202,11 +210,23 @@ void alt_printk_exit(void)
{
struct alt_printk_ctx *ctx = this_cpu_ptr(&alt_printk_ctx);
- if (ctx->entry_count == 1)
+ /*
+ * If we are returning from a normal alt_printk context or
+ * from printk() recursion -- switch back to default printk.
+ */
+ if (ctx->entry_count == 1 ||
+ ctx->entry_count == CTX_ENTRY_FLUSHING_RECURSION)
__lockless_printk_exit();
ctx->entry_count--;
}
+bool recursed_printk_call(void)
+{
+ struct alt_printk_ctx *ctx = this_cpu_ptr(&alt_printk_ctx);
+
+ return oops_in_progress && (ctx->entry_count > CTX_ENTRY_FLUSHING);
+}
+
static void alt_printk_flush_line(const char *text, int len)
{
/*
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index b030ca0..7d082b7 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -34,11 +34,16 @@ DECLARE_PER_CPU(printk_func_t, printk_func);
void alt_printk_enter(void);
void alt_printk_exit(void);
+bool recursed_printk_call(void);
#else
void alt_printk_enter(void) { }
void alt_printk_exit(void) { }
+bool recursed_printk_call(void)
+{
+ return false;
+}
#endif /* CONFIG_PRINTK */
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index e5dacfb..47f1e0e 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1748,18 +1748,14 @@ asmlinkage int vprintk_emit(int facility, int level,
const char *dict, size_t dictlen,
const char *fmt, va_list args)
{
- static bool recursion_bug;
static char textbuf[LOG_LINE_MAX];
char *text = textbuf;
size_t text_len = 0;
enum log_flags lflags = 0;
unsigned long flags;
- int this_cpu;
int printed_len = 0;
int nmi_message_lost;
bool in_sched = false;
- /* cpu currently holding logbuf_lock in this function */
- static unsigned int logbuf_cpu = UINT_MAX;
if (level == LOGLEVEL_SCHED) {
level = LOGLEVEL_DEFAULT;
@@ -1770,42 +1766,13 @@ asmlinkage int vprintk_emit(int facility, int level,
printk_delay();
local_irq_save(flags);
- this_cpu = smp_processor_id();
+ alt_printk_enter();
- /*
- * Ouch, printk recursed into itself!
- */
- if (unlikely(logbuf_cpu == this_cpu)) {
- /*
- * If a crash is occurring during printk() on this CPU,
- * then try to get the crash message out but make sure
- * we can't deadlock. Otherwise just return to avoid the
- * recursion and return - but flag the recursion so that
- * it can be printed at the next appropriate moment:
- */
- if (!oops_in_progress && !lockdep_recursing(current)) {
- recursion_bug = true;
- local_irq_restore(flags);
- return 0;
- }
+ if (recursed_printk_call())
zap_locks();
- }
- alt_printk_enter();
/* This stops the holder of console_sem just where we want him */
raw_spin_lock(&logbuf_lock);
- logbuf_cpu = this_cpu;
-
- if (unlikely(recursion_bug)) {
- static const char recursion_msg[] =
- "BUG: recent printk recursion!";
-
- recursion_bug = false;
- /* emit KERN_CRIT message */
- printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
- NULL, 0, recursion_msg,
- strlen(recursion_msg));
- }
nmi_message_lost = get_nmi_message_lost();
if (unlikely(nmi_message_lost)) {
@@ -1898,7 +1865,6 @@ asmlinkage int vprintk_emit(int facility, int level,
dict, dictlen, text, text_len);
}
- logbuf_cpu = UINT_MAX;
raw_spin_unlock(&logbuf_lock);
alt_printk_exit();
local_irq_restore(flags);
--
2.10.0.372.g6fe1b14
[toc] | [prev] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-09-29 15:30 +0200 |
| Subject | Re: [RFC][PATCH 7/7] printk: new printk() recursion detection |
| Message-ID | <smJzr-4DI-11@gated-at.bofh.it> |
| In reply to | #1491950 |
On Tue 2016-09-27 23:22:37, Sergey Senozhatsky wrote: > We can't use alt_printk when we are flushing alt_printk buffers to logbuf, > because otherwise we would just flush messages back to alt_printk buffers. > At the same time, this opens a door for potential deadlock, should flushing > endup in recursive printk() call: > > irq_work_run() > alt_printk_flush_line() > printk() > WARN_ON() > ^^^^^^^^^ > depending on circumstances this can result in printk-deadlock. > > To cope with it, we can use alt_printk context ->entry_count: > - __alt_printk_flush() sets ->entry_count to 1 > - every printk() call from alt_printk_flush_foo() calls > alt_printk_enter() and alt_printk_exit() > - alt_printk_enter() increments ->entry_count and tests the value: > - if it's `==2' then we are in normal alt_printk_flush()->printk() path > - if it's `>=3' then we are in recursion. The first time we detect > recursion (->entry_count == 3) we switch from default printk() to > alt_printk(), to avoid possible deadlocks. > - in alt_printk_exit() we test if we were in normal printk() path or > in printk() recursion and rollback to default printk() if so; > and decrement ->entry_count. I am sorry but I do not understand this much. printk() should set the alternative implementation in the critical section by default. Why do we need to handle this so specially? Is it because of flushing in NMI context when panicing? I would call vprintk_emit() directly from the flush_line() function in this case. Then all other possible error printk's will get redirected to the NMI buffer which is good enouh. Best Regards, Petr
[toc] | [prev] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> |
|---|---|
| Date | 2016-09-30 04:10 +0200 |
| Subject | Re: [RFC][PATCH 7/7] printk: new printk() recursion detection |
| Message-ID | <smVqV-3ZL-5@gated-at.bofh.it> |
| In reply to | #1493463 |
On (09/29/16 15:19), Petr Mladek wrote: > I am sorry but I do not understand this much. printk() should set the > alternative implementation in the critical section by default. > Why do we need to handle this so specially? > > Is it because of flushing in NMI context when panicing? I would call > vprintk_emit() directly from the flush_line() function in this case. > Then all other possible error printk's will get redirected to the > NMI buffer which is good enouh. I'm going to re-do the entire thing. I had some cases in mind, like WARN from vsnprintf from printk from alt_printk_flushing from panic. or something like this. perhaps too complicated, will re-think it. -ss
[toc] | [prev] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-09-29 15:30 +0200 |
| Subject | Re: [RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls |
| Message-ID | <smJzs-4DI-29@gated-at.bofh.it> |
| In reply to | #1491941 |
On Tue 2016-09-27 23:22:30, Sergey Senozhatsky wrote: > Hello, > > RFC > > This patch set extends a lock-less NMI per-cpu buffers idea to > handle recursive printk() calls. The basic mechanism is pretty much the > same -- at the beginning of a deadlock-prone section we switch to lock-less > printk callback, and return back to a default printk implementation at the > end; the messages are getting flushed to a logbuf buffer from a safer > context. I was skeptical but I really like this way now. The switching of the buffers is a bit hairy in this version but I think that we could make it much better. Other than that it looks like a big win. It kills a lot of printk-related pain points. And it will not be that complicated after all. Best Regards, Petr
[toc] | [prev] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> |
|---|---|
| Date | 2016-09-30 04:50 +0200 |
| Subject | Re: [RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls |
| Message-ID | <smW3D-4iP-1@gated-at.bofh.it> |
| In reply to | #1493462 |
On (09/29/16 15:25), Petr Mladek wrote: > On Tue 2016-09-27 23:22:30, Sergey Senozhatsky wrote: > > Hello, > > > > RFC > > > > This patch set extends a lock-less NMI per-cpu buffers idea to > > handle recursive printk() calls. The basic mechanism is pretty much the > > same -- at the beginning of a deadlock-prone section we switch to lock-less > > printk callback, and return back to a default printk implementation at the > > end; the messages are getting flushed to a logbuf buffer from a safer > > context. > > I was skeptical but I really like this way now. > > The switching of the buffers is a bit hairy in this version but I > think that we could make it much better. > > Other than that it looks like a big win. It kills a lot of > printk-related pain points. And it will not be that complicated > after all. many thanks for looking at this train wreck. so, like I said, it addresses printk()-recursion in *ideally* quite a minimalistic way -- just several alt_printk_enter/exit calls in printk.c, without ever touching any other parts of the kernel. gunning down printk deadlocks in general, however, requires much more effort; or even a completely different approach. a) a lock-less printk() by default um, `#define printk alt_printk'. but this will break printk() from irq. and the ordering of messages from per-cpu buffers may be far from correct. b) combining a DEFERRED_WARN + alt_printk DEFERRED_WARN potentially is a never ending thing. we can add some lockdep annotations, perhaps, and hope that error handling branches that may contain WARN_ONs/printk-s will be executed with prove_locking enabled on someone's machine. c) ... -ss
[toc] | [prev] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-09-30 13:30 +0200 |
| Subject | Re: [RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls |
| Message-ID | <sn4aS-17X-17@gated-at.bofh.it> |
| In reply to | #1493856 |
On Fri 2016-09-30 11:43:07, Sergey Senozhatsky wrote: > On (09/29/16 15:25), Petr Mladek wrote: > > On Tue 2016-09-27 23:22:30, Sergey Senozhatsky wrote: > > > Hello, > > > > > > RFC > > > > > > This patch set extends a lock-less NMI per-cpu buffers idea to > > > handle recursive printk() calls. The basic mechanism is pretty much the > > > same -- at the beginning of a deadlock-prone section we switch to lock-less > > > printk callback, and return back to a default printk implementation at the > > > end; the messages are getting flushed to a logbuf buffer from a safer > > > context. > > > > I was skeptical but I really like this way now. > > > > The switching of the buffers is a bit hairy in this version but I > > think that we could make it much better. > > > > Other than that it looks like a big win. It kills a lot of > > printk-related pain points. And it will not be that complicated > > after all. > > many thanks for looking at this train wreck. > > so, like I said, it addresses printk()-recursion in *ideally* quite > a minimalistic way -- just several alt_printk_enter/exit calls in > printk.c, without ever touching any other parts of the kernel. > > gunning down printk deadlocks in general, however, requires much more > effort; or even a completely different approach. > > a) a lock-less printk() by default > um, `#define printk alt_printk'. but this will break printk() from irq. > and the ordering of messages from per-cpu buffers may be far from correct. Well, the current vprintk_nmi() is lockless. The alternative printk() is going to use the same code, so it will be lockless as well. It means that even this patchset is supposed to avoid all possible deadlocks via printk() calls. There is still a risk of an infinite recursion. But vprintk_nmi() bails out early when the buffer is full. This should minimalize the risk. In fact, the recursion would become rather theoretical problem. Best Regards, Petr
[toc] | [prev] | [next] | [standalone]
| From | Sergey Senozhatsky <sergey.senozhatsky.work@gmail.com> |
|---|---|
| Date | 2016-10-01 05:10 +0200 |
| Subject | Re: [RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls |
| Message-ID | <sniQx-2AT-11@gated-at.bofh.it> |
| In reply to | #1494031 |
On (09/30/16 13:27), Petr Mladek wrote:
> > > > This patch set extends a lock-less NMI per-cpu buffers idea to
> > > > handle recursive printk() calls. The basic mechanism is pretty much the
> > > > same -- at the beginning of a deadlock-prone section we switch to lock-less
> > > > printk callback, and return back to a default printk implementation at the
> > > > end; the messages are getting flushed to a logbuf buffer from a safer
> > > > context.
> > >
> > > I was skeptical but I really like this way now.
> > >
> > > The switching of the buffers is a bit hairy in this version but I
> > > think that we could make it much better.
> > >
> > > Other than that it looks like a big win. It kills a lot of
> > > printk-related pain points. And it will not be that complicated
> > > after all.
> >
> > many thanks for looking at this train wreck.
> >
> > so, like I said, it addresses printk()-recursion in *ideally* quite
> > a minimalistic way -- just several alt_printk_enter/exit calls in
> > printk.c, without ever touching any other parts of the kernel.
> >
> > gunning down printk deadlocks in general, however, requires much more
> > effort; or even a completely different approach.
> >
> > a) a lock-less printk() by default
> > um, `#define printk alt_printk'. but this will break printk() from irq.
> > and the ordering of messages from per-cpu buffers may be far from correct.
>
> Well, the current vprintk_nmi() is lockless. The alternative printk()
> is going to use the same code, so it will be lockless as well. It
> means that even this patchset is supposed to avoid all possible
> deadlocks via printk() calls.
I meant that printk-recursion and printk-deadlock can be different
scenarios. deadlocks are harder to handle
devkmsg_open()
raw_spin_lock_irq(&logbuf_lock)
spin_dump()
printk()
raw_spin_lock_irqsave(&logbuf_lock)
this one can be handled by alt_printk.
devkmsg_open()
local_irq_save();
alt_printk_enter()
raw_spin_lock(&logbuf_lock)
spin_dump()
printk()
vprintk_alt()
but there are some that can't be handled solely in printk.c
-ss
[toc] | [prev] | [next] | [standalone]
| From | Petr Mladek <pmladek@suse.com> |
|---|---|
| Date | 2016-10-04 13:40 +0200 |
| Subject | Re: [RFC][PATCH 0/7] printk: use alt_printk to handle printk() recursive calls |
| Message-ID | <soweK-23L-33@gated-at.bofh.it> |
| In reply to | #1494342 |
On Sat 2016-10-01 12:02:51, Sergey Senozhatsky wrote: > On (09/30/16 13:27), Petr Mladek wrote: > > > > > This patch set extends a lock-less NMI per-cpu buffers idea to > > > > > handle recursive printk() calls. The basic mechanism is pretty much the > > > > > same -- at the beginning of a deadlock-prone section we switch to lock-less > > > > > printk callback, and return back to a default printk implementation at the > > > > > end; the messages are getting flushed to a logbuf buffer from a safer > > > > > context. > > > > > > > > I was skeptical but I really like this way now. > > > > > > > > The switching of the buffers is a bit hairy in this version but I > > > > think that we could make it much better. > > > > > > > > Other than that it looks like a big win. It kills a lot of > > > > printk-related pain points. And it will not be that complicated > > > > after all. > > > > > > many thanks for looking at this train wreck. > > > > > > so, like I said, it addresses printk()-recursion in *ideally* quite > > > a minimalistic way -- just several alt_printk_enter/exit calls in > > > printk.c, without ever touching any other parts of the kernel. > > > > > > gunning down printk deadlocks in general, however, requires much more > > > effort; or even a completely different approach. > > > > > > a) a lock-less printk() by default > > > um, `#define printk alt_printk'. but this will break printk() from irq. > > > and the ordering of messages from per-cpu buffers may be far from correct. > > > > Well, the current vprintk_nmi() is lockless. The alternative printk() > > is going to use the same code, so it will be lockless as well. It > > means that even this patchset is supposed to avoid all possible > > deadlocks via printk() calls. > > I meant that printk-recursion and printk-deadlock can be different > scenarios. deadlocks are harder to handle > > devkmsg_open() > raw_spin_lock_irq(&logbuf_lock) > spin_dump() > printk() > raw_spin_lock_irqsave(&logbuf_lock) > > this one can be handled by alt_printk. > > devkmsg_open() > local_irq_save(); > alt_printk_enter() > raw_spin_lock(&logbuf_lock) > spin_dump() > printk() > vprintk_alt() > > but there are some that can't be handled solely in printk.c Do you have an example of the still problematic code, please? vprintk_alt() must be lockless because the same code is used also in NMI context. If it takes a lock, it is a bug. Therefore it should not cause a deadlock. The only problem might be an infinite loop. But the loop should break once the per-CPU buffer is full. We only need to make sure that there is no printk() called before the check for the full buffer. But this reduces the error-prone part of the code to a minimum. Therefore it should be bearable. Best Regards, Petr
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web