2009-04-17 21:32:07

by David VomLehn

[permalink] [raw]
Subject: [Patch] Wait for console to become available, ver 3

Parallelization to improve boot times has been successful enough that race
conditions now exist between the init_post() open of /dev/console and
initialization of the console device. When this occurs, opening /dev/console
fails and any applications inherited from init have no standard in/out/error
devices. This is expected behavior if no console device is available, but
quite unfortunate in the case where the console is just a bit slow waking up.

Some buses, such as USB, offer no guarantees about how long it takes to
discover devices, so there is no reliable way to distinguish between a missing
console and a slow one. The pragmatic approach taken in this patch is to
wait for a while to see if a console shows up, and just go on if it doesn't.
The default delay is 1000 msec (1 second).

There are two new command line parameters:
consolewait Wait forever for a console to be registered
consoledelay=msec Use the given number of milliseconds as the delay
interval instead of the default

Note that, though these parameters are modeled after the rootwait and rootdelay
parameters, details differ. Instead of sleeping and polling, which can increase
boot time, this code uses a waitqueue and will proceed as soon as a console is
available.

It could be argued that providing both command line parameters and a Kconfig
option for the console wait time is over-engineering. There doesn't really
seem to be a reasonable way to determine a default, though, which drives the
Kconfig option. The selection of USB devices connected to the system can
only be known at runtime, which drives the need for command line parameters.

History
v3 Increase the default delay to 1 second and add kernel command line
parameters to override the default delay. Thanks to David Brownell for
his helpful suggestions.
v2 Wait for the preferred console rather than any console. Make the
delay interval a tunable.
v1 Initial version

Signed-off-by: David VomLehn <[email protected]>
---
Documentation/kernel-parameters.txt | 10 ++++++++
arch/mips/configs/powertv_defconfig | 2 +-
init/Kconfig | 12 ++++++++++
kernel/printk.c | 41 +++++++++++++++++++++++++++++++++++
4 files changed, 64 insertions(+), 1 deletions(-)

diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 6172e43..2b0c4e6 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -507,6 +507,16 @@ and is between 256 and 4096 characters. It is defined in the file
console=brl,ttyS0
For now, only VisioBraille is supported.

+ consoledelay=mS [KNL] Wait up to mS milliseconds for the a preferred
+ console to be registered, then continue. Useful for
+ systems where a console may not be plugged in, such as
+ for USB serial devices.
+
+ consolewait [KNL] Wait (indefinitely) for preferred console device
+ to be registered. Useful, for example, for USB serial
+ devices, but will never complete booting if no console
+ is plugged in.
+
coredump_filter=
[KNL] Change the default value for
/proc/<pid>/coredump_filter.
diff --git a/arch/mips/configs/powertv_defconfig b/arch/mips/configs/powertv_defconfig
index 7311e63..b4a046d 100644
--- a/arch/mips/configs/powertv_defconfig
+++ b/arch/mips/configs/powertv_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
# Linux kernel version: 2.6.30-rc2
-# Thu Apr 16 11:29:44 2009
+# Fri Apr 17 12:38:42 2009
#
CONFIG_MIPS=y

diff --git a/init/Kconfig b/init/Kconfig
index 7be4d38..a04eba1 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -835,6 +835,18 @@ config PRINTK
very difficult to diagnose system problems, saying N here is
strongly discouraged.

+config PRINTK_CONSOLE_WAIT
+ int "Default number of milliseconds to wait for console device"
+ default 1000
+ help
+ Some systems use console devices, such as USB serial devices, which
+ may not be present or which may take an unspecified amount of time
+ to be initialized. This setting is the default for the maximum number
+ of milliseconds the system will wait for a console to be registered.
+ This value can be overridden by the command line parameters
+ consolewait, to wait forever, or consoledelay=msec, to give a
+ different value for the wait.
+
config BUG
bool "BUG() support" if EMBEDDED
default y
diff --git a/kernel/printk.c b/kernel/printk.c
index 5052b54..aa6db96 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -105,6 +105,11 @@ static unsigned log_start; /* Index into log_buf: next char to be read by syslog
static unsigned con_start; /* Index into log_buf: next char to be sent to consoles */
static unsigned log_end; /* Index into log_buf: most-recently-written-char + 1 */

