Comment 7 for bug 901038

Revision history for this message
James Hunt (jamesodhunt) wrote :

I believe the problem here is that although upgrading the Upstart package itself and any of its dependent library packages will force a stateful re-exec, that operation severs all D-Bus connections (since D-Bus does not provide a way to serialise objects such as DBusConnection) and crucially that operation is async...

= Scenario causing this Bug =

I think the behaviour these bugs are caused by is something like:

1) dpkg upgrades Upstart (or one of its dependent libraries).
2) The relevant postinst maintainer script requests Upstart re-exec itself.
3) The re-exec starts (asynchronously).
4) dpkg moves on to installing/upgrading other packages.
5) invoke-rc.d, called from a maintainer script from another package decides it needs to call start(8) or initctl(8) for example.
6) The appropriate command is run (start/initctl), but fails since Upstart is still finishing re-exec'ing itself.

= Thoughts =

== Tweak invoke-rc.d ==

One possible fix would be to modify invoke-rc.d so that before attempting to run start etc, it first checks that Upstart is contactable by waiting for a "reasonable amount of time" for Upstart to respond (assuming it could be in the process of being re-exec'ed). However, that could be unreliable unless that check occurred before *every* call to initctl/start/stop/restart/reload-configuration. This is achievable but would clutter the code a little.

== Create a dpkg Upstart trigger ==

Another option might be to create a dpkg trigger to handle restarting upstart and have that trigger call 'telinit u' *and then wait* again for that "reasonable amount of time" until Upstart responds before the trigger ends. This sounds attractive since the logic for restarting and waiting is contained in one location. However, if my understanding of triggers is correct (?) this would actually cause another problem: since Upstart grew the ability to re-exec, the expected behaviour is that "as soon as Upstart has been upgraded, the running version of Upstart will match the installed version of Upstart". Using a trigger would break this understanding since the Upstart restart would only occur *after* all the other packages (that declare an interest in the upstart trigger) have been updated.

== Modify initctl ==

A third option could be to modify initctl to make it retry on failure to connect. This could in fact be the default since on a normally working system, there would be no behaviour change. Then, when invoke-rc.d calls initctl/start/etc, it should DTRT under all scenarios.

= Plan =

Short term, tweaking invoke-rc.d is probably the most pragmatic (albeit potentially racy) solution. Long term, we should modify initctl.