FS#10483 - [mkinitcpio] initcpio script's rootdelay parameter should be renamed or reworked

Attached to Project: Arch Linux
Opened by Bryan Ischo (bji) - Saturday, 24 May 2008, 06:47 GMT
Last edited by Thomas Bächler (brain0) - Sunday, 07 February 2010, 20:54 GMT
Task Type Feature Request
Category Packages: Core
Status Closed
Assigned To Tobias Powalowski (tpowa)
Aaron Griffin (phrakture)
Thomas Bächler (brain0)
Architecture All
Severity Medium
Priority Normal
Reported Version 2007.08-2
Due in Version Undecided
Due Date Undecided
Percent Complete 100%
Votes 1
Private No

Details

Description:

The purpose of the rootdelay kernel parameter is to cause the kernel to delay for the specified number of seconds before mounting the root device, to allow devices which need to be discovered before the mount can succeed to be discovered.

The init script and filesystem hook of the initcpio scripts (located in /lib/initcpio, and used by mkinitcpio to create the boot ramdisk image) also use rootdelay to pause before using the root device, for the same reason.

The thing about this delay is, if it's done by the initial ramdisk init scripts, then it doesn't need to be done by the kernel - the device, if the ramdisk init scripts ensure that it is valid (which they do), does not need to be waited on by the kernel as well.

The end result is an extra unnecessary delay in bootup. One of the great things about Arch Linux is how fast it boots, and an unnecessary 8 second (or more) delay kind of sucks.

I can think of three ways to solve this problem:

1) The easy way: just have the initcpio scripts base their delay off of a parameter that does not conflict with the kernel's rootdelay parameter. For example, rename it to "udevdelay". I tested this solution in my own Arch installation and it works perfectly. I just set a kernel parameter "udevdelay=8" and *don't* set any rootdelay parameter, and also modified the initcpio scripts to expect udevdelay instead of rootdelay, and - bingo, my device is properly waited on and the initcpio scripts work fine, and then the kernel doesn't bother to do any extra delay before mounting root and my boot works perfectly and is faster.

2) Continue to use rootdelay but have some way to strip it from the kernel's parameters before continuing on to the part where the kernel mounts the root filesystem. I don't know if this is even possible, but it would allow the rootdelay parameter to be used exclusively by the initcpio scripts. I don't think this is a very attractive solution anyway.

3) Implement "wait" logic for causing the initcpio scripts to poll for the existence of the root disk device rather than doing what they currently do, which is to (optionally) wait a specified length of time and then try to manually create the device if it doesn't exist. This could be a new behavior invoked by a kernel argument like "waitroot=30", which if set, would cause the initcpio scripts do invoke this logic (the 30 means wait at most 30 seconds) instead of the normal test-and-create-root-device logic:

COUNTER=0
while [ ! -b "${root}" -a $COUNTER -lt "${waitroot}" ]; do
sleep 1;
done

I think this is the best solution of all, because it gives users the option to simply wait until their root device is detected, rather than having to guess a delay that may often be much more than needed, but sometimes still not be enough.

Additional info:
* package version(s)
* config and/or log files etc.

Relevent packages:

kernel26 2.6.24.4-1
mkinitcpio 0.5.18.1-1
grub 0.97-12

Steps to reproduce:

Add a parameter "rootdelay=10" to your grub kernel line.