+/* Definitions controlling the wait for a console device to be initialized */
+static bool console_wait; /* If true, wait forever for console */
+static long console_delay = CONFIG_PRINTK_CONSOLE_WAIT; /* In milliseconds */
+static DECLARE_WAIT_QUEUE_HEAD(console_wq);
+
/*
* Array of consoles built from command line options (console=)
*/
@@ -195,6 +200,30 @@ out:

__setup("log_buf_len=", log_buf_len_setup);

+/*
+ * Set up to wait forever for the console to appear
+ * @str: Ignored
+ * Returns one.
+ */
+static int __init consolewait_setup(char *str)
+{
+ console_wait = true;
+ return 1;
+}
+__setup("consolewait", consolewait_setup);
+
+/*
+ * Set the delay, in milliseconds, to wait for the console.
+ * @str: Pointer to the start of the delay value
+ * Returns one.
+ */
+static int __init consoledelay_setup(char *str)
+{
+ console_delay = simple_strtoul(str, NULL, 10);
+ return 1;
+}
+__setup("consoledelay=", consoledelay_setup);
+
#ifdef CONFIG_BOOT_PRINTK_DELAY

static unsigned int boot_delay; /* msecs delay after each printk during bootup */
@@ -1081,6 +1110,17 @@ struct tty_driver *console_device(int *index)
struct console *c;
struct tty_driver *driver = NULL;

+ /* The console device may not be initialized yet. We can either wait
+ * forever if consolewait is specified on the command line, or wait
+ * for some number of milliseconds if console_delay=msec is used */
+ if (console_wait)
+ wait_event(console_wq, preferred_console >= 0);
+
+ else if (wait_event_timeout(console_wq, preferred_console >= 0,
+ msecs_to_jiffies(console_delay)) == 0)
+ pr_warning("No preferred console after waiting %ld msec; "
+ "continuing anyway\n", console_delay);
+
acquire_console_sem();
for (c = console_drivers; c != NULL; c = c->next) {
if (!c->device)
@@ -1230,6 +1270,7 @@ void register_console(struct console *console)
spin_unlock_irqrestore(&logbuf_lock, flags);
}
release_console_sem();
+ wake_up_all(&console_wq);
}
EXPORT_SYMBOL(register_console);


2009-04-17 22:16:46

by H. Peter Anvin

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

David VomLehn wrote:
>>
> + consoledelay=mS [KNL] Wait up to mS milliseconds for the a preferred
> + console to be registered, then continue. Useful for
> + systems where a console may not be plugged in, such as
> + for USB serial devices.
> +

Pet peeve:

The symbol for millisecond is "ms". mS is a unit of conductance,
millisiemens.

-hpa

2009-04-17 23:13:21

by David VomLehn

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

On Fri, Apr 17, 2009 at 03:15:28PM -0700, H. Peter Anvin wrote:
> David VomLehn wrote:
>>>
>> + consoledelay=mS [KNL] Wait up to mS milliseconds for the a preferred
>> + console to be registered, then continue. Useful for
>> + systems where a console may not be plugged in, such as
>> + for USB serial devices.
>> +
>
> Pet peeve:
>
> The symbol for millisecond is "ms". mS is a unit of conductance,
> millisiemens.

Thanks for the info; this stuff does matter.

2009-04-20 21:33:24

by Andrew Morton

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

On Fri, 17 Apr 2009 14:31:48 -0700
David VomLehn <[email protected]> wrote:

