Re: [boot-time]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




Am 12.01.25 um 02:03 schrieb Rob Landley:
On 1/11/25 12:57, Bird, Tim wrote:
Hey Rob, This is a great review of /dev, /sys and the different
ways that /dev gets populated.

Feel free to link stuff from wikis or some such. The newest of those documents was written in 2007.

For a lot of embedded Linux devices, the only bus where
new items can show up dynamically is USB.

SDCARD readers connected via MMC are common in automtove head units as well ...



Yup, /sys/bus/usb/devices is in there too and when a driver binds to them, they wind up in /sys/block and such as well. (you USED to have to seprately mount a usbfs under /sys but they finally acknowledged that was silly about 5 years ago, hence https://askubuntu.com/questions/1218321/if-usbfs-has-been-deprecated-then-why-is-sys-bus-usb-drivers-usbfs-directory-p)

When a driver DOESN'T automatically bind to them it gets a bit complicated, and one of the things mdev can be configured to do is act as a firmware loader! Which is just... Ahem, there are YEARS of poor design decisions the kernel guys made, where they ignored a mechanism they already had an implemented something more complicated. The mechanism whereby the kernel opens a firmware file and read it directly out of the filesystem instead of calling a hotplug helper was... I'm just going to gloss over that.

WIFI & Bluetooth devices often use this firmware mechanism. And yes I agree, it looks a bit ** ugly** seeing the kernel loading a firmware file from /lib/firmware  searching it in the root file system w/o knowing the state of it during boot ... For WIFI and bluetooth I do not see a big issue here since I'd prevent putting such features on a critical chain by system design in any way since bringing them up and (re)connecting external devices is time consuming by nature. Nothing you shall need to wait for ...

Anyway, I saw patches go by ala https://patchwork.ozlabs.org/project/buildroot/patch/1436188175-7912-1-git-send-email-luca@xxxxxxxxxxxxxxxx/ which says it's from 2015. I haven't really tried to do it because I often know how the plumbing works and usually just implement a ten line hack rather than looking up how to configure the more generic tool. (Even the generic tool grew out of something I wrote 10 years earlier...)

Anyway, the kernel's "request module" plumbing tends to do a "give me usb-vendorID-deviceID thing, and then there's alias plumbing lookup that figures out what module name to insmod for that, and at various points I've seen said alias lookup plumbing A) in the kernel, B) in module headers, C) in modprobe config files under /etc or /lib or something.

*shrug* I build static kernels when given a choice, and don't source hardware that needs drivers WITHOUT built-in firmware, so I am WAY out of date on that stuff.

Compiling in modules vs. loading them later from user space is a trade-off. The effect of putting stuff into modules is to keep the kernel small which helps you in the "unpacking & loading kernel" phase before the kernel is actually started. Having an 1MB unpacked kernel is significantly a difference to a 5MB one. On the other hand, my experience is that there is lot of overhead (CPU time and IO) loading modules from user space. So it really only makes sense, if you have drivers to load at a point in time during startup where you have enough time and resources left.

I remember enough to look it up but not the details off the top of my head. And I say that as someone who really SHOULD care more:

http://lists.landley.net/pipermail/toybox-landley.net/2024-October/030549.html

It's on the todo list...

I've always thought the best solution (in terms of boot time)
was to use static nodes in /dev during early boot (that is, just
mknod the /dev nodes in the rootfs manually, and have them be present
before the kernel even runs).  No dynamic discovery or boot-time
population of /dev needed.

The system knows what devices are available. While you can mknod a major:minor node the kernel doesn't have a driver for, if you open it you get some sort of -EWTF where the kernel goes "nope".

The kernel has a CONFIG_DEVTMPFS_MOUNT that automatically mounts devtmpfs on /dev, but for SOME reason it doesn't apply to initramfs. I've been irregularly posting a patch to MAKE it apply on and off for most of a decade now:

https://lkml.iu.edu/hypermail/linux/kernel/2005.1/09399.html

And it's part of my mkroot kernel patches:

https://landley.net/bin/mkroot/latest/linux-patches/0003-Wire-up-CONFIG_DEVTMPFS_MOUNT-to-initramfs.patch

But Greg KH. Oh well...

Then, sometime later, use either
mdev or devtmpfs to accumulate (and remove?) other
runtime-plugged devices.  This can be done after the time-critical
phase of booting.

Does this overall approach work, or is there some in-kernel
connections that may be missing if the dynamic tools are
not used from startup?

I mean it more or less works, it's just... pointless manual maintenance of something the kernel does for you in a very small amount of code? (In devtmpfs, the /dev node being there means something. In a static /dev, it doesn't.)