Boot from a USB device (this problem may not be evident if you are booting from a device which is immediately known to the kernel rather than having to be queried for, because I think the initcpio scripts detect when the device is already there and don't do the rootdelay).

Observe that there is a 10 second pause during the initcpio script run (which is acceptable), and also that the kernel later pauses before mounting the root device (which is unnecessary and slows the boot down).

This task depends upon

Closed by  Thomas Bächler (brain0)
Sunday, 07 February 2010, 20:54 GMT
Reason for closing:  Implemented
Additional comments about closing:  I did this a while ago, and there was no response indicating it was a bad idea. Closing.
Comment by Bryan Ischo (bji) - Saturday, 24 May 2008, 06:49 GMT
Oh my script logic was wrong; it would be something like this:

<pre>
COUNTER=0
while [ ! -b "${root}" -a $COUNTER -lt "${waitroot}" ]; do
sleep 1;
COUNTER=$[COUNTER+1];
done
</pre>

If there is agreement from the Linux Arch crew that this "waitroot" parameter is a good idea (and maybe someone could suggest a better name, I'm OK with anything reasonable), then I can even implement this and submit a patch for mkinitcpio for you guys to verify and check in ...
Comment by Aaron Griffin (phrakture) - Saturday, 24 May 2008, 22:11 GMT
Can you verify that the kernel is actually using rootdelay? If it is a kernel param that is used _before mounting the root device_ and we are NOT letting the kernel mount a root device (we are doing it ourselves), then it doesn't make sense that the kernel is doing this too.

What I mean is this: when using initramfs, the kernel skips ALL of that code that mounts root devices.
Comment by Aaron Griffin (phrakture) - Saturday, 24 May 2008, 23:24 GMT
Additionally, if we were to implement wait functionality, I would do it in C (klibc-extras) so we have a utility to poll for any device node. /me shrugs
Comment by Bryan Ischo (bji) - Sunday, 25 May 2008, 06:38 GMT
In terms of whether or not the kernel uses rootdelay, I am pretty sure that it does, although I am not super familiar with the kernel code involved. In init/do_mounts.c, starting with kernel 2.6.11, the kernel obeys the rootdelay parameter in the prepare_namespace() function, which prints out:

"Waiting %d sec before mounting root device...\n"

right before sleeping. I have definitely seen this message printed out from my Arch Linux boot when I had rootdelay set, and the kernel did seem to wait 8 seconds at that point.

I don't see anywhere in the /lib/initcpio directory that the 'mount' command is used, except in the encrypt hook (and in init where /sys and /proc are mounted). So I think that the kernel really is doing the mount. My reading of the /lib/initcpio files is that they attempt to ensure that the root device exists before handing control over to the kernel to actually mount it, but they don't do the mounting themselves.

From what I can tell, the initcpio scripts are just trying to verify that the root device exists, and create it (with the help of the /usr/lib/klibc/bin/parseblock program, whose sole purpose as far as I can tell is to detect what the major and minor numbers of a 'standard' disk device would be, such as for /dev/sdc1 and the like, so that the initcpio scripts can create it just by knowing that it needs to exist because the user named it as the root device in their kernel parameters). This whole process does not work for /dev/disk/by-uuid devices, because parseblock has no idea what the major and minor device numbers of such a device would be. So the initcpio scripts really don't do anything useful for me in this circumstance; I just want them to do nothing because they can't create my device for me if it doesn't exist, and the kernel will obey rootdelay and wait for the device for me before mounting it anyway.

The only useful thing I can see the initcpio scripts doing for me if I use a udev-named device file like /dev/disk/by-uuid/xxxxx, is providing a 'better' "rootdelay" type behavior: polling until the device exists. The linux kernel could do this too and I think it would be a better implementation of rootdelay also. But until the kernel provides this functionality, it is something that the initcpio scripts could provide.

Also I don't understand what you mean when you say that you would want to do it in klibc-extras. I'm not talking about some generic funtionality for polling for device nodes. I'm talking about the specific logic in the /lib/initcpio/init script which I think could be improved. If this script is not supposed to be checking for the existence of root device files and making them if necessary, then all of that logic should just be taken out. But if it is supposed to be doing that stuff, then I'm simply proposing a better way to do it - using polling instead of a fixed delay period.
Comment by Aaron Griffin (phrakture) - Monday, 26 May 2008, 17:19 GMT
Well, I know that the do_mounts code is skipped when using initramfs. It may, however, be used in kinit itself. Glancing at the code real quick, if we have rootdelay, we sleep and then export rootdelay=0. I will have to investigate this a little more.

Regarding parseblock failing for uuid-based devices, that's another issue (would you mind opening another bug report regarding that? I like the one-bug-per-report thing)
Comment by Bryan Ischo (bji) - Monday, 26 May 2008, 18:24 GMT
I have created a separate bug for the parseblock issue, it is  FS#10509 .

I agree that it seems like the mount is happening in kinit itself, and I also agree that the init script does set rootdelay=0 before invoking kinit. However, I think that the init script re-setting this value to zero somehow does not affect the actual parameter being passed to the kernel's mounting functions. Perhaps this is the real problem.

Don't you agree that a polling interval would be even better than a rootdelay though? I modified my own init script to poll for the root device if it does not exist (only if a new boot parameter 'rootpoll' is set) and it works great. It only ever has to wait long enough for the device to be created by udevd, it doesn't have to wait a fixed amount of time which may be too long in most cases but still sometimes not long enough. I think this is a good feature to include in the init script.
Comment by Aaron Griffin (phrakture) - Tuesday, 27 May 2008, 19:51 GMT
Yes, polling is definitely a better idea, and I want to implement something of the sort. Could you perhaps attach a git patch for the changes you have made, so I can review?
Comment by Bryan Ischo (bji) - Tuesday, 27 May 2008, 20:14 GMT
Absolutely. I will do so later tonight (US Pacific time). It may take me some time because I have to set up git (which I have never used before) and pull sources and such. But I will be happy to do so.
Comment by Bryan Ischo (bji) - Thursday, 05 June 2008, 07:51 GMT
Sorry for the delay. Some stuff came up. Anyway, here is a patch that implements the rootpoll parameter. A few things of note:

* The rootdelay parameter is converted to rootpoll if rootdelay is set but rootpoll is not. The idea is that rootpoll does everything that rootdelay does, but better, so if the user has rootdelay set, we'll still poll instead of just sleeping a fixed number of seconds. However, using rootdelay means that the kernel will also sleep unnecessarily so it' still a worse option and the user is notified that it would be better to use rootpoll than rootdelay.

* I removed the duplicated logic in init that is also in filesystems. Basically, it doesn't make any sense to me that filesystems would have the same logic that init does. So filesystems becomes necessary if you need to do one or both of the following:

- Wait for a device to become ready that may take time, such as usb or fw
- Load a kernel module for the root filesystem type

init doesn't need to do any of this stuff; if this stuff is expected to be done, then you must include the filesystems hook. You may also include the udev hook if you are using udev style root device names (and you should be). The redundancy of this logic in init and filesystems is a maintainance issue that I think is best handled by simply requiring users to use the filesystems hook if that's what they need.

I tested this on my usb flash drive boot and it works great. I think that someone using a normal hard drive device that isn't polled for should test these changes also.

Comments welcome. Thanks.
Comment by Glenn Matthys (RedShift) - Friday, 05 December 2008, 22:17 GMT
What's the status of this issue?
Comment by Bryan Ischo (bji) - Saturday, 06 December 2008, 01:35 GMT
The status is: waiting for Arch developers to incorporate the patch into Arch.

More details: a patch for this issue was submitted about 7 months ago. The Arch developers have not commented on this patch, provided any feedback, or done anything to resolve this bug.
Comment by Thomas Bächler (brain0) - Saturday, 06 December 2008, 08:35 GMT
It seems I have never before looked at this bug report, although it was assigned to me. A short look at your patch tells me I generally like the idea.

I don't like that the code is added twice (once in init, once in the filesystem hook), but that can be easily solved by completely removing the filesystem hook (which I wanted to do over a year ago, it's an unnecessary piece of shit).

Another thing that is related: If you use encryption, this delay should rather be added before opening the encrypted device than before running kinit. The best thing would be to add a function wait_for_device which takes a device as parameter and does what your script is doing, so it could be used in several hooks.
Comment by Bryan Ischo (bji) - Saturday, 06 December 2008, 09:56 GMT
Thank you for your response. Please feel free to use my patch as an example of how to accomplish the goal of improving the wait behavior for USB root devices, while incorporating whatever other improvements you think are worthwhile in the scripts.

I agree that the boot scripts have undesireable redundancy, and it's rather unsavory to fix this USB device waiting problem without also cleaning up the scripts a bit to eliminate some code duplication.

It's not hard at all to implement the "rootpoll" behavior I have described, and I think it is a great addition to the scripts, because it makes booting from "discovered at boot time" devices much faster and more reliable.

So to summarize: I thank you for your comments, which I agree with. My patch can be used as an example of how this problem would be solved, but you are more than welcome to re-implement the fix in a way that is more maintainable and re-usable, rather than just using my patch directly.
Comment by Aaron Griffin (phrakture) - Monday, 08 December 2008, 23:37 GMT
Thomas: Would you be willing to make these changes? Remove the filesystem hook, and add in some sort of polling mechanism? Should be fairly easy
Comment by Thomas Bächler (brain0) - Tuesday, 09 December 2008, 10:14 GMT
Yeah, I gotta finish my thesis this week, so I'll probably get around to fixing up mkinitcpio around Christmas. I will definitely implement this rootpoll behaviour and some other things that are annoying about mkinitcpio.
Comment by Thomas Bächler (brain0) - Sunday, 07 June 2009, 12:23 GMT

Loading...