> Parallelization to improve boot times has been successful enough that race
> conditions now exist between the init_post() open of /dev/console and
> initialization of the console device. When this occurs, opening /dev/console
> fails and any applications inherited from init have no standard in/out/error
> devices. This is expected behavior if no console device is available, but
> quite unfortunate in the case where the console is just a bit slow waking up.
>
> Some buses, such as USB, offer no guarantees about how long it takes to
> discover devices, so there is no reliable way to distinguish between a missing
> console and a slow one. The pragmatic approach taken in this patch is to
> wait for a while to see if a console shows up, and just go on if it doesn't.
> The default delay is 1000 msec (1 second).
>
> There are two new command line parameters:
> consolewait Wait forever for a console to be registered
> consoledelay=msec Use the given number of milliseconds as the delay
> interval instead of the default

This is all pretty nasty, isn't it?

Let's step back for a bit from any implementation and ask "what is the
ideal behaviour"? I think it's one of

a) we permit init_post()'s open() to succeed. Console output is
buffered by the kernel (could be in the printk log_buf). When the
initial console is eventually registered, we flush all the queued
characters into it.

b) we block in init_post(), waiting for the initial console to
become available.

I think b) is better. Simpler, safer, less likely for information loss
if the kernel were to crash in that delay window.

Am I right? Did I miss any options?

If we want b) then how to do it?

One possibility: the initcalls have been completed when init_post() is
called. How about: if one of those initcalls will be asynchronously
registering a console, it should inform the console layer about this.
It should call the new i_will_be_adding_a_console_soon() function
within its initcall. The console subsystem will remember this, and we
can cause init_post() to block until that registration has occurred.

We'll need to be able to handle errors, and we'll need to be able to
handle the case where the initcall function isn't sure whether or not
it will be registering a console. So there will also need to be an
oops_im_not_adding_a_console_after_all() function, which will withdraw
the effects of i_will_be_adding_a_console_soon().

Which means that i_will_be_adding_a_console_soon() will need to return
a handle for the oops_im_not_adding_a_console_after_all() caller to
pass.

If init_post() is currently blocked awaiting the arrival of the
console, oops_im_not_adding_a_console_after_all() will unblock
init_post() if there are no more potential console registrations
pending, and inti_post()'s attempt to open a console will fail.


Or something like that?

2009-04-20 21:51:30

by Alan Stern

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

On Mon, 20 Apr 2009, Andrew Morton wrote:

> If we want b) then how to do it?
>
> One possibility: the initcalls have been completed when init_post() is
> called. How about: if one of those initcalls will be asynchronously
> registering a console, it should inform the console layer about this.
> It should call the new i_will_be_adding_a_console_soon() function
> within its initcall. The console subsystem will remember this, and we
> can cause init_post() to block until that registration has occurred.
>
> We'll need to be able to handle errors, and we'll need to be able to
> handle the case where the initcall function isn't sure whether or not
> it will be registering a console. So there will also need to be an
> oops_im_not_adding_a_console_after_all() function, which will withdraw
> the effects of i_will_be_adding_a_console_soon().
>
> Which means that i_will_be_adding_a_console_soon() will need to return
> a handle for the oops_im_not_adding_a_console_after_all() caller to
> pass.
>
> If init_post() is currently blocked awaiting the arrival of the
> console, oops_im_not_adding_a_console_after_all() will unblock
> init_post() if there are no more potential console registrations
> pending, and inti_post()'s attempt to open a console will fail.
>
>
> Or something like that?

What if a subsystem simply doesn't know in advance whether or not it's
going to register a console? Or doesn't know when it has finished
probing all devices (since a new device could be plugged in at any
time)?

Not to mention that this scheme appears more complicated than the one
it's intended to replace... although it doesn't have any boot-line
parameters.

Personally, I'm in favor of adding a boot parameter. Things could be
simplified slightly by treating a negative value (or a missing value)
as indicating an infinite timeout; then only one new parameter would be
needed instead of two.

