[Debian-eeepc-devel] Using a pre-populated /dev for faster boot

Phil Endecott spam_from_debian_eee at chezphil.org
Thu Oct 16 23:42:52 UTC 2008


Hi everyone,

It's clear that it's possible to save a few seconds of boot time by 
using a pre-populated /dev, rather than letting udev populate it 
dynamically.  This would be simple in a "locked down" system where 
upgrades were impossible or monolithic, but it's harder to do neatly in 
Debian.  What I've done is not perfect, but it's a start and I thought 
I ought to write it up.

The existing code is in /etc/init.d/udev, which basically
- starts udevd
- runs udevadm trigger
- runs udevadm settle

The last two steps implement "coldplugging" - they generate hotplug 
events for the devices that were already attached when you started up, 
which mostly means things that are physically built in.  It's this 
coldplugging that takes the time; I still start udev and it looks after 
any genuinely hotplugged devices.  Also, I still use coldplugging for 
removeable devices that are already connected at boot - i.e. usb 
devices.  I do this by adding the option "--subsystem-match=usb" to the 
udevadm trigger call.  It's only the coldplugging for built-in devices 
that I've removed.

In order to pre-populate /dev with entries for the coldplugged devices, 
I have hacked /etc/init.d/udev to check for and untar a file called 
/etc/init-devs.tar.  If it doesn't find it, it falls back to the old 
behaviour.  If it does exist, after untarring it does coldplugging for 
only usb devices as described above.

More code in the same script generates the tar file if a sentinel file 
has been created asking it to do so.  The tar file should be generated 
early on as other steps in the boot process may change permissions on 
things in /dev.

It's important to remember that udev can be configured to carry out 
arbitrary actions.  So simply recording what /dev entries it created 
may not be sufficient in some cases.  The other thing that it commonly 
does is to load modules, but I've already bypassed that by building the 
drivers needed by built-in devices into the kernel.

Net devices are one class of things that do more than just create /dev 
nodes, so they need to be properly coldplugged.  But I've chosen to do 
that in a separate init script that runs much later, concurrent with X 
starting up.

Wireless networking causes further complications because this is the 
one thing that I have in a module.  I have currently hacked this based 
on its PCI ID to run during the later network coldplugging.

So in summary I have the following in /etc/init.d/udev; I hope it's 
obvious where it goes:

     log_daemon_msg "Starting the hotplug events dispatcher" "udevd"
     if udevd --daemon; then
         log_end_msg $?
     else
         log_end_msg $?
     fi

     mkdir -p /dev/.udev/queue/ /dev/.udev/rules.d/
     create_dev_root_rule /dev/.udev/

     # Pre-populate /dev if this file exists.  If you remove this
     # file you'll get the old behaviour.
     if [ -r /etc/init-devs.tar ]
     then
         echo "Installing initial devices"
         tar -x -C / -f /etc/init-devs.tar
         trigger_rules="--subsystem-match=usb"
     else
         trigger_rules="--subsystem-nomatch=net --attr-nomatch=vendor=0x1814"
     fi

     log_action_begin_msg "Synthesizing the initial hotplug events"
     if udevadm trigger $trigger_rules ; then
         log_action_end_msg $?
     else
         log_action_end_msg $?
     fi

     create_dev_makedev

     # wait for the udevd childs to finish
     log_action_begin_msg "Waiting for /dev to be fully populated"
     if udevadm settle; then
         log_action_end_msg 0
     else
         log_action_end_msg 0 'timeout'
     fi

     if [ -f /etc/create-init-devs ]
     then
         tar cf /dev/init-devs.tar /dev
         # /etc is read-only or something I think
     fi

and I have this in /etc/init.d/coldplug_networking:

         echo "Coldplugging network devices..."
         udevadm trigger --attr-match=vendor=0x1814
         udevadm trigger --subsystem-match=net
         udevadm settle
         echo "Coldplugging network done."

To use it, I touch /etc/create-init-devs, reboot, mv /dev/init-devs.tar 
/etc; rm /etc/create-init-devs.  If for some reason I want to 
regenerate the files (after a kernel upgrade perhaps?) I rm 
/etc/init-devs.tar and do it again.

I haven't used this much yet so if anyone can see any flaws please let 
me know.

The main time saving comes from doing the network startup concurrently 
with the X startup; I forget exactly what that saves because I did it a 
while ago, but it's perhaps 3 seconds (in part due to a sleep in 
net.agent).  The main /dev pre-population saves about 2 seconds.

I don't think I'm going to spend much more time on this fast boot 
exercise, but there are two things that still bother me:
- I want to get the kernel's 2 second probing of the touchpad off the 
critical path.
- Setting the clock takes up to a second.  But I don't think it would 
if we didn't have to use --directisa.  So can someone remind me why we 
do that?

I also look forward to improved X startup time using kernel mode 
setting, but I think I'll wait until someone else implements it.


Cheers,  Phil.






More information about the Debian-eeepc-devel mailing list