anatol/booster

RFE: support systemd InitRDTimestampMonotonic

Closed this issue · 6 comments

systemd dbus api has a property InitRDTimestampMonotonic which provides the initrd boot timing information, when using supported initrd images such as those generated by mkinitcpio, for utilities like systemd-analyze to report.

I'm not totally sure what is required here, but I believe https://systemd.io/INITRD_INTERFACE/ may be relevant. Including a (possibly empty) /etc/initrd-release in the image may be all that is needed.

I looked through the systemd sources and the initrd timing recording happens in https://github.com/systemd/systemd/blob/master/src/core/main.c#L2616

if (in_initrd())
   initrd_timestamp = userspace_timestamp;
...
m->timestamps[MANAGER_TIMESTAMP_INITRD]

and then this timestamp is exported via DBus.

It looks like this main() code is called twice. First time from initrd and then from the normal userspace. But it is not clear for me how the dbus properties survive initrd->userspace switch. Does it assume that dbus process is started in inird and later used in userspace?

Intresting enough that long time ago systemd had RD_TIMESTAMP envvar passed from inird to userspace init. It would be easy for us to implement such approach. But it got removed unfortunately systemd/systemd@c72aadd

Okay, here's what I found on further investigation:

In this sequence: main() -> invoke_main_loop() -> prepare_reexecute() -> manager_serialize() the manager is serialized, including the timestamps recorded earlier in the line in your comment. It writes the serialization to a fd opened with memfd_create [1] (and MFD_CLOEXEC, so presumably it's dup'd somewhere but I didn't see where).

Then in the do_reexecute() function, the new init is invoked with --deserialize <fd> argument with the fd of the previously recorded manager state [2] and the initrd timestamps are recovered. I think it's later that dbus is started in userspace and the value may be exported.

So booster would need to include the initrd-release file and invoke systemctl switch-root like the page says.

EDIT: mkinitcpio uses util-linux's switch_root and it works for them, so I'm not quite sure what's required. I'm a bit too fuzzy on the sequence of events in the initrd / early userspace to say how it should work.

EDIT2: Actually the systemd hook (which I had been using) installs systemd as init.

[1] https://github.com/systemd/systemd/blob/87cc47ba1d3a4016e84eb1b3f6bddf76266bf978/src/core/manager.c#L3151
[2] https://github.com/systemd/systemd/blob/87cc47ba1d3a4016e84eb1b3f6bddf76266bf978/src/core/main.c#L1762

@rpigott any chance you can pull #4 and try if it fixes this issue for you?

It writes the serialization to a fd opened with memfd_create [1] (and MFD_CLOEXEC, so presumably it's dup'd somewhere but I didn't see where).

It unsets MFD_CLOEXEC flag here https://github.com/systemd/systemd/blob/87cc47ba1d3a4016e84eb1b3f6bddf76266bf978/src/core/main.c#L1154

Hmm I wonder if the serialization format is a reliable interface.

TBH I think I'd rather have the minimal init + no initrd timestamp OR systemd init + timestamp than try to get systemd init to deserialize a constructed manager state from booster.

Passing initrd start time in the serialized format exists since at least 2013 (an it seems it was implemented as early as 2010). So it looks like a pretty stable interface. But if its stability becomes an issues for booster then other options proposed by you could be explored.