Alan Stern

2009-04-20 22:30:47

by David VomLehn

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

> Personally, I'm in favor of adding a boot parameter. Things could be
> simplified slightly by treating a negative value (or a missing value)
> as indicating an infinite timeout; then only one new parameter would be
> needed instead of two.

I'm allergic to the idea of a user interface using negative one to mean
infinity. It's an bizzare idea that makes sense only to programming
wankers. Such as ourselves. Having a missing value mean infinitity is a
not whole lot better.

I do agree with the idea of adding one boot parameter rather than two. How
about keeping the consoledelay parameter, but allow it to either take a
string, such as "forever", or an integer, which is the number of milliseconds
to delay? I think that will make sense to a lot more people.

Note that, as far as the implementation goes, using a -1 to mean an infinite
wait may very well make sense. I just don't think it makes sense where decent
people can see it.
--
David VomLehn

2009-04-20 22:30:25

by Andrew Morton

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

On Mon, 20 Apr 2009 17:51:16 -0400 (EDT)
Alan Stern <[email protected]> wrote:

> On Mon, 20 Apr 2009, Andrew Morton wrote:
>
> > If we want b) then how to do it?
> >
> > One possibility: the initcalls have been completed when init_post() is
> > called. How about: if one of those initcalls will be asynchronously
> > registering a console, it should inform the console layer about this.
> > It should call the new i_will_be_adding_a_console_soon() function
> > within its initcall. The console subsystem will remember this, and we
> > can cause init_post() to block until that registration has occurred.
> >
> > We'll need to be able to handle errors, and we'll need to be able to
> > handle the case where the initcall function isn't sure whether or not
> > it will be registering a console. So there will also need to be an
> > oops_im_not_adding_a_console_after_all() function, which will withdraw
> > the effects of i_will_be_adding_a_console_soon().
> >
> > Which means that i_will_be_adding_a_console_soon() will need to return
> > a handle for the oops_im_not_adding_a_console_after_all() caller to
> > pass.
> >
> > If init_post() is currently blocked awaiting the arrival of the
> > console, oops_im_not_adding_a_console_after_all() will unblock
> > init_post() if there are no more potential console registrations
> > pending, and inti_post()'s attempt to open a console will fail.
> >
> >
> > Or something like that?
>
> What if a subsystem simply doesn't know in advance whether or not it's
> going to register a console? Or doesn't know when it has finished
> probing all devices (since a new device could be plugged in at any
> time)?

Fix it. It's trivial to make a sub-driver call back into a higher
layer to tell it that it registered a console. Or just do the
i_will_be_adding_a_console_soon()/oops_im_not_adding_a_console_after_all()
calls from the layer which _does_ know.

> Not to mention that this scheme appears more complicated than the one
> it's intended to replace... although it doesn't have any boot-line
> parameters.

It isn't very complicated.

Yes, a boot parameter is "simple" to inplement. But it's ghastly from
a usability POV. Especially if you care about boot times. For how
long do you delay? The user has to experiment with different delays
until he finds the magic number. Then he adds 10% and waits for the
inevitable failure reports to come in.

It's much better to just get it right, even if that makes it more
"complex".

2009-04-20 22:35:29

by David VomLehn

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

On Mon, Apr 20, 2009 at 03:14:00PM -0700, Andrew Morton wrote:
> On Mon, 20 Apr 2009 17:51:16 -0400 (EDT)
> Alan Stern <[email protected]> wrote:
...
> > What if a subsystem simply doesn't know in advance whether or not it's
> > going to register a console? Or doesn't know when it has finished
> > probing all devices (since a new device could be plugged in at any
> > time)?
>
> Fix it. It's trivial to make a sub-driver call back into a higher
> layer to tell it that it registered a console. Or just do the
> i_will_be_adding_a_console_soon()/oops_im_not_adding_a_console_after_all()
> calls from the layer which _does_ know.