I agree. There is kind of dynamic device enumeration done by the kernel drivers anyway once loaded. Any data structures to devices are build up internally. Nothing you can save ...

I'm even not sure how devtmpfs can be combined w/ your static devnodes you created in any kind of persistent partition. And if you even can get the kernel accepting your partition to use as /dev, you need to have it writeable for the case of dynamics you might need (usb for instance) which does not really go well with a read only RFS ... You could ... overlay fs ... well no, I think this goes into a wrong direction -> too complicated ;)


So: I blather on a lot about my mkroot project, which is a 400 line bash script that builds tiny linux system that boots to shell prompt (mostly under qemu) on a dozen different architectures. And the init script in that starts here:

https://github.com/landley/toybox/blob/master/mkroot/mkroot.sh#L102

And you see how the script does this setup (which is only needed when you don't apply my patch to the kernel):

if ! mountpoint -q dev; then
  mount -t devtmpfs dev dev
  [ $$ -eq 1 ] && ! 2>/dev/null <0 && exec 0<>/dev/console 1>&0 2>&1
  for i in ,fd /0,stdin /1,stdout /2,stderr
  do ln -sf /proc/self/fd${i/,*/} dev/${i/*,/}; done
  mkdir -p dev/shm
  chmod +t /dev/shm
fi

(Don't ask me why devtmfs doesn't automatically have a "shm" directory with the sticky bit, it's a subclass of tmpfs so it does the right thing when it's there. And the middle two lines are just making /dev/{stdin,stdout,stderr} because toysh doesn't special case /dev/stdin like bash does so needs it in the filesystem if you're gonna use that.)

But that exec redirect line hit a bug, because when you don't have devtmpfs automounting but ALSO don't have /dev/console in your statically linked initramfs image... oh here, I explained it when I fixed it:

https://github.com/landley/toybox/commit/0b2d5c2bb3f1

https://landley.net/notes-2024.html#06-08-2024

tl;dr in usr/main.c the kernel tries to open /dev/console and fails if it's not already there, so PID 1 starts with stdin, stdout, and stderr closed, so if something goes wrong in early boot init can't tell you why it failed. This ONLY happens with static initramfs (created with cpio as a normal user and you can't mknod without root access), because of COURSE the kernel has two different codepaths for static vs dynamic, and the dynamic one does a manual fixup for this issue. No really!

https://github.com/torvalds/linux/blob/master/init/noinitramfs.c#L18

And of course the code doing the fixup runs for ANY system that doesn't have a static linked initramfs, including one where the bootloader points it at an EXTERNAL cpio.gz image like qemu -initrd blah.cpio.gz, because it checks for the external one AFTER doing the fixup. (Pop quiz: if you have static _and_ external initrd, and they include the same file, does the old one prevent the new one from extracting, does the new one replace the old one, or does the new one APPEND to the old one? At various points in history, it's done ALL THREE! I forget which is current, replace I think?) So external initramfs and built-in initramfs behave DIFFERENTLY in a subtle sharp edge ath I've complained at them about for YEARS...

*shrug* I make this stuff work in as simple a way as I know how. Been doing it for an embarrassingly long time now. But you _reach_ simple by process of elimination, and proving a negative is a lot of work.

Thanks,
  -- Tim


Rob

To summarize from my point of view:

* It's worth talking a bit about the effect of udev and about alternatives

* "mdev" is surely worth being named as an potential option besides "selective triggering" and "static setup and moving triggers back in time"

* I wouldn't regard mknode as an real alternative in todays system

* In addition I can imagine is "modules loading" vs. "compiling in drivers" something which is worth mentioning

* Once I've access to the wiki, I can try to put these ideas into an initial structure filled up w/ info we discussed in this thread

Marko





[Index of Archives]     [Gstreamer Embedded]     [Linux MMC Devel]     [U-Boot V2]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux ARM Kernel]     [Linux OMAP]     [Linux SCSI]

  Powered by Linux