In the case of the console, we already have register_console(), which is
what I'm using. I think your proposal will require adding code all over
the place. And buses such as USB simply have no way of knowing whether they
are done enumerating devices. A new device could take hours to come on line.

> Yes, a boot parameter is "simple" to inplement. But it's ghastly from
> a usability POV. Especially if you care about boot times. For how
> long do you delay? The user has to experiment with different delays
> until he finds the magic number. Then he adds 10% and waits for the
> inevitable failure reports to come in.
>
> It's much better to just get it right, even if that makes it more
> "complex".

With USB, you just can't *ever* get it right. There is no limit on how
long a device has to tell you its there. I wish this weren't the case,
but our good friends in the USB world tell us that we have been lucky
to have had USB consoles work as long as they have.
--
David VomLehn

2009-04-20 22:54:20

by Andrew Morton

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

On Mon, 20 Apr 2009 15:35:00 -0700
David VomLehn <[email protected]> wrote:

> On Mon, Apr 20, 2009 at 03:14:00PM -0700, Andrew Morton wrote:
> > On Mon, 20 Apr 2009 17:51:16 -0400 (EDT)
> > Alan Stern <[email protected]> wrote:
> ...
> > > What if a subsystem simply doesn't know in advance whether or not it's
> > > going to register a console? Or doesn't know when it has finished
> > > probing all devices (since a new device could be plugged in at any
> > > time)?
> >
> > Fix it. It's trivial to make a sub-driver call back into a higher
> > layer to tell it that it registered a console. Or just do the
> > i_will_be_adding_a_console_soon()/oops_im_not_adding_a_console_after_all()
> > calls from the layer which _does_ know.
>
> In the case of the console, we already have register_console(), which is
> what I'm using. I think your proposal will require adding code all over
> the place. And buses such as USB simply have no way of knowing whether they
> are done enumerating devices. A new device could take hours to come on line.

Add a timeout parameter to i_will_be_adding_a_console_soon(). (This
means that the how-long-to-wait-for policy is probably ahrd-coded into
the kernel which might be a problem).

> > Yes, a boot parameter is "simple" to inplement. But it's ghastly from
> > a usability POV. Especially if you care about boot times. For how
> > long do you delay? The user has to experiment with different delays
> > until he finds the magic number. Then he adds 10% and waits for the
> > inevitable failure reports to come in.
> >
> > It's much better to just get it right, even if that makes it more
> > "complex".
>
> With USB, you just can't *ever* get it right. There is no limit on how
> long a device has to tell you its there. I wish this weren't the case,
> but our good friends in the USB world tell us that we have been lucky
> to have had USB consoles work as long as they have.

Sigh, OK, I appreciate the problem better. But the proposed "solution"
is really quite fragile. I expect that it will only prove usable in
highly controlled hardware setups.

Is my option a) any use?

2009-04-20 22:55:32

by Andrew Morton

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

On Mon, 20 Apr 2009 15:29:48 -0700
David VomLehn <[email protected]> wrote:

> I do agree with the idea of adding one boot parameter rather than two.

zero parameters if at all possible, please...

2009-04-20 22:57:20

by Greg KH

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

On Mon, Apr 20, 2009 at 03:35:00PM -0700, David VomLehn wrote:
> With USB, you just can't *ever* get it right. There is no limit on how
> long a device has to tell you its there. I wish this weren't the case,
> but our good friends in the USB world tell us that we have been lucky
> to have had USB consoles work as long as they have.

Lucky? You all are _more_ than lucky. USB consoles was a bad hack
written on a drunken dare. I'm still constantly amazed that the thing
even works at all, let alone the fact that people are actually using it :)

The things I agree to over beers, you would think I would learn...

thanks,

greg k-h

2009-04-20 23:23:41

by David VomLehn

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

On Mon, Apr 20, 2009 at 03:50:33PM -0700, Andrew Morton wrote:
> On Mon, 20 Apr 2009 15:35:00 -0700
> David VomLehn <[email protected]> wrote:
>
> > On Mon, Apr 20, 2009 at 03:14:00PM -0700, Andrew Morton wrote:
> > > On Mon, 20 Apr 2009 17:51:16 -0400 (EDT)
> > > Alan Stern <[email protected]> wrote:
> > ...
> > > > What if a subsystem simply doesn't know in advance whether or not it's
> > > > going to register a console? Or doesn't know when it has finished
> > > > probing all devices (since a new device could be plugged in at any
> > > > time)?
> > >
> > > Fix it. It's trivial to make a sub-driver call back into a higher
> > > layer to tell it that it registered a console. Or just do the
> > > i_will_be_adding_a_console_soon()/oops_im_not_adding_a_console_after_all()
> > > calls from the layer which _does_ know.
> >
> > In the case of the console, we already have register_console(), which is
> > what I'm using. I think your proposal will require adding code all over
> > the place. And buses such as USB simply have no way of knowing whether they
> > are done enumerating devices. A new device could take hours to come on line.
>
> Add a timeout parameter to i_will_be_adding_a_console_soon(). (This
> means that the how-long-to-wait-for policy is probably ahrd-coded into
> the kernel which might be a problem).

Yes, it breaks one problem into a host of smaller problems.
>
> > > Yes, a boot parameter is "simple" to inplement. But it's ghastly from
> > > a usability POV. Especially if you care about boot times. For how
> > > long do you delay? The user has to experiment with different delays
> > > until he finds the magic number. Then he adds 10% and waits for the
> > > inevitable failure reports to come in.
> > >
> > > It's much better to just get it right, even if that makes it more
> > > "complex".
> >
> > With USB, you just can't *ever* get it right. There is no limit on how
> > long a device has to tell you its there. I wish this weren't the case,
> > but our good friends in the USB world tell us that we have been lucky
> > to have had USB consoles work as long as they have.
>
> Sigh, OK, I appreciate the problem better. But the proposed "solution"
> is really quite fragile. I expect that it will only prove usable in
> highly controlled hardware setups.
>
> Is my option a) any use?

I thought about option a). The problem is, given that it might take a very
long time for the console device to appear, you either have to buffer an
arbitrarily large amount of output or simply drop data on the floor. Dropping
log buffer output from printk is one issue, but what's more scary is that
you'll eventually lose data from innocent programs that you start running
from init.

I just don't see any great solutions here; what I've offered is one pragmatic
approach to coming to grips with the Great Unknowns of USB. As Greg KH says,
we're lucky it worked at all. My USB console broke a few months ago and my
primary focus has been to get things back to where, if we are as lucky as
we used to be, things will be no broken than they were. Hey, I'm an engineer,
not a miracle worker!
--
David VomLehn

2009-04-25 08:17:26

by Pavel Machek

[permalink] [raw]
Subject: Re: [Patch] Wait for console to become available, ver 3

Hi!

> Parallelization to improve boot times has been successful enough that race
> conditions now exist between the init_post() open of /dev/console and
> initialization of the console device. When this occurs, opening /dev/console
> fails and any applications inherited from init have no standard in/out/error
> devices. This is expected behavior if no console device is available, but
> quite unfortunate in the case where the console is just a bit slow waking up.
>
> Some buses, such as USB, offer no guarantees about how long it takes to
> discover devices, so there is no reliable way to distinguish between a missing
> console and a slow one. The pragmatic approach taken in this patch is to
> wait for a while to see if a console shows up, and just go on if it doesn't.
> The default delay is 1000 msec (1 second).
>
> There are two new command line parameters:
> consolewait Wait forever for a console to be registered
> consoledelay=msec Use the given number of milliseconds as the delay
> interval instead of the default

Could you use rootfsdelay for this? Root needs to be mounted for init
to run, so...?
Pavel